C#:AES 错误:填充无效且无法删除。相同的钥匙和一切,帮助

发布于 2024-10-18 17:37:26 字数 2597 浏览 0 评论 0原文

我对 C# 还很陌生,所以请耐心等待。我知道这个问题被问了很多次,但我找不到我的问题的答案。

我正在保存一些数据,在将其写入文件之前,我将其转换为二进制并将其存储在数组中,对其进行加密,然后写入文件。我以块(32 字节)的形式加密数据。以同样的方式,我读取 32 字节块的数据,然后解密该数据,然后重复此操作直到文件末尾。但在解密时会抛出以下错误:

填充无效且无法删除。

我使用相同的密钥和 iv(硬编码直到我开始工作)

这是我的加密代码,可以正常工作:

        //result
        byte[] data = new byte[32];

        //setup encryption (AES)
        SymmetricAlgorithm aes = Aes.Create();
        byte[] key = { 145, 12, 32, 245, 98, 132, 98, 214, 6, 77, 131, 44, 221, 3, 9,50};
        byte[] iv = { 15, 122, 132, 5, 93, 198, 44, 31, 9, 39, 241, 49, 250, 188, 80, 7 };
        ICryptoTransform encryptor = aes.CreateEncryptor(key, iv);

        FileStream fStream = new FileStream(file, FileMode.OpenOrCreate, FileAccess.Write, FileShare.Read, 1024, false);

        //prepare data to write (byte array 'data') ...

        //encrypt
               MemoryStream m = new MemoryStream();
               using (Stream c = new CryptoStream(m, encryptor, CryptoStreamMode.Write))
                   c.Write(data, 0, data.Length);
               data = m.ToArray();
               fStream.Write(data, 0, data.Length);

这是我的解密代码:

FileStream fStream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read, 4096, false);

            //setup encryption (AES)
            SymmetricAlgorithm aes = Aes.Create();
            byte[] key = { 145, 12, 32, 245, 98, 132, 98, 214, 6, 77, 131, 44, 221, 3, 9, 50 };
            byte[] iv = { 15, 122, 132, 5, 93, 198, 44, 31, 9, 39, 241, 49, 250, 188, 80, 7 };
            ICryptoTransform decryptor = aes.CreateDecryptor(key, iv);

            //result
            byte[] data = new byte[32];

            //loop for reading the whole file ...
            int len = fStream.Read(data, 0, 32);

            //decrypt
                MemoryStream m = new MemoryStream();
                using (Stream c = new CryptoStream(m, decryptor, CryptoStreamMode.Write))
                    c.Write(data, 0, data.Length); //The exception is thrown in this line                  
                data = m.ToArray();

                //using the decrypted data and then looping back to reading and decrypting...

我尝试了我能想到的所有方法(这并不多,因为我对密码学很陌生),我到处搜索,但找不到解决我的问题的方法。我还帮助自己阅读了《C# in a Nutshell》一书。

如果有人知道为什么会发生这种情况,我将非常感激,因为我没有任何想法。

感谢您的时间和答复。

编辑: 看来加密数据的大小是48字节(比原来多了12字节)。为什么会这样呢?我认为它只会添加字节,如果它们不是块大小的倍数(16 字节,我的数据是 32 字节)。数据是否总是较大,并且不断增加(我需要知道这一点才能正确读取和解密)。

注意:我不能直接使用其他流,因为我需要控制输出格式,并且我相信在内存中加密也更安全、更快。

I'm quite new to C# so please be patient with me. I know this question was asked a lot if times, but I couldn't find an answer to my problem.

I'm saving some data and before writing it to a file I convert it to binary and store it in array, which I encrypt and then write to file. I encrypt data in chunks (32 bytes). In the same way I read data in chunks of 32 bytes and then decrypt that data and then this should repeat till the end of file. But when it comes to decryption the following error is thrown:

Padding is invalid and cannot be removed.

I use the same key and iv (hardcoded just until I get it working)

Here is my encryption code, which works without problems:

        //result
        byte[] data = new byte[32];

        //setup encryption (AES)
        SymmetricAlgorithm aes = Aes.Create();
        byte[] key = { 145, 12, 32, 245, 98, 132, 98, 214, 6, 77, 131, 44, 221, 3, 9,50};
        byte[] iv = { 15, 122, 132, 5, 93, 198, 44, 31, 9, 39, 241, 49, 250, 188, 80, 7 };
        ICryptoTransform encryptor = aes.CreateEncryptor(key, iv);

        FileStream fStream = new FileStream(file, FileMode.OpenOrCreate, FileAccess.Write, FileShare.Read, 1024, false);

        //prepare data to write (byte array 'data') ...

        //encrypt
               MemoryStream m = new MemoryStream();
               using (Stream c = new CryptoStream(m, encryptor, CryptoStreamMode.Write))
                   c.Write(data, 0, data.Length);
               data = m.ToArray();
               fStream.Write(data, 0, data.Length);

And here is my decryption code:

