簡體   English   中英

如何使用 crypto-js 從 C# 解密 AES

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM