5

我们正在使用与 java 安装捆绑在一起的 keytool 来生成密钥以进行非对称 RSA 加密。鉴于最近发生的事件,有人问我 java keytool 的幕后发生了什么。特别是关于结果数字的随机性。(例如“嗯,为什么没有像鼠标移动或键盘输入这样的随机用户输入?”

那么创建密钥的 java keytool 的“随机源”是什么?

我自己做了一个快速的研究,但我发现的唯一信息是 2000 年的一篇文章

  • keytool.exe 使用 SecureRandom 作为其随机数的基础。
  • SecureRandom 的 Sun 提供程序遵循 IEEE P1363 标准,
  • Sun SecureRandom 提供程序符合 NIST 的 FIPS PUB 140-1 第 4.11 节。
  • 用于 SecureRandom 的 Sun 提供程序将其他熵源与线程争用过程的结果混合在一起。其中包括当前时间、VM 内存使用状态、系统属性和文件系统活动。
  • 该算法在没有 JIT 的情况下可能表现不佳,因此我们正在考虑提供替代提供商,该提供商将利用平台特定的对熵收集设备的支持,例如 /dev/random 或 Pentium III 热噪声 RNG。

但这又回到了 2K,所以你们中的某个人可能会对此有所了解并提供对上述内容的更新(在 Java7 中不同?)。根据您的回答,如果您建议切换到其他提供商,例如 bouncycastle,我会很感兴趣...

更新:我现在假设 keytool 使用 java.security.SecureRandom (因此是默认提供程序)作为其随机数的基础。我发现了另一篇有趣的文章,它指向了控制 SecureRandom API JAVA_HOME/lib/security/java.security 配置的文件

在那里它陈述了以下内容:

选择 SecureRandom 的种子数据源。默认情况下,尝试使用由 securerandom.source 属性指定的熵收集设备。如果访问 URL 时发生异常,则使用传统的系统/线程活动算法。在 Solaris 和 Linux 系统上,如果指定了 file:/dev/urandom 并且它存在,则默认激活特殊的 SecureRandom 实现。这个“NativePRNG”直接从 /dev/urandom 读取随机字节。在 Windows 系统上,URL 文件:/dev/random 和文件:/dev/urandom 允许使用 Microsoft CryptoAPI 种子功能。

securerandom.source=文件:/dev/urandom

由于我们使用的是 Windows 系统,因此我假设使用了Microsoft CryptoAPI。由于使用的是 Win7,因此它是 CNG(下一代 CryptoAPI)。有谁知道“使用 Microsoft CryptoAPI 种子功能”。方法?最可能的方法似乎是:CryptGenRandom function

更新:Oracle 似乎改进了Java 8的一些问题。

4

4 回答 4

4

我想在这里分享我的发现:

  1. keytool.exe 使用 SecureRandom 作为其随机数的基础,如其源代码所示:KeytoolCertAndKeyGen

  2. 通常,正如SecureRandom API 所述:“加密强随机数至少符合 FIPS 140-2,加密模块的安全要求,第 4.9.1 节中指定的统计随机数生成器测试。” 因此,SecureRandom 的所有实现都应符合FIPS-140-2

  3. 安全提供程序的配置(因此也适用于 SecureRandom)在JAVA_HOME/lib/security/java.security. 默认值为(列表顶部):security.provider.1=sun.security.provider.Sun

  4. 在 Linux 上不更改 3.) 时,SecureRandom 的默认实现是NativePRNG,而在 Windows 上,默认实现是SHA1PRNG。在我们的例子中,它是一个生成密钥的 windows pc,因此它是SHA1PRNG

  5. 在查看实现时,以下内容很突出:

    “请注意,如果没有提供种子,我们会尝试提供足够的种子字节来完全随机化生成器的内部状态(20 个字节)。但是,我们的种子生成算法尚未得到彻底研究或广泛部署

  6. SeedGenerator(所有 SHA1PRNG SecureRandom 对象的单一实例)的“种子源”具有以下顺序:

  7. 现在发现SHA1PRNG有以下问题:

    • 不一致
    • 统计偏差 I(pp.152,法语,如果 n. 则使用翻译器)

      “然而,使用生成的 500MB 文件进行的黑盒测试显示,输出的统计偏差存在 15 个数量级。”

    • 统计偏差 II (pp.1)

      “本文中的实验结果表明,由伪随机生成器 SHA1PRNG(Java 中)产生的序列可以以高概率与统一选择的序列区分开来”

    • 方差差(第 12 页)和有限的状态大小(第 9 页)

      “随机字节在 STS 测试中遇到了严重的困难,在 Monobit、Runs 和前八次串行测试中失败。这表明单个位和最多 8 位元组的差异很差。” 并且 “在 Java 中,向实例添加更多熵(> 160 位)不会增强安全性。这个限制令人担忧,因为它使 PRNG 无法生成 > 160 位的密钥(例如,在 AES 的情况下)。”

结果是:

  • 所有 java windows 安装的默认实现是 SHA1PRNG
  • SHA1PRNG 的行为非常不稳定
  • SHA1PRNG 是高度专有的——它不符合 FIPS-140-2(应该如此)。
  • 不幸的是(引用实现者的话)“我们的种子生成算法还没有被彻底研究”。但是随着 java 的广泛分布,它现在被广泛部署和使用。

因此,可以假定 Java 密钥生成机制(至少在 Windows 上)已损坏。因此,大多数作者建议使用一些硬件,例如 HSM/ TRNG

于 2013-10-15T12:55:15.077 回答
1

实际上有一篇来自 Ruhr-Uni Bochum 的 Michaelis, Meyer, Schwenk 的论文更仔细地分析了 Java 中的随机性。它被称为“随机失败”。它没有给 Java 实现最好的分数,但它似乎并不太令人警觉,八分。

请注意,Java 8 已经围绕 JEP123 进行了一些改进(但是它仍然缺少使用更具弹性算法的 RNG(如 Fortuna)。您可以在 OpenJDK 安全开发列表中看到一些围绕 JEP123 的讨论:

于 2014-02-03T10:36:28.160 回答
1

似乎,除了此处记录的高级 API的详细信息外,实现可能是平台(Windows/Linux)和 JDK 实现(OpenJDK/OracleJDK)特定的。您可以在此处查看 NativePRNG(在 Linux 上使用)的 OpenJDK 实现的源代码。

也许考虑使用 bouncycastle 提供程序只是为了提高跨平台的透明度和一致性。

于 2013-10-01T15:41:53.553 回答
0

除非您使用的是硬件安全模块,否则我真的不会担心。关于您的随机数是否真正随机的微妙担忧淡入了背景,而主要关注的是您的密钥是否存在于硬盘上。

回到您的问题 - keytool 会将所有加密操作移交给 JCA/JCE 提供者。每个提供者都有自己的SecureRandom实现,这些实现的细节在网上很难找到,除非通过挖掘源代码。您链接到的线程包含的信息比我以前看到的更多。

于 2013-10-01T15:21:17.877 回答