winforms 使用C# AES加密解密期间MAC验证失败

olhwl3o2  于 2023-08-07  发布在  C#
关注(0)|答案(1)|浏览(148)

我在使用AES加密和MAC验证的C#应用程序中遇到了加密和解密过程的问题。加密似乎工作正常,但当我试图解密数据时,我遇到了“MAC验证失败”。数据完整性受损”错误。

using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;

namespace HellsgateDeveloperManager
{
    public static class EncryptionManager
    {
        private const string encryptionKey = "MyEncryptionKey";

        public static byte[] EncryptWithIntegrity(string plaintext)
        {
            byte[] iv = GenerateRandomBytes(16);
            byte[] plaintextBytes = Encoding.UTF8.GetBytes(plaintext);

            // Calculate the MAC over the plaintext data
            byte[] mac = CalculateMAC(plaintextBytes, encryptionKey);

            using (Aes aesAlg = Aes.Create())
            {
                aesAlg.Key = Encoding.UTF8.GetBytes(encryptionKey);
                aesAlg.IV = iv;
                ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);

                byte[] encryptedData;
                using (MemoryStream msEncrypt = new MemoryStream())
                {
                    using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
                    {
                        csEncrypt.Write(plaintextBytes, 0, plaintextBytes.Length);
                    }
                    encryptedData = msEncrypt.ToArray();
                }

                byte[] encryptedDataWithMAC = new byte[iv.Length + encryptedData.Length + mac.Length];
                
                Buffer.BlockCopy(iv, 0, encryptedDataWithMAC, 0, iv.Length);
                Buffer.BlockCopy(encryptedData, 0, encryptedDataWithMAC, iv.Length, encryptedData.Length);
                Buffer.BlockCopy(mac, 0, encryptedDataWithMAC, iv.Length + encryptedData.Length, mac.Length);

                return encryptedDataWithMAC;
            }
        }

        public static string DecryptWithIntegrity(byte[] encryptedDataWithMAC)
        {
            int ivLength = 16;
            int macLength = 32;
            int expectedMinLength = ivLength + macLength;

            if (encryptedDataWithMAC == null || encryptedDataWithMAC.Length < expectedMinLength)
            {
                throw new ArgumentException("Invalid encrypted data format.");
            }

            byte[] iv = new byte[ivLength];
            byte[] encryptedData = new byte[encryptedDataWithMAC.Length - ivLength - macLength];
            byte[] receivedMAC = new byte[macLength];

            Buffer.BlockCopy(encryptedDataWithMAC, 0, iv, 0, iv.Length);
            Buffer.BlockCopy(encryptedDataWithMAC, iv.Length, encryptedData, 0, encryptedData.Length);
            Buffer.BlockCopy(encryptedDataWithMAC, iv.Length + encryptedData.Length, receivedMAC, 0, receivedMAC.Length);

            byte[] calculatedMAC = CalculateMAC(encryptedData, encryptionKey);

            if (!CompareMACs(receivedMAC, calculatedMAC))
            {
                throw new CryptographicException("MAC verification failed. Data integrity compromised.");
            }

            using (Aes aesAlg = Aes.Create())
            {
                aesAlg.Key = Encoding.UTF8.GetBytes(encryptionKey);
                aesAlg.IV = iv;
                ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);

                using (MemoryStream msDecrypt = new MemoryStream(encryptedData))
                {
                    using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
                    {
                        using (StreamReader srDecrypt = new StreamReader(csDecrypt))
                        {
                            return srDecrypt.ReadToEnd();
                        }
                    }
                }
            }
        }

        private static byte[] CalculateMAC(byte[] data, string key)
        {
            byte[] keyBytes = Encoding.UTF8.GetBytes(key);
            using (HMACSHA256 hmac = new HMACSHA256(keyBytes))
            {
                return hmac.ComputeHash(data);
            }
        }

        private static bool CompareMACs(byte[] mac1, byte[] mac2)
        {
            if (mac1.Length != mac2.Length)
            {
                return false;
            }

            for (int i = 0; i < mac1.Length; i++)
            {
                if (mac1[i] != mac2[i])
                {
                    return false;
                }
            }

            return true;
        }

        private static byte[] GenerateRandomBytes(int length)
        {
            byte[] randomBytes = new byte[length];
            using (RandomNumberGenerator rng = RandomNumberGenerator.Create())
            {
                rng.GetBytes(randomBytes);
            }
            return randomBytes;
        }
    }
}

字符串
每当我尝试比较MAC时,就会出现错误。
我将非常感谢任何见解,建议或可能的解决方案,以帮助我解决这个问题。如果任何人在使用C# AES加密和MAC验证时遇到类似的问题,或者如果我可以采取任何其他故障排除步骤,请告诉我。提前感谢您的帮助!
为了调试这个问题,我仔细检查了加密代码,包括IV的生成和MAC。我还检查了加密和解密使用的密钥是否相同。我实施了大量的日志记录来跟踪过程中的数据和密钥,但我无法确定任何差异。我尝试使用Chat-gpt来获得一些指导,但没有进一步的帮助。

hmtdttj4

hmtdttj41#

您正在计算加密明文的MAC,并且正在计算解密密文 * 的MAC *。最好转换为使用encrypt-then-mac。这基本上就是你在解密过程中所做的。如果你这样做,你应该确保将IV包括在计算中。
就目前而言,您应该知道发送相同的消息将导致加密期间相同的MAC,这意味着有关消息的少量信息将被泄露。更糟糕的是,在解密过程中,你可能容易受到填充oracle攻击。
还有其他安全问题,例如使用字符串来构成密钥,使用依赖于静态密钥的静态方法,用于认证标签(MAC结果)的非时间常数比较。也许你可以使用GCM来代替,这样大部分问题都可以很容易地解决。
即使这样,你也应该担心你的协议是否安全,是否容易受到例如重播攻击这就是为什么,你最好不要尝试创建自己的。

相关问题