11cb0ef41Sopenharmony_ci'use strict'; 21cb0ef41Sopenharmony_ci 31cb0ef41Sopenharmony_ciconst { 41cb0ef41Sopenharmony_ci ArrayFrom, 51cb0ef41Sopenharmony_ci SafeSet, 61cb0ef41Sopenharmony_ci} = primordials; 71cb0ef41Sopenharmony_ci 81cb0ef41Sopenharmony_ciconst { 91cb0ef41Sopenharmony_ci HmacJob, 101cb0ef41Sopenharmony_ci KeyObjectHandle, 111cb0ef41Sopenharmony_ci kCryptoJobAsync, 121cb0ef41Sopenharmony_ci kSignJobModeSign, 131cb0ef41Sopenharmony_ci kSignJobModeVerify, 141cb0ef41Sopenharmony_ci} = internalBinding('crypto'); 151cb0ef41Sopenharmony_ci 161cb0ef41Sopenharmony_ciconst { 171cb0ef41Sopenharmony_ci getBlockSize, 181cb0ef41Sopenharmony_ci hasAnyNotIn, 191cb0ef41Sopenharmony_ci jobPromise, 201cb0ef41Sopenharmony_ci normalizeHashName, 211cb0ef41Sopenharmony_ci validateBitLength, 221cb0ef41Sopenharmony_ci validateKeyOps, 231cb0ef41Sopenharmony_ci kHandle, 241cb0ef41Sopenharmony_ci kKeyObject, 251cb0ef41Sopenharmony_ci} = require('internal/crypto/util'); 261cb0ef41Sopenharmony_ci 271cb0ef41Sopenharmony_ciconst { 281cb0ef41Sopenharmony_ci lazyDOMException, 291cb0ef41Sopenharmony_ci promisify, 301cb0ef41Sopenharmony_ci} = require('internal/util'); 311cb0ef41Sopenharmony_ci 321cb0ef41Sopenharmony_ciconst { 331cb0ef41Sopenharmony_ci generateKey: _generateKey, 341cb0ef41Sopenharmony_ci} = require('internal/crypto/keygen'); 351cb0ef41Sopenharmony_ci 361cb0ef41Sopenharmony_ciconst { 371cb0ef41Sopenharmony_ci InternalCryptoKey, 381cb0ef41Sopenharmony_ci SecretKeyObject, 391cb0ef41Sopenharmony_ci createSecretKey, 401cb0ef41Sopenharmony_ci} = require('internal/crypto/keys'); 411cb0ef41Sopenharmony_ci 421cb0ef41Sopenharmony_ciconst generateKey = promisify(_generateKey); 431cb0ef41Sopenharmony_ci 441cb0ef41Sopenharmony_ciasync function hmacGenerateKey(algorithm, extractable, keyUsages) { 451cb0ef41Sopenharmony_ci const { hash, name } = algorithm; 461cb0ef41Sopenharmony_ci let { length } = algorithm; 471cb0ef41Sopenharmony_ci 481cb0ef41Sopenharmony_ci if (length === undefined) 491cb0ef41Sopenharmony_ci length = getBlockSize(hash.name); 501cb0ef41Sopenharmony_ci 511cb0ef41Sopenharmony_ci validateBitLength(length, 'algorithm.length', true); 521cb0ef41Sopenharmony_ci 531cb0ef41Sopenharmony_ci const usageSet = new SafeSet(keyUsages); 541cb0ef41Sopenharmony_ci if (hasAnyNotIn(usageSet, ['sign', 'verify'])) { 551cb0ef41Sopenharmony_ci throw lazyDOMException( 561cb0ef41Sopenharmony_ci 'Unsupported key usage for an HMAC key', 571cb0ef41Sopenharmony_ci 'SyntaxError'); 581cb0ef41Sopenharmony_ci } 591cb0ef41Sopenharmony_ci 601cb0ef41Sopenharmony_ci const key = await generateKey('hmac', { length }).catch((err) => { 611cb0ef41Sopenharmony_ci throw lazyDOMException( 621cb0ef41Sopenharmony_ci 'The operation failed for an operation-specific reason', 631cb0ef41Sopenharmony_ci { name: 'OperationError', cause: err }); 641cb0ef41Sopenharmony_ci }); 651cb0ef41Sopenharmony_ci 661cb0ef41Sopenharmony_ci return new InternalCryptoKey( 671cb0ef41Sopenharmony_ci key, 681cb0ef41Sopenharmony_ci { name, length, hash: { name: hash.name } }, 691cb0ef41Sopenharmony_ci ArrayFrom(usageSet), 701cb0ef41Sopenharmony_ci extractable); 711cb0ef41Sopenharmony_ci} 721cb0ef41Sopenharmony_ci 731cb0ef41Sopenharmony_cifunction getAlgorithmName(hash) { 741cb0ef41Sopenharmony_ci switch (hash) { 751cb0ef41Sopenharmony_ci case 'SHA-1': // Fall through 761cb0ef41Sopenharmony_ci case 'SHA-256': // Fall through 771cb0ef41Sopenharmony_ci case 'SHA-384': // Fall through 781cb0ef41Sopenharmony_ci case 'SHA-512': // Fall through 791cb0ef41Sopenharmony_ci return `HS${hash.slice(4)}`; 801cb0ef41Sopenharmony_ci default: 811cb0ef41Sopenharmony_ci throw lazyDOMException('Unsupported digest algorithm', 'DataError'); 821cb0ef41Sopenharmony_ci } 831cb0ef41Sopenharmony_ci} 841cb0ef41Sopenharmony_ci 851cb0ef41Sopenharmony_ciasync function hmacImportKey( 861cb0ef41Sopenharmony_ci format, 871cb0ef41Sopenharmony_ci keyData, 881cb0ef41Sopenharmony_ci algorithm, 891cb0ef41Sopenharmony_ci extractable, 901cb0ef41Sopenharmony_ci keyUsages) { 911cb0ef41Sopenharmony_ci const usagesSet = new SafeSet(keyUsages); 921cb0ef41Sopenharmony_ci if (hasAnyNotIn(usagesSet, ['sign', 'verify'])) { 931cb0ef41Sopenharmony_ci throw lazyDOMException( 941cb0ef41Sopenharmony_ci 'Unsupported key usage for an HMAC key', 951cb0ef41Sopenharmony_ci 'SyntaxError'); 961cb0ef41Sopenharmony_ci } 971cb0ef41Sopenharmony_ci let keyObject; 981cb0ef41Sopenharmony_ci switch (format) { 991cb0ef41Sopenharmony_ci case 'raw': { 1001cb0ef41Sopenharmony_ci const checkLength = keyData.byteLength * 8; 1011cb0ef41Sopenharmony_ci 1021cb0ef41Sopenharmony_ci if (checkLength === 0 || algorithm.length === 0) 1031cb0ef41Sopenharmony_ci throw lazyDOMException('Zero-length key is not supported', 'DataError'); 1041cb0ef41Sopenharmony_ci 1051cb0ef41Sopenharmony_ci // The Web Crypto spec allows for key lengths that are not multiples of 1061cb0ef41Sopenharmony_ci // 8. We don't. Our check here is stricter than that defined by the spec 1071cb0ef41Sopenharmony_ci // in that we require that algorithm.length match keyData.length * 8 if 1081cb0ef41Sopenharmony_ci // algorithm.length is specified. 1091cb0ef41Sopenharmony_ci if (algorithm.length !== undefined && 1101cb0ef41Sopenharmony_ci algorithm.length !== checkLength) { 1111cb0ef41Sopenharmony_ci throw lazyDOMException('Invalid key length', 'DataError'); 1121cb0ef41Sopenharmony_ci } 1131cb0ef41Sopenharmony_ci 1141cb0ef41Sopenharmony_ci keyObject = createSecretKey(keyData); 1151cb0ef41Sopenharmony_ci break; 1161cb0ef41Sopenharmony_ci } 1171cb0ef41Sopenharmony_ci case 'jwk': { 1181cb0ef41Sopenharmony_ci if (!keyData.kty) 1191cb0ef41Sopenharmony_ci throw lazyDOMException('Invalid keyData', 'DataError'); 1201cb0ef41Sopenharmony_ci 1211cb0ef41Sopenharmony_ci if (keyData.kty !== 'oct') 1221cb0ef41Sopenharmony_ci throw lazyDOMException('Invalid JWK "kty" Parameter', 'DataError'); 1231cb0ef41Sopenharmony_ci 1241cb0ef41Sopenharmony_ci if (usagesSet.size > 0 && 1251cb0ef41Sopenharmony_ci keyData.use !== undefined && 1261cb0ef41Sopenharmony_ci keyData.use !== 'sig') { 1271cb0ef41Sopenharmony_ci throw lazyDOMException('Invalid JWK "use" Parameter', 'DataError'); 1281cb0ef41Sopenharmony_ci } 1291cb0ef41Sopenharmony_ci 1301cb0ef41Sopenharmony_ci validateKeyOps(keyData.key_ops, usagesSet); 1311cb0ef41Sopenharmony_ci 1321cb0ef41Sopenharmony_ci if (keyData.ext !== undefined && 1331cb0ef41Sopenharmony_ci keyData.ext === false && 1341cb0ef41Sopenharmony_ci extractable === true) { 1351cb0ef41Sopenharmony_ci throw lazyDOMException( 1361cb0ef41Sopenharmony_ci 'JWK "ext" Parameter and extractable mismatch', 1371cb0ef41Sopenharmony_ci 'DataError'); 1381cb0ef41Sopenharmony_ci } 1391cb0ef41Sopenharmony_ci 1401cb0ef41Sopenharmony_ci if (keyData.alg !== undefined) { 1411cb0ef41Sopenharmony_ci if (keyData.alg !== getAlgorithmName(algorithm.hash.name)) 1421cb0ef41Sopenharmony_ci throw lazyDOMException( 1431cb0ef41Sopenharmony_ci 'JWK "alg" does not match the requested algorithm', 1441cb0ef41Sopenharmony_ci 'DataError'); 1451cb0ef41Sopenharmony_ci } 1461cb0ef41Sopenharmony_ci 1471cb0ef41Sopenharmony_ci const handle = new KeyObjectHandle(); 1481cb0ef41Sopenharmony_ci handle.initJwk(keyData); 1491cb0ef41Sopenharmony_ci keyObject = new SecretKeyObject(handle); 1501cb0ef41Sopenharmony_ci break; 1511cb0ef41Sopenharmony_ci } 1521cb0ef41Sopenharmony_ci default: 1531cb0ef41Sopenharmony_ci throw lazyDOMException(`Unable to import HMAC key with format ${format}`); 1541cb0ef41Sopenharmony_ci } 1551cb0ef41Sopenharmony_ci 1561cb0ef41Sopenharmony_ci const { length } = keyObject[kHandle].keyDetail({}); 1571cb0ef41Sopenharmony_ci 1581cb0ef41Sopenharmony_ci return new InternalCryptoKey( 1591cb0ef41Sopenharmony_ci keyObject, { 1601cb0ef41Sopenharmony_ci name: 'HMAC', 1611cb0ef41Sopenharmony_ci hash: algorithm.hash, 1621cb0ef41Sopenharmony_ci length, 1631cb0ef41Sopenharmony_ci }, 1641cb0ef41Sopenharmony_ci keyUsages, 1651cb0ef41Sopenharmony_ci extractable); 1661cb0ef41Sopenharmony_ci} 1671cb0ef41Sopenharmony_ci 1681cb0ef41Sopenharmony_cifunction hmacSignVerify(key, data, algorithm, signature) { 1691cb0ef41Sopenharmony_ci const mode = signature === undefined ? kSignJobModeSign : kSignJobModeVerify; 1701cb0ef41Sopenharmony_ci return jobPromise(() => new HmacJob( 1711cb0ef41Sopenharmony_ci kCryptoJobAsync, 1721cb0ef41Sopenharmony_ci mode, 1731cb0ef41Sopenharmony_ci normalizeHashName(key.algorithm.hash.name), 1741cb0ef41Sopenharmony_ci key[kKeyObject][kHandle], 1751cb0ef41Sopenharmony_ci data, 1761cb0ef41Sopenharmony_ci signature)); 1771cb0ef41Sopenharmony_ci} 1781cb0ef41Sopenharmony_ci 1791cb0ef41Sopenharmony_cimodule.exports = { 1801cb0ef41Sopenharmony_ci hmacImportKey, 1811cb0ef41Sopenharmony_ci hmacGenerateKey, 1821cb0ef41Sopenharmony_ci hmacSignVerify, 1831cb0ef41Sopenharmony_ci}; 184