2024-01-01 14:58:21 -05:00
|
|
|
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
2023-06-27 02:18:22 -04:00
|
|
|
|
|
|
|
// TODO(petamoriken): enable prefer-primordials for node polyfills
|
|
|
|
// deno-lint-ignore-file prefer-primordials
|
|
|
|
|
2024-01-29 08:58:08 -05:00
|
|
|
import { op_node_pbkdf2, op_node_pbkdf2_async } from "ext:core/ops";
|
2024-01-10 17:37:25 -05:00
|
|
|
|
2023-07-02 14:19:30 -04:00
|
|
|
import { Buffer } from "node:buffer";
|
2023-03-08 06:44:54 -05:00
|
|
|
import { HASH_DATA } from "ext:deno_node/internal/crypto/types.ts";
|
2024-07-05 04:10:22 -04:00
|
|
|
import {
|
|
|
|
validateFunction,
|
|
|
|
validateString,
|
|
|
|
validateUint32,
|
|
|
|
} from "ext:deno_node/internal/validators.mjs";
|
|
|
|
import { getArrayBufferOrView } from "ext:deno_node/internal/crypto/keys.ts";
|
|
|
|
import {
|
|
|
|
ERR_CRYPTO_INVALID_DIGEST,
|
|
|
|
ERR_OUT_OF_RANGE,
|
|
|
|
} from "ext:deno_node/internal/errors.ts";
|
2023-02-14 11:38:45 -05:00
|
|
|
|
|
|
|
export const MAX_ALLOC = Math.pow(2, 30) - 1;
|
2024-07-05 04:10:22 -04:00
|
|
|
export const MAX_I32 = 2 ** 31 - 1;
|
2023-02-14 11:38:45 -05:00
|
|
|
|
|
|
|
export type NormalizedAlgorithms =
|
|
|
|
| "md5"
|
|
|
|
| "ripemd160"
|
|
|
|
| "sha1"
|
|
|
|
| "sha224"
|
|
|
|
| "sha256"
|
|
|
|
| "sha384"
|
|
|
|
| "sha512";
|
|
|
|
|
|
|
|
export type Algorithms =
|
|
|
|
| "md5"
|
|
|
|
| "ripemd160"
|
|
|
|
| "rmd160"
|
|
|
|
| "sha1"
|
|
|
|
| "sha224"
|
|
|
|
| "sha256"
|
|
|
|
| "sha384"
|
|
|
|
| "sha512";
|
|
|
|
|
2024-07-05 04:10:22 -04:00
|
|
|
function check(
|
|
|
|
password: HASH_DATA,
|
|
|
|
salt: HASH_DATA,
|
|
|
|
iterations: number,
|
|
|
|
keylen: number,
|
|
|
|
digest: string,
|
|
|
|
) {
|
|
|
|
validateString(digest, "digest");
|
|
|
|
password = getArrayBufferOrView(password, "password", "buffer");
|
|
|
|
salt = getArrayBufferOrView(salt, "salt", "buffer");
|
|
|
|
validateUint32(iterations, "iterations", true);
|
|
|
|
validateUint32(keylen, "keylen");
|
|
|
|
|
|
|
|
if (iterations > MAX_I32) {
|
|
|
|
throw new ERR_OUT_OF_RANGE("iterations", `<= ${MAX_I32}`, iterations);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (keylen > MAX_I32) {
|
|
|
|
throw new ERR_OUT_OF_RANGE("keylen", `<= ${MAX_I32}`, keylen);
|
|
|
|
}
|
|
|
|
|
|
|
|
return { password, salt, iterations, keylen, digest };
|
|
|
|
}
|
|
|
|
|
2023-02-14 11:38:45 -05:00
|
|
|
/**
|
|
|
|
* @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,
|
2024-07-05 04:10:22 -04:00
|
|
|
digest: string,
|
2023-02-14 11:38:45 -05:00
|
|
|
): Buffer {
|
2024-07-05 04:10:22 -04:00
|
|
|
({ password, salt, iterations, keylen, digest } = check(
|
|
|
|
password,
|
|
|
|
salt,
|
|
|
|
iterations,
|
|
|
|
keylen,
|
|
|
|
digest,
|
|
|
|
));
|
|
|
|
|
|
|
|
digest = digest.toLowerCase() as NormalizedAlgorithms;
|
2023-02-14 11:38:45 -05:00
|
|
|
|
2023-03-28 05:40:56 -04:00
|
|
|
const DK = new Uint8Array(keylen);
|
2024-01-10 17:37:25 -05:00
|
|
|
if (!op_node_pbkdf2(password, salt, iterations, digest, DK)) {
|
2024-07-05 04:10:22 -04:00
|
|
|
throw new ERR_CRYPTO_INVALID_DIGEST(digest);
|
2023-02-14 11:38:45 -05:00
|
|
|
}
|
|
|
|
|
2023-03-28 05:40:56 -04:00
|
|
|
return Buffer.from(DK);
|
2023-02-14 11:38:45 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @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,
|
2024-07-05 04:10:22 -04:00
|
|
|
digest: string,
|
2023-02-14 11:38:45 -05:00
|
|
|
callback: (err: Error | null, derivedKey?: Buffer) => void,
|
|
|
|
) {
|
2024-07-05 04:10:22 -04:00
|
|
|
if (typeof digest === "function") {
|
|
|
|
callback = digest;
|
|
|
|
digest = undefined as unknown as string;
|
2023-03-28 05:40:56 -04:00
|
|
|
}
|
|
|
|
|
2024-07-05 04:10:22 -04:00
|
|
|
({ password, salt, iterations, keylen, digest } = check(
|
|
|
|
password,
|
|
|
|
salt,
|
|
|
|
iterations,
|
|
|
|
keylen,
|
|
|
|
digest,
|
|
|
|
));
|
|
|
|
|
|
|
|
validateFunction(callback, "callback");
|
|
|
|
|
|
|
|
digest = digest.toLowerCase() as NormalizedAlgorithms;
|
|
|
|
|
2023-12-26 20:30:26 -05:00
|
|
|
op_node_pbkdf2_async(
|
2023-03-28 05:40:56 -04:00
|
|
|
password,
|
|
|
|
salt,
|
|
|
|
iterations,
|
|
|
|
digest,
|
|
|
|
keylen,
|
|
|
|
).then(
|
|
|
|
(DK) => callback(null, Buffer.from(DK)),
|
|
|
|
)
|
|
|
|
.catch((err) => callback(err));
|
2023-02-14 11:38:45 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
export default {
|
|
|
|
MAX_ALLOC,
|
|
|
|
pbkdf2,
|
|
|
|
pbkdf2Sync,
|
|
|
|
};
|