UNPKG

nstdlib-nightly

Version:

Node.js standard library converted to runtime-agnostic ES modules.

182 lines (158 loc) 4.76 kB
// Source: https://github.com/nodejs/node/blob/65eff1eb/lib/internal/crypto/mac.js import { HmacJob, KeyObjectHandle, kCryptoJobAsync, kSignJobModeSign, kSignJobModeVerify, } from "nstdlib/stub/binding/crypto"; import { getBlockSize, hasAnyNotIn, jobPromise, normalizeHashName, validateBitLength, validateKeyOps, kHandle, kKeyObject, } from "nstdlib/lib/internal/crypto/util"; import { lazyDOMException, promisify } from "nstdlib/lib/internal/util"; import { generateKey as _generateKey } from "nstdlib/lib/internal/crypto/keygen"; import { InternalCryptoKey, SecretKeyObject, createSecretKey, } from "nstdlib/lib/internal/crypto/keys"; const generateKey = promisify(_generateKey); async function hmacGenerateKey(algorithm, extractable, keyUsages) { const { hash, name } = algorithm; let { length } = algorithm; if (length === undefined) length = getBlockSize(hash.name); validateBitLength(length, "algorithm.length", true); const usageSet = new Set(keyUsages); if (hasAnyNotIn(usageSet, ["sign", "verify"])) { throw lazyDOMException( "Unsupported key usage for an HMAC key", "SyntaxError", ); } const key = await generateKey("hmac", { length }).catch((err) => { throw lazyDOMException( "The operation failed for an operation-specific reason", { name: "OperationError", cause: err }, ); }); return new InternalCryptoKey( key, { name, length, hash: { name: hash.name } }, Array.from(usageSet), extractable, ); } function getAlgorithmName(hash) { switch (hash) { case "SHA-1": // Fall through case "SHA-256": // Fall through case "SHA-384": // Fall through case "SHA-512": // Fall through return `HS${hash.slice(4)}`; default: throw lazyDOMException("Unsupported digest algorithm", "DataError"); } } async function hmacImportKey( format, keyData, algorithm, extractable, keyUsages, ) { const usagesSet = new Set(keyUsages); if (hasAnyNotIn(usagesSet, ["sign", "verify"])) { throw lazyDOMException( "Unsupported key usage for an HMAC key", "SyntaxError", ); } let keyObject; switch (format) { case "raw": { const checkLength = keyData.byteLength * 8; if (checkLength === 0 || algorithm.length === 0) throw lazyDOMException("Zero-length key is not supported", "DataError"); // The Web Crypto spec allows for key lengths that are not multiples of // 8. We don't. Our check here is stricter than that defined by the spec // in that we require that algorithm.length match keyData.length * 8 if // algorithm.length is specified. if (algorithm.length !== undefined && algorithm.length !== checkLength) { throw lazyDOMException("Invalid key length", "DataError"); } keyObject = createSecretKey(keyData); break; } case "jwk": { if (!keyData.kty) throw lazyDOMException("Invalid keyData", "DataError"); if (keyData.kty !== "oct") throw lazyDOMException('Invalid JWK "kty" Parameter', "DataError"); if ( usagesSet.size > 0 && keyData.use !== undefined && keyData.use !== "sig" ) { throw lazyDOMException('Invalid JWK "use" Parameter', "DataError"); } validateKeyOps(keyData.key_ops, usagesSet); if ( keyData.ext !== undefined && keyData.ext === false && extractable === true ) { throw lazyDOMException( 'JWK "ext" Parameter and extractable mismatch', "DataError", ); } if (keyData.alg !== undefined) { if (keyData.alg !== getAlgorithmName(algorithm.hash.name)) throw lazyDOMException( 'JWK "alg" does not match the requested algorithm', "DataError", ); } const handle = new KeyObjectHandle(); handle.initJwk(keyData); keyObject = new SecretKeyObject(handle); break; } default: throw lazyDOMException(`Unable to import HMAC key with format ${format}`); } const { length } = keyObject[kHandle].keyDetail({}); return new InternalCryptoKey( keyObject, { name: "HMAC", hash: algorithm.hash, length, }, keyUsages, extractable, ); } function hmacSignVerify(key, data, algorithm, signature) { const mode = signature === undefined ? kSignJobModeSign : kSignJobModeVerify; return jobPromise( () => new HmacJob( kCryptoJobAsync, mode, normalizeHashName(key.algorithm.hash.name), key[kKeyObject][kHandle], data, signature, ), ); } export { hmacImportKey }; export { hmacGenerateKey }; export { hmacSignVerify };