【问题标题】:Why am I able to decrypt modified encrypt data using AES 256Bit decryption为什么我能够使用 AES 256Bit 解密来解密修改后的加密数据
【发布时间】:2014-04-19 07:05:17
【问题描述】:

我创建了一个简单的加密和解密程序。我在这个程序中使用AESManaged 类。密钥和 IV 来自使用 Rfc2898DeriveBytes 的预定义密码。

我按照以下说明测试了我的程序:

  1. 在我的程序中输入示例文本并捕获加密文本。
  2. 在程序中输入相同的加密文本,验证解密文本与我的原始文本相同。
  3. 修改了步骤 2 中加密文本中“=”之前的字母(进入下一个字母表),并使用相同的密钥 ad 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 一个很好的问题:)

标签: c# .net encryption cryptography aes


【解决方案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= 。我听说 = 是填充,但为什么当我更改另一个字符时,我能够解密字符串。
  • 剥离加密部分。你的问题是关于 Base64 的。它内置了一些冗余。
【解决方案2】:

除此之外,您还需要意识到低级加密和解密只是一点点转换。它不知道输入和输出是什么,应该是什么。 IE。如果您加密 16 个字节,修改第 5 个字节并解密这 16 个字节,您将得到与您加密的数据不对应的输出,但您也不会收到错误。

要检测到更改,您需要使用某种完整性检查。这通常在高级加密方案(如 OpenPGP 或 CMS)或 SSL/TLS 和 SSH 等协议中完成。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-25
    • 2012-02-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多