我正在嘗試使用 C# 在后端解密使用 AES 加密的值。解密部分將在 Angular 的前端發生(使用crypto-js ) 我遇到的問題是我總是得到一個空字串作為解密的結果。我不知道我做錯了什么。我是否缺少某種配置?
我要加密的 C# 代碼如下所示:
//
EncryptAES("XEMFkT92UtR1VJI8kU8XQJALk98GGEFM", "random text to encrypt");
public static string EncryptAES(string passPhrase, string plainText)
{
byte[] iv = Generate256BitsOfRandomEntropy();
byte[] temp;
byte[] array;
using (Aes aes = Aes.Create())
{
byte[] salt = Generate256BitsOfRandomEntropy();
Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(passPhrase, salt, 100);
aes.Key = pdb.GetBytes(32);
aes.KeySize = 256;
aes.Padding = PaddingMode.PKCS7;
aes.Mode = CipherMode.CBC;
aes.IV = iv;
ICryptoTransform encryptor = aes.CreateEncryptor(aes.Key, aes.IV);
using (MemoryStream memoryStream = new MemoryStream())
{
using (CryptoStream cryptoStream = new CryptoStream((Stream)memoryStream, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter streamWriter = new StreamWriter((Stream)cryptoStream, Encoding.UTF8))
{
streamWriter.Write(plainText);
}
temp = memoryStream.ToArray();
array = salt.Concat(iv).Concat(temp).ToArray();
cryptoStream.Flush();
encryptor.Dispose();
}
}
}
return Convert.ToBase64String(array);
}
//Random byte[] generator
private static byte[] Generate256BitsOfRandomEntropy()
{
var randomBytes = new byte[16];
using (var rngCsp = new RNGCryptoServiceProvider())
{
rngCsp.GetBytes(randomBytes);
}
return randomBytes;
}
.ts檔案中的解密部分為:
//The param "key" will be same as the C# code: XEMFkT92UtR1VJI8kU8XQJALk98GGEFM
//The param "toDecrypt" will the the Base64 returned by the service in C#
decryptAES(key: string, toDecrypt: string) {
var data = Buffer.from(toDecrypt, 'base64');
var salt = data.slice(0, 16); //first 16 bytes to get the salt
var iv = data.slice(16, 32);// next 16 bytes to get the IV
const wordArrayIV = CryptoJS.lib.WordArray.create(Array.from(iv));
const wordArraySalt = CryptoJS.lib.WordArray.create(Array.from(salt))
var keyPBKDF2 = CryptoJS.PBKDF2(key, wordArraySalt, {
keySize: 256 / 32,
iterations: 100
});
var decrypted = CryptoJS.AES.decrypt(toDecrypt, keyPBKDF2,
{
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7,
iv: wordArrayIV
});
//Return empty string
return decrypted.toString();
}
uj5u.com熱心網友回復:
在C#代碼中,沒有使用PBKDF2派生的密鑰,而是隨機生成的密鑰。這是因為設定密鑰大小時,會隱式生成一個新密鑰。
作為修復,只需洗掉鍵大小的設定,即行aes.KeySize = 256(鍵大小在設定鍵時隱式設定)。
...
aes.Key = pdb.GetBytes(32);
//aes.KeySize = 256; // Fix: remove
//aes.Padding = PaddingMode.PKCS7; // default
//aes.Mode = CipherMode.CBC; // default
aes.IV = iv;
...
此外,CryptoJS代碼中還有幾個問題:首先,Buffers被錯誤地轉換為WordArrays,導致IV和salt錯誤。
此外,在分離時不考慮密文,而且還錯誤地傳遞給AES.decrypt().
解密后的資料是十六進制編碼的,但應該是 UTF-8 解碼的。
function decryptAES(key, toDecrypt) {
var data = CryptoJS.enc.Base64.parse(toDecrypt);
var wordArraySalt = CryptoJS.lib.WordArray.create(data.words.slice(0, 4)); // Fix: Array -> WordArray conversion
var wordArrayIV = CryptoJS.lib.WordArray.create(data.words.slice(4, 8)); // Fix: Array -> WordArray conversion
var wordArrayCt = CryptoJS.lib.WordArray.create(data.words.slice(8)); // Fix: Consider ciphertext
var keyPBKDF2 = CryptoJS.PBKDF2(key, wordArraySalt, {keySize: 256 / 32, iterations: 100});
var decrypted = CryptoJS.AES.decrypt({ciphertext: wordArrayCt}, keyPBKDF2, {iv: wordArrayIV}); // Fix: Pass ciphertext as CipherParams object
return decrypted.toString(CryptoJS.enc.Utf8); // Fix: UTF-8 decode
}
var decrypted = decryptAES('XEMFkT92UtR1VJI8kU8XQJALk98GGEFM', '4YI4unJecVXvvNQVgBsdUwrr7rlwcImDb7t1LT88UO0w8BdFpOp5PLsu6PRJ eCeKB01rWdVVrGMLj7tOi3KHg==');
console.log(decrypted);
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js"></script>
請注意,上面代碼中的密文是使用固定的C# 代碼生成的。
關于漏洞:PBKDF2 密鑰派生中的 100 次迭代計數通常太小。
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/537239.html
上一篇:Angular2選擇表單不捕獲值
