5

I have the private key stored as .key file..

-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQD5YBS6V3APdgqaWAkijIUHRK4KQ6eChSaRWaw9L/4u8o3T1s8J
rUFHQhcIo5LPaQ4BrIuzHS8yzZf0m3viCTdZAiDn1ZjC2koquJ53rfDzqYxZFrId
7a4QYUCvM0gqx5nQ+lw1KoY/CDAoZN+sO7IJ4WkMg5XbgTWlSLBeBg0gMwIDAQAB
AoGASKDKCKdUlLwtRFxldLF2QPKouYaQr7u1ytlSB5QFtIih89N5Avl5rJY7/SEe
rdeL48LsAON8DpDAM9Zg0ykZ+/gsYI/C8b5Ch3QVgU9m50j9q8pVT04EOCYmsFi0
DBnwNBRLDESvm1p6NqKEc7zO9zjABgBvwL+loEVa1JFcp5ECQQD9/sekGTzzvKa5
SSVQOZmbwttPBjD44KRKi6LC7rQahM1PDqmCwPFgMVpRZL6dViBzYyWeWxN08Fuv
p+sIwwLrAkEA+1f3VnSgIduzF9McMfZoNIkkZongcDAzjQ8sIHXwwTklkZcCqn69
qTVPmhyEDA/dJeAK3GhalcSqOFRFEC812QJAXStgQCmh2iaRYdYbAdqfJivMFqjG
vgRpP48JHUhCeJfOV/mg5H2yDP8Nil3SLhSxwqHT4sq10Gd6umx2IrimEQJAFNA1
ACjKNeOOkhN+SzjfajJNHFyghEnJiw3NlqaNmEKWNNcvdlTmecObYuSnnqQVqRRD
cfsGPU661c1MpslyCQJBAPqN0VXRMwfU29a3Ve0TF4Aiu1iq88aIPHsT3GKVURpO
XNatMFINBW8ywN5euu8oYaeeKdrVSMW415a5+XEzEBY=
-----END RSA PRIVATE KEY-----

And i extracted public key from ssl certificate file..

Below is the code i tried to verify if private key matches with ssl certificate or not..

I used the modulus[i.e. private key get modulus==public key get modulus] to check if they are matching..

And this seems to hold only for RSAKEYS..

But i want to check for other keys as well..

Is there any other alternative to do the same..??

  private static boolean verifySignature(File serverCertificateFile, File serverCertificateKey) {
    try {
        byte[] certificateBytes = FileUtils.readFileToByteArray(serverCertificateFile);
        //byte[] keyBytes = FileUtils.readFileToByteArray(serverCertificateKey);
        RandomAccessFile raf = new RandomAccessFile(serverCertificateKey, "r");
        byte[] buf = new byte[(int) raf.length()];
        raf.readFully(buf);
        raf.close();
        PKCS8EncodedKeySpec kspec = new PKCS8EncodedKeySpec(buf);
        KeyFactory kf;
        try {
            kf = KeyFactory.getInstance("RSA");

            RSAPrivateKey privKey = (RSAPrivateKey) kf.generatePrivate(kspec);


            CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
            InputStream in = new ByteArrayInputStream(certificateBytes);
            //Generate Certificate in X509 Format
            X509Certificate cert = (X509Certificate) certFactory.generateCertificate(in);
            RSAPublicKey publicKey = (RSAPublicKey) cert.getPublicKey();

            in.close();
            return privKey.getModulus() == publicKey.getModulus();

        } catch (NoSuchAlgorithmException ex) {
            logger.log(Level.SEVERE, "Such algorithm is not found", ex);
        }  catch (CertificateException ex) {
            logger.log(Level.SEVERE, "certificate exception", ex);
        } catch (InvalidKeySpecException ex) {
            Logger.getLogger(CertificateConversion.class.getName()).log(Level.SEVERE, null, ex);
        }

    } catch (IOException ex) {
        logger.log(Level.SEVERE, "Signature verification failed.. This could be because the file is in use", ex);
    }
    return false;
}

And the code isn't working either.. throws invalidkeyspec exception

surendhar_s
  • 824
  • 2
  • 12
  • 20

6 Answers6

3

Sign something with the private key and verify it with the public key from the certificate. This will fail unless they are a pair.

