Is there a way to validate in java if the given private key, say certain *.key file matches with the certain public key, to a certain .pub file using RSA algorithm?
You can verify if a key pair matches by
- creating a challenge (random byte sequence of sufficient length)
- signing the challenge with the private key
- verifying the signature using the public key
This gives you a sufficiently high confidence (almost certainity) that a key pair matches if the signature verification is ok, and an absolute certainity that a key pair does not match otherwise.
Example code:
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);
This also works with Elliptic Curve (EC) key pairs, but you need to use a different signature algorithm (SHA256withECDSA
):
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC");
keyGen.initialize(new ECGenParameterSpec("sect571k1"));
...
Signature sig = Signature.getInstance("SHA256withECDSA");
The answer that was marked as being correct wastes a lot of CPU cycles. This answer is waaaay more CPU efficient:
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());
(the other answer signs a message with the private key and then verifies it with the public key whereas my answer checks to see if the modulus and public exponent are the same)
ECPrivateKey
can't access the public even if it is in the provider object. DSA, DH, EdDSA and XDH private keys standardly don't contain the public, although some things (not Java) sometimes use rfc5958 to add it. –
Pilgrim boolean keyPairMatches = privateKey.getModulus().equals(publicKey.getModulus()) && privateKey.getPublicExponent().equals(publicKey.getPublicExponent());
java.security.interfaces.RSAPrivateKey
doesn't have getPublicExponent() method.
org.bouncycastle.asn1.pkcs.RSAPrivateKey
has getPublicExponent() method.
So,if you don't want to use bouncycastle
, you have to use the sign&verify
answer.
interfaces.RSAPrivateKey
doesn't, but in practice more than 99.9999% of RSA private key objects in Java actually implement (and can be cast to) the subinterface interfaces.RSAPrivateCrtKey
which does, as neubert's code correctly shows. –
Pilgrim asn1.pkcs.RSAPrivateKey
only works if you have a CRT-from encoding, and in that case you can write an ad-hoc DER parser good enough to get n and e in about 10 lines of code. –
Pilgrim © 2022 - 2024 — McMap. All rights reserved.