[英]Is rapidly creating BouncyCastle SecureRandom instances problematic?
正如在随机数生成器中所指出的, 只生成一个随机数 ,每次需要另一个随机数时,创建System.Random
的新实例通常是不正确的,因为System.Random
是根据时钟播种的,因此在相同的刻度将产生相同的随机数。 因此,一种常见的做法(至少在单线程应用程序中)是创建一个存储在静态字段中的Random
实例,用于生成所有随机数。
另一方面, RNGCryptoServiceProvider
没有这个特殊的缺陷......但实例化成本显然RNGCryptoServiceProvider
,因此再次建议存储和重用它的单个实例。
Org.BouncyCastle.Security.SecureRandom
怎么Org.BouncyCastle.Security.SecureRandom
? 我是否同样需要存储和重用它的单个实例,或者每次我需要另一个随机数时,按需创建实例基本上没问题?
我们可以再次(比如在相关问题中)查看源代码来得出一些结论( 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版本中,它不是这样,不确定。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.