Encryption 解密更改最后一个字母的AES

Encryption 解密更改最后一个字母的AES,encryption,aes,Encryption,Aes,我需要在客户端应用程序中加密一些数据,然后在服务器应用程序中验证它。 我假设如果消息被解密,那么它来自有效的客户端,因为密钥是创建有效加密字符串所必需的 我正在使用MSDN中的AES实现 我选择AES是因为在我的测试中它生成了一个短字符串。这对我来说是一个重要的问题 public static void Main() { string original = "message to secure"; using (Aes myAes = Aes.Creat

我需要在客户端应用程序中加密一些数据,然后在服务器应用程序中验证它。 我假设如果消息被解密,那么它来自有效的客户端,因为密钥是创建有效加密字符串所必需的

我正在使用MSDN中的AES实现

我选择AES是因为在我的测试中它生成了一个短字符串。这对我来说是一个重要的问题

public static void Main()
    {
        string original = "message to secure";

        using (Aes myAes = Aes.Create())
        {
            myAes.Key = Convert.FromBase64String("AAECAwQFBgcICQoLDA0ODw=="); 

            byte[] encrypted = EncryptStringToBytes_Aes(original, myAes.Key, myAes.IV);

            var encryptedString = Convert.ToBase64String(encrypted);

            string roundtrip = DecryptStringFromBytes_Aes(Convert.FromBase64String(encryptedString), myAes.Key, myAes.IV);

            Console.WriteLine("Encrypted: " + encryptedString); 
            Console.WriteLine("Decrypted: " + roundtrip); 
        }

        Console.ReadKey();
    }

    static byte[] EncryptStringToBytes_Aes(string plainText, byte[] Key, byte[] IV)
    { 
        if (plainText == null || plainText.Length <= 0)
            throw new ArgumentNullException("plainText");
        if (Key == null || Key.Length <= 0)
            throw new ArgumentNullException("Key");
        if (IV == null || IV.Length <= 0)
            throw new ArgumentNullException("IV");
        byte[] encrypted;

        using (Aes aesAlg = Aes.Create())
        {
            aesAlg.Key = Key;
            aesAlg.IV = IV;

            ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);

            using (MemoryStream msEncrypt = new MemoryStream())
            {
                using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
                {
                    using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
                    {
                        swEncrypt.Write(plainText);
                    }
                    encrypted = msEncrypt.ToArray();
                }
            }
        }

        return encrypted;
    }

    static string DecryptStringFromBytes_Aes(byte[] cipherText, byte[] Key, byte[] IV)
    { 
        if (cipherText == null || cipherText.Length <= 0)
            throw new ArgumentNullException("cipherText");
        if (Key == null || Key.Length <= 0)
            throw new ArgumentNullException("Key");
        if (IV == null || IV.Length <= 0)
            throw new ArgumentNullException("IV");

        string plaintext = null;

        using (Aes aesAlg = Aes.Create())
        {
            aesAlg.Key = Key;
            aesAlg.IV = IV;

            ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);

            using (MemoryStream msDecrypt = new MemoryStream(cipherText))
            {
                using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
                {
                    using (StreamReader srDecrypt = new StreamReader(csDecrypt))
                    {
                        plaintext = srDecrypt.ReadToEnd();
                    }
                }
            }
        }

        return plaintext;
    }
publicstaticvoidmain()
{
string original=“要保护的消息”;
使用(Aes myAes=Aes.Create())
{
myAes.Key=Convert.FromBase64String(“AAECAwQFBgcICQoLDA0ODw=”;
byte[]encrypted=EncryptStringToBytes_Aes(原始,myAes.Key,myAes.IV);
var encryptedString=Convert.ToBase64String(加密);
字符串往返=DecryptStringFromBytes_Aes(Convert.FromBase64String(encryptedString)、myAes.Key、myAes.IV);
Console.WriteLine(“加密:+encryptedString”);
Console.WriteLine(“解密:+往返);
}
Console.ReadKey();
}
静态字节[]加密StringToBytes_Aes(字符串明文,字节[]密钥,字节[]IV)
{ 

if(plainText==null | | plainText.Length所罗门的所有评论或多或少都一针见血

我假设如果消息被解密,那么它来自有效的客户端,因为密钥是创建有效加密字符串所必需的

这一基本假设实际上是错误的。在许多情况下(在未经验证的操作模式下),即使修改了密文,解密也可以成功——导致明文与最初加密的明文不同

回想一下,AES是一种分组密码。它将一个128位的块转换为另一个128位的块。唯一的其他变量是使用的密钥和操作(例如加密或解密)。没有机制检测传入的128位块是否已被修改,因为之前的一些操作-AES不知道。它只是一个键控转换函数

要避免此问题,请使用经过身份验证的操作模式(如GCM)或使用HMAC。有关在C#中使用GCM的示例,请参阅中的示例


关于第二个问题:

但我注意到,如果最后一个字符(在等号之前)发生了更改,字符串将被解密,因为没有任何更改

从技术上讲,没有任何更改-这是一个“功能”。每个base64字符代表原始数据的6位。这意味着,除非您的密文长度可被8和6整除,否则将有位“剩余”。请参阅下面的示例,其中我们对16位进行编码:

Raw                      : { 0x00, 0x01 }
Binary                   : 00000000 00000001

Base64                   : AAE=
Binary (6 Digit Grouping): 000000 000000 000100
Binary (8 Digit Grouping): 00000000 00000001 00
                                             ^^ these bits are irrelevant

本质上,没什么好担心的。

我不知道那里到底发生了什么,但是AES工作在正好256位的块上,该字符串是258位块的base-64编码。这意味着,字符串中有两位填充。您将最后一个字符的最低顺序位从零更改为一。如果这是一个wo填充位,那么更改对字符串的解密没有影响可能是完全合理的。P.S.,什么是“…并验证它”意思是?如果密码文本的任何非填充位被翻转,那么我希望解码结果看起来非常随机。但是您的应用程序能够通过“验证”可靠地分辨256个随机位和某种有意义的输入之间的差异吗我的意思是能够解密它。我认为只有使用特定密钥加密的字符串才能用它解密。因此,如果我做对了,我只需要将算法的填充改为0,以删除那些“可以更改的”字符?任何256位的字符串都是基本AES加密和解密算法的有效输入;任何256位的字符串都是可能的输出。AES解密无法判断密码文本是否“有效”或者不是。这完全取决于你的应用程序来判断它是否能对结果产生某种意义。如果明文有很多冗余(即信息密度低),那么这可能是一项简单的任务,但是如果您的数据非常紧凑,那么您可能需要使用某种类型的a来验证没有任何更改。任何256的字符串都是有效的,但只有使用AES密钥加密的字符串才能使用相同的密钥解密。不是吗?谢谢您Luke。我确实必须提高我的加密技能。您给了我一个轻松的工作机会关于我的问题,我去查一下GCM。