注意:
以下代码示例仅用于演示目的,并实现了不安全的方案。如果您正在寻找安全方案,请查看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=");
}
答案 0 :(得分:2)
这里的解决方案是从存储的或常量Guid
引入。致电
Guid.NewGuid();
每次都会返回不同的结果。来自文档:
这是一个方便的静态方法,您可以调用它来获取新的Guid。该方法包装对Windows CoCreateGuid函数的调用。返回的Guid保证不等于Guid.Empty。
或者在测试时,您可以使用Guid.Empty,它将返回所有零。
或者,您可以使用其字符串构造函数overload来存储它:
var guid = new Guid("0f8fad5b-d9cb-469f-a165-70867728950e");