nstdlib-nightly
Version:
Node.js standard library converted to runtime-agnostic ES modules.
131 lines (110 loc) • 3.13 kB
JavaScript
// Source: https://github.com/nodejs/node/blob/65eff1eb/lib/internal/crypto/pbkdf2.js
import { Buffer } from "nstdlib/lib/buffer";
import {
PBKDF2Job,
kCryptoJobAsync,
kCryptoJobSync,
} from "nstdlib/stub/binding/crypto";
import {
validateFunction,
validateInt32,
validateString,
} from "nstdlib/lib/internal/validators";
import {
getArrayBufferOrView,
normalizeHashName,
kKeyObject,
} from "nstdlib/lib/internal/crypto/util";
import { lazyDOMException, promisify } from "nstdlib/lib/internal/util";
function pbkdf2(password, salt, iterations, keylen, digest, callback) {
if (typeof digest === "function") {
callback = digest;
digest = undefined;
}
({ password, salt, iterations, keylen, digest } = check(
password,
salt,
iterations,
keylen,
digest,
));
validateFunction(callback, "callback");
const job = new PBKDF2Job(
kCryptoJobAsync,
password,
salt,
iterations,
keylen,
digest,
);
job.ondone = (err, result) => {
if (err !== undefined)
return Function.prototype.call.call(callback, job, err);
const buf = Buffer.from(result);
return Function.prototype.call.call(callback, job, null, buf);
};
job.run();
}
function pbkdf2Sync(password, salt, iterations, keylen, digest) {
({ password, salt, iterations, keylen, digest } = check(
password,
salt,
iterations,
keylen,
digest,
));
const job = new PBKDF2Job(
kCryptoJobSync,
password,
salt,
iterations,
keylen,
digest,
);
const { 0: err, 1: result } = job.run();
if (err !== undefined) throw err;
return Buffer.from(result);
}
function check(password, salt, iterations, keylen, digest) {
validateString(digest, "digest");
password = getArrayBufferOrView(password, "password");
salt = getArrayBufferOrView(salt, "salt");
// OpenSSL uses a signed int to represent these values, so we are restricted
// to the 31-bit range here (which is plenty).
validateInt32(iterations, "iterations", 1);
validateInt32(keylen, "keylen", 0);
return { password, salt, iterations, keylen, digest };
}
const pbkdf2Promise = promisify(pbkdf2);
async function pbkdf2DeriveBits(algorithm, baseKey, length) {
const { iterations, hash, salt } = algorithm;
if (iterations === 0)
throw lazyDOMException("iterations cannot be zero", "OperationError");
const raw = baseKey[kKeyObject].export();
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");
}
let result;
try {
result = await pbkdf2Promise(
raw,
salt,
iterations,
length / 8,
normalizeHashName(hash.name),
);
} catch (err) {
throw lazyDOMException(
"The operation failed for an operation-specific reason",
{ name: "OperationError", cause: err },
);
}
return result.buffer;
}
export { pbkdf2 };
export { pbkdf2Sync };
export { pbkdf2DeriveBits };