Как получить ключ и начальный вектор в 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 равны ожидаемым значениям.