FileStream fStream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read, 4096, false);

            //setup encryption (AES)
            SymmetricAlgorithm aes = Aes.Create();
            byte[] key = { 145, 12, 32, 245, 98, 132, 98, 214, 6, 77, 131, 44, 221, 3, 9, 50 };
            byte[] iv = { 15, 122, 132, 5, 93, 198, 44, 31, 9, 39, 241, 49, 250, 188, 80, 7 };
            ICryptoTransform decryptor = aes.CreateDecryptor(key, iv);

            //result
            byte[] data = new byte[32];

            //loop for reading the whole file ...
            int len = fStream.Read(data, 0, 32);

            //decrypt
                MemoryStream m = new MemoryStream();
                using (Stream c = new CryptoStream(m, decryptor, CryptoStreamMode.Write))
                    c.Write(data, 0, data.Length); //The exception is thrown in this line                  
                data = m.ToArray();

                //using the decrypted data and then looping back to reading and decrypting...

I tried all I could think of (which is not much because I'm very new to cryptography), I searched everywhere and I couldn't find a solution to my problem. I also helped myself with the book C# in a Nutshell .

If anyone has ideas on why this could happen I'll be really thankful because I have no ideas.

Thank you for your time and answers.

EDIT:
It seems that the size of the encrypted data is 48 bytes (12 bytes more than the original). Why is that so? I thought that it only adds bytes if they are not a multiple of the block size (16 bytes, my data is 32 bytes). Is data always larger, and with constant increase (I need to know that in order to properly read and decrypt).

Note: I can't directly use other streams because I need to have control over the output format and I believe it is also safer and faster to encrypt in memory.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

绝不服输 2024-10-25 17:37:26

根据您的编辑:

编辑:加密数据的大小似乎是 48 字节(比原始数据多 12 字节)。为什么会这样呢?我认为它只会添加字节,如果它们不是块大小的倍数(16 字节,我的数据是 32 字节)。数据是否总是较大,并且不断增加(我需要知道这一点才能正确读取和解密)。

如果加密数据为 48 字节,则比原始数组大 16 字节。这是有道理的,因为算法会填充数据,因为默认值是 PKCS7(即使大小与块大小匹配,因为它会填充到块大小的下一个倍数)。如果您希望将其保留为 32 字节,只需更改 填充

aes.Padding = PaddingMode.None;

Based on your edit:

EDIT: It seems that the size of the encrypted data is 48 bytes (12 bytes more than the original). Why is that so? I thought that it only adds bytes if they are not a multiple of the block size (16 bytes, my data is 32 bytes). Is data always larger, and with constant increase (I need to know that in order to properly read and decrypt).

If the encrypted data is 48 bytes, thats 16 bytes larger than your original array. This makes sense because the algorithm with pad the data because the default is PKCS7 (even if the size matches the block size, because it pads to the next multiple of the block-size). If you wish to keep it exactly 32 bytes, just change the Padding to None

aes.Padding = PaddingMode.None;
夏末染殇 2024-10-25 17:37:26

您似乎将明文的长度视为密文的长度。这不是一个安全的假设。

MemoryStream之间复制,你可以直接将FileStream传递给加密器/解密器。

为什么要在FileStreamPKCS7,最少有1个填充字节(用于存储填充字节数)。因此输出大小将为 Ceil16(input.Length + 1)(input.Length & ~15) + 1

You seem to be treating the length of the plaintext as the length of the ciphertext. That's not a safe assumption.

Why are you copying between FileStream and MemoryStream, you can pass a FileStream directly to the encryptor/decryptor.

In PKCS7, there is a minimum of one padding byte (to store the number of padding bytes). So the output size will be Ceil16(input.Length + 1), or (input.Length & ~15) + 1.

只是在用心讲痛 2024-10-25 17:37:26

缺点是 AES 以 16 字节块的形式对消息进行加密。如果您的消息不是 16 字节的偶数倍,则最后一个块的算法需要稍有不同;具体来说,最后一个块必须用算法已知的值“填充”作为填充值(通常为零,有时是其他值,例如空格字符值)。

您可以自己完成此操作,将数据放入固定长度的字节数组中。您自己填充了数据,但解密器现在尝试去填充最后一个块并获取它无法识别为加密器对应部分将添加的填充的字节值。

关键是不要填充消息。您可以使用 BitConverter 类在字节数组与 IConvertible 类型(值类型和字符串)之间进行转换,然后使用它而不是滚动您自己的字节数组。然后,当您解密时,您可以从解密流中读取密文长度,但不要期望解密结果中有那么多实际字节。

The short of it is that AES encrypts messages in blocks of 16 bytes. If your message isn't an even multiple of 16 bytes, the algorithm needs to be a little different for the last block; specifically, the last block must be "padded" with a value known to the algorithm as a padding value (usually zero, sometimes something else like a space character value).

You're doing that yourself, by putting the data into a fixed-length byte array. You padded the data yourself, but the decrypter is now attempting to de-pad the last block and getting byte values it doesn't recognize as the padding that its encrypter counterpart would have added.

The key is not to pad the message. You can use the BitConverter class to cast byte arrays to and from IConvertible types (value types and strings), and then use that instead of rolling your own byte array. Then, when you decrypt, you can read from the decryption stream up to the ciphertext length, but don't expect there to be that many actual bytes in the decrypted result.

じ违心 2024-10-25 17:37:26

在创建对象时,我没有设置填充,因此它抛出错误。添加填充值后,它工作完全正常。
aes.Padding = PaddingMode.PKCS7;

while creating the object i did not set padding , therefore it was throwing error . After adding the padding value , it works completely fine.
aes.Padding = PaddingMode.PKCS7;

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文