[英]How can I generate a cryptographically strong sequence of random bytes from a seed?
How can I generate a sequence of cryptographically strong random bytes from a seed value (so that the sequence can be regenerated from the same seed again)? 如何从种子值生成具有加密强度的随机字节序列(以便可以再次从同一种子重新生成序列)? Are there maybe any good CSPRNG algorithms that I could implement in C# (preferably with good documentation)?
我是否可以在C#中实现任何良好的CSPRNG算法(最好带有良好的文档)?
Niether the RNGCryptoServiceProvider
or Random
class will fulfill my requirments, since Random
isn't cryptographically strong and RNGCryptoServiceProvider
won't allow you to set the seed value. Niether的
RNGCryptoServiceProvider
或Random
类会履行我的质量要求,因为Random
不强加密和RNGCryptoServiceProvider
不会允许你设置种子值。
Rfc2898DeriveBytes is perfect for the job, most often it is used as a password hashing function, however you can request as many bytes as you want from it and it will always return the same series of bytes for a given seed (the combination of password, salt, and iteration count) Rfc2898DeriveBytes非常适合此工作,通常将其用作密码哈希函数,但是您可以从中请求任意多个字节,并且对于给定的种子,它将始终返回相同的字节序列(密码,盐和迭代计数)
Here is the example from the MSDN that shows two instances of Rfc2898DeriveBytes
returning the same sequence for both (by using the first sequence to encrypt aa block of data with symmetric encryption and using the 2nd sequence to decrypt it). 这是来自MSDN的示例,该示例显示
Rfc2898DeriveBytes
两个实例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);
}
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.