Что такое аналог WebCrypto.subtle.decrypt для node.js crypto.createDecipheriv (алгоритм AES-CTR)?

Я пытаюсь переписать старый алгоритм шифрования NodeJs из

      crypto.createDecipheriv(algorithm, key, iv[, options])

в веб-крипто

      subtle.decrypt(algorithm, key, data)

Этот код достаточно хорошо работает с алгоритмом AES-128-CTR.

      const algorithm = 'aes-128-ctr';

const iv = '0123456789ABCDEF0123456789ABCDEF';
const privateKey = '16Random_Letters';
const hexBufferFromIv = Buffer.from(iv, 'hex');
const utfBufferFromPrivateKey = Buffer.from(privateKey, 'utf8');

function oldEncryptData(data: string): string {
  const cipher = createCipheriv(
    algorithm,
    utfBufferFromPrivateKey,
    hexBufferFromIv,
  );
  let crypted = cipher.update(data, 'utf8', 'base64');
  crypted += cipher.final('base64');
  return crypted;
}

function oldDecryptData(data: string): string {
  const decipher = createDecipheriv(
    algorithm,
    utfBufferFromPrivateKey,
    hexBufferFromIv,
  );
  let dec = decipher.update(data, 'base64', 'utf8');
  dec += decipher.final('utf8');
  return dec;
}

async function testDecrypt() {
  const sourceText = `any text to encrypt!`;

  const encryptedText = oldEncryptData(sourceText);

  const decryptedText = oldDecryptData(encryptedText);

  return sourceText === decryptedText;
}

testDecrypt().then(console.log);

Прямо сейчас я тестирую этот код и примеры WebCrypto в nodejs, но в конечном итоге я не буду переносить функциональность webCrypto.subtle.decrypt в NGINX njs, и, насколько мне известно, njs не поддерживает другие варианты расшифровки, кроме WebCrypto.

Интерфейс для расшифровки WebCrypto для AES-CTR в целом выглядит так

      const data = await crypto.subtle.decrypt(
  {
    name: "AES-CTR",
    counter,     // BufferSource
    length: 128, // 1-128
  },
  key,  // AES key
  encData, // BufferSource
);

И я не понимаю.

  1. счетчик - это то же самое, чтоInitialization vectorвcreateDecipherivметод?
  2. Как я должен сгенерировать ключ дляsubtle.decryptметод из той же кодовой фразы?
  3. Нужно ли мне делать какие-либо дополнительные преобразования из или вbase64илиutf8кодирование для воспроизведения входной и выходной кодировки вcipher.update(data, 'utf8', 'base64');И вdecipher.update(data, 'base64', 'utf8');методы?

1 ответ

Спасибо Топако за подсказки. Напишу более полный ответ. Может быть, это будет полезно для кого-то.

  1. Да,Initialization vectorиcounterможно рассматривать как одно и то же.
  2. Для генерации ключа из той же парольной фразы следует использовать метод importKey . И вы должны отправить тот же ArrayBuffer из парольной фразы, что и вcreateCipherivметод.
  3. Да, если ваш старый метод использовал какое-то конкретное кодирование и декодирование, вы должны повторить ту же логику кодирования/декодирования после методов Webcrypto.SubtleCrypto.encrypt() и decrypt().

Полный работоспособный пример может выглядеть примерно так

      import { webcrypto } from 'crypto';

const iv = '0123456789ABCDEF0123456789ABCDEF';
const privateKey = '16Random_Letters';
const hexBufferFromIv = Buffer.from(iv, 'hex');
const utfBufferFromPrivateKey = Buffer.from(privateKey, 'utf8');

async function generateKeyFromPassPhrase(): Promise<CryptoKey> {
  return webcrypto.subtle.importKey(
    'raw',
    utfBufferFromPrivateKey,
    {
      name: 'AES-CTR',
    },
    true,
    ['decrypt', 'encrypt'],
  );
}

async function newEncryptData(data: string): Promise<string> {
  const key = await generateKeyFromPassPhrase();

  const encryptResult = await webcrypto.subtle.encrypt(
    {
      name: 'AES-CTR',
      length: 128,
      counter: hexBufferFromIv,
    },
    key,
    Buffer.from(data),
  );

  return Buffer.from(encryptResult).toString('base64');
}

async function newDecryptData(data: string): Promise<string> {
  const key = await generateKeyFromPassPhrase();

  const decryptResult = await webcrypto.subtle.decrypt(
    {
      name: 'AES-CTR',
      length: 128,
      counter: hexBufferFromIv,
    },
    key,
    Buffer.from(data, 'base64'),
  );

  return Buffer.from(decryptResult).toString();
}

async function testDecrypt() {
  const sourceText = `any text to encrypt!`;
  const encrypted2 = await newEncryptData(sourceText);

  const decrypted2 = await newDecryptData(encrypted2);

  return sourceText === decrypted2;
}

testDecrypt().then(console.log);
Другие вопросы по тегам