简体   繁体   English

快速创建BouncyCastle SecureRandom实例是否有问题?

[英]Is rapidly creating BouncyCastle SecureRandom instances problematic?

As noted at Random number generator only generating one random number , it's generally incorrect to create a new instance of System.Random every time that you need another random number, since System.Random is seeded based upon the clock and so multiple instances created in the same tick will yield identical random numbers. 正如在随机数生成器中所指出的, 只生成一个随机数 ,每次需要另一个随机数时,创建System.Random的新实例通常是不正确的,因为System.Random是根据时钟播种的,因此在相同的刻度将产生相同的随机数。 As such, one common practice (at least in single-threaded applications) is to create a single instance of Random stored in a static field that is used for all random number generation. 因此,一种常见的做法(至少在单线程应用程序中)是创建一个存储在静态字段中的Random实例,用于生成所有随机数。

RNGCryptoServiceProvider , on the other hand, does not have this particular flaw... but is apparently costly to instantiate , and therefore it's again recommended to store and reuse a single instance of it. 另一方面, RNGCryptoServiceProvider没有这个特殊的缺陷......但实例化成本显然RNGCryptoServiceProvider ,因此再次建议存储和重用它的单个实例。

How about Org.BouncyCastle.Security.SecureRandom ? Org.BouncyCastle.Security.SecureRandom怎么Org.BouncyCastle.Security.SecureRandom Do I similarly need to store and reuse a single instance of it, or is it basically fine to create instances on demand every time that I need another random number? 我是否同样需要存储和重用它的单个实例,或者每次我需要另一个随机数时,按需创建实例基本上没问题?

We can again (like in related question) look at source code to draw some conclusions ( SecureRandom source code for reference). 我们可以再次(比如在相关问题中)查看源代码来得出一些结论( SecureRandom源代码供参考)。

All work in constructor goes for creating pseudo-random generator: 构造函数中的所有工作都用于创建伪随机生成器:

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

Creating digest (hash) costs nothing (relative to other work). 创建摘要(哈希)不需要任何费用(相对于其他工作)。 For example Sha256Digest used by default (with empty constructor) just allocates small byte[] buffer. 例如,默认情况下使用的Sha256Digest (使用空构造函数)只分配小byte[]缓冲区。 Creating DigestRandomGenerator itself also costs nothing (couple small buffers). 创建DigestRandomGenerator本身也不需要任何费用(耦合小缓冲区)。 Major work done is here: 主要工作在这里:

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

It uses "master" RNG to generate seed value. 它使用“主”RNG生成种子值。 Master RNG on full .NET platform is RNGCryptoServiceProvider (which for SecureRandom is stored in static field and initialized only once). 完整.NET平台上的主RNG是RNGCryptoServiceProviderSecureRandom存储在静态字段中并仅初始化一次)。 So all work when creating SecureRandom goes to creating cryptographically random seed for pseudo RNG. 因此,创建SecureRandom时的所有工作都是为伪RNG创建加密随机种子。

I'd say, it's better not create new instance every time, at least for small generation (for one-two NextInt() calls), because if you create new instance for every single generated number - you essentially double the costs (one time to generate crypto random number for seed and one to generate your target random number). 我想说,最好不要每次创建新实例,至少对于小代(对于一两个NextInt()调用),因为如果为每个生成的数字创建新实例 - 基本上是成本的两倍(一次)为种子生成加密随机数,并生成一个目标随机数)。 Because (as far as I know), SecureRandom is thread safe - there is not much reason to not reuse one instance. 因为(据我所知), SecureRandom是线程安全的 - 没有太多理由不重用一个实例。

Side note - I don't think RNGCryptoServiceProvider is heavy to create as your link claims. 旁注 - 我不认为RNGCryptoServiceProvider很难创建链接声明。 Its constructor goes like this: 它的构造函数如下:

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

So when you create new instance (without providing csp) - it reuses the same Utils.StaticProvHandle , so it uses the same "unmanaged" instance of RNG provider. 因此,当您创建新实例(不提供csp)时 - 它会重用相同的Utils.StaticProvHandle ,因此它使用相同的“非托管”RNG提供程序实例。 Which in turn means creating new instance and reusing the same instance have no difference in performance. 这反过来意味着创建新实例并重用相同的实例在性能上没有区别。 Maybe in previous versions of .NET it was not like this, not sure. 也许在以前的.NET版本中,它不是这样,不确定。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM