为什么KeyPairGenerator.genKeyPair()如此缓慢

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();
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. 获取一个本地实现的Java Provider,它被知道是快速的,例如使用本地代码或专用硬件,如HSM;
  2. 切换到另一种算法,其密钥对生成速度很快,例如椭圆曲线加密;
  3. 使用openssl生成密钥,然后在你的Java应用程序中导入/使用它们。

通常情况下,你需要修复协议而不是密钥对生成器。通常,你只使用静态密钥对,它们不需要经常生成(编辑:除了提供前向安全性的密钥建立之外,但对于这个你通常使用(椭圆曲线)Diffie-Hellman,而不是RSA)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接