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

使用CryptoJS解密Python Cryptodome AES加密数据时遇UTF-8错误

问题:Angular中使用CryptoJS解密Python Cryptodome加密内容时出现「Malformed UTF-8 data」错误

我尝试在Angular中用CryptoJS解密Python Cryptodome加密的消息,已编写Python加密函数和Angular解密服务,但解密时触发「ERROR Error: Malformed UTF-8 data」错误。我知道是转UTF-8时出现非法字符,但找不到解决办法,恳请提供解决方案。

Python加密代码

import os
from Crypto.Cipher import AES
from Crypto.Util import padding
import base64

def encrypt_aes_256_cbc(data):
    key = os.getenv('ENCRYPT_KEY')
    iv = os.getenv('ENCRYPT_IV')
    
    # 确保密钥和IV为字节类型
    key = bytes.fromhex(key)
    iv = bytes.fromhex(iv)

    # 将数据转为字节
    data_bytes = data.encode('utf-8')
    padded_data = _pkcs7_pad(data_bytes, AES.block_size)
    # 创建AES-256 CBC模式的密码器
    cipher = AES.new(key, AES.MODE_CBC, iv)

    # 加密数据
    ciphertext = cipher.encrypt(padded_data)

    # 拼接IV和密文后做Base64编码
    combined_data = iv + ciphertext
    encoded_ciphertext = base64.b64encode(combined_data).decode("utf-8")
    return encoded_ciphertext

def _pkcs7_pad(data, block_size):
    padder = padding.PKCS7(block_size).padder()
    padded_data = padder.update(data) + padder.finalize()
    print('padded data =', padded_data)
    return padded_data

Angular解密代码(原错误版本)

export class EncryptDecryptService {
  iv = CryptoJS.enc.Hex.parse(environment.iv);
  decryptKey = CryptoJS.enc.Hex.parse(environment.keyDecryptage);

  decryptData(encrypted_json_string: string) {
    // const  or = CryptoJS.enc.Base64.parse(encrypted_json_string).toString(CryptoJS.enc.Utf8)
    const decrypted = CryptoJS.AES.decrypt(
      encrypted_json_string,
      this.decryptKey,
      { iv: this.iv }
    );
    console.log("decrypted.toString(CryptoJS.enc.Latin1) =", decrypted.toString(CryptoJS.enc.Utf8));
    
    return decrypted.toString(CryptoJS.enc.Utf8);
  }
}
解决方案

问题核心是CryptoJS解密参数格式与Python加密输出不匹配:

Python端把IV + 密文拼接后做了Base64编码,但CryptoJS的AES.decrypt方法直接接收Base64字符串时,默认会按OpenSSL格式或CipherParams JSON解析,而非我们需要的「IV+密文」组合格式,导致解密出乱码,转UTF-8时报错。

修改后的Angular解密代码:

export class EncryptDecryptService {
  decryptKey = CryptoJS.enc.Hex.parse(environment.keyDecryptage);

  decryptData(encrypted_json_string: string) {
    // 1. 将Base64编码的IV+密文解析为WordArray
    const combinedData = CryptoJS.enc.Base64.parse(encrypted_json_string);
    
    // 2. 拆分IV(AES块大小为16字节,对应4个Word,每个Word占4字节)和密文
    const iv = CryptoJS.lib.WordArray.create(combinedData.words.slice(0, 4));
    const ciphertext = CryptoJS.lib.WordArray.create(combinedData.words.slice(4));

    // 3. 传入CipherParams对象解密,显式指定PKCS7填充(与Python端对齐)
    const decrypted = CryptoJS.AES.decrypt(
      { ciphertext: ciphertext },
      this.decryptKey,
      { iv: iv, padding: CryptoJS.pad.Pkcs7 }
    );

    // 4. 转换为UTF-8字符串返回
    return decrypted.toString(CryptoJS.enc.Utf8);
  }
}

额外注意事项

  • 确保Python和Angular使用的密钥、IV完全一致:密钥需为32字节(对应64位十六进制字符串),IV为16字节(对应32位十六进制字符串)
  • 两端填充方式均为PKCS7,CryptoJS默认使用该填充,但显式指定可避免潜在兼容性问题
  • 不要直接将Base64字符串传给AES.decrypt的第一个参数,需拆分为包含ciphertext字段的CipherParams对象

内容的提问来源于stack exchange,提问作者girl of data

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 10:57:37