mirror of
https://github.com/denoland/deno.git
synced 2025-09-23 02:42:34 +00:00
![gitstart-app[bot]](/assets/img/avatar_default.png)
Some checks failed
ci / pre-build (push) Has been cancelled
ci / build libs (push) Has been cancelled
ci / publish canary (push) Has been cancelled
ci / test debug linux-aarch64 (push) Has been cancelled
ci / test release linux-aarch64 (push) Has been cancelled
ci / test debug macos-aarch64 (push) Has been cancelled
ci / test release macos-aarch64 (push) Has been cancelled
ci / bench release linux-x86_64 (push) Has been cancelled
ci / lint debug linux-x86_64 (push) Has been cancelled
ci / lint debug macos-x86_64 (push) Has been cancelled
ci / lint debug windows-x86_64 (push) Has been cancelled
ci / test debug linux-x86_64 (push) Has been cancelled
ci / test release linux-x86_64 (push) Has been cancelled
ci / test debug macos-x86_64 (push) Has been cancelled
ci / test release macos-x86_64 (push) Has been cancelled
ci / test debug windows-x86_64 (push) Has been cancelled
ci / test release windows-x86_64 (push) Has been cancelled
The original HKDF implementation incorrectly handled TypedArrays by converting them through the toBuf() function, which only handles strings and Buffers. This caused TypedArrays to be processed incorrectly, losing their actual byte representation. Closes https://github.com/denoland/deno/issues/29913 --------- Co-authored-by: gitstart-app[bot] <80938352+gitstart-app[bot]@users.noreply.github.com> Co-authored-by: Bartek Iwańczuk <biwanczuk@gmail.com>
187 lines
4.2 KiB
TypeScript
187 lines
4.2 KiB
TypeScript
// Copyright 2018-2025 the Deno authors. MIT license.
|
|
// Copyright Joyent, Inc. and Node.js contributors. All rights reserved. MIT license.
|
|
|
|
// TODO(petamoriken): enable prefer-primordials for node polyfills
|
|
// deno-lint-ignore-file prefer-primordials
|
|
|
|
import {
|
|
op_node_get_hash_size,
|
|
op_node_hkdf,
|
|
op_node_hkdf_async,
|
|
} from "ext:core/ops";
|
|
|
|
import {
|
|
validateFunction,
|
|
validateInteger,
|
|
validateString,
|
|
} from "ext:deno_node/internal/validators.mjs";
|
|
import {
|
|
ERR_CRYPTO_INVALID_DIGEST,
|
|
ERR_CRYPTO_INVALID_KEYLEN,
|
|
ERR_INVALID_ARG_TYPE,
|
|
ERR_OUT_OF_RANGE,
|
|
hideStackFrames,
|
|
} from "ext:deno_node/internal/errors.ts";
|
|
import {
|
|
kHandle,
|
|
toBuf,
|
|
validateByteSource,
|
|
} from "ext:deno_node/internal/crypto/util.ts";
|
|
import {
|
|
createSecretKey,
|
|
KeyObject,
|
|
} from "ext:deno_node/internal/crypto/keys.ts";
|
|
import type { BinaryLike } from "ext:deno_node/internal/crypto/types.ts";
|
|
import { kMaxLength } from "ext:deno_node/internal/buffer.mjs";
|
|
import {
|
|
isAnyArrayBuffer,
|
|
isArrayBufferView,
|
|
} from "ext:deno_node/internal/util/types.ts";
|
|
import { isKeyObject } from "ext:deno_node/internal/crypto/_keys.ts";
|
|
import { getHashes } from "ext:deno_node/internal/crypto/hash.ts";
|
|
import { Buffer } from "node:buffer";
|
|
|
|
// Consume raw bytes for any ArrayBufferView/ArrayBuffer; strings via toBuf.
|
|
function toRawBytes(x: unknown): Buffer {
|
|
if (isArrayBufferView(x)) {
|
|
const v = x as ArrayBufferView;
|
|
return Buffer.from(v.buffer, v.byteOffset, v.byteLength);
|
|
}
|
|
if (isAnyArrayBuffer(x)) {
|
|
return Buffer.from(x as ArrayBufferLike);
|
|
}
|
|
// For strings / other BinaryLike, keep existing semantics (UTF-8 etc.)
|
|
return Buffer.from(toBuf(x as unknown as string));
|
|
}
|
|
|
|
const validateParameters = hideStackFrames((hash, key, salt, info, length) => {
|
|
validateString(hash, "digest");
|
|
key = prepareKey(key);
|
|
validateByteSource(salt, "salt");
|
|
validateByteSource(info, "info");
|
|
|
|
salt = toRawBytes(toBuf(salt));
|
|
info = toRawBytes(toBuf(info));
|
|
|
|
validateInteger(length, "length", 0, kMaxLength);
|
|
|
|
if (info.byteLength > 1024) {
|
|
throw new ERR_OUT_OF_RANGE(
|
|
"info",
|
|
"must not contain more than 1024 bytes",
|
|
info.byteLength,
|
|
);
|
|
}
|
|
|
|
validateAlgorithm(hash);
|
|
|
|
const size = op_node_get_hash_size(hash);
|
|
if (typeof size === "number" && size * 255 < length) {
|
|
throw new ERR_CRYPTO_INVALID_KEYLEN();
|
|
}
|
|
|
|
return {
|
|
hash,
|
|
key,
|
|
salt,
|
|
info,
|
|
length,
|
|
};
|
|
});
|
|
|
|
function prepareKey(key: BinaryLike | KeyObject) {
|
|
if (isKeyObject(key)) {
|
|
return key;
|
|
}
|
|
|
|
if (isAnyArrayBuffer(key)) {
|
|
return createSecretKey(new Uint8Array(key as unknown as ArrayBufferLike));
|
|
}
|
|
|
|
key = toBuf(key as string);
|
|
|
|
if (!isArrayBufferView(key)) {
|
|
throw new ERR_INVALID_ARG_TYPE(
|
|
"ikm",
|
|
[
|
|
"string",
|
|
"SecretKeyObject",
|
|
"ArrayBuffer",
|
|
"TypedArray",
|
|
"DataView",
|
|
"Buffer",
|
|
],
|
|
key,
|
|
);
|
|
}
|
|
|
|
return createSecretKey(key);
|
|
}
|
|
|
|
export function hkdf(
|
|
hash: string,
|
|
key: BinaryLike | KeyObject,
|
|
salt: BinaryLike,
|
|
info: BinaryLike,
|
|
length: number,
|
|
callback: (err: Error | null, derivedKey: ArrayBuffer | undefined) => void,
|
|
) {
|
|
({ hash, key, salt, info, length } = validateParameters(
|
|
hash,
|
|
key,
|
|
salt,
|
|
info,
|
|
length,
|
|
));
|
|
|
|
validateFunction(callback, "callback");
|
|
|
|
hash = hash.toLowerCase();
|
|
|
|
op_node_hkdf_async(hash, key[kHandle], salt, info, length)
|
|
.then((okm) => callback(null, okm.buffer))
|
|
.catch((err) => callback(new ERR_CRYPTO_INVALID_DIGEST(err), undefined));
|
|
}
|
|
|
|
export function hkdfSync(
|
|
hash: string,
|
|
key: BinaryLike | KeyObject,
|
|
salt: BinaryLike,
|
|
info: BinaryLike,
|
|
length: number,
|
|
) {
|
|
({ hash, key, salt, info, length } = validateParameters(
|
|
hash,
|
|
key,
|
|
salt,
|
|
info,
|
|
length,
|
|
));
|
|
|
|
hash = hash.toLowerCase();
|
|
|
|
const okm = new Uint8Array(length);
|
|
try {
|
|
op_node_hkdf(hash, key[kHandle], salt, info, okm);
|
|
} catch (e) {
|
|
throw new ERR_CRYPTO_INVALID_DIGEST(e);
|
|
}
|
|
|
|
return okm.buffer;
|
|
}
|
|
|
|
let hashes: Set<string> | null = null;
|
|
function validateAlgorithm(algorithm: string) {
|
|
if (hashes === null) {
|
|
hashes = new Set(getHashes());
|
|
}
|
|
|
|
if (!hashes.has(algorithm)) {
|
|
throw new ERR_CRYPTO_INVALID_DIGEST(algorithm);
|
|
}
|
|
}
|
|
|
|
export default {
|
|
hkdf,
|
|
hkdfSync,
|
|
};
|