在需要重新设定种子之前,我可以从 Java 的 SecureRandom CSPRNG 中提取的最大字节数是多少

Sta*_*nov 5 java random encryption cryptography

我正在用 Java 实现一个应用程序,并使用 SecureRandom 来生成随机性。我需要能够加密 10 亿个文件。我在 StackOverflow 上寻找问题的答案,但没有找到确切的答案。大家都很模糊:

\n\n
    \n
  • 您不需要\xe2\x80\x99 重新播种 SecureRandom。它有一个 \xe2\x80\x9clarge\xe2\x80\x9d 周期。但什么是呢?
  • \n
  • 您不需要\xe2\x80\x99t 重新播种 SecureRandom,因为它是 \xe2\x80\x9c 设计良好的 CSPRNG。但是什么是设计良好的CSPRNG\xe2\x80\x99s 周期?
  • \n
\n\n

所以我决定自己算一下,看看是否有人可以帮我检查一下。关于 Java 8 中 SecureRandom\xe2\x80\x99s 当前的实现,我们了解哪些事实?事实上,从我发现的消息来源来看,存在一些争议。

\n\n
\n\n

我对 Java 的 SecureRandom 实现的了解

\n\n
    \n
  • 在通过调用nextBytes()、等nextInt()生成随机性时,它在内部使用 SHA1PRNG nextLong()(请参阅TersesystemsCigital)。

    \n\n

    Cigital 对 SecureRandom 底层功能的解释与Java 文档的官方解释相矛盾。Oracle 的官方文档指出,NativePRNG、NativePRNGBlocking、NativePRNGNonBlocking 和 Windows-PRNG 始终使用本机随机源,而不是 Java\xe2\x80\x99s 自己的 SHA1PRNG 算法(这个答案这个提到了)。Cigital\xe2\x80\x99s 链接表示 Java 始终使用 SHA1PRNG,但 SecureRandom 的类型决定了它的种子来源(/dev/random/dev/urandom)。

    \n\n

    SecureRandom 是否始终在幕后使用 SHA1PRNG?这是我在数学计算中假设的,所以如果情况并非如此,请纠正我。

  • \n
  • Oracle官方文档指出 SHA1PRNG 将其输出从完整的 160 位哈希输出截断为 64 位?查看SecureRandom 的OpenJDK\xe2\x80\x99s 实现,我没有看到 SHA1 输出的截断。实际上它的作用相反:它保存 SHA1 哈希中任何未使用的输出,以供将来调用engineNextBytes(). 如果 Oracle 官方文档是该主题的主要权威,那么为什么 OpenJDK\xe2\x80\x99s 的实现会有所不同呢?这很奇怪。

  • \n
  • nextBytes()在 SecureRandom 实例上立即调用时,它会由操作系统\xe2\x80\x99s CSPRNG(在 Linux/Unix 中和 Windows 中的 CryptGenRandom 中)自动播种,或者当定制的熵生成器(如ThreadLocalRandom )/dev/random不可用时,它会自动播种。但 ThreadLocalRandom 提供的熵非常低且缓慢,因此应尽可能避免使用。

  • \n
  • 我没有在 SecureRandom 中看到自动重新播种功能的证据。正如《密码学工程》中所解释的,Fortuna CSPRNG 有一个复杂的重新播种机制,我希望任何现代 CSPRNG 都能从客户端抽象出该逻辑并自动处理它。我不知道为什么对 CSPRNG 重新播种的信息和理解如此缺乏。如果您耗尽 CSPRNG 的周期,则需要发生这种情况。这个毋庸置疑。问题是周期是什么,它是 Java 中真正关心的问题吗?

  • \n
\n\n
\n\n

做数学题

\n\n

由于生日攻击,我们知道当我们产生内部哈希输出数一半的输出大小时,通常会发生冲突。我们知道内部哈希被截断为 64 位。这意味着我们最多可以生成 2^32-1 轮 64 位随机性,然后才有 50% 的机会发生碰撞。这将是我们想要重新播种的时间。

\n\n

(2^32-1) * 64 = 274,877,906,880SecureRandom 每个种子的随机性位数

\n\n

转换为字节我们得到

\n\n

(2^32 - 1) * 64 / 8 / (1024 * 1000 * 1000 ) = ~33.55SecureRandom 的每个种子的 GB 随机性。

\n\n

这意味着我们通常可以预期 SecureRandom\xe2\x80\x99s SHA1PRNG 生成约 33.55GB 的高质量随机性,然后需要使用强种子重新播种。

\n\n

我的数学正确吗?

\n\n

为什么这很重要?因为我的用例是加密 10 亿个文件。每个都需要一个 IV(128 位)和一个密钥(256 位)或 384 位。最好情况下需要 46.875GB 的随机性。因此,如果 SecureRandom 的周期只有 33.55GB,我将耗尽该周期。在这种情况下,需要重新播种策略,我将其作为单独的问题发布。

\n\n

我的碰撞和 SecureRandom 问题

\n\n

关于密码学我有很多东西要学,所以我的理解一直在提高。我没有\xe2\x80\x99t 找到任何有关 CSPRNG 冲突问题的信息,但猜测生成器的内部状态是有害的(请参阅WikiSchneir\xe2\x80\x99s 关于 CSPRNG 的密码分析论文)。

\n\n

不过,这是我对碰撞的思路。我生成了一个 (2^32-1) 随机、唯一 64 位值的表(结果约为 33.55GB,非常容易实现)。那么我就有 50% 的机会猜测 SecureRandom 的任何 64 位输出。例如,IV/密钥由 2 x 64 = 128 位组成。这意味着我可以以 50% 的概率猜测 IV/Key 的前 64 位,以 50% 的概率猜测第二个 64 位,而无需知道 CSPRNG 的内部状态。猜测完整密钥的组合概率将低于 50%,但远高于我们在使用此类加密原语时看到的可忽略的概率。这可能会导致生成弱密钥,这是我试图避免的。换句话说,我认为仅基于 64 位输出的冲突属性(由于生日攻击),CSPRNG 的 64 位输出对于严肃的加密工作来说太小了。另一方面,如果 SecureRandom 使用 512 位 SHA-2 散列并将其截断为 256 位输出,那么由于密钥空间的巨大大小,我在这里推理的碰撞攻击将是不可能的。我说得有道理还是我搞错了?

\n