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

.NET Core中AES解密返回空字符串问题排查

问题:Angular CryptoJS AES加密后,.NET Core解密返回空字符串

在Angular项目中使用CryptoJS结合PBKDF2显式实现AES加密,对应在.NET Core代码中进行解密时,调用解密方法返回空字符串,无法定位问题。

Angular端加密代码

import { Injectable } from '@angular/core';
import * as CryptoJS from 'crypto-js';

@Injectable({
    providedIn: 'root',
})
export class CryptoService {
private secretkey = "MyOwnKey";

encrypt(text: string): string {
    // random salt for derivation
    let keySize = 256;
    let salt = CryptoJS.lib.WordArray.random(16);
    // well known algorithm to generate key
    let key = CryptoJS.PBKDF2(this.secretkey, salt, {
        keySize: keySize/32,
        iterations: 100
        });
    // random IV
    let iv = CryptoJS.lib.WordArray.random(16);      
    // specify everything explicitly
    let encrypted = CryptoJS.AES.encrypt(text, key, { 
        iv: iv, 
        padding: CryptoJS.pad.Pkcs7,
        mode: CryptoJS.mode.CBC        
    });
    // combine everything together in base64 string
    let result = CryptoJS.enc.Base64.stringify(salt.concat(iv).concat(encrypted.ciphertext));
    return result;
}
}

.NET Core端解密代码

public string decrypt(string cipherText)
{
    if (string.IsNullOrEmpty(cipherText))
        return string.Empty;
    
    try
    {
        byte[] cipherBytes = Convert.FromBase64String(cipherText);

        using (Aes encryptor = Aes.Create())
        {
            // extract salt (first 16 bytes)
            byte[] salt = new byte[16];
            Array.Copy(cipherBytes, 0, salt, 0, 16);
            _logger.LogInformation("salt: {salt}", salt);

            // extract iv (next 16 bytes)
            byte[] iv = new byte[16];
            Array.Copy(cipherBytes, 16, iv, 0, 16);
            _logger.LogInformation("iv: {iv}", iv);

            // the rest is encrypted data
            byte[] encrypted = new byte[cipherBytes.Length - 32];
            Array.Copy(cipherBytes, 32, encrypted, 0, cipherBytes.Length - 32);
            _logger.LogInformation("encrypted: {encrypted}", encrypted);

            Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes("MyOwnKey", salt, 100);
            encryptor.Key = pdb.GetBytes(32);
            encryptor.Padding = PaddingMode.PKCS7;
            encryptor.Mode = CipherMode.CBC;
            encryptor.IV = iv;

            string plaintext;
            using (MemoryStream ms = new MemoryStream(encrypted))
            {
                using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateDecryptor(), CryptoStreamMode.Read))
                {
                    using (var reader = new StreamReader(cs, Encoding.UTF8))
                    {
                        plaintext = reader.ReadToEnd();
                        reader?.Dispose();
                    }
                    cs?.Dispose();
                }
            }
            var cbLength = plaintext.Length;
            _logger.LogInformation("plaintext Lenght: {cbLength}", cbLength);
            return plaintext;
        }
    }
    catch (Exception ex)
    {
        return "Decryption error: " + ex.Message;
    }
}

问题原因

核心问题是密钥的编码不一致:

  • CryptoJS的PBKDF2默认将密钥字符串按UTF-8编码转换为字节数组进行密钥派生。
  • .NET的Rfc2898DeriveBytes构造函数直接传入字符串时,默认使用UTF-16LE(Unicode)编码转换密钥,导致两端生成的派生密钥完全不同,解密过程实际失败,最终返回空字符串。

解决方法

修改.NET端的密钥派生代码,将密钥字符串按UTF-8编码转换为字节数组后传入Rfc2898DeriveBytes:

// 替换原来的Rfc2898DeriveBytes初始化代码
byte[] keyBytes = Encoding.UTF8.GetBytes("MyOwnKey");
Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(keyBytes, salt, 100);

修改后,两端的密钥派生逻辑使用相同的编码规则,生成一致的AES密钥,即可正常解密出明文。

内容的提问来源于stack exchange,提问作者Ameetesh Sharma

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 22:20:28