nstdlib-nightly
Version:
Node.js standard library converted to runtime-agnostic ES modules.
151 lines (127 loc) • 3.52 kB
JavaScript
// Source: https://github.com/nodejs/node/blob/65eff1eb/lib/internal/crypto/hkdf.js
import {
HKDFJob,
kCryptoJobAsync,
kCryptoJobSync,
} from "nstdlib/stub/binding/crypto";
import {
validateFunction,
validateInteger,
validateString,
} from "nstdlib/lib/internal/validators";
import { kMaxLength } from "nstdlib/lib/buffer";
import {
normalizeHashName,
toBuf,
validateByteSource,
kKeyObject,
} from "nstdlib/lib/internal/crypto/util";
import { createSecretKey, isKeyObject } from "nstdlib/lib/internal/crypto/keys";
import { lazyDOMException, promisify } from "nstdlib/lib/internal/util";
import {
isAnyArrayBuffer,
isArrayBufferView,
} from "nstdlib/lib/internal/util/types";
import {
codes as __codes__,
hideStackFrames,
} from "nstdlib/lib/internal/errors";
const { ERR_INVALID_ARG_TYPE, ERR_OUT_OF_RANGE } = __codes__;
const validateParameters = hideStackFrames((hash, key, salt, info, length) => {
validateString.withoutStackTrace(hash, "digest");
key = prepareKey(key);
salt = validateByteSource.withoutStackTrace(salt, "salt");
info = validateByteSource.withoutStackTrace(info, "info");
validateInteger.withoutStackTrace(length, "length", 0, kMaxLength);
if (info.byteLength > 1024) {
throw new ERR_OUT_OF_RANGE.HideStackFramesError(
"info",
"must not contain more than 1024 bytes",
info.byteLength,
);
}
return {
hash,
key,
salt,
info,
length,
};
});
function prepareKey(key) {
if (isKeyObject(key)) return key;
if (isAnyArrayBuffer(key)) return createSecretKey(key);
key = toBuf(key);
if (!isArrayBufferView(key)) {
throw new ERR_INVALID_ARG_TYPE(
"ikm",
[
"string",
"SecretKeyObject",
"ArrayBuffer",
"TypedArray",
"DataView",
"Buffer",
],
key,
);
}
return createSecretKey(key);
}
function hkdf(hash, key, salt, info, length, callback) {
({ hash, key, salt, info, length } = validateParameters(
hash,
key,
salt,
info,
length,
));
validateFunction(callback, "callback");
const job = new HKDFJob(kCryptoJobAsync, hash, key, salt, info, length);
job.ondone = (error, bits) => {
if (error) return Function.prototype.call.call(callback, job, error);
Function.prototype.call.call(callback, job, null, bits);
};
job.run();
}
function hkdfSync(hash, key, salt, info, length) {
({ hash, key, salt, info, length } = validateParameters(
hash,
key,
salt,
info,
length,
));
const job = new HKDFJob(kCryptoJobSync, hash, key, salt, info, length);
const { 0: err, 1: bits } = job.run();
if (err !== undefined) throw err;
return bits;
}
const hkdfPromise = promisify(hkdf);
async function hkdfDeriveBits(algorithm, baseKey, length) {
const { hash, salt, info } = algorithm;
if (length === 0)
throw lazyDOMException("length cannot be zero", "OperationError");
if (length === null)
throw lazyDOMException("length cannot be null", "OperationError");
if (length % 8) {
throw lazyDOMException("length must be a multiple of 8", "OperationError");
}
try {
return await hkdfPromise(
normalizeHashName(hash.name),
baseKey[kKeyObject],
salt,
info,
length / 8,
);
} catch (err) {
throw lazyDOMException(
"The operation failed for an operation-specific reason",
{ name: "OperationError", cause: err },
);
}
}
export { hkdf };
export { hkdfSync };
export { hkdfDeriveBits };