Как получить ключ и начальный вектор в Node.js

У меня есть общий ключ, из которого мне нужно получить iv, чтобы я мог расшифровать. Он работает в образце кода Python, любезно предоставленном Apple.

В документации по бизнес-чату Apple указано:

Генерация производного ключа и начального вектора. Запустите общий ключ с помощью функции деривации ключа X9.63 с хэш-функцией SHA256. В результате получается 48-байтовая полезная нагрузка. Ваши результаты должны быть rV3qrszd0PMPgeRhNnlOYA==

Вот что я пробовал. Я использовал криптографические функции scryptSync и pbkdf2Sync со многими «солеными» конфигурациями. Я не уверен, подходят ли эти функции для этой работы.

      const crypto = require('crypto');

const keyLength = 48;
// sharedKey is a base64 string
const sharedKey "2lvSJsBO2keUHRfvPG6C1RMUmGpuDbdgNrZ9YD7RYnvAcfgq/fjeYr1p0hWABeif";

const key1 = crypto.scryptSync(sharedKey, 'salt', keyLength);
console.log(key2.toString('base64'));

const key2 = crypto.pbkdf2Sync(sharedKey, 'salt', 10000, keyLength, 'sha256');
console.log(key2.toString('base64'));

// results should be:
// mAzkYatDlz4SzrCyM23NhgL/+mE3eGgfUz9h1CFPhZM=
// iv: rV3qrszd0PMPgeRhNnlOYA==

1 ответ

X9.63 KDF — это функция получения ключа, описанная, например, здесь и здесь . scrypt и PBKDF2 — это тоже KDF, но разные, поэтому ожидаемый результат с ними, конечно, не воспроизвести.

Итак, вам нужна библиотека NodeJS, поддерживающая X.963 KDF. Если вы не можете найти его, вы также можете реализовать свой собственный.

X9.63 KDF ожидает общий секрет и общую информацию и определяет размер большого ключа следующим образом:

  • Создайте 4-байтовый счетчик ci , который увеличивается, начиная с 0x0000001.
  • Объединить данные conci = общий секрет | с я | общая информация
  • Хэш-результат хэш i = хеш (conci )
  • Объединить хэши hash 1 | хэш 2 | ... до тех пор, пока не будет сгенерирован вывод длины ключа .

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

Одна из возможных реализаций NodeJS (без проверок из спецификации):

      var crypto = require('crypto');

var digest = 'sha256';
var digestLen = 32;

function X963KDF(sharedSecret, sharedInfo, keySize){
  var maxCount = Math.ceil(keySize/digestLen);
  var result = Buffer.allocUnsafe(0);
  for (var count = 1; count < maxCount + 1; count++){
      var counter = Buffer.allocUnsafe(4);
      counter.writeUInt32BE(count, 0);
      var current = Buffer.concat([sharedSecret, counter, sharedInfo]);
      var hash = crypto.createHash(digest).update(current).digest();
      result = Buffer.concat([result, hash]);
  }
  
  return result.slice(0, keySize);
}

Тест:

В вопросе публикуется общий секрет, но не общая информация. Поиск в Интернете показывает, что опубликованная проблема описана, например , здесь , чтобы можно было также определить общую информацию (тем не менее, было бы лучше, если бы вы добавили эту информацию к своему вопросу):

      var sharedSecret = Buffer.from('2lvSJsBO2keUHRfvPG6C1RMUmGpuDbdgNrZ9YD7RYnvAcfgq/fjeYr1p0hWABeif', 'base64')
var sharedInfo = Buffer.from('04389128d9cf88f51be686a56b7d6792609a5cc0748b25b2dd0f77a7a7cdeef3f111049494556c227909ccf041aa65b5154218d4a040dc141bdd6dd0bf86a467c91b96a6e6beea44fc42733ca6d139914136fc69bd53871e03b6a9a7661c08c74a', 'hex');

var keyiv = X963KDF(sharedSecret, sharedInfo, 48);
var key = keyiv.slice(0,32).toString('base64');
var iv = keyiv.slice(32, 48).toString('base64');
console.log("Key: ", key); // Key:  mAzkYatDlz4SzrCyM23NhgL/+mE3eGgfUz9h1CFPhZM=
console.log("IV: ", iv); // IV:  rV3qrszd0PMPgeRhNnlOYA==

Сгенерированный ключ и IV равны ожидаемым значениям.

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