summaryrefslogtreecommitdiff
path: root/ext/node/polyfills/internal/crypto/pbkdf2.ts
blob: 5cf102fa98ea12be84ff7dae6e93e339c3ab5c4d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.

// TODO(petamoriken): enable prefer-primordials for node polyfills
// deno-lint-ignore-file prefer-primordials

import { op_node_pbkdf2, op_node_pbkdf2_async } from "ext:core/ops";

import { Buffer } from "node:buffer";
import { HASH_DATA } from "ext:deno_node/internal/crypto/types.ts";

export const MAX_ALLOC = Math.pow(2, 30) - 1;

export type NormalizedAlgorithms =
  | "md5"
  | "ripemd160"
  | "sha1"
  | "sha224"
  | "sha256"
  | "sha384"
  | "sha512";

export type Algorithms =
  | "md5"
  | "ripemd160"
  | "rmd160"
  | "sha1"
  | "sha224"
  | "sha256"
  | "sha384"
  | "sha512";

/**
 * @param iterations Needs to be higher or equal than zero
 * @param keylen  Needs to be higher or equal than zero but less than max allocation size (2^30)
 * @param digest Algorithm to be used for encryption
 */
export function pbkdf2Sync(
  password: HASH_DATA,
  salt: HASH_DATA,
  iterations: number,
  keylen: number,
  digest: Algorithms = "sha1",
): Buffer {
  if (typeof iterations !== "number" || iterations < 0) {
    throw new TypeError("Bad iterations");
  }
  if (typeof keylen !== "number" || keylen < 0 || keylen > MAX_ALLOC) {
    throw new TypeError("Bad key length");
  }

  const DK = new Uint8Array(keylen);
  if (!op_node_pbkdf2(password, salt, iterations, digest, DK)) {
    throw new Error("Invalid digest");
  }

  return Buffer.from(DK);
}

/**
 * @param iterations Needs to be higher or equal than zero
 * @param keylen  Needs to be higher or equal than zero but less than max allocation size (2^30)
 * @param digest Algorithm to be used for encryption
 */
export function pbkdf2(
  password: HASH_DATA,
  salt: HASH_DATA,
  iterations: number,
  keylen: number,
  digest: Algorithms = "sha1",
  callback: (err: Error | null, derivedKey?: Buffer) => void,
) {
  if (typeof iterations !== "number" || iterations < 0) {
    throw new TypeError("Bad iterations");
  }
  if (typeof keylen !== "number" || keylen < 0 || keylen > MAX_ALLOC) {
    throw new TypeError("Bad key length");
  }

  op_node_pbkdf2_async(
    password,
    salt,
    iterations,
    digest,
    keylen,
  ).then(
    (DK) => callback(null, Buffer.from(DK)),
  )
    .catch((err) => callback(err));
}

export default {
  MAX_ALLOC,
  pbkdf2,
  pbkdf2Sync,
};