mirror of
https://github.com/denoland/deno.git
synced 2024-11-26 16:09:27 -05:00
08e5606c34
Previously we had many different code paths all handling digests in different places, all with wildly different digest support. This commit rewrites this to use a single digest handling mechanism for all digest operations. It adds various aliases for digest algorithms, like node does. For example `sha1WithRSAEncryption` is an alias for `sha1`. It also adds support for `md5-sha1` digests in various places.
143 lines
3.3 KiB
TypeScript
143 lines
3.3 KiB
TypeScript
// 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";
|
|
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";
|
|
|
|
export const MAX_ALLOC = Math.pow(2, 30) - 1;
|
|
export const MAX_I32 = 2 ** 31 - 1;
|
|
|
|
export type NormalizedAlgorithms =
|
|
| "md5"
|
|
| "ripemd160"
|
|
| "sha1"
|
|
| "sha224"
|
|
| "sha256"
|
|
| "sha384"
|
|
| "sha512";
|
|
|
|
export type Algorithms =
|
|
| "md5"
|
|
| "ripemd160"
|
|
| "rmd160"
|
|
| "sha1"
|
|
| "sha224"
|
|
| "sha256"
|
|
| "sha384"
|
|
| "sha512";
|
|
|
|
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 };
|
|
}
|
|
|
|
/**
|
|
* @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: string,
|
|
): Buffer {
|
|
({ password, salt, iterations, keylen, digest } = check(
|
|
password,
|
|
salt,
|
|
iterations,
|
|
keylen,
|
|
digest,
|
|
));
|
|
|
|
digest = digest.toLowerCase() as NormalizedAlgorithms;
|
|
|
|
const DK = new Uint8Array(keylen);
|
|
if (!op_node_pbkdf2(password, salt, iterations, digest, DK)) {
|
|
throw new ERR_CRYPTO_INVALID_DIGEST(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: string,
|
|
callback: (err: Error | null, derivedKey?: Buffer) => void,
|
|
) {
|
|
if (typeof digest === "function") {
|
|
callback = digest;
|
|
digest = undefined as unknown as string;
|
|
}
|
|
|
|
({ password, salt, iterations, keylen, digest } = check(
|
|
password,
|
|
salt,
|
|
iterations,
|
|
keylen,
|
|
digest,
|
|
));
|
|
|
|
validateFunction(callback, "callback");
|
|
|
|
digest = digest.toLowerCase() as NormalizedAlgorithms;
|
|
|
|
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,
|
|
};
|