Node.js使用hex/base64编码加解密文件时报错:错误的最终块长度
Node.js 文件加解密编码问题解决指南
这个问题我之前也碰到过!你遇到的wrong final block length错误,核心原因是加密和解密过程中的编码没有严格匹配,尤其是用pipe处理流的时候,很容易因为编码转换的细节踩坑。下面我给你拆解问题和解决方案:
为什么设置编码后解密会失败?
Node.js 的 crypto 模块中,Cipher 和 Decipher 对编码的处理很严格:
- 如果你加密时把输出转换成了
hex/base64字符串,解密时必须把输入的字符串完全还原成加密时的二进制格式才能正常解密。 - 用
pipe处理流时,默认是传输二进制Buffer,如果直接给Cipher设置setEncoding('hex'),会让流输出字符串,后续写入文件时默认按utf8编码转成Buffer,导致解密时读取的Buffer和加密时的原始二进制数据不一致,最终出现块长度错误。
解决方案:分两种场景处理
1. 非流方式(同步/异步读写文件)
确保加密时的输出编码和解密时的输入编码严格对应,示例代码如下:
加密(输出 hex 编码)
const fs = require('fs'); const crypto = require('crypto'); const algorithm = 'aes-256-cbc'; const key = crypto.randomBytes(32); // 生成密钥 const iv = crypto.randomBytes(16); // 生成初始化向量 // 读取原始文件(默认返回 Buffer) const inputData = fs.readFileSync('input.txt'); // 创建加密器,输出 hex 字符串 const cipher = crypto.createCipheriv(algorithm, key, iv); let encrypted = cipher.update(inputData, undefined, 'hex'); encrypted += cipher.final('hex'); // 写入加密后的字符串文件(指定 utf8 编码) fs.writeFileSync('encrypted.hex', encrypted, 'utf8');
解密(输入 hex 编码)
// 读取加密后的 hex 文件(按 utf8 编码读取字符串) const encryptedStr = fs.readFileSync('encrypted.hex', 'utf8'); // 创建解密器,输入 hex 字符串,输出 utf8 内容 const decipher = crypto.createDecipheriv(algorithm, key, iv); let decrypted = decipher.update(encryptedStr, 'hex', 'utf8'); decrypted += decipher.final('utf8'); // 写入解密后的文件 fs.writeFileSync('decrypted.txt', decrypted);
2. 流方式(pipe 处理大文件)
流处理时不能直接给 Cipher/Decipher 设置编码,需要通过转换流显式处理 Buffer 和字符串的转换,避免编码失真:
加密(pipe + hex 编码输出)
const { createReadStream, createWriteStream } = require('fs'); const { createCipheriv, randomBytes } = require('crypto'); const { pipeline } = require('stream'); const { Transform } = require('stream'); const algorithm = 'aes-256-cbc'; const key = randomBytes(32); const iv = randomBytes(16); // 管道流程:读取原始文件 → 加密(输出 Buffer)→ 转 hex 字符串 → 写入文件 pipeline( createReadStream('input.txt'), createCipheriv(algorithm, key, iv), // 转换流:把加密后的 Buffer 转成 hex 字符串 new Transform({ transform(chunk, _, callback) { callback(null, chunk.toString('hex')); } }), createWriteStream('encrypted.hex', { encoding: 'utf8' }), (err) => { if (err) console.error('加密失败:', err); else console.log('加密完成'); } );
解密(pipe + hex 编码输入)
// 管道流程:读取 hex 文件 → 转成加密后的 Buffer → 解密 → 写入文件 pipeline( createReadStream('encrypted.hex', { encoding: 'utf8' }), // 转换流:把 hex 字符串转成原始加密 Buffer new Transform({ transform(chunk, _, callback) { try { // 确保输入的是合法 hex 字符串,避免转换错误 const buf = Buffer.from(chunk, 'hex'); callback(null, buf); } catch (err) { callback(new Error('无效的 hex 编码数据')); } } }), createDecipheriv(algorithm, key, iv), createWriteStream('decrypted.txt'), (err) => { if (err) console.error('解密失败:', err); else console.log('解密完成'); } );
关键注意点
- 编码严格匹配:加密用
hex,解密必须用hex;加密用base64,解密必须用base64,不能混用。 - 流处理避免直接设置编码:不要给
Cipher/Decipher调用setEncoding(),而是用转换流处理编码转换,保证流中传输的是正确格式的数据。 - 文件读写指定编码:写入加密后的字符串文件时,要指定
utf8编码;读取时也要用相同编码读取,再转成对应格式的Buffer。
内容的提问来源于stack exchange,提问作者Antony
相关产品推荐
相关产品推荐

