.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
相关产品推荐
相关产品推荐

