如何使用RNGCryptoServiceProvider根据我的首选字符创建随机密码?

Dex*_*ter 6 c# random rngcryptoserviceprovider

我目前正在创建一个随机密码是这样的:

    public static int getRandomNumber(int maxNumber)
    {
        if (maxNumber < 1)
            throw new System.Exception("The maxNumber value should be greater than 1");
        byte[] b = new byte[4];
        new System.Security.Cryptography.RNGCryptoServiceProvider().GetBytes(b);
        int seed = (b[0] & 0x7f) << 24 | b[1] << 16 | b[2] << 8 | b[3];
        System.Random r = new System.Random(seed);
        return r.Next(1, maxNumber);
    }
Run Code Online (Sandbox Code Playgroud)

一些可能的问题?这是一个静态函数,有一些奇怪的种子模式可能不安全,仍然使用System.Random().

使用上面的随机数生成器,我以这种低效的方式创建一个字符串:

  validCharacters = "abcdefghjkmnoxyz023456789#!@";
Run Code Online (Sandbox Code Playgroud)

然后使用有效数组循环并获取"createPassword(length)"类型字符串(注意使用不包含容错字符的字符集,如1 i等).

这是如何做到的,还是有更简单,更安全,更有效的方式

Mar*_*ark 7

为了生成随机数,您可以返回余数seed除以maxNumber:

public static int getRandomNumber(int maxNumber)
{
    if (maxNumber < 1)
        throw new System.Exception("The maxNumber value should be greater than 1");
    byte[] b = new byte[4];
    new System.Security.Cryptography.RNGCryptoServiceProvider().GetBytes(b);
    int seed = (b[0] & 0x7f) << 24 | b[1] << 16 | b[2] << 8 | b[3];
    return seed % maxNumber;
}
Run Code Online (Sandbox Code Playgroud)

maxNumber在这种情况下是独家的,这也是Random.Next(maxNumber)有效的.

编辑

来自@Servy的评论非常有趣,并引导我阅读了一篇名为"来自CryptoRandom的故事"的Stephen Toub和Shawn Farkas在2007年9月的MSDN杂志上发表的文章,可在此处下载,其中有一个使用RNGCryptoServiceProvider重新实现Random的示例这有偏见的解决方法.我在这里已经包含了它们的实现,因为源代码的格式非常讨厌,但是文章值得阅读它背后的原因.

public class CryptoRandom : Random
{
    private RNGCryptoServiceProvider _rng = new RNGCryptoServiceProvider();
    private byte[] _uint32Buffer = new byte[4];
    public CryptoRandom() { }
    public CryptoRandom(Int32 ignoredSeed) { }
    public override Int32 Next()
    {
        _rng.GetBytes(_uint32Buffer);
        return BitConverter.ToInt32(_uint32Buffer, 0) & 0x7FFFFFFF;
    }
    public override Int32 Next(Int32 maxValue)
    {
        if (maxValue < 0) throw new ArgumentOutOfRangeException("maxValue");
        return Next(0, maxValue);
    }
    public override Int32 Next(Int32 minValue, Int32 maxValue)
    {
        if (minValue > maxValue) throw new ArgumentOutOfRangeException("minValue");
        if (minValue == maxValue) return minValue;
        Int64 diff = maxValue - minValue;
        while (true)
        {
            _rng.GetBytes(_uint32Buffer);
            UInt32 rand = BitConverter.ToUInt32(_uint32Buffer, 0);
            Int64 max = (1 + (Int64)UInt32.MaxValue);
            Int64 remainder = max % diff;
            if (rand < max - remainder)
            {
                return (Int32)(minValue + (rand % diff));
            }
        }
    }
    public override double NextDouble()
    {
        _rng.GetBytes(_uint32Buffer);
        UInt32 rand = BitConverter.ToUInt32(_uint32Buffer, 0);
        return rand / (1.0 + UInt32.MaxValue);
    }
    public override void NextBytes(byte[] buffer)
    {
        if (buffer == null) throw new ArgumentNullException("buffer");
        _rng.GetBytes(buffer);
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 您在这里没有严格统一的概率分布.[这是一篇文章](http://ericlippert.com/2013/12/16/how-much-bias-is-introduced-by-the-remainder-technique/)进行详细解释. (2认同)