如何在Java中验证公钥和私钥对

9

有办法在Java中验证给定的私钥,例如某个*.key文件是否与某个公钥匹配,使用RSA算法来验证?


你没有指定所使用的算法,但是也许这个链接会有所帮助:https://dev59.com/_lLTa4cB1Zd3GeqPcJ0H - Thilo
它的RSA算法已在标签中指定并更新了问题。感谢提供链接。 - Aravind S
3个回答

18
您可以通过以下步骤验证密钥对是否匹配:
  • 创建一个具有足够长度的随机字节序列挑战(challenge)
  • 使用私钥(private key)签署挑战
  • 使用公钥(public key)验证签名
这将使您在签名验证正确时获得足够高的置信度(几乎确定密钥对匹配),否则您可以绝对确定密钥对不匹配。 示例代码:
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(2048);

KeyPair keyPair = keyGen.generateKeyPair();
PublicKey publicKey = keyPair.getPublic();
PrivateKey privateKey = keyPair.getPrivate();

// create a challenge
byte[] challenge = new byte[10000];
ThreadLocalRandom.current().nextBytes(challenge);

// sign using the private key
Signature sig = Signature.getInstance("SHA256withRSA");
sig.initSign(privateKey);
sig.update(challenge);
byte[] signature = sig.sign();

// verify signature using the public key
sig.initVerify(publicKey);
sig.update(challenge);

boolean keyPairMatches = sig.verify(signature);

这也适用于椭圆曲线(EC)密钥对,但您需要使用不同的签名算法(SHA256withECDSA):

KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC");
keyGen.initialize(new ECGenParameterSpec("sect571k1"));
...
Signature sig = Signature.getInstance("SHA256withECDSA");

1
非常感谢,它起作用了!我也必须研究一下这段代码。 - Aravind S
你能提供任何相关链接吗?这样我就可以了解它的工作原理了吗? - Aravind S
Java教程:生成和验证签名 -> https://docs.oracle.com/javase/tutorial/security/apisign/index.html - Peter Walser
通常,签名用于验证消息是否被更改过。它也可以用于通过使用签名的挑战来识别双方(一个拥有私钥,另一个拥有公钥)。我们将其用于身份验证:服务器提出挑战,客户端使用私钥对其进行签名,服务器通过验证签名的挑战(使用客户端的公钥)来验证其身份。 - Peter Walser
感谢您的解释,我也会查看链接。 - Aravind S

7
被标记为正确答案的那个答案浪费了很多 CPU 循环。而这个答案非常高效:
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(2048);

KeyPair keyPair = keyGen.generateKeyPair();
RSAPrivateCrtKey privateKey = (RSAPrivateCrtKey) keyPair.getPrivate();
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();

// comment this out to verify the behavior when the keys are different
//keyPair = keyGen.generateKeyPair();
//publicKey = (RSAPublicKey) keyPair.getPublic();

boolean keyPairMatches = privateKey.getModulus().equals(publicKey.getModulus()) &&
    privateKey.getPublicExponent().equals(publicKey.getPublicExponent());

(另一个答案使用私钥签名消息,然后使用公钥验证该消息,而我的答案则检查模数和公共指数是否相同。)

这个答案不适用于通用密钥对(EC,DSA,...),只适用于RSA密钥对。 - Peter Walser
1
@PeterWalser - 这是正确的,但OP的问题是“_使用RSA算法_”。但即使如此,您仍不需要签名/验证,即使使用EC或DSA。 使用EC,您会检查曲线和QA参数是否相同。 从技术上讲,我认为EC私钥可能没有可用的QA,但我觉得大多数真实世界的EC密钥就像大多数真实世界的RSA私钥一样,在其中嵌入了公共指数。 我的意思是,就像RSA一样,从技术上讲,你所需要的只是模数和私有指数,但是大多数真实世界的RSA私钥也包括CRT组件。 - neubert

0

boolean keyPairMatches = privateKey.getModulus().equals(publicKey.getModulus()) && privateKey.getPublicExponent().equals(publicKey.getPublicExponent());

java.security.interfaces.RSAPrivateKey 没有 getPublicExponent() 方法。

org.bouncycastle.asn1.pkcs.RSAPrivateKey 有 getPublicExponent() 方法。

因此,如果您不想使用 bouncycastle,您必须使用 sign&verify 答案。


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