如何使用Node.js解密经OpenSSL加密的文件
解决OpenSSL AES-256加密文件的Crypto库解密问题
核心问题原因
你用openssl enc -aes256 -k加密时,不是直接将密码作为密钥,而是通过OpenSSL特定的密钥派生算法生成密钥和IV。不同OpenSSL版本使用的派生逻辑不同,这是解密失败的核心。
解密步骤(分版本处理)
1. 提取加密文件中的Salt
OpenSSL默认会在加密文件开头添加Salted__标识(8字节)+ 8字节的salt值,解密必须使用这个salt:
// 示例:Node.js中读取并提取salt const fs = require('fs'); const encryptedData = fs.readFileSync('encrypted'); const salt = encryptedData.slice(8, 16); // 第9-16字节是salt const ciphertext = encryptedData.slice(16); // 剩余部分是实际密文
2. 根据OpenSSL版本生成密钥和IV
先通过openssl version确认你的版本:
情况1:OpenSSL版本 < 1.1.0c
使用EVP_BytesToKey算法,默认参数:MD5哈希、迭代次数1,生成32字节密钥(AES-256)+16字节IV:
const crypto = require('crypto'); function evpBytesToKey(passwordBytes, salt, keyLen, ivLen) { let key = Buffer.alloc(0); let iv = Buffer.alloc(0); let last = Buffer.alloc(0); while (key.length < keyLen || iv.length < ivLen) { last = crypto.createHash('md5') .update(Buffer.concat([last, passwordBytes, salt])) .digest(); // 填充密钥和IV if (key.length < keyLen) { const need = keyLen - key.length; key = Buffer.concat([key, last.slice(0, need)]); } if (iv.length < ivLen) { const need = ivLen - iv.length; iv = Buffer.concat([iv, last.slice(Math.max(0, last.length - need))]); } } return { key, iv }; } // 生成密钥和IV const passwordBytes = Buffer.from('myverystrongpassword', 'utf8'); const { key, iv } = evpBytesToKey(passwordBytes, salt, 32, 16);
情况2:OpenSSL版本 >= 1.1.0c
默认改用PBKDF2算法,参数:SHA256哈希、迭代次数10000,生成48字节派生数据(前32字节密钥,后16字节IV):
const crypto = require('crypto'); const passwordBytes = Buffer.from('myverystrongpassword', 'utf8'); // 生成48字节派生数据:32字节密钥 + 16字节IV const derived = crypto.pbkdf2Sync(passwordBytes, salt, 10000, 32 + 16, 'sha256'); const key = derived.slice(0, 32); const iv = derived.slice(32);
3. 执行解密
使用AES-256-CBC算法(OpenSSL默认模式)+ PKCS#7填充(默认填充方式)解密:
const decipher = crypto.createDecipheriv('aes-256-cbc', key, iv); let decrypted = decipher.update(ciphertext); decrypted = Buffer.concat([decrypted, decipher.final()]); // 保存解密后的文件 fs.writeFileSync('decrypted_data', decrypted);
常见错误排查
- 忽略salt:必须提取加密文件中的salt,不能用自定义或空salt
- 哈希函数/迭代次数不匹配:严格对应OpenSSL版本的默认参数
- 加密模式错误:OpenSSL
aes256默认是CBC模式,不是ECB或GCM
内容的提问来源于stack exchange,提问作者Karol M
相关产品推荐
相关产品推荐

