【发布时间】:2023-04-01 16:54:01
【问题描述】:
注意:
以下代码示例仅用于演示目的,并实现了不安全的方案。如果您正在寻找安全方案,请查看https://stackoverflow.com/a/10177020/40347
我正在使用 AESCryptoServiceProvider 类来测试一些加密概念。到目前为止,在所有示例和文章中,它们都会生成一个随机密钥用于加密,然后立即用于解密。当然,它工作正常,因为您正在使用那里的密钥,但是如果您加密,保存文本,稍后您想要解密它,您将需要相同的密钥。并且为此目的也是相同的 IV。
现在,在这段代码中,我在多次传递中使用相同的密钥和 IV,每次运行批处理时,该批处理都会给出相同的结果(如预期的那样)。但随后我关闭测试应用程序并重新运行相同的代码而不做任何更改,结果(Base64 编码的)密码文本对于相同的输入参数是不同的,为什么?
我从上一次运行中“保存”了一个 B64 编码的密码,并将其提供给 TestDecrypt 方法,正如预期的那样,它抛出了一个加密异常,提到了一些关于填充的内容,尽管我确信这与以下事实有关不知何故,对于相同的 Key、IV、纯文本和参数,它在应用程序的每次单独运行时都会给出不同的结果。
为了加密,我有这个:
public string Test(string password, Guid guid, string text)
{
const int SaltSize = 16;
string b64Cryptogram;
MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
Rfc2898DeriveBytes pwbytes = new Rfc2898DeriveBytes(password, SaltSize);
// Block 128-bits Key 128/192/256 bits (16/24/32 bytes)
using (AesCryptoServiceProvider aes = new AesCryptoServiceProvider())
{
aes.Padding = PaddingMode.PKCS7;
aes.Mode = CipherMode.CBC;
//aes.IV = pwbytes.GetBytes(aes.BlockSize / 8);
aes.IV = md5.ComputeHash(System.Text.Encoding.UTF8.GetBytes(password));
aes.Key = guid.ToByteArray();
ICryptoTransform encryptor = aes.CreateEncryptor(aes.Key, aes.IV);
using (MemoryStream msEncrypt = new MemoryStream())
{
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
{
//Write all data to the stream.
swEncrypt.Write(text);
}
b64Cryptogram = Convert.ToBase64String(msEncrypt.ToArray());
}
}
Console.WriteLine("E: {0}", b64Cryptogram);
aes.Clear();
}
return b64Cryptogram;
}
请注意,我没有使用 RFC2898DeriveBytes,因为它会随机派生一些我将不再记得的东西 :) 加密它的想法正是我知道我用来加密它的东西。
解密方法如下:
public void TestDecrypt(string password, Guid guid, string ciphertextB64)
{
const int SaltSize = 16;
byte[] cipher = Convert.FromBase64String(ciphertextB64);
string plaintext;
MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
Rfc2898DeriveBytes pwbytes = new Rfc2898DeriveBytes(password, SaltSize);
// Block 128-bits Key 128/192/256 bits (16/24/32 bytes)
using (AesCryptoServiceProvider aes = new AesCryptoServiceProvider())
{
aes.Padding = PaddingMode.PKCS7;
aes.Mode = CipherMode.CBC;
//aes.IV = pwbytes.GetBytes(aes.BlockSize / 8);
aes.IV = md5.ComputeHash(System.Text.Encoding.UTF8.GetBytes(password));
aes.Key = guid.ToByteArray();
ICryptoTransform decryptor = aes.CreateDecryptor(aes.Key, aes.IV);
using (MemoryStream msEncrypt = new MemoryStream(cipher))
{
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, decryptor, CryptoStreamMode.Read))
{
using (StreamReader swEncrypt = new StreamReader(csEncrypt))
{
plaintext = swEncrypt.ReadToEnd();
}
}
}
Console.WriteLine("D: {0}", plaintext);
aes.Clear();
}
}
现在,只需将其放入控制台应用程序并运行即可。然后退出并再次运行,您会看到对于相同的 Mode、Padding、IV、Key 和纯文本数据,每次应用程序运行时输出的密码都不相同。如果您在应用程序的同一运行中重复运行该方法,它们将是相同的。
如果不是很明显,这里是我用来测试的控制台代码:
Guid guid = Guid.NewGuid();
string plain = "Text to be encrypted 123458970";
string password = "This is a test of the emergency broadcast system";
TestDecrypt(password, guid, Test(password, guid, plain));
TestDecrypt(password, guid, Test(password, guid, plain));
Test(password, guid, plain);
Test(password, guid, plain);
Test(plain, guid, password);
TestDecrypt(password, guid, "W4Oi0DrKnRpxFwtE0xVbYJwWgcA05/Alk6LrJ5XIPl8=");
}
【问题讨论】:
-
传入的guid总是一样的吗?
-
是的,正如我所说,参数是恒定的。
-
你是如何生成你的 guid 的? var guid = Guid.NewGuid();这将在每次运行时生成一个新的 guid,并在每次运行时生成不同的文本。如果您正在硬编码一个 guid 值,那么我不知道,因为每次运行都会给我相同的文本。
-
你用这个代码做什么?为什么不使用随机 IV?这是一个严重的安全漏洞,因为它使您的方案容易受到字典攻击(请参阅cwe.mitre.org/data/definitions/329.html)。
-
查看这里以获得更好的方法:stackoverflow.com/a/10177020/40347
标签: c# encryption aes encryption-symmetric rijndael