Dav*_*d G 157 java security random performance entropy
如果你想在Java中使用加密强大的随机数,你可以使用SecureRandom.不幸的是,SecureRandom可能会很慢.如果它/dev/random在Linux上使用,它可以阻止等待足够的熵建立.你如何避免性能损失?
有没有人使用Uncommon Maths作为解决这个问题的方法?
任何人都可以确认JDK 6中已经解决了这个性能问题吗?
Tho*_*ard 174
您应该能够在Linux上选择速度更快但安全性稍差的/ dev/urandom使用:
-Djava.security.egd=file:/dev/urandom
Run Code Online (Sandbox Code Playgroud)
但是,这不适用于Java 5及更高版本(Java Bug 6202721).建议的解决方法是使用:
-Djava.security.egd=file:/dev/./urandom
Run Code Online (Sandbox Code Playgroud)
(注意额外的/./)
Ste*_*sop 74
如果你想要真正的随机数据,那么不幸的是你必须等待它.这包括SecureRandomPRNG 的种子.SecureRandom尽管可以连接到互联网从特定网站下载种子数据,但不常见的数学不能以更快的速度收集真正的随机数据.我的猜测是,这不可能比/dev/random现有的更快.
如果你想要一个PRNG,做这样的事情:
SecureRandom.getInstance("SHA1PRNG");
Run Code Online (Sandbox Code Playgroud)
支持哪些字符串取决于SecureRandomSPI提供程序,但您可以使用Security.getProviders()和枚举它们Provider.getService().
Sun喜欢SHA1PRNG,所以它广泛使用.它并不像PRNG那样特别快,但PRNG只会处理数字,而不是阻止熵的物理测量.
例外情况是,如果您setSeed()在获取数据之前未进行呼叫,则PRNG将在您第一次呼叫时自行播种next()或nextBytes().通常使用来自系统的相当少量的真随机数据来做到这一点.此调用可能会阻止,但会使您的随机数源比"将当前时间与PID一起散列,添加27,并希望获得最佳"的任何变量更安全.如果您需要的只是游戏的随机数,或者如果您希望将来使用相同的种子进行测试时可重复使用流,则不安全的种子仍然有用.
Dan*_*yer 34
在Linux上,默认实现SecureRandom是NativePRNG(这里是源代码),这往往非常慢.在Windows上,默认值是SHA1PRNG,正如其他人指出的那样,如果明确指定,也可以在Linux上使用.
NativePRNG不同于SHA1PRNG和Uncommons Maths的AESCounterRNG,因为它不断地从操作系统接收熵(通过读取/dev/urandom).其他PRNG在播种后不会获得任何额外的熵.
AESCounterRNG的速度比SHA1PRNGIIRC 快10倍,而IIRC本身的速度要快2到3倍NativePRNG.
如果您需要更快的PRNG,在初始化后获取熵,请查看是否可以找到Fortuna的Java实现.Fortuna实现的核心PRNG与AESCounterRNG使用的相同,但也有一个复杂的熵池和自动重播系统.
rus*_*tyx 23
许多Linux发行版(主要是基于Debian的)将OpenJDK配置为/dev/random用于熵.
/dev/random 根据定义是慢的(甚至可以阻止).
从这里你有两个选项来解锁它:
选项1,改善熵
要获得更多的熵/dev/random,请尝试使用hasged守护进程.它是一个持续收集HAVEGE熵的守护进程,也可以在虚拟化环境中工作,因为它不需要任何特殊硬件,只需要CPU本身和时钟.
在Ubuntu/Debian上:
apt-get install haveged
update-rc.d haveged defaults
service haveged start
Run Code Online (Sandbox Code Playgroud)
在RHEL/CentOS上:
yum install haveged
systemctl enable haveged
systemctl start haveged
Run Code Online (Sandbox Code Playgroud)
选项2.降低随机性要求
如果由于某种原因上面的解决方案没有帮助,或者你不关心加密强随机性,你可以切换到/dev/urandom相反,这保证不会阻止.
要全局执行此操作,请编辑jre/lib/security/java.security要使用的默认Java安装中的文件/dev/urandom(由于需要将其指定为另一个错误/dev/./urandom).
像这样:
#securerandom.source=file:/dev/random
securerandom.source=file:/dev/./urandom
Run Code Online (Sandbox Code Playgroud)
然后,您将不必在命令行上指定它.
注意:如果您进行加密,则需要良好的熵.一个例子 - android PRNG问题降低了比特币钱包的安全性.
小智 16
我SecureRandom在无头Debian服务器上一次调用阻塞大约25秒时遇到了类似的问题.我安装了haveged守护进程以确保/dev/random在无头服务器上保持充足,你需要这样的东西来生成所需的熵.我SecureRandom现在的电话可能需要几毫秒.
小智 11
如果你想要真正"加密强"的随机性,那么你需要一个强大的熵源./dev/random很慢,因为它必须等待系统事件收集熵(磁盘读取,网络数据包,鼠标移动,按键等).
更快的解决方案是硬件随机数生成器.您的主板可能已经内置了一个; 查看hw_random文档,了解有关确定是否拥有它以及如何使用它的说明.rng-tools包中包含一个守护进程,它将硬件生成的熵提供给/dev/random.
如果您的系统上没有HRNG,并且您愿意牺牲熵强度以获得性能,那么您将希望为PRNG提供数据/dev/random,并让PRNG完成大部分工作.SP800-90中列出了几个经NIST批准的PRNG, 它们很容易实现.
根据文档, SecureRandom 使用的不同算法按优先顺序排列:
既然你问了 Linux,我就忽略了 Windows 实现,还有 SunPKCS11,它只在 Solaris 上真正可用,除非你自己安装了它——那么你就不会问这个问题了。
根据这些相同的文档,这些算法使用的是
SHA1PRNG
初始种子目前是通过系统属性和 java.security 熵收集设备的组合完成的。
NativePRNG
nextBytes()使用/dev/urandom
generateSeed()用途/dev/random
NativePRNG阻塞
nextBytes()和generateSeed()使用/dev/random
NativePRNGNonBlocking
nextBytes()和generateSeed()使用/dev/urandom
这意味着如果您使用SecureRandom random = new SecureRandom(),它会在该列表中向下移动,直到找到一个有效的,通常是 NativePRNG。这意味着它从/dev/random(或使用它,如果你明确地生成一个种子),然后/dev/urandom用于获取下一个字节,整数,双精度,布尔值,你有什么。
由于/dev/random正在阻塞(它阻塞直到熵池中有足够的熵),这可能会影响性能。
一种解决方案是使用 hasged 之类的东西来产生足够的熵,另一种解决方案是使用/dev/urandom。虽然您可以为整个 jvm 设置它,但更好的解决方案是SecureRandom使用SecureRandom random = SecureRandom.getInstance("NativePRNGNonBlocking"). 请注意,如果 NativePRNGNonBlocking 不可用,该方法可能会抛出 NoSuchAlgorithmException,因此准备回退到默认值。
SecureRandom random;
try {
random = SecureRandom.getInstance("NativePRNGNonBlocking");
} catch (NoSuchAlgorithmException nsae) {
random = new SecureRandom();
}
Run Code Online (Sandbox Code Playgroud)
另请注意,在其他 *nix 系统上,/dev/urandom行为可能有所不同。
/dev/urandom随机就够了吗?传统观点认为只有/dev/random足够随机。然而,有些声音是不同的。在"The Right Way to Use SecureRandom"和"Myths about /dev/urandom" 中,有人认为这/dev/urandom/同样好。
信息安全堆栈上的用户同意这一点。基本上,如果你不得不问,/dev/urandom就可以满足你的目的。
使用 Java 8,我发现在 Linux 上调用SecureRandom.getInstanceStrong()会给我NativePRNGBlocking算法。这通常会阻塞几秒钟以生成几个字节的盐。
我转而明确要求NativePRNGNonBlocking,正如名称所预期的那样,它不再被阻止。我不知道这有什么安全隐患。据推测,非阻塞版本不能保证使用的熵量。
更新:好的,我找到了这个很好的解释。
简而言之,为避免阻塞,请使用new SecureRandom(). 这使用/dev/urandom,它不会阻止并且基本上与/dev/random. 来自帖子:“您唯一想要调用 /dev/random 的时间是机器首次启动时,并且熵尚未累积”。
SecureRandom.getInstanceStrong() 给你绝对最强的 RNG,但它只在一堆阻塞不会影响你的情况下使用它是安全的。
您所参考的问题/dev/random不在于SecureRandom算法,而在于它使用的随机性来源。两者是正交的。您应该找出两者中的哪一个正在减慢您的速度。
您明确链接的“罕见的数学”页面提到它们没有解决随机性的问题。
您可以尝试使用不同的JCE提供程序,例如BouncyCastle,以查看它们的实现SecureRandom是否更快。
简短的搜索还显示了用Fortuna替换默认实现的Linux补丁。我对此了解不多,但是欢迎您进行调查。
我还应该提到,虽然使用执行SecureRandom不当的算法和/或随机性源非常危险,但是您可以使用的自定义实现来滚动自己的JCE Provider SecureRandomSpi。您将需要与Sun进行合作,以使您的提供商签名,但是实际上非常简单。他们只需要您传真给他们一张表格,说明您知道美国对加密库的出口限制。
有一个工具(至少在Ubuntu上)可以将人工随机性输入系统.命令很简单:
rngd -r /dev/urandom
Run Code Online (Sandbox Code Playgroud)
你可能需要前面的sudo.如果您没有rng-tools软件包,则需要安装它.我试过这个,这绝对帮助了我!
来源:亚光vs世界
我遇到了同样的问题.在使用正确的搜索条款进行Google搜索之后,我在DigitalOcean上看到了这篇精彩的文章.
我只是引用了这篇文章中的相关部分.
基于HAVEGE原理,并且之前基于其相关联的库,hasged允许基于处理器上的代码执行时间的变化来生成随机性.由于一段代码几乎不可能花费相同的执行时间,即使在同一硬件上的相同环境中,运行单个或多个程序的时间也应该适合种子随机源.在反复执行循环后,使用处理器的时间戳计数器(TSC)中的差异,伪造的实现会使系统的随机源(通常为/ dev/random)变为种子
我在这里贴了它
| 归档时间: |
|
| 查看次数: |
136223 次 |
| 最近记录: |