How to verify if the private key matches with the certificate..?

14,995

Solution 1

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.

Solution 2

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

Solution 3

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;
}

Solution 4

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));
  }
Share:
14,995
surendhar_s
Author by

surendhar_s

Updated on June 04, 2022

Comments

  • surendhar_s
    surendhar_s almost 2 years

    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

  • Vadzim
    Vadzim over 6 years
    Did you find the solution for EC by now?
  • user207421
    user207421 over 6 years
    That's just a coding problem. It has nothing to do with this answer.
  • deFreitas
    deFreitas over 6 years
    java.lang.ClassCastException: sun.security.rsa.RSAPrivateKeyImpl cannot be cast to java.security.interfaces.ECKey
  • Vadzim
    Vadzim over 6 years
    @deFreitas, refer to other answers on RSA case. This one only complements them on EC case.
  • Steffen Heil
    Steffen Heil over 6 years
    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.
  • Vadzim
    Vadzim over 6 years
    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?
  • Bassam
    Bassam over 5 years
    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
    Bassam over 5 years
    @user207421 this would work only if the algorithm is supported by a provider in Java.
  • user207421
    user207421 over 5 years
    @SteffenHeil It only has to hold for one certain variable. The private key only has one value.