user207421
  • 305,947
  • 44
  • 307
  • 483
  • That's just a coding problem. It has nothing to do with this answer. – user207421 Oct 16 '17 at 19:24
  • Signing something and checking the result is like validating a mathematical formula by testing if it holds for one certain variable assignment. It's better to check the properties of the parameters against the algorithm requirement. As an example, see my answer for code for RSA and ECC. DSA is as easy as RSA. – Steffen Heil Nov 17 '17 at 04:35
  • If you're worried about getting lucky with one test. Run the test against different values. If it checks out, the keys very highly likely make a pair. – Bassam Oct 26 '18 at 18:01
  • @user207421 this would work only if the algorithm is supported by a provider in Java. – Bassam Oct 26 '18 at 18:02
  • @SteffenHeil It only has to hold for one certain variable. The private key only has one value. – user207421 Oct 27 '18 at 19:59
2

So, what's the problem with pairwise parameter checking?

  • If certificate specifies public key of type “RSA”, then:
    1. Extract n, e from key file.
    2. Compare these values with those in certificate.
  • If certificate specifies public key of type “DSA”, then:
    1. Extract p, q, g, y from key file.
    2. Compare these values with those in certificate.
  • If certificate specifies public key of type “blah-blah”, then:
    1. Extract corresponding values from key file.
    2. Compare these values with those in certificate.

And so on, i. e. each algorithm requires its own proper handling. No general algorithm may exist, provided that key file format is actually custom. However, you may still slightly generalize it by specifying value indexes only:

ComparisonScheme = new Dictionary<String, Integer[2][]> {
    { "RSA", {{0, 0}, {1, 1}} },
    { "DSA", {{0, 1}, {1, 2}, {2, 3}, {3, 0}} },
}

This is just an illustration, of course, — don't get syntax and numbers seriously.

Anton Samsonov
  • 1,380
  • 17
  • 34
2

If you want to check, if a RSA publicKey and a RSA privateKey belong together, you can use the following code:

RSAPublicKey rsaPublicKey = (RSAPublicKey) publicKey;
RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) privateKey;
return rsaPublicKey.getModulus().equals( rsaPrivateKey.getModulus() )
    && BigInteger.valueOf( 2 ).modPow( rsaPublicKey.getPublicExponent()
    .multiply( rsaPrivateKey.getPrivateExponent() ).subtract( BigInteger.ONE ),
    rsaPublicKey.getModulus() ).equals( BigInteger.ONE );

I am searching for a similar solution for EC...


By now we already found a way for ECC: It is however a little more complicated:

ECPublicKey pk = (ECPublicKey) publicKey;
ECPrivateKey sk = (ECPrivateKey) privateKey;
ECParameterSpec pkSpec = pk.getParams(), skSpec = sk.getParams();
EllipticCurve skCurve = skSpec.getCurve(), pkCurve = pkSpec.getCurve();
ECField skField = skCurve.getField(), pkField = pkCurve.getField();
BigInteger skA = skCurve.getA(), skB = skCurve.getB();
if ( pkSpec != skSpec //
  && ( pkSpec.getCofactor() != skSpec.getCofactor() //
    || ! pkSpec.getOrder().equals( skSpec.getOrder() ) //
    || ! pkSpec.getGenerator().equals( skSpec.getGenerator() ) //
    || pkCurve != skCurve //
    && ( ! pkCurve.getA().equals( skA ) //
      || ! pkCurve.getB().equals( skB ) //
      || skField.getFieldSize() != pkField.getFieldSize() ) ) ) //
  return false;
ECPoint w = pk.getW();
BigInteger x = w.getAffineX(), y = w.getAffineY();
if ( skField instanceof ECFieldFp ) {
  BigInteger skP = ( (ECFieldFp) skField ).getP();
  return pkField instanceof ECFieldFp && skP.equals( ( (ECFieldFp) pkField ).getP() ) //
    && y.pow( 2 ).subtract( x.pow( 3 ) ).subtract( skA.multiply( x ) ).subtract( skB ).mod( skP ).signum() == 0;
}
if ( skField instanceof ECFieldF2m ) {
  int m = ( (ECFieldF2m) skField ).getM();
  BigInteger rp = ( (ECFieldF2m) skField ).getReductionPolynomial();
  if ( ! ( pkField instanceof ECFieldF2m ) || m != ( (ECFieldF2m) skField ).getM() || ! rp.equals( ( (ECFieldF2m) skField ).getReductionPolynomial() ) )
    return false;
  BigInteger x2 = f2mReduce( f2mMultiply( x, x ), rp, m );
  return f2mReduce( f2mSum( f2mMultiply( y, y ), f2mMultiply( x, y ), f2mMultiply( x, x2 ), f2mMultiply( skA, x2 ), skB ), rp, m ).signum() == 0;
}

And here are the math helper function:

