我目前正在创建一个随机密码是这样的:
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等).
这是如何做到的,还是有更简单,更安全,更有效的方式?
解决方法
为了生成随机数,您可以返回种子的剩余部分除以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的评论非常有趣,并引导我阅读2007年9月MSDN杂志上发表的题为“来自CryptoRandom的故事”的Stephen Toub和Shawn Farkas的一篇文章,可以下载here,其中有一个使用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); } }