如何解决慢Java`SecureRandom`?

问题

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

有没有人用过Uncommon Maths这个问题的解决方案?

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


#1 热门回答(151 赞)

你应该能够在Linux上使用以下选项来选择速度更快但稍微不那么安全的/ dev / urandom:

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

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

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

(注意extra/./)


#2 热门回答(65 赞)

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

如果你想要一个PRNG,做这样的事情:

SecureRandom.getInstance("SHA1PRNG");

支持哪些字符串取决于SecureRandomSPI提供程序,但你可以使用Security.getProviders()Provider.getService()枚举它们。

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

例外情况是,如果你在获取数据之前没有致电setSeed(),那么PRNG将在你第一次调用next()ornextBytes()时自行播种。它通常使用来自系统的相当少量的真随机数据来完成此操作。这个调用可能会阻塞,但会使你的随机数源比任何"将当前时间与PID一起散列,加上27,并希望最好"的变体更安全。但是,如果你需要的只是游戏的随机数,或者如果你希望将来使用相同的种子进行测试时可重复使用流,则不安全的种子仍然有用。


#3 热门回答(31 赞)

在Linux上,SecureRandomisNativePRNG(源代码here)的默认实现,往往非常慢。在Windows上,默认值为SHA1PRNG,正如其他人指出的那样,如果明确指定它,也可以在Linux上使用。

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

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

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