将Node.js原生crypto的AES-256-CBC加密函数改写为crypto-js版本
用CryptoJS改写AES-256-CBC加密函数,兼容原Node.js crypto解密逻辑
问题背景
我有一套基于Node.js原生crypto库的encrypt()/decrypt()函数,采用AES-256-CBC算法且运行正常。现在需要仅修改encrypt()函数,改用CryptoJS库实现,同时保证原有的decrypt()函数能正常解密新加密的结果。自行尝试改写后失败,求正确实现方式。
原代码(原生crypto版本)
const crypto = require('crypto'); const ENC_KEY = "bf37b0999c7717c17b2c1d90470cb41e"; function encrypt(data, key, ivLength = 16) { const iv = crypto.randomBytes(ivLength); const cipher = crypto.createCipheriv('aes-256-cbc', key, iv); let encrypted = cipher.update(data, 'utf8', 'base64'); encrypted += cipher.final('base64'); const resultData = { 'iv': iv.toString('base64'), 'data': encrypted } const response = btoa(JSON.stringify(resultData)) return response; }; function decrypt(data, key) { const jsonData = JSON.parse(Buffer.from(data, 'base64').toString('ascii')); const iv = Buffer.from(jsonData['iv'], 'base64') let decipher = crypto.createDecipheriv('aes-256-cbc', key, iv); let decrypted = decipher.update(jsonData['data'], 'base64', 'utf8'); const result = (decrypted + decipher.final('utf8')); return result; }; const phrase = "ORIGINAL PHRASE"; const encryptedCrypto = encrypt(phrase, ENC_KEY); const decryptedCrypto = decrypt(encryptedCrypto, ENC_KEY); console.log(`Decoded string: ${decryptedCrypto}`);
我尝试的错误实现
function encrypt(data, key, ivLength = 16) { const iv = CryptoJS.lib.WordArray.random(ivLength); const encrypted = CryptoJS.AES.encrypt(data, CryptoJS.enc.Hex.parse(key), { iv: iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.NoPadding }); const resultData = { 'iv': CryptoJS.enc.Hex.parse(iv).toString('base64'), 'data': encrypted } const result = btoa(JSON.stringify(resultData)) return result; }
修正后的正确实现
function encrypt(data, key, ivLength = 16) { // 生成与原生crypto长度一致的随机IV const iv = CryptoJS.lib.WordArray.random(ivLength); // 按原生crypto逻辑解析密钥:将字符串按UTF-8转成字节数组 const parsedKey = CryptoJS.enc.Utf8.parse(key); const encrypted = CryptoJS.AES.encrypt(data, parsedKey, { iv: iv, mode: CryptoJS.mode.CBC, // 匹配原生crypto默认的PKCS#7填充规则 padding: CryptoJS.pad.Pkcs7 }); const resultData = { // IV直接转base64,与原生iv.toString('base64')结果一致 'iv': iv.toString(CryptoJS.enc.Base64), // 取纯密文的base64字符串,而非CryptoJS默认的OpenSSL复合格式 'data': encrypted.ciphertext.toString(CryptoJS.enc.Base64) } const result = btoa(JSON.stringify(resultData)) return result; }
错误点说明
- 填充规则不匹配:原生
crypto默认使用PKCS#7填充,原尝试代码设置了NoPadding,导致密文结构与解密逻辑冲突,必须改为CryptoJS.pad.Pkcs7。 - IV处理错误:原代码错误地对
iv执行CryptoJS.enc.Hex.parse(iv)操作,直接用iv.toString(CryptoJS.enc.Base64)就能得到与原生逻辑一致的结果。 - 加密结果处理错误:
CryptoJS.AES.encrypt返回的是CipherParams对象,直接转字符串会得到包含IV的OpenSSL格式内容,而原逻辑只需要纯密文的base64,因此必须取encrypted.ciphertext.toString(CryptoJS.enc.Base64)。 - 密钥解析错误:原生
crypto会将传入的密钥字符串按UTF-8编码转成字节数组,原尝试代码用Hex.parse会把32位十六进制字符串转成16字节密钥,与原逻辑不符,需改为CryptoJS.enc.Utf8.parse(key)。
内容的提问来源于stack exchange,提问作者Pavlo Skliarenko
相关产品推荐
相关产品推荐

