AES-192-CBC加密正常但解密失败,请求技术协助
问题排查与修复方案
你的AES-192-CBC解密失败核心原因有三个,逐一解决即可:
1. IV未复用,解密时生成新IV导致不匹配
AES-CBC模式要求加密和解密必须使用完全相同的IV,你当前加密时生成的IV没有返回给前端,解密时又重新生成新的随机IV,这直接导致解密失败。
2. 密钥生成不一致
convertKey函数每次调用都会生成新的随机盐,PBKDF2算法的密钥是基于密码+盐生成的,加密和解密用同一个密码但不同盐,生成的密钥完全不同,自然无法解密。必须把加密时用的盐也返回给前端,解密时复用该盐。
3. 解密函数参数不匹配
decrypt函数定义仅接收data和key两个参数,但解密路由里传了三个参数(encryptedData, key, ivHex),导致传入的ivHex根本没被使用,函数内部还是用了新生成的IV。
修复后的完整代码
const crypto = require('crypto'); // 假设cryptRouter和logger已提前定义 // Create an initialization vector (IV) const generateInitializationVector = () => { return crypto.randomBytes(16); // 16 bytes = 128 bits }; // Encrypt the data function encrypt(data, key, iv) { const cipher = crypto.createCipheriv('aes-192-cbc', key, iv); let encrypted = cipher.update(data, 'utf8', 'hex'); encrypted += cipher.final('hex'); return encrypted; } // Decrypt the data function decrypt(data, key, iv) { const decipher = crypto.createDecipheriv('aes-192-cbc', key, iv); let decrypted = decipher.update(data, 'hex', 'utf8'); decrypted += decipher.final('utf8'); return decrypted; } // Convert key to a 24-byte Buffer using PBKDF2 function convertKey(keyHex, salt) { const iterations = 100000; // Number of iterations const keyLength = 24; // Desired key length in bytes // 加密时传null则生成新盐,解密时传入加密返回的盐 const usedSalt = salt || crypto.randomBytes(16); const key = crypto.pbkdf2Sync(keyHex, usedSalt, iterations, keyLength, 'sha512'); return { key, salt: usedSalt }; } // Encryption route cryptRouter.post('/encrypt', (req, res) => { try { const originalData = req.body.data; const keyHex = req.body.key; if (!originalData || !keyHex) { return res.status(400).json({ error: 'Data and key are required' }); } const { key, salt } = convertKey(keyHex); // 生成密钥和盐 const iv = generateInitializationVector(); // 生成IV const encryptedData = encrypt(originalData, key, iv); // 返回加密数据、盐、IV(都转成hex字符串方便前端存储/传输) res.json({ encryptedData, salt: salt.toString('hex'), iv: iv.toString('hex') }); } catch (error) { logger.error('Encryption error:', error); res.status(500).json({ error: 'Encryption failed' }); } }); // Decryption route cryptRouter.post('/decrypt', (req, res) => { try { const encryptedData = req.body.data; const keyHex = req.body.key; const saltHex = req.body.salt; const ivHex = req.body.iv; if (!encryptedData || !keyHex || !saltHex || !ivHex) { return res.status(400).json({ error: 'Encrypted data, key, salt, and IV are required' }); } // 将hex字符串转回Buffer const salt = Buffer.from(saltHex, 'hex'); const iv = Buffer.from(ivHex, 'hex'); const { key } = convertKey(keyHex, salt); // 用加密时的盐生成相同密钥 const decryptedData = decrypt(encryptedData, key, iv); res.json({ decryptedData }); } catch (catchError) { logger.error('Error in decryption route:', catchError); res.status(500).json({ error: 'Decryption failed' }); } }); module.exports = cryptRouter;
关键修复点说明
- 加密时将盐、IV、加密数据一起返回给前端,解密时前端需要把这三个参数都传回来
- 修改
convertKey函数,支持传入已有的盐,保证加密解密生成相同密钥 - 修正
decrypt函数的参数,接收传入的IV而非重新生成 - 所有二进制数据(盐、IV)转成hex字符串传输,避免二进制传输的编码问题
内容的提问来源于stack exchange,提问作者Zionnaire
相关产品推荐
相关产品推荐

