如果您想在Java中使用加密强大的随机数,则使用 SecureRandom 。不幸的是, SecureRandom 可能非常慢。如果它在Linux上使用 / dev / random ,它可以阻止等待足够的熵建立。你如何避免性能损失?

是否有人使用罕见的数学作为此问题的解决方案?

有人可以确认JDK 6中已解决了这个性能问题吗?

有帮助吗?

解决方案

如果你想要真正的随机数据,那么不幸的是你必须等待它。这包括 SecureRandom PRNG的种子。尽管可以连接到互联网从特定网站下载种子数据,但不常见的Maths无法以比 SecureRandom 更快的速度收集真正的随机数据。我的猜测是,这不可能比 / dev / random 更快。

如果您想要PRNG,请执行以下操作:

SecureRandom.getInstance("SHA1PRNG");

支持哪些字符串取决于 SecureRandom SPI提供程序,但您可以使用 Security.getProviders() Provider.getService()

Sun喜欢SHA1PRNG,所以它广泛使用。 PRNG并不是特别快,但PRNG只会处理数字,而不是阻止物理测量熵。

例外情况是,如果您在获取数据之前未调用 setSeed(),那么PRNG将在您第一次调用 next()时自行播种或<代码>的nextBytes()。通常使用来自系统的相当少量的真随机数据来做到这一点。此调用可能会阻止,但会使您的随机数源比任何“将当前时间与PID一起散列,添加27,并希望获得最佳”的变体更安全。如果你需要的只是游戏的随机数,或者如果你希望将来使用相同的种子进行测试,那么一个不安全的种子仍然有用。

其他提示

您应该可以在Linux上使用以下选项来选择速度更快但安全性更低的/ dev / urandom:

-Djava.security.egd=file:/dev/urandom

但是,这不适用于Java 5及更高版本( Java Bug 6202721 )。建议的解决方法是使用:

-Djava.security.egd=file:/dev/./urandom

