如何从种子生成加密强度高的随机字节序列
本文关键字:随机 字节 种子 加密 | 更新日期: 2023-09-27 18:37:19
如何从种子值生成加密强度高的随机字节序列(以便可以从同一种子再次生成序列)?是否有任何好的 CSPRNG 算法可以在 C# 中实现(最好有良好的文档)?
Niether RNGCryptoServiceProvider
或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);
}
}
}
}