【问题标题】:Why does my AES-decrypted data have garbage bytes at the end?为什么我的 AES 解密数据末尾有垃圾字节?
【发布时间】:2019-02-01 05:03:07
【问题描述】:

我正在尝试使用 AesCryptoProvider 来加密和解密字节数组。

这是我的加密和解密方法:

public static byte[] EncryptAes(byte[] data, out byte[] key, out byte[] iv)
{
    if (data == null || data.Length <= 0)
        throw new ArgumentNullException("data");

    try
    {
        using (AesCryptoServiceProvider aesAlg = new AesCryptoServiceProvider())
        {
            aesAlg.KeySize = 256;
            aesAlg.BlockSize = 128;
            aesAlg.Padding = PaddingMode.PKCS7;
            aesAlg.Mode = CipherMode.CBC;
            aesAlg.GenerateKey();
            aesAlg.GenerateIV();

            key = aesAlg.Key;
            iv = aesAlg.IV;

            using (MemoryStream msEncrypt = new MemoryStream())
            {
                using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, aesAlg.CreateEncryptor(), CryptoStreamMode.Write))
                {
                    csEncrypt.Write(data, 0, data.Length);
                }

                return msEncrypt.ToArray();
            }
        }
    }
    catch (CryptographicException e)
    {
        Log.Error(e);
        key = null;
        iv = null;
        return null;
    }
}

public static byte[] DecryptAes(byte[] encryptedData, byte[] key, byte[] iv)
{
    if (encryptedData == null || encryptedData.Length <= 0)
        throw new ArgumentNullException("encryptedData");
    if (key == null || key.Length <= 0)
        throw new ArgumentNullException("key");
    if (iv == null || iv.Length <= 0)
        throw new ArgumentNullException("iv");

    try
    {
        using (AesCryptoServiceProvider aesAlg = new AesCryptoServiceProvider())
        {
            aesAlg.KeySize = 256;
            aesAlg.BlockSize = 128;
            aesAlg.Padding = PaddingMode.PKCS7;
            aesAlg.Mode = CipherMode.CBC;
            aesAlg.Key = key;
            aesAlg.IV = iv;

            using (MemoryStream msDecrypt = new MemoryStream(encryptedData))
            {
                using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, aesAlg.CreateDecryptor(), CryptoStreamMode.Write))
                {
                    csDecrypt.Write(encryptedData, 0, encryptedData.Length);
                }

                return msDecrypt.ToArray();
            }
        }
    }
    catch (CryptographicException e)
    {
        Log.Error(e);
        return null;
    }
}

然后为了测试它,我正在使用这个代码:

originalMessage = "This is a test message.";
originalData = System.Text.Encoding.UTF8.GetBytes(originalMessage);

byte[] key, iv;
byte[] encryptedData = Encryption.EncryptAes(originalData, out key, out iv);
byte[] decryptedData = Encryption.DecryptAes(encryptedData, key, iv);
string decryptedMessage = System.Text.Encoding.UTF8.GetString(decryptedData);
Log.Debug(decryptedMessage); // This is a test message.?{?o?}??

日志输出显示解密消息中有一堆乱码“?{?o?}??”在末尾。

我见过类似的问题,但他们的答案似乎没有帮助。我尝试在解密过程中写入另一个数组,如下所示:

using (MemoryStream msDecrypt = new MemoryStream(encryptedData))
{
    using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, aesAlg.CreateDecryptor(), CryptoStreamMode.Write))
    {
        byte[] decryptedData = new byte[encryptedData.Length];
        csDecrypt.Write(decryptedData, 0, decryptedData.Length);
    }

    return msDecrypt.ToArray();
}

但这会导致这个异常:

System.Security.Cryptography.CryptographicException: Padding is invalid and cannot be removed.

所以我一定缺少一些东西。有任何想法吗?谢谢!

【问题讨论】:

    标签: c# encryption .net-core aes aescryptoserviceprovider


    【解决方案1】:

    是的,重用缓冲区会让你很痛苦。您通常不希望加密和解密的数据大小相同,因此重用缓冲区会导致您在解密数据中看到剩余的加密数据。

    使您的解密类似于加密。不要将缓冲区传递给MemoryStream的构造函数,让它分配一个正确大小的缓冲区:

    using (MemoryStream msDecrypt = new MemoryStream())
    {
        using (CryptoStream csDecrypt =
              new CryptoStream(msDecrypt,
                               aesAlg.CreateDecryptor(),
                               CryptoStreamMode.Write))
        {
            csDecrypt.Write(encryptedData, 0, encryptedData.Length);
        }
        return msDecrypt.ToArray();
    }
    

    我尝试在解密过程中写入另一个数组,如下所示:

    using (MemoryStream msDecrypt = new MemoryStream(encryptedData))
    {
        using (CryptoStream csDecrypt =
              new CryptoStream(msDecrypt,
                               aesAlg.CreateDecryptor(),
                               CryptoStreamMode.Write))
        {
            byte[] decryptedData = new byte[encryptedData.Length];
            csDecrypt.Write(decryptedData, 0, decryptedData.Length);
        }
    
        return msDecrypt.ToArray();
    }
    

    不要把它读给自己听。您仍在将加密流配置为写入而不是读取。您在这里所做的是分配一个新缓冲区,然后告诉 AES 将那个空缓冲区 解密 到使用加密数据初始化的内存流中。

    【讨论】:

    • 他也不需要打FlushFinalBlock()吗?
    • @gusto2 - 如果他们在通过内部using 访问密码流的Dispose 之前访问内存流的内容,他们会这样做。处理流会导致它call that
    • 啊,是的,做到了!谢谢!我肯定对溪流感到困惑,但现在它是有道理的。关于重命名,方法名称有什么误导性?
    • @OneOfPaperEqualsFourOfCoin - 我的一个错误。一旦我修复了代码以正常工作,我显然将加密代码复制并粘贴到我的答案中,而不是解密代码(它们现在非常相似)。然后我没有回过头来看看我犯了这个错误,并意识到在代码示例中使用 csEncryptmsEncrypt 是我的错误,而不是你的错误。
    猜你喜欢
    • 2019-01-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-21
    • 1970-01-01
    相关资源
    最近更新 更多