current commit
261025.12 · test,benchmark: drop OpenSSL 1.x-only coverage
'use strict';

const common = require('../common');

if (!common.hasCrypto) {
  common.skip('missing crypto');
}

const { isBoringSSL } = require('../common/crypto');

if (isBoringSSL) {
  common.skip('OpenSSL EVP_MAC support is required');
}

const assert = require('node:assert');
const fixtures = require('../common/fixtures');
const {
  createMac,
  createPublicKey,
  createSecretKey,
  getMacs,
} = require('node:crypto');

const key = Buffer.alloc(32, 0x42);
const data = Buffer.from('data');
const availableMacs = new Set(getMacs());

function invalidType(fn) {
  assert.throws(fn, { code: 'ERR_INVALID_ARG_TYPE' });
}

function invalidValue(fn) {
  assert.throws(fn, { code: 'ERR_INVALID_ARG_VALUE' });
}

for (const algorithm of [undefined, null, 1, true, [], {}]) {
  invalidType(() => createMac(algorithm, key));
}

for (const algorithm of ['', 'hmac\0sha256']) {
  invalidValue(() => createMac(algorithm, key));
}

for (const [algorithm, options] of [
  ['hmac', { digest: 1 }],
  ['cmac', { cipher: 1 }],
  ['gmac', { iv: 'not a BufferSource' }],
  ['kmac128', { customization: 'not a BufferSource' }],
  ['blake2bmac', { salt: 'not a BufferSource' }],
  ['kmac128', { outputLength: '32' }],
]) {
  invalidType(() => createMac(algorithm, key, options));
}

for (const [algorithm, options] of [
  ['hmac', { digest: 'sha256\0sha512' }],
  ['cmac', { cipher: 'aes-128-cbc\0aes-256-cbc' }],
]) {
  invalidValue(() => createMac(algorithm, key, options));
}

for (const outputLength of [-1, 0.5, 2 ** 32, Infinity, NaN]) {
  assert.throws(
    () => createMac('kmac128', key, { outputLength }),
    { code: 'ERR_OUT_OF_RANGE' },
  );
}

assert.throws(
  () => createMac('definitely-not-a-mac', key),
  { code: 'ERR_CRYPTO_INVALID_MAC' },
);

if (availableMacs.has('siphash')) {
  assert.throws(() => createMac('siphash', Buffer.alloc(15)), (error) => {
    assert.strictEqual(error.name, 'Error');
    assert.strictEqual(error.message, 'Failed to initialize MAC');
    assert.strictEqual(error.code, 'ERR_CRYPTO_OPERATION_FAILED');
    for (const property of [
      'function',
      'library',
      'reason',
      'opensslErrorStack',
    ]) {
      assert.ok(!(property in error));
    }
    return true;
  });
}

if (availableMacs.has('hmac')) {
  const algorithm = 'hmac';
  const options = { digest: 'sha256' };
  assert.throws(
    () => createMac(algorithm, key, { digest: 'definitely-not-a-digest' }),
    {
      code: 'ERR_OSSL_EVP_UNSUPPORTED',
      library: 'digital envelope routines',
      reason: 'unsupported',
    },
  );
  const publicKey = createPublicKey(fixtures.readKey('rsa_public.pem'));
  const cryptoKey = createSecretKey(key).toCryptoKey(
    { name: 'HMAC', hash: 'SHA-256' }, false, ['sign']);
  for (const invalidKey of [
    undefined,
    null,
    'key',
    {},
    publicKey,
    cryptoKey,
  ]) {
    invalidType(() => createMac(algorithm, invalidKey, options));
  }

  for (const invalidData of [
    undefined,
    null,
    1,
    true,
    {},
    new ArrayBuffer(4),
  ]) {
    invalidType(() => createMac(algorithm, key, options).update(invalidData));
  }

  invalidType(() => createMac(algorithm, key, options).update('data', 1));
  invalidType(() => createMac(algorithm, key, options).final(1));
  invalidType(() => createMac(algorithm, key, 'hex'));

  invalidValue(() => createMac(algorithm, key, options)
    .update('data', 'not-an-encoding'));
  const invalidFinalEncoding = createMac(algorithm, key, options);
  invalidValue(() => invalidFinalEncoding.final('not-an-encoding'));
  assert.deepStrictEqual(
    invalidFinalEncoding.update(data).final(),
    createMac(algorithm, key, options).update(data).final(),
  );
  invalidValue(() => createMac(algorithm, key, options).update('0', 'hex'));

  invalidValue(() => createMac('hmac', key));
  for (const extra of [
    { cipher: 'aes-128-cbc' },
    { iv: Buffer.alloc(12) },
    { customization: Buffer.alloc(0) },
    { salt: Buffer.alloc(16) },
    { outputLength: 16 },
  ]) {
    invalidValue(() => createMac('hmac', key, {
      ...options,
      ...extra,
    }));
  }
}

if (availableMacs.has('cmac')) {
  invalidValue(() => createMac('cmac', key));
  invalidValue(() => createMac('cmac', key, { digest: 'sha256' }));
  invalidValue(() => createMac('cmac', key, {
    cipher: 'aes-256-cbc',
    iv: Buffer.alloc(16),
  }));
}

if (availableMacs.has('gmac')) {
  invalidValue(() => createMac('gmac', key));
  invalidValue(() => createMac('gmac', key, { cipher: 'aes-256-gcm' }));
  invalidValue(() => createMac('gmac', key, { iv: Buffer.alloc(12) }));
  invalidValue(() => createMac('gmac', key, {
    cipher: 'aes-256-gcm',
    iv: Buffer.alloc(12),
    digest: 'sha256',
  }));
}

if (availableMacs.has('poly1305')) {
  invalidValue(() => createMac('poly1305', key, {
    customization: Buffer.alloc(0),
  }));
}