8

我有一些 Java 代码,当我运行函数时KeyPairGenerator.genKayPair(),它的工作时间为 40 秒或更长时间。如何改变这种状况?如果我跑

openssl req -x509 -nodes -days 365 -newkey rsa:4096 -keyout server.key -out cert.pem 

它的工作 3 秒。慢代码:

KeyPairGenerator gen = KeyPairGenerator.getInstance("RSA");
SecureRandom random = new SecureRandom();
gen.initialize(4096, random);        
keyPair = gen.generateKeyPair();        
PublicKey pubk = keyPair.getPublic();
PrivateKey prvk = keyPair.getPrivate();
4

1 回答 1

9

首先,尽管 Java 在业务逻辑方面确实很快,但优化的 C 代码(在其重要的地方包含汇编)将在涉及密码学时将其从水中吹走。

Java 将使用BigInteger来执行这些计算,并且BigInteger- 并不总是包含针对所有功能的本机优化方法。请注意,Oracle JDK / OpenJDK在发布此答案时进行了一些更改,并且确实允许从 JDK 8 开始的多种方法的内在函数BigInteger,包括蒙哥马利乘法。脚本语言通常比 Java 差得多,除非它们调用本机代码。

Java 也需要时间来优化字节码。这意味着如果多次调用它,它会运行得更快。因此,您至少需要先调用一个密钥生成器,然后才能查看如果在您的应用程序中多次调用此类方法会发生什么。在这种情况下,运行时间可能会很高,以至于它已经能够优化——这取决于 VM 的实现。

RSA 密钥生成主要取决于找到两个大小约为密钥大小一半的大素数。寻找大素数是一个非常占用 CPU 资源的过程。它还依赖于随机数生成器来创建起点。因此,实际使用的随机数生成器实现会产生很大的不同——尤其是如果没有足够的熵可用,随机数生成器会阻塞。因此,请使用可用的随机数生成器,直到找到足够快速和安全的随机数生成器。

寻找一定长度的素数是一个没有指定运行时间的过程;该过程不是确定性的。选择一个非常大的数字(在这种情况下,大小约为 4096 / 2 = 2048 位)并开始测试后续数字是否为素数。这就是锤击你的 CPU 的原因。所以你需要计算生成素数的平均运行时间——以防你生成很多素数——否则你将不得不忍受它所花费的时间的不确定性。


不过,这一切都没有实际意义。一般来说,您不需要大量的 RSA 密钥——您为每个用户生成一到三个。所以这只会在以下情况下成为问题:

  1. 你有很多用户
  2. 您有一个需要大量密钥对的协议或
  3. 您需要非常大的 RSA 密钥。

如果您想以更快的方式生成密钥对,您可以执行以下操作:

  1. 获得Provider已知速度快的 Java 的本机实现,例如使用本机代码或专用硬件(如 HSM);
  2. 切换到另一种密钥对生成速度较快的算法,例如椭圆曲线密码术;
  3. 使用生成密钥openssl并在您的 Java 应用程序中导入/使用它们。

通常虽然您需要修复协议而不是密钥对生成器。通常您只使用不需要经常生成的静态密钥对(编辑:除了提供前向安全性的密钥建立,但您通常会使用(椭圆曲线)Diffie-Hellman,而不是 RSA)。

于 2015-04-03T12:45:43.077 回答