public static final BigInteger f2mSum( BigInteger ... values )
{
  if ( values.length == 0 )
    return BigInteger.ZERO;
  BigInteger result = values[ 0 ];
  for ( int i = values.length - 1; i > 0; i -- )
    result = result.xor( values[ i ] );
  return result;
}


public static final BigInteger f2mAdd( BigInteger a, BigInteger b )
{
  return a.xor( b );
}


public static final BigInteger f2mSubtract( BigInteger a, BigInteger b )
{
  return a.xor( b );
}


public static final BigInteger f2mMultiply( BigInteger a, BigInteger b )
{
  BigInteger result = BigInteger.ZERO, sparse, full;
  if ( a.bitCount() > b.bitCount() ) {
    sparse = b;
    full = a;
  } else {
    sparse = b;
    full = a;
  }
  for ( int i = sparse.bitLength(); i >= 0; i -- )
    if ( sparse.testBit( i ) )
      result = result.xor( full.shiftLeft( i ) );
  return result;
}


public static final BigInteger f2mReduce( BigInteger input, BigInteger reductionPolynom, int bitLength )
{
  while ( input.bitLength() > bitLength )
    input = input.xor( reductionPolynom.shiftLeft( input.bitLength() - reductionPolynom.bitLength() ) );
  return input;
}
Steffen Heil
  • 4,286
  • 3
  • 32
  • 35
  • Did you find the solution for EC by now? – Vadzim Oct 13 '17 at 16:04
  • Thanks for the EC case, Steffen. But I've noticed that `f2mAdd` and `f2mSubtract` are unused and `f2mMultiply` has identical branches for `if ( a.bitCount() > b.bitCount() )` which seems to be a mistake. Could you, please, also reference the source of the algorythm? – Vadzim Feb 06 '18 at 22:11
2

Your code is fine, just add the following:

    String file = "qwerty";
    byte[] fileBytes = file.getBytes();
    byte[] digitalSignature = signData(fileBytes, privKey);
    System.out.println("SIGNATURE MADE");
    boolean verified;
    verified = verifySig(fileBytes, publicKey, digitalSignature);
    System.out.println("verified: " + verified) ;

  public static byte[] signData(byte[] data, PrivateKey key) throws Exception {
    Signature signer = Signature.getInstance("SHA256withRSA");
    signer.initSign(key);
    signer.update(data);
    return (signer.sign());
  }

  public static boolean verifySig(byte[] data, PublicKey key, byte[] sig) throws Exception {
    Signature signer = Signature.getInstance("SHA256withRSA");
    signer.initVerify(key);
    signer.update(data);
    return (signer.verify(sig));
  }
USer22999299
  • 5,284
  • 9
  • 46
  • 78
0

I'm a bit rusty on this, but a little help is better than none right?

In general, once you have a public/private key, you should be able to use a Cipher to encrypt some small amount of data with one key, and see if it can be successfully decrypted with the other. This is brute force and could have performance implications, but may be suitable for what you are trying to do (I would provide code, but I am in an environment where I can't test it, and I don't want to post anything untested. Encrypt and decrypt large string in java using RSA has code snippets using a Cipher if you are interested).

Also, unless the headers have been tampered with in your example private key file, it is not in PKCS8 format. PKCS8 files won't specify an algorithm (such as RSA) in the header, as they can use different algorithms and thus specify the algorithm being used in the encoding itself.

In addition, if i recall correctly, native java has terrible support for PEM. I believe you need to remove the the PEM headers from the key file and base64 decode it before you can do anything with it. Alternatively, if possible, you can ensure that your keyfiles are DER encoded, in which case the key spec should read it just fine.

Community
  • 1
  • 1
matthrms
  • 161
  • 6
0

This solution works in my case for preliminary check if elliptic curve keys do match:

boolean matches(PrivateKey privateKey, PublicKey publicKey) {
    return ((ECKey) privateKey).getParams().equals(((ECKey) publicKey).getParams());
}

See also @SteffenHeil's answer for more math checks which give the same result for me.

It's also interesting that Merchant Payment Processing certificate issued by Apple Pay has exactly the same ((ECKey) publicKey).getParams() as parent "Apple Worldwide Developer Relations CA - G2" certificate. So they both match the private key and the leaf can be resolved only with getSubjectDN() = getIssuerDN() checks involved.

Vadzim
  • 24,954
  • 11
  • 143
  • 151
  • java.lang.ClassCastException: sun.security.rsa.RSAPrivateKeyImpl cannot be cast to java.security.interfaces.ECKey – deFreitas Nov 13 '17 at 07:21
  • @deFreitas, refer to other answers on RSA case. This one only complements them on EC case. – Vadzim Nov 13 '17 at 08:08