Здесь есть несколько проблем.
Во-первых: ДРУЗЬЯ НЕ ПОЗВОЛЯЮТ ДРУЗЬЯМ ЗАВЕРШИТЬ СВОЙ КРИПТО (по крайней мере, если вы хотите получить что-то безопасное). Вместо этого используйте высокоуровневые примитивы из некоторой стандартной библиотеки шифрования.
Тогда остальные вещи:
- Основная проблема, которая позволяет вам расшифровывать вещи с неправильным ключом, состоит в том, что вы используете
Buffer.from()
неправильно и в итоге вы получаете ключ <Buffer 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00>
. Изменение этого вызова на Buffer.from(hash).slice(0, 32)
дает вам вид ключа, полученный из результата bcrypt.hash()
, но:
- При использовании
bcrypt.hash()
он никогда не возвращает одну и ту же строку для одной и той же входной строки, что делает невозможным дешифрование данных, даже если вы знаете правильную ключевую фразу. Кроме того, функция возвращает строку, подобную $2b$10$z3X6QVxZtl4JmrkH2u7rV.bVq0vFUY9XSrTKVnoyZ7s8X4cybmox6
, и по мере того, как обстоят дела (даже при правильном использовании Buffer.from()
), вам придется использовать только первые 32 символа, что, вероятно, не то, что вам нужно.
- В вашей схеме шифрования отсутствует аутентификация; Вы не можете знать, правильно ли вы расшифровали строку. Например, с фиксированным вызовом
Buffer.from()
я получаю (например, - это всегда случайно -) decrypted 嶥,벗Jꢣ틣FMnZhH줰]}H㥋z⮕gL⎕
в качестве вывода, и, не зная исходного открытого текста, я не могу знать, является ли это правильным результатом дешифрования.
Вот переработанный код, который я использовал.
Изменение saltRounds
на солт-строку, полученную с помощью const salt = await bcrypt.genSalt(10);
или аналогичной в основной функции, делает дешифрование обратимым, , но код все равно не будет безопасным .
"use strict";
const bcrypt = require("bcrypt");
const aesjs = require("aes-js");
async function deriveKey(password, saltRounds) {
const hash = await bcrypt.hash(password, saltRounds);
console.log("Hash:", hash);
return Buffer.from(hash).slice(0, 32);
}
async function getEncryptionObject(password, saltRounds, counter) {
const key = await deriveKey(password, saltRounds);
console.log("Key:", key);
return new aesjs.ModeOfOperation.ctr(key, new aesjs.Counter(counter));
}
async function encrypt(text, password, saltRounds, counter = 5) {
const aesCtr = await getEncryptionObject(password, saltRounds, counter);
const textBytes = aesjs.utils.utf8.toBytes(text);
const encryptedBytes = aesCtr.encrypt(textBytes);
return aesjs.utils.hex.fromBytes(encryptedBytes);
}
async function decrypt(encryptedHex, password, saltRounds, counter = 5) {
const aesCtr = await getEncryptionObject(password, saltRounds, counter);
const encryptedBytes = aesjs.utils.hex.toBytes(encryptedHex);
const decryptedBytes = aesCtr.decrypt(encryptedBytes);
return aesjs.utils.utf8.fromBytes(decryptedBytes);
}
(async () => {
const encryptionPassword = "pass";
const decryptionPassword = "sdfs6654df";
const saltRounds = 10;
const text = "ЧЕРТ ВОЗЬМИ, КАК ЖЕ ЭТО СЕКРЕТНО!";
console.log("original: " + text);
const encryptedHex = await encrypt(text, encryptionPassword, saltRounds, 5);
console.log("encrypted " + encryptedHex);
const decryptedText = await decrypt(
encryptedHex,
decryptionPassword,
saltRounds,
5,
);
console.log("decrypted " + decryptedText);
})();