我如何使用RNGCryptoServiceProvider根据我喜欢的字符创建一个随机密码

本文关键字:一个 密码 随机 创建 字符 RNGCryptoServiceProvider 何使用 我喜欢 | 更新日期: 2023-09-27 17:49:39

我现在创建的随机密码是这样的:

    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);
    }

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

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

  validCharacters = "abcdefghjkmnoxyz023456789#!@";

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

是这样做的,还是有更容易,更安全,更有效的方法?

我如何使用RNGCryptoServiceProvider根据我喜欢的字符创建一个随机密码

对于生成随机数,您可以返回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;
}

maxNumber在这种情况下是排他的,这也是Random.Next(maxNumber)的工作方式。

编辑

@Servy的评论非常有趣,让我看到了Stephen Toub和Shawn Farkas在2007年9月的MSDN杂志上发表的一篇题为"来自加密随机的故事"的文章,可以在这里下载,其中有一个使用RNGCryptoServiceProvider重新实现随机的例子,它有一个解决偏差的方法。我在这里包含了它们的实现,因为源代码的格式非常糟糕,但这篇文章值得一读,因为它背后的原因。

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);
    }
}

使用System.Random使得断言安全属性非常困难,因为它的输出不是加密强的。现在只有40亿个密码,因为只有40亿个可能的种子。

非常不安全。由于类似的问题,Debian密码安全被破坏。

使用RNGCryptoServiceProvider直接生成完全随机的整数作为密码算法的输入

您可以使用validCharacters字符串将原始字节和以28为基数的编码作为以28为基数的数字的"位数"。您可以使用下面的代码https://stackoverflow.com/a/14110071/2076

您可以从System继承。随机使用RNGCryptoServiceProvider来获取数字,但你必须要小心,因为你需要覆盖相当多的方法:

/*
[MSDN]
Notes to Inheritors:
In the .NET Framework versions 1.0 and 1.1, a minimum implementation of
a class derived from Random required overriding the Sample method
to define a new or modified algorithm for generating random numbers.
The derived class could then rely on the base class implementation
of the Random.Next(), Random.Next(Int32), Random.Next(Int32, Int32),
NextBytes, and NextDouble methods to call the derived class implementation of the Sample method.
In the .NET Framework version 2.0 and later, the behavior of the Random.Next(),
Random.Next(Int32, Int32), and NextBytes methods have changed
so that these methods do not necessarily call the derived class implementation
of the Sample method.
As a result, classes derived from Random that target the .NET Framework 2.0
and later should also override these three methods.
*/
class CryptoRandom : System.Random {
    private RandomNumberGenerator rng;
    public CryptoRandom() {
        rng = new RNGCryptoServiceProvider();
    }
    public override int Next() {
        byte[] bytes = new byte[4];
        rng.GetBytes(bytes);
        return int.MaxValue & BitConverter.ToInt32(bytes, 0);
    }
    public override void NextBytes(byte[] b)
    {
        rng.GetBytes(b);
    }
    public override int Next(int lo, int hi){
        throw new Exception("TODO override (arc4random_uniform is beautiful)");
    }
    protected override double Sample()
    {
        throw new Exception("TODO override");
    }
}

或者,由于您将使用所有这些只是为了获得一个小字符串(length<=255)的索引,您可以直接使用字节来获得索引(避免模偏置,这就是我首先写这个答案的原因—参见http://BXR.SU/OpenBSD/lib/libc/crypt/arc4random_uniform.c#arc4random_uniform的arc4random_uniform)。

相关文章: