TL;DR: 当您不确定时,请使用
new SecureRandom()
并让系统自行决定。长期密钥生成可能使用
SecureRandom.getInstanceStrong()
。
请不要期望随机数生成器在运行时应用程序中生成特定的输出序列,即使您自己进行种子处理也是如此。
使用随机数生成器时很难说哪个是最好的。Linux和大多数Unix系统都有一个非常好的随机数生成器,因此使用
/dev/random
或
/dev/urandom
,即
"NativePRNG"
,不会有什么问题。使用
/dev/random
的问题在于它会一直阻塞,直到足够的熵可用。因此,除非您对密钥生成有特殊要求,否则我建议不要使用它。
"
SHA1PRNG
"使用哈希函数和计数器,以及种子。算法相对简单,但描述不够清晰。通常认为它是安全的。由于仅在启动期间从系统生成器之一种子化,并因此需要较少调用内核,因此可能消耗更少资源-在我的双核Ubuntu笔记本电脑上运行约比
"NativePRNG"
(配置使用
/dev/urandom
)快9倍。两者似乎只会占用我的笔记本电脑的一个内核(有时会切换到另一个内核,这可能是内核调度造成的)。如果需要高性能,请选择这个版本,特别是在特定系统配置中
/dev/urandom
设备较慢的情况下。
请注意,在已停用的Apache Harmony实现中出现的"SHA1PRNG"
与SUN提供程序中的版本(由Oracle在标准Java SE实现中使用)不同。位于Jakarta中的版本也用于旧版本的Android。虽然我还没有进行全面评审,但看起来并不太安全。"
编辑:我对此并不完全错误, SHA1PRNG 已被证明在版本<4.2.2中不是伪随机数生成器,更多信息请看这里。
请注意,"SHA1PRNG"
不是 Java SE 的实现要求。在大多数运行时中它都将存在,但直接从代码中引用它会使您的代码不够可移植。
现在(从Java 9开始),OpenJDK和Oracle JDK也包含多个实现,这些实现简称为“DRBG”。它们实现了NIST在SP-108中指定的动态随机位生成器列表。但这些不是Java实现的要求,如果需要符合FIPS的随机数生成器,则可以使用它们。然而,它们并没有改变这里的建议;如果开发人员认为这些实现比默认实现更好,那么他们只需将其作为默认实现即可。SecureRandom的契约不会改变:它仍然需要生成随机数。过去已经对默认算法做出了更改。
一般来说,要求特定提供者不是一个好主意。指定提供者可能会影响互操作性;例如,并不是每个Java运行时都可以访问SUN提供者——Android肯定没有。它还会使你的应用程序在运行时更加缺乏灵活性,即你不能将提供者放在列表中更靠前并使用它。
因此,只有在依赖于其提供的某些功能时才指示提供者。例如,如果您有一个生成随机数的特定硬件设备或已获得FIPS认证的密码库,则可能希望指定提供者。如果必须指定提供程序,则将算法/提供程序作为应用程序的配置选项可能是一个好主意。
不指定提供者的想法也在
Android developer Security Blog中提出。
请尽量避免选择任何特定的随机生成器,而是选择空参数构造函数:
new SecureRandom()
,让系统选择最佳的随机数生成器。如果您需要长期密钥生成等特定要求,则可以在Java 8及更高版本中使用新的可配置
SecureRandom.getInstanceStrong()
。
不要缓存
SecureRandom
实例,只需让它们最初自行进行种子生成并让 VM 处理即可。我没有看到操作上有明显的差异。
何时不应使用SecureRandom
:
总的来说,我强烈建议只将随机数生成器用于随机数生成,不要用于其他任何目的。即使您可以自己提供种子,并且即使您选择了Sun的SHA1PRNG,也不要指望能够从随机数生成器中提取相同的随机数序列。因此,请不要将其用于从密码派生密钥等用途。
如果确实需要重复序列,则使用流密码并使用种子信息作为密钥和IV。加密由零组成的明文以检索伪随机值的密钥流。或者,您可以使用可扩展输出函数(XOF),例如SHAKE128或SHAKE256(如果可用)。
如果可用的随机数生成器提供的性能不足且安全性不是问题,您可能希望考虑使用不同的非安全随机数生成器,而不是使用
SecureRandom
。像Mersenne Twister算法或
Random
类实现的算法这样的非安全随机数生成器已经被优化为简单和快速,而不是安全。没有一个
SecureRandom
实现会像非安全随机数生成器一样快。
可以扩展
SecureRandom
类并将确定性种子随机实现插入到库调用中。这样库就可以检索具有定义良好输出的伪随机数生成器。但应注意,随机数生成器可能会以不同的方式被算法使用。例如,RSA可能会切换到更好的优化方式来查找质数,而DES密钥可能会生成具有调整或直接计算的奇偶校验位。