为什么我能够使用AES 256位解密修改后的加密数据

3
我创建了一个简单的加密和解密程序,使用了AESManaged类。密码和IV是使用Rfc2898DeriveBytes从预定义密码生成的。
我按照以下步骤测试了我的程序:
  1. 将样本文本输入程序并捕获加密文本。
  2. 将相同的加密文本输入程序并验证解密后的文本与原始文本相同。
  3. 修改第2步中加密文本中“=”前面的字母(改为下一个字母),并使用相同的密钥和IV进行解密,然后我收到了我的原始文本。
在第3步,我期望程序出现错误,但它却解密了错误的文本。
请问有人能帮助我理解我的程序出了什么问题,并防止程序解密错误的数据。
以下是程序输出:
Please put in input message
Some Text
Encrypted text is "xJzgOiMzimNOY6UsB+TNw9gUmcpdiZxQq70FxwbmkCc="
Please put in encrypted text to decrypt
xJzgOiMzimNOY6UsB+TNw9gUmcpdiZxQq70FxwbmkCc=
Decrypted text is "Some Text"
Please put in encrypted text to decrypt  <<here I have modified "c=" to "d=">>
xJzgOiMzimNOY6UsB+TNw9gUmcpdiZxQq70FxwbmkCd=
Decrypted text is "Some Text"
Enter "Exit" to exit!

AesExample.cs:

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

namespace Aes_Example
{
    class AesExample
    {
        public static void Main()
        {
            string action, plainText, encryptedText, decryptedText;

            Begin:
            Console.WriteLine("Please put in input message");
            plainText = Console.ReadLine();

            encryptedText = Encrypt(plainText);
            Console.WriteLine("Encrypted text is \"{0}\"", encryptedText);

            Console.WriteLine("Please put in encrypted text to decrypt");
            encryptedText = Console.ReadLine();

            decryptedText = Decrypt(encryptedText);
            Console.WriteLine("Decrypted text is \"{0}\"", decryptedText);

            Console.WriteLine("Please put in encrypted text to decrypt");
            encryptedText = Console.ReadLine();

            decryptedText = Decrypt(encryptedText);
            Console.WriteLine("Decrypted text is \"{0}\"", decryptedText);

            Console.WriteLine("Enter \"Exit\" to exit!");
            action = Console.ReadLine();

            if (action.ToUpper() != "EXIT") { goto Begin; }

        }
        public static string Encrypt(string clearText)
        {
            string EncryptionKey = "TESTPWD@#52";
            byte[] clearBytes = Encoding.Unicode.GetBytes(clearText);

            using (AesManaged encryptor = new AesManaged())
            {
                Rfc2898DeriveBytes pdb = new
                    Rfc2898DeriveBytes(EncryptionKey, new byte[] { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 });
                encryptor.Key = pdb.GetBytes(32);
                encryptor.IV = pdb.GetBytes(16);
                using (MemoryStream ms = new MemoryStream())
                {
                    using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateEncryptor(), CryptoStreamMode.Write))
                    {
                        cs.Write(clearBytes, 0, clearBytes.Length);
                        cs.Close();
                    }
                    clearText = Convert.ToBase64String(ms.ToArray());
                }
            }
            return clearText;
        }
        public static string Decrypt(string cipherText)
        {
            string EncryptionKey = "TESTPWD@#52";
            byte[] cipherBytes = Convert.FromBase64String(cipherText);

            using (AesManaged encryptor = new AesManaged())
            {
                Rfc2898DeriveBytes pdb = new
                    Rfc2898DeriveBytes(EncryptionKey, new byte[] { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 });
                encryptor.Key = pdb.GetBytes(32);
                encryptor.IV = pdb.GetBytes(16);
                using (MemoryStream ms = new MemoryStream())
                {
                    using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateDecryptor(), CryptoStreamMode.Write))
                    {
                        cs.Write(cipherBytes, 0, cipherBytes.Length);
                        cs.Close();
                    }
                    cipherText = Encoding.Unicode.GetString(ms.ToArray());
                }
            }
            return cipherText;
        }

    }
}

欢迎来到StackOverflow!+1,这是一个非常好的问题 :) - BradleyDotNET
2个回答

1
那个字符串的最后部分="是填充。而且不仅是加密填充,而是Base64填充。
简短版:
 byte[] data = { 1, 2, 3, 4 };
 clearText = Convert.ToBase64String(data);
 cipherText = clearText.Replace("A==", "B==");  // crude test
 byte[] cipherBytes = Convert.FromBase64String(cipherText);

在此之后,cipherBytes 仍将为{1, 2, 3, 4}
Base64编码使用6位/字符,因此当你有N个字节时,它将需要(N*8)/6个字符。通常这意味着会有一些剩余的位和最后一个字符有一些空间可以利用。但只有很少的,而且只在最后一个字符中。

谢谢回复。我的加密文本是xJzgOiMzimNOY6UsB+TNw9gUmcpdiZxQq70FxwbmkCc=,我将最后两个字符(c =)修改为d =并尝试解密xJzgOiMzimNOY6UsB+TNw9gUmcpdiZxQq70FxwbmkCd=。我听说=是填充,但为什么当我改变另一个字符时,我能够解密字符串。 - Shibu Thannikkunnath
1
去掉加密部分。你的问题是关于Base64的。它内置了一些冗余。 - H H

1
除了所说的,您需要意识到低级加密和解密只是一种位转换。它不知道输入和输出以及它应该是什么。例如,如果您加密16个字节,修改第5个字节并将这些16个字节解密回来,您将得到与您加密的数据不对应的输出,但您也不会收到错误。
要检测更改,您需要使用某种完整性检查。这通常在高级加密方案(如OpenPGP或CMS)或协议(如SSL / TLS和SSH)中完成。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接