.NET 7 AES解密抛出填充无效且无法删除错误

问题描述 投票:0回答:1

我正在尝试使用变量 IV 进行一些(基本?)AES 加密,但会返回垃圾,如果要加密的字符串太短,我会收到“填充无效且无法删除”。我将 IV 包含在加密值中以实现随机性,然后在解密剩余值之前将其删除。

 public class AesEncryption
 {
    private static byte[] key = new byte[32] { some key }; // 256-bit key
    public static string Encrypt(string plaintext)
    {
        using (Aes aesAlg = Aes.Create())
        {
            var iv = aesAlg.IV;
            aesAlg.Mode = CipherMode.CBC;
            aesAlg.Padding = PaddingMode.PKCS7;
            ICryptoTransform encryptor = aesAlg.CreateEncryptor(key, iv);
            byte[] encryptedBytes;
            using (var msEncrypt = new MemoryStream())
            {
                using (var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
                {
                    using (var streamWriter = new StreamWriter(csEncrypt))
                    {
                        streamWriter.Write(plaintext);
                    }
                }
                encryptedBytes = msEncrypt.ToArray();
            }
            return new AesCbcCiphertext(iv, encryptedBytes).ToString();
        }
    }

    public static string Decrypt(string ciphertext)
    {
    var cbcCiphertext = AesCbcCiphertext.FromBase64String(ciphertext);
    using (Aes aesAlg = Aes.Create())
    {
        aesAlg.Padding = PaddingMode.PKCS7;
        ICryptoTransform decryptor = aesAlg.CreateDecryptor(key, aesAlg.IV);
        using (var msDecrypt = new MemoryStream(cbcCiphertext.CiphertextBytes))
        {
            using (var csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
            {
                using (var streamReader = new StreamReader(csDecrypt))
                { 
                    return streamReader.ReadToEnd();
                }
            }
        }
    }
}



internal class AesCbcCiphertext
{
    public byte[] IV { get; }
    public byte[] CiphertextBytes { get; }

    public static AesCbcCiphertext FromBase64String(string data)
    {
        var dataBytes = Convert.FromBase64String(data);
        return new AesCbcCiphertext(
        dataBytes.Take(16).ToArray(),
        dataBytes.Skip(16).ToArray()
        );
    }

    public AesCbcCiphertext(byte[] iv, byte[] ciphertextBytes)
    {
        IV = iv;
        CiphertextBytes = ciphertextBytes;
    }

    public override string ToString()
    {
        var total = IV.Concat(CiphertextBytes).ToArray();
        return Convert.ToBase64String(IV.Concat(CiphertextBytes).ToArray());
    }
}

我想我已经阅读了 Stack 上与其相关的所有帖子,并以各种方式调整了解密,但没有成功。有趣的是,如果我使用相同的硬编码 IV,它就可以工作。我以为 IV 对于解密来说并不重要?

c# encryption aes
1个回答
0
投票

.NET 8
中尝试这样:

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

public class Program
{
    private const int AES_BLOCK_SIZE = 16;
    
    public static String AesEncrypt(String strPlain, byte[] Key, byte[] IV)
    {
        try
        {
            if(String.IsNullOrEmpty(strPlain))
            {
                return String.Empty;
            }
            byte[] bytesEncrypted = Array.Empty<byte>();
            using (Aes aes = Aes.Create())
            {
                aes.KeySize = AES_BLOCK_SIZE * 8 * 2; // 32 bytes = 256 bits
                aes.BlockSize =  AES_BLOCK_SIZE * 8;  // 16 bytes = 128 bits
                aes.Key = Key;
                aes.IV = IV;
                aes.Padding = PaddingMode.Zeros;
                aes.Mode = CipherMode.CBC;

                ICryptoTransform encryptor = aes.CreateEncryptor(aes.Key, aes.IV);
                using (MemoryStream ms = new MemoryStream())
                {
                    using (CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
                    {
                        using (StreamWriter sw = new StreamWriter(cs))
                        {
                            sw.Write(strPlain);
                        }
                        bytesEncrypted = ms.ToArray();
                    }
                }
            }
            return Convert.ToBase64String(bytesEncrypted);
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
        return String.Empty;
    }

    public static String AesDecrypt(String strCipher, byte[] Key, byte[] IV)
    {
        try
        {
            if(String.IsNullOrEmpty(strCipher))
            {
                return String.Empty;
            }
            byte[] bytesCipher = Convert.FromBase64String(strCipher);
            if (bytesCipher is null)
            {
                return String.Empty;
            }
            if (bytesCipher.Length == 0)
            {
                return String.Empty;
            }
            String strPlain = String.Empty;
            byte[] bytesPlain = Array.Empty<byte>();
            using (Aes aes = Aes.Create())
            {
                aes.KeySize = AES_BLOCK_SIZE * 8 * 2; // 32 bytes = 256 bits
                aes.BlockSize =  AES_BLOCK_SIZE * 8;  // 16 bytes = 128 bits
                aes.Key = Key;
                aes.IV = IV;
                aes.Padding = PaddingMode.Zeros;
                aes.Mode = CipherMode.CBC;
                
                ICryptoTransform decryptor = aes.CreateDecryptor(aes.Key, aes.IV);
                using (MemoryStream ms = new MemoryStream(bytesCipher))
                {
                    using (CryptoStream cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read))
                    {
                        using (StreamReader sr = new StreamReader(cs))
                        {
                            strPlain = sr.ReadToEnd();
                        }
                    }
                }
            }
            return strPlain;
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
        return String.Empty;
    }

    public static void Main()
    {
        //41413744443430333035394e36373038 41413744443430333035394e36373038 = 256 bits
        byte[] key = new byte[] {0x41, 0x41, 0x37, 0x44, 0x44, 0x34, 0x30, 0x33, 0x30, 0x35, 0x39, 0x4e, 0x36, 0x37, 0x30, 0x38,
                                 0x41, 0x41, 0x37, 0x44, 0x44, 0x34, 0x30, 0x33, 0x30, 0x35, 0x39, 0x4e, 0x36, 0x37, 0x30, 0x38};

        //000102030405060708090A0B0C0D0E0F = 128 bits
        byte[] iv = new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,  0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F};

        string plaintext = "Islam Rahmatan lil 'Alamin";

        using (Aes myAes = Aes.Create())
        {
            string ciphertext = AesEncrypt(plaintext, key, iv);
            string plaintext2  = AesDecrypt(ciphertext, key, iv);
            
            Console.WriteLine("Plaintext:  {0}", plaintext);
            Console.WriteLine("Cipher:  {0}", ciphertext);
            Console.WriteLine("Plaintext2: {0}", plaintext2);
            Console.ReadLine();
        }
    }
}

输出:

Plaintext:  Islam Rahmatan lil 'Alamin
Cipher:     q/EtEjCBlyfWkHET3WwbZDt1XLN3XDrq/oO7D0m4Txg=
Plaintext2: Islam Rahmatan lil 'Alamin
© www.soinside.com 2019 - 2024. All rights reserved.