[英]How to decrypt AES with crypto-js from C#
我正在嘗試在后端使用 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();
}
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 次迭代計數通常太小。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.