如何从种子值生成一个加密强随机字节序列(以便可以再次从同一个种子重新生成该序列)?有没有我可以在 C# 中实现的好的 CSPRNG 算法(最好有好的文档)?
orRNGCryptoServiceProvider
类Random
都不会满足我的要求,因为Random
它的密码强度不高,并且RNGCryptoServiceProvider
不允许您设置种子值。
如何从种子值生成一个加密强随机字节序列(以便可以再次从同一个种子重新生成该序列)?有没有我可以在 C# 中实现的好的 CSPRNG 算法(最好有好的文档)?
orRNGCryptoServiceProvider
类Random
都不会满足我的要求,因为Random
它的密码强度不高,并且RNGCryptoServiceProvider
不允许您设置种子值。
Rfc2898DeriveBytes非常适合这项工作,它通常用作密码散列函数,但是您可以从它请求任意数量的字节,并且对于给定的种子(密码的组合,盐和迭代次数)
这是来自 MSDN 的示例,它显示了两个Rfc2898DeriveBytes
返回相同序列的实例(通过使用第一个序列使用对称加密加密数据块并使用第二个序列对其进行解密)。
using System;
using System.IO;
using System.Text;
using System.Security.Cryptography;
public class rfc2898test
{
// Generate a key k1 with password pwd1 and salt salt1.
// Generate a key k2 with password pwd1 and salt salt1.
// Encrypt data1 with key k1 using symmetric encryption, creating edata1.
// Decrypt edata1 with key k2 using symmetric decryption, creating data2.
// data2 should equal data1.
private const string usageText = "Usage: RFC2898 <password>\nYou must specify the password for encryption.\n";
public static void Main(string[] passwordargs)
{
//If no file name is specified, write usage text.
if (passwordargs.Length == 0)
{
Console.WriteLine(usageText);
}
else
{
string pwd1 = passwordargs[0];
// Create a byte array to hold the random value.
byte[] salt1 = new byte[8];
using (RNGCryptoServiceProvider rngCsp = new RNGCryptoServiceProvider())
{
// Fill the array with a random value.
rngCsp.GetBytes(salt1);
}
//data1 can be a string or contents of a file.
string data1 = "Some test data";
//The default iteration count is 1000 so the two methods use the same iteration count.
int myIterations = 1000;
try
{
Rfc2898DeriveBytes k1 = new Rfc2898DeriveBytes(pwd1, salt1, myIterations);
Rfc2898DeriveBytes k2 = new Rfc2898DeriveBytes(pwd1, salt1);
// Encrypt the data.
TripleDES encAlg = TripleDES.Create();
encAlg.Key = k1.GetBytes(16);
MemoryStream encryptionStream = new MemoryStream();
CryptoStream encrypt = new CryptoStream(encryptionStream, encAlg.CreateEncryptor(), CryptoStreamMode.Write);
byte[] utfD1 = new System.Text.UTF8Encoding(false).GetBytes(data1);
encrypt.Write(utfD1, 0, utfD1.Length);
encrypt.FlushFinalBlock();
encrypt.Close();
byte[] edata1 = encryptionStream.ToArray();
k1.Reset();
// Try to decrypt, thus showing it can be round-tripped.
TripleDES decAlg = TripleDES.Create();
decAlg.Key = k2.GetBytes(16);
decAlg.IV = encAlg.IV;
MemoryStream decryptionStreamBacking = new MemoryStream();
CryptoStream decrypt = new CryptoStream(decryptionStreamBacking, decAlg.CreateDecryptor(), CryptoStreamMode.Write);
decrypt.Write(edata1, 0, edata1.Length);
decrypt.Flush();
decrypt.Close();
k2.Reset();
string data2 = new UTF8Encoding(false).GetString(decryptionStreamBacking.ToArray());
if (!data1.Equals(data2))
{
Console.WriteLine("Error: The two values are not equal.");
}
else
{
Console.WriteLine("The two values are equal.");
Console.WriteLine("k1 iterations: {0}", k1.IterationCount);
Console.WriteLine("k2 iterations: {0}", k2.IterationCount);
}
}
catch (Exception e)
{
Console.WriteLine("Error: ", e);
}
}
}
}