(请注意额外的 /./

在Linux上, SecureRandom 的默认实现是 NativePRNG (源代码这里),这往往很慢。在Windows上,默认为 SHA1PRNG ,正如其他人指出的那样,如果明确指定它,也可以在Linux上使用。

NativePRNG 不同于 SHA1PRNG 和Uncommons Maths' AESCounterRNG ,它不断从操作系统接收熵(通过读取 / dev / urandom )。其他PRNG在播种后不会获得任何额外的熵。

AESCounterRNG比 SHA1PRNG 快约10倍,其中IIRC本身比 NativePRNG 快两到三倍。

如果您需要更快的PRNG,在初始化后获取熵,请查看是否可以找到财神。 Fortuna实现的核心PRNG与AESCounterRNG使用的相同,但也有一个复杂的熵池和自动重播系统。

许多Linux发行版(主要是基于Debian的)将OpenJDK配置为使用 / dev / random 进行熵。

/ dev / random 根据定义很慢(甚至可以阻止)。

从这里您可以选择两种解锁方式:

  1. 改善熵,或
  2. 降低随机性要求。
  3. 选项1,改善熵

    要获得更多熵到 / dev / random ,请尝试 hasged 守护程序。它是一个持续收集HAVEGE熵的守护进程,也可以在虚拟化环境中工作,因为它不需要任何特殊硬件,只需要CPU本身和时钟。

    在Ubuntu / Debian上:

    apt-get install haveged
    update-rc.d haveged defaults
    service haveged start
    

    在RHEL / CentOS上:

    yum install haveged
    systemctl enable haveged
    systemctl start haveged
    

    选项2.降低随机性要求

    如果由于某种原因上面的解决方案没有帮助,或者您不关心加密强随机性,则可以改为 / dev / urandom ,这样可以保证不会阻塞。

    要全局执行此操作,请在默认Java安装中编辑 jre / lib / security / java.security 文件以使用 / dev / urandom (由于另一个< a href =“https://bugs.openjdk.java.net/browse/JDK-6202721”rel =“noreferrer”> bug 需要指定为 / dev /./ urandom )。

    像这样:

    #securerandom.source=file:/dev/random
    securerandom.source=file:/dev/./urandom
    

    然后您将不必在命令行上指定它。


    注意:如果您进行加密,则需要良好的熵。例如, Android PRNG问题降低了比特币钱包的安全性。

在无头Debian服务器上一次调用 SecureRandom 阻塞大约25秒,我遇到了类似的问题。我安装了 hasged 守护进程以确保 / dev / random 保持充实,在无头服务器上你需要这样的东西来生成所需的熵。 我现在对 SecureRandom 的调用可能需要几毫秒。

如果你想要真正“加密强大”的话。随机性,那么你需要一个强大的熵源。 / dev / random 很慢,因为它必须等待系统事件收集熵(磁盘读取,网络数据包,鼠标移动,按键等)。

更快的解决方案是硬件随机数生成器。您的主板可能已经内置了一个;查看 hw_random文档,了解有关确定是否拥有该文档的说明,以及如何使用它。 rng-tools包中包含一个守护进程,它将硬件生成的熵提供给 / dev / random

如果您的系统上没有HRNG,并且您愿意为性能牺牲熵强度,那么您将希望使用来自 / dev / random 的数据为PRNG播种,并让PRNG负责大部分工作。有几个NIST批准的PRNG列在 SP800-90 很容易实现。

有一个工具(至少在Ubuntu上)可以将人工随机性输入系统。命令很简单:

rngd -r /dev/urandom

你可能需要前面的sudo。如果您没有rng-tools软件包,则需要安装它。我试过这个,这绝对帮助了我!

来源: matt vs world

我遇到了同样的问题。在使用正确的搜索条款进行Google搜索后,我在 DigitalOcean

hasged是一种潜在的解决方案,不会影响安全性。

我只是引用文章中的相关部分。

  

基于HAVEGE原理,以前基于其相关联   库,hasged允许根据变化产生随机性   处理器上的代码执行时间。因为它几乎是不可能的   一段代码可以执行相同的准确时间,即使在   相同硬件上的相同环境,运行单个的时间   或多个程序应该适合播种随机源。该   为实现种子系统的随机源(通常是   / dev / random)使用处理器时间戳计数器的差异   (TSC)重复执行循环后

如何安装hasged

按照本文中的步骤操作。 https:// www.digitalocean.com/community/tutorials/how-to-setup-additional-entropy-for-cloud-servers-using-haveged

我已发布此处

使用secure random作为循环算法的初始化源;你可以使用Mersenne twister进行批量工作而不是UncommonMath中的那个,它已经存在了一段时间并且证明比其他prng更好

http://en.wikipedia.org/wiki/Mersenne_twister

确保立即刷新然后用于初始化的安全随机数,例如,每个客户端可以使用一个mersenne twister伪随机生成器生成一个安全的随机生成,获得足够高的随机化程度

使用Java 8,我发现在Linux上调用 SecureRandom.getInstanceStrong()会给我 NativePRNGBlocking 算法。这通常会阻塞很多秒来生成几个字节的盐。

我转而明确要求 NativePRNGNonBlocking ,并且正如名称所预期的那样,它不再被阻止。我不知道这是什么安全隐患。据推测,非阻塞版本不能保证使用的熵量。

更新:好的,我发现这个出色的解释

简而言之,要避免阻塞,请使用 new SecureRandom()。这使用 / dev / urandom ,它不会阻塞,并且基本上与 / dev / random 一样安全。从帖子:“你唯一想要调用/ dev / random的时间是机器首次启动时,熵尚未累积”。

SecureRandom.getInstanceStrong()为您提供绝对最强的RNG,但在一堆阻塞不会影响您的情况下使用它是唯一安全的。

您引用的有关 / dev / random 的问题不在于 SecureRandom 算法,而在于它使用的随机源。两者是正交的。你应该弄清楚这两者中的哪一个会让你失望。

您明确链接的罕见数学页面提到他们没有解决随机性来源。

您可以尝试不同的JCE提供程序,例如BouncyCastle,以查看它们的 SecureRandom 的实现是否更快。

简短的搜索还会显示取代默认值的Linux补丁与Fortuna一起实施。我对此并不了解,但欢迎您进行调查。

我还应该提一下,虽然使用一个实施不当的 SecureRandom 算法和/或随机源非常危险,但您可以使用 SecureRandomSpi的自定义实现来推广自己的JCE Provider 。您需要与Sun一起完成一个流程,让您的提供商签名,但实际上它非常简单;他们只是需要你传真给他们一张表格,说明你了解美国对加密图书馆的出口限制。

我自己没有遇到过这个问题,但是我会在程序启动时产生一个线程,它会立即尝试生成一个种子,然后死掉。你调用randoms的方法将连接到该线程,如果它处于活动状态,那么第一个调用仅在程序执行的早期发生时才会阻塞。

我的经验只是PRNG的初始化缓慢,而不是随后生成随机数据。尝试更热切的初始化策略。由于它们的创建成本很高,因此将其视为单例并重用相同的实例。如果一个实例的线程争用太多,请将它们集中在一起或使它们成为线程局部的。

不要在随机数生成上妥协。那里的弱点会影响你的所有安全。

我没有看到很多基于COTS原子衰变的生成器,但如果你真的需要大量的随机数据,那么它们有几个计划。一个总是有趣的东西,包括HotBits,是 John Walker的Fourmilab。

听起来你应该更清楚你的RNG要求。最强的加密RNG要求(据我所知)即使您知道用于生成它们的算法,并且您知道所有先前生成的随机数,您也无法获得有关生成的任何随机数的任何有用信息。未来,没有花费不切实际的计算能力。

如果您不需要这种随机性的完整保证,那么可能需要进行适当的性能权衡。我倾向于同意 Dan Dyer的回复来自Uncommons-Maths的AESCounterRNG,或Fortuna(其作者之一是Bruce Schneier,密码学专家)。我从来没有使用过,但这些想法乍一看似乎很有信誉。

我会认为如果你可以定期生成一个初始随机种子(例如每天或每小时一次或其他),你可以使用快速流密码从连续的块中生成随机数。 stream(如果流密码使用XOR,则只传入空值流或直接获取XOR位)。 ECRYPT的 eStream 项目有很多很好的信息,包括性能基准。这不会在你补充它的时间点之间保持熵,所以如果有人知道你使用的随机数和算法之一,从技术上来说,有可能,有很多计算能力,打破流密码和猜测它的内部状态能够预测未来的随机数。但是你必须决定这种风险及其后果是否足以证明维持熵的成本。

编辑:这里有一些关于RNG的加密课程说明我在'网上找到了与此主题非常相关的内容。

如果您的硬件支持,请尝试使用Java RdRand Utility ,我是作者

它基于英特尔的 RDRAND 指令,比 SecureRandom 快10倍,并且没有大容量实现的带宽问题。


请注意,此实现仅适用于提供指令的CPU(即设置 rdrand 处理器标志时)。您需要通过 RdRandRandom()构造函数显式地实例化它;没有实现特定的 Provider

要查看的其他内容是文件lib / security / java.security中的属性securerandom.source

使用/ dev / urandom而不是/ dev / random可能会带来性能优势。请记住,如果随机数的质量很重要,请不要做出破坏安全性的妥协。

你可以尝试Apache commons Math项目,它有一些众所周知的算法实现:

https://commons.apache.org/proper/commons-数学/ userguide / random.html

但是,请注意性能。 RandomDataGenerator 的默认构造函数创建 Well19937c 的专用实例,这是一项非常昂贵的操作。

根据文档,此类不是线程安全的,但如果您可以保证只有一个线程将访问此类,则每个线程只能初始化一个实例。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top