Проблема на стороне расшифровки. encrypted_phex.enc
имеет строку в кодировке base64 (потому что в вашем примере используется «base64» вместо «hex»). Однако decipher.setEncoding('base64')
указывает поток преобразования decipher
для приема некодированных буферов и вывода строк в кодировке base64. Чтобы это работало, нам нужно сначала декодировать кодировку base64 перед расшифровкой, и нам не нужно снова кодировать вывод с помощью base64.
Вот наивная реализация декодирования base64 перед расшифровкой. Это может быть неэффективно для больших данных, потому что он буферизует все чанки и декодирует сразу. Функцию decode()
можно заменить на более эффективную реализацию [1] , но это должно работать как минимум (при условии, что вы вызываете decrypt_phex()
после того, как encrypt_phex()
закончит запись файла).
function decode(encoding) {
const chunks = [];
return new stream.Transform({
transform(chunk, _encoding, callback) {
chunks.push(chunk);
callback();
},
flush(callback) {
const str = Buffer.concat(chunks).toString();
const decoded = Buffer.from(str, encoding);
callback(null, decoded);
}
});
}
function decrypt_phex() {
let inf = "encrypted_phex.enc";
let outf = "decrypted_phex.txt";
let decipher = crypto.createDecipheriv(algorithm, key, iv);
inp_enc = fs.createReadStream(inf);
let decrypted = fs.createWriteStream(outf);
inp_enc
.pipe(decode("base64"))
.pipe(decipher)
.pipe(decrypted);
}
РЕДАКТИРОВАТЬ
Версия .on("data").on("end")
имеет аналогичную проблему при кодировании. Параметры encoding
(utf8, hex, base64 и т. Д.) действительны только для строк. Они нам не нужны при получении или выводе Buffer
с.
Документация Cipher
гласит:
Обновляет шифр данными. Если задан аргумент inputEncoding, аргумент data представляет собой строку, использующую указанную кодировку. Если аргумент inputEncoding не указан, данные должны быть Buffer, TypedArray или DataView. Если data - это Buffer, TypedArray или DataView, то inputEncoding игнорируется.
И чтобы компоненты Node.js понимали «шестнадцатеричное» кодирование, нам необходимо преобразовать Buffer
s в строки,Вот пример использования функции decode()
сверху.
function encrypt_shex() {
let inf = "copyright.txt";
let outf = "encrypted_shex.enc";
let cipher = crypto.createCipheriv(algorithm, key, iv);
let writeStream = fs.createWriteStream(outf);
let readStream = fs.createReadStream(inf);
readStream
.on("data", chunk => {
// The second argument is not necessary because `chunk` is a Buffer.
writeStream.write(cipher.update(chunk, null, "hex"));
})
.on("end", () => {
writeStream.write(cipher.final("hex"));
writeStream.end();
});
}
function decrypt_shex() {
let inf = "encrypted_shex.enc";
let outf = "decrypted_shex.txt";
let decipher = crypto.createDecipheriv(algorithm, key, iv);
let writeStream = fs.createWriteStream(outf);
let readStream = fs.createReadStream(inf);
readStream
// Decode hex string into a Buffer
.pipe(decode("hex"))
.on("data", chunk => {
writeStream.write(decipher.update(chunk));
})
.on("end", () => {
writeStream.write(decipher.final());
writeStream.end();
});
}
Мы могли бы подумать о декодировании шестнадцатеричной строки в обработчике data
, как показано ниже. Однако этот подход имеет проблему, потому что шестнадцатеричное кодирование представляет один байт с двумя символами (два байта). Хотя он работает до тех пор, пока chunk
имеет четное число байтов, когда chunk
имеет нечетное число байтов, decipher
не может его понять и выдает ошибку TypeError: Bad input string
.
function decrypt_shex() {
let inf = "encrypted_shex.enc";
let outf = "decrypted_shex.txt";
let decipher = crypto.createDecipheriv(algorithm, key, iv);
let writeStream = fs.createWriteStream(outf);
let readStream = fs.createReadStream(inf);
readStream
.on("data", chunk => {
// `chunk` is a Buffer, so convert it into a string before giving it as a hex string to `decipher`.
writeStream.write(decipher.update(chunk.toString("ascii"), "hex"));
})
.on("end", () => {
writeStream.write(decipher.final());
writeStream.end();
});
}
[1] Потоковые реализации должны быть более эффективными для больших данных. Например: b64 . Я не проверял это все же.