快速创建BouncyCastle SecureRandom实例是否有问题? [英] Is rapidly creating BouncyCastle SecureRandom instances problematic?

查看:267
本文介绍了快速创建BouncyCastle SecureRandom实例是否有问题?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

随机数生成器仅生成一个随机数所述,通常创建新的<$实例是不正确的每次需要另一个随机数时,c $ c> System.Random ,因为 System.Random 是基于时钟的种子,因此有多个实例在同一刻度内创建的将产生相同的随机数。因此,一种常见的做法(至少在单线程应用程序中)是创建一个 Random 的单个实例,该实例存储在用于所有随机数生成的静态字段中。

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. 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.

RNGCryptoServiceProvider 则没有此缺陷……但显然是实例化成本很高,因此再次建议存储和重用它的单个实例。

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.

Org.BouncyCastle.Security.SecureRandom ?我是否同样需要存储和重用它的单个实例,还是每次需要另一个随机数时都可以按需创建实例基本上很好?

How about 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?

推荐答案

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

We can again (like in related question) look at source code to draw some conclusions (SecureRandom source code for reference).

构造函数中的所有工作都用于创建伪-random generator:

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

创建摘要(哈希)不会花费任何费用(相对于其他工作)。例如,默认情况下使用的 Sha256Digest (具有空构造函数)仅分配较小的 byte [] 缓冲区。创建 DigestRandomGenerator 本身也不会花费任何费用(使用小型缓冲区)。完成的主要工作在这里:

Creating digest (hash) costs nothing (relative to other work). For example Sha256Digest used by default (with empty constructor) just allocates small byte[] buffer. Creating DigestRandomGenerator itself also costs nothing (couple small buffers). Major work done is here:

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

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

It uses "master" RNG to generate seed value. Master RNG on full .NET platform is RNGCryptoServiceProvider (which for SecureRandom is stored in static field and initialized only once). So all work when creating SecureRandom goes to creating cryptographically random seed for pseudo RNG.

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

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). Because (as far as I know), SecureRandom is thread safe - there is not much reason to not reuse one instance.

旁注-我认为 RNGCryptoServiceProvider 创建起来并不繁琐,就像您的链接所声称的那样。其构造函数如下所示:

Side note - I don't think RNGCryptoServiceProvider is heavy to create as your link claims. 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;
  }
}

因此,当您创建新实例时(不提供csp) -它重用了相同的 Utils.StaticProvHandle ,因此它使用了RNG提供程序的相同非托管实例。反过来,这意味着创建新实例并重用同一实例在性能上没有区别。不确定在以前的.NET版本中不是这样。

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. 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.

这篇关于快速创建BouncyCastle SecureRandom实例是否有问题?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