Reputation: 884
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
Upvotes: 5
Views: 19158
Reputation: 26200
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.
Upvotes: 0
Reputation: 4346
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;
}
Upvotes: 2
Reputation: 5694
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));
}
Upvotes: 2
Reputation: 1432
So, what's the problem with pairwise parameter checking?
n
, e
from key file.p
, q
, g
, y
from key file.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.
Upvotes: 2
Reputation: 311016
Sign something with the private key and verify it with the public key from the certificate. This will fail unless they are a pair.
Upvotes: 3
Reputation: 161
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.
Upvotes: 0