简体   繁体   English

如何从种子生成密码强的随机字节序列?

[英]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的RNGCryptoServiceProviderRandom类会履行我的质量要求,因为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.

相关问题 如何在某个范围内生成加密安全的随机 integer? - How can I generate a cryptographically secure random integer within a range? C# 中 HashCode 的随机种子是否可以认为是密码随机的? - Can the random seed of HashCode in C# be considered cryptographically random? 如何在C#中生成加密安全的伪随机数? - How can I generate a cryptographically secure pseudorandom number in C#? 随机种子c# - 如何为调试生成相同的数字序列 - Random seed c# - How to generate same sequence of numbers for debug 我可以使用 RandomNumberGenerator.GetInt32() 方法生成加密安全的随机字符串吗? - Can I use the RandomNumberGenerator.GetInt32() method to generate a cryptographically-secure random string? 我可以使用种子在AutoFixture中重新生成随机值吗? - Can I re-generate random values in AutoFixture using a seed? 如何从字节数组的某些值之间生成随机整数 - How to generate a random integer between certain values from an array of bytes 如何从矢量或ImageTargets列表中生成随机Target - How can I generate random Target from a vector or list of ImageTargets 如何在0和1之间生成加密安全的Double? - How to generate a cryptographically secure Double between 0 and 1? 如何在内存池中找到字节序列? - How can I find a sequence of bytes in a pool of memory?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM