Проблемы с воспроизведением SubtleCrypto в Crypto

У меня есть код, использующий SubtleCrypto, который шифрует ключ и сохраняет его в базе данных.

Для другой функциональности я должен иметь возможность зашифровать ее в Node 12. Без SubtleCrypto мне нужно воссоздать функциональность в Crypto.

Я получаю вывод того же размера, но кажется, что он не может быть расшифрован SubtleCrypto, и я пытаюсь выяснить, где я ошибаюсь.

Это код, работающий с SubtleCrypto в браузерах:

      key = getKeyMaterial(password)];
salt = base64ToArraybuffer(optionalSalt)
aesKey = crypto.subtle.deriveKey(
{
    name: constants.algorithms.pbkdf2,
    salt: salt,
    iterations: pbkdf2Iterations,
    hash: { name: constants.hash.sha256 },
},
key,
{
    name: constants.algorithms.aesGcm,
    length: aesWrapKeyBitsLength,
},
true,
['wrapKey', 'unwrapKey']
),
return {
  salt: arraybufferTobase64(salt),
  aesKey: aesKey,
}


function getKeyMaterial(password) {
var enc = new TextEncoder();
crypto.subtle.importKey(
  constants.format.raw,
  enc.encode(password),
  {
    name: constants.algorithms.pbkdf2,
  },
  false,
  ['deriveKey']
)

Без SubtleCrypto в Node 12 я вынужден работать с библиотекой Crypto .. Это моя текущая итерация кода.

      const ivByteLength = 12;

function wrapKey(privateKey, aesKey) {
  const IV = crypto.randomBytes(ivByteLength);
  const ALGORITHM = 'aes-256-gcm';

  const cipher = crypto.createCipheriv(ALGORITHM, aesKey, IV);
  let encrypted = cipher.update(privateKey, undefined, 'binary');
  encrypted += cipher.final('binary');

  const authTag = cipher.getAuthTag();

  encrypted += authTag;
  const output = {
    wrappedKey: arraybufferTobase64(Buffer.from(encrypted, 'ascii')),
    iv: arraybufferTobase64(IV),
  };
  return output;
}

async function deriveAesGcmKey(password, salt) {
  return new Promise((resolve, reject) => {
    crypto.pbkdf2(password, salt, 100000, 32, 'sha256', (err, derivedKey) => {
      if (err) reject(err);
      else resolve(derivedKey);
    });
  });
}

function arraybufferTobase64(buffer) {
  let binary = '';
  const bytes = new Uint8Array(buffer);
  const len = bytes.byteLength;
  for (let i = 0; i < len; i += 1) {
    binary += String.fromCharCode(bytes[i]);
  }
  return btoa(binary);
}

function base64ToArraybuffer(base64) {
  const binary = atob(base64);
  const len = binary.length;
  const bytes = new Uint8Array(len);
  for (let i = 0; i < len; i += 1) {
    bytes[i] = binary.charCodeAt(i);
  }
  return bytes;
}

Обернутый ключ имеет одинаковый размер в обеих реализациях, но ключ, сгенерированный Node, не может быть развернут в браузере.

Я предполагаю, что некоторые значения по умолчанию неверны или что-то в этом роде?

1 ответ

В NodeJS есть что-то под названием webcrypto Класс внутри crypto пакет, который имеет тонкую криптографическую реализацию.

Пример из Документов :

      const { subtle } = require('crypto').webcrypto;

async function digest(data, algorithm = 'SHA-512') {
  const ec = new TextEncoder();
  const digest = await subtle.digest(algorithm, ec.encode(data));
  return digest;
}

Также проверьте: https://nodejs.org/api/webcrypto.html#webcrypto_class_subtlecrypto

Редактировать:

Как сказано в комментариях для более низкой версии Node, вы можете использовать полифилл, например https://www.npmjs.com/package/@peculiar/webcrypto, чтобы его реализация webcrypto для версии Nodejs выше, чем Node10

Другие вопросы по тегам