Java 为什么KeyPairGenerator.genKeyPair()这么慢

Java 为什么KeyPairGenerator.genKeyPair()这么慢,java,openssl,cryptography,rsa,key-generator,Java,Openssl,Cryptography,Rsa,Key Generator,我有一些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 ra

我有一些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();

首先,尽管Java在业务逻辑方面确实很快,但在密码技术方面,优化的C代码(在它重要的地方有汇编)将使它一败涂地

Java将使用
biginger
执行这些计算,并且
biginger
并不总是包含针对所有功能的本机优化方法。请注意,OracleJDK/OpenJDK和确实允许从JDK8开始的几个
BigInteger
方法使用内部函数,包括Montgomery乘法。脚本语言通常比Java差得多,除非它们调用本机代码

Java还需要时间来优化字节码。这意味着如果多次调用它,它运行得更快。因此,您需要在调用之前至少调用一个key gen,以查看如果在应用程序中多次调用这样的方法会发生什么。在这种情况下,运行时可能非常高,以至于它已经能够进行优化—这取决于VM实现

RSA密钥生成主要依赖于找到两个大素数,它们的大小大约是密钥大小的一半。寻找大素数是一个非常CPU密集的过程。它还依赖于随机数生成器来创建起点。因此,实际使用的随机数生成器实现会产生很大的差异——特别是如果没有足够的熵可用时,随机数生成器会阻塞。所以,在你找到一个足够快和安全的随机数生成器之前,请使用可用的随机数生成器

查找某个长度的素数是一个没有指定运行时的进程;这个过程是不确定的。选择一个非常大的数字(在本例中,大小约为4096/2=2048位),然后开始测试后续的数字是否为素数。这就是影响CPU的因素。所以你需要计算生成素数的平均运行时间——如果你生成了很多素数的话——否则你将不得不忍受所需时间的不确定性


不过,这一切都有点毫无意义。一般来说,您不需要大量的RSA密钥—您可以为每个用户生成一到三个密钥。因此,只有在以下情况下,这才成为问题:

  • 你有很多用户
  • 您有一个需要大量密钥对或密钥的协议
  • 您需要非常大的RSA密钥
  • 如果您想以更快的方式生成密钥对,可以做以下几件事:

  • 获取已知快速的Java
    提供者的本机实现,例如使用本机代码或HSM等专用硬件
    
  • 切换到另一种生成密钥对速度较快的算法,如椭圆曲线密码
  • 使用
    openssl
    生成密钥,然后在Java应用程序中导入/使用它们
  • 通常情况下,您需要修复协议,而不是密钥对生成器。通常,您只使用不需要经常生成的静态密钥对