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