2017-10-17 78 views
3

Random number generator only generating one random number所述,每当您需要另一个随机数时,创建System.Random的新实例通常是不正确的,因为System.Random是基于时钟播种的,因此在同一个tick中创建的多个实例将产生相同的随机数。因此,一种常见做法(至少在单线程应用程序中)是创建存储在用于所有随机数生成的静态字段中的单个实例Random正在快速创建BouncyCastle SecureRandom实例有问题吗?

RNGCryptoServiceProvider另一方面,没有这个特殊的缺陷......但显然costly to instantiate,因此,它再次建议存储和重新使用它的单个实例。

Org.BouncyCastle.Security.SecureRandom怎么样?我是否同样需要存储和重用其单个实例,或者每次需要另一个随机数时按需创建实例都基本上没问题?

+0

相关(因为它也是关于如何正确使用这个类的未公开基础知识):https://stackoverflow.com/q/46792243/1709587 –

+0

我认为这取决于你需要一个随机数在实践中。在我自己的一个项目中,我使用'RNGCryptoServiceProvider.Create()'为每个站点的新用户生成一个会话标记,并且性能每天处理1,000次访问。那么你多久需要一个随机数? – DiskJunky

+0

从您评论中链接的答案中,您将最终为每个SecureRandom实例实例化一个新的RNGCryptoServiceProvider。除了这种性能打击,它看起来很好。 –

回答

2

我们可以再次(如在相关问题中)看源代码来得出一些结论(SecureRandom源代码供参考)。

在构造函数中的所有工作去创造伪随机生成:

private static DigestRandomGenerator CreatePrng(string digestName, bool autoSeed) 
{ 
    IDigest digest = DigestUtilities.GetDigest(digestName); 
    if (digest == null) 
     return null; 
    DigestRandomGenerator prng = new DigestRandomGenerator(digest); 
    if (autoSeed) 
    { 
     prng.AddSeedMaterial(NextCounterValue()); 
     prng.AddSeedMaterial(GetNextBytes(Master, digest.GetDigestSize())); 
    } 
    return prng; 
} 

创建摘要(散)支付任何费用(相对于其他工作)。例如默认使用的Sha256Digest(带空构造函数)只分配小的byte[]缓冲区。创建DigestRandomGenerator本身也没有花费(几个小缓冲区)。主要完成的工作是:

prng.AddSeedMaterial(GetNextBytes(Master, digest.GetDigestSize())); 

它使用“主”RNG生成种子值。完整的.NET平台上的主RNG为RNGCryptoServiceProvider(其中SecureRandom存储在静态字段中并仅初始化一次)。因此,在创建SecureRandom时,所有工作都会为伪RNG创建加密随机种子。

我想说,最好不要每次都创建一个新实例,至少对于小一代(对于一个二代的NextInt()调用)来说,因为如果您为每个生成的数字创建新实例 - 基本上会使成本加倍(一次为种子生成密码随机数,另一次生成目标随机数)。因为(据我所知),SecureRandom是线程安全的 - 没有太多理由不重用一个实例。

附注 - 我不认为RNGCryptoServiceProvider重要创建您的链接声称。它的构造是这样的:

public RNGCryptoServiceProvider() 
    : this((CspParameters) null) 
{ 
} 

[SecuritySafeCritical] 
public RNGCryptoServiceProvider(CspParameters cspParams) 
{ 
    if (cspParams != null) 
    { 
    this.m_safeProvHandle = Utils.AcquireProvHandle(cspParams); 
    this.m_ownsHandle = true; 
    } 
    else 
    { 
    // we are interested in this path 
    this.m_safeProvHandle = Utils.StaticProvHandle; 
    this.m_ownsHandle = false; 
    } 
} 

所以,当你创建新的实例(不提供CSP) - 它重复使用相同的Utils.StaticProvHandle,所以它使用RNG提供的相同的“非托管”的实例。这又意味着创建新实例并重新使用同一个实例在性能上没有差异。也许在以前的.NET版本中,它不是这样的,不确定。