You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

将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;
}

错误点说明

  1. 填充规则不匹配:原生crypto默认使用PKCS#7填充,原尝试代码设置了NoPadding,导致密文结构与解密逻辑冲突,必须改为CryptoJS.pad.Pkcs7。
  2. IV处理错误:原代码错误地对iv执行CryptoJS.enc.Hex.parse(iv)操作,直接用iv.toString(CryptoJS.enc.Base64)就能得到与原生逻辑一致的结果。
  3. 加密结果处理错误:CryptoJS.AES.encrypt返回的是CipherParams对象,直接转字符串会得到包含IV的OpenSSL格式内容,而原逻辑只需要纯密文的base64,因此必须取encrypted.ciphertext.toString(CryptoJS.enc.Base64)。
  4. 密钥解析错误:原生crypto会将传入的密钥字符串按UTF-8编码转成字节数组,原尝试代码用Hex.parse会把32位十六进制字符串转成16字节密钥,与原逻辑不符,需改为CryptoJS.enc.Utf8.parse(key)。

内容的提问来源于stack exchange,提问作者Pavlo Skliarenko

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 14:49:56