Aravind S
Aravind S

Reputation: 495

How to validate a public and private key pair in Java

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?

Upvotes: 9

Views: 17031

Answers (3)

cyberhorse
cyberhorse

Reputation: 1

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.

Upvotes: 0

Peter Walser
Peter Walser

Reputation: 15706

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");

Upvotes: 18

neubert
neubert

Reputation: 16822

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)

Upvotes: 9

Related Questions