我需要加密客户端应用程序中的某些数据,并稍后在服务器应用程序中进行验证。 我假设消息是解密的,那么它是来自有效的客户端,因为密钥是创建有效的加密字符串所必需的。
我正在使用MSDN https://docs.microsoft.com/pt-br/dotnet/api/system.security.cryptography.aes?view=netframework-4.8中的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;
}
但是我注意到,如果最后一个字符发生变化(等号之前),则该字符串将被解密,因为没有任何变化。
例如:
HdPAmfHTxkMmj8D3VelWjH2A8iGm6gnzzPYGNT5NR14 =已生成,我将其更改为HdPAmfHTxkMmj8D3VelWjH2A8iGm6gnzzPYGNT5NR1 5 =并得到了相同的结果。
有人可以指导我如何保证如果生成的字符串被更改了吗?
答案 0 :(得分:1)
所罗门发表的所有评论或多或少都触及了头。
我假设消息是解密的,那么它是来自有效的客户端的,因为密钥是创建有效的加密字符串所必需的。
这个基本假设实际上是错误的。在许多情况下(未经身份验证的操作模式),即使密文已被修改,解密也可以成功进行-导致明文与原始加密的明文不同。
回想一下,AES是一种分组密码。它将一个128位的块转换为另一个128位的块。唯一的其他变量是所使用的密钥以及操作(例如加密或解密)。自从某些先前的操作以来,没有机制可以检测传入的128位块是否已被修改-AES对此不了解。它只是一个键转换函数。
为避免此问题,请使用GCM等经过身份验证的操作模式,或使用HMAC。有关在C#中使用GCM的示例,请参见this repository中的示例。
关于第二个问题:
但是我注意到,如果最后一个字符发生变化(等号之前),则该字符串将被解密,因为没有任何变化。
从技术上说,什么都没改变-这是一个“功能”。每个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
本质上,没有什么可担心的。