11

I have my pair of Public and Private keys and my certificate. Those where created in OpenSSL (why? because I was asked to do it in OpenSSL). Now I want to use those things to make a Java app that uses digital signatures. How can I use my private and public keys to encrypt/decrypt info (and use the certificate to see if data is valid? What are the classes in java that allow me to do that?

My keys are in plain text something like this:

-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDDuyg3h0VbP9iZ6RCxSU6x4WX4
anAwedMVUTqF0WHlvHl1Kiqa6N6TiUk23uXAVUX8RwLFjXWHlG0xwW7mGByA2mX9
5oPQpQFu8C70aMuUotGv87iiLi0UKCZV+9wS9rMdg5LHu1mMPilwgOO6MlyTxKem
-----END PUBLIC KEY-----

UPDATE

I made this code but still can't use the private key to sign a string.

public void encryptHash(String hashToEncrypt, String pathOfKey, String Algorithm) {
    FileInputStream fis = null;
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    int len;

        File f = new File(pathOfKey);

        fis = new FileInputStream(pathOfKey);
        len = 0;
        while((len = fis.read()) != -1){
            baos.write(len);
        }

        KeyFactory kf = KeyFactory.getInstance(Algorithm); //Algorithm = "RSA"
        KeySpec keySpec = new PKCS8EncodedKeySpec(baos.toByteArray());
        baos.close();
        PrivateKey privateKey = kf.generatePrivate(keySpec);  //Here's the exception thrown

        Signature rsaSigner = Signature.getInstance("SHA1withRSA");
        rsaSigner.initSign(privateKey);

        fis = new FileInputStream(hashToEncrypt);
        BufferedInputStream bis = new BufferedInputStream(fis);
        byte[] buffer = new byte[1024];
        len = 0;
        while((len = bis.read(buffer)) >= 0){
            try {
                rsaSigner.update(buffer, 0, len);
            } catch (SignatureException ex) {
                Logger.getLogger(DataEncryptor.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        bis.close();

        byte[] signature = rsaSigner.sign();

        System.out.println(new String(signature));
}

the exception I'm gettin' is

dic 09, 2011 12:49:02 PM firmaelectronica.DataEncryptor encryptHash
Grave: null
java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: IOException : DER input, Integer tag error
    at sun.security.rsa.RSAKeyFactory.engineGeneratePrivate(RSAKeyFactory.java:217)
    at java.security.KeyFactory.generatePrivate(KeyFactory.java:372)
    at firmaelectronica.DataEncryptor.encryptHash(DataEncryptor.java:40)
    at firmaelectronica.FirmaElectronica.main(FirmaElectronica.java:39)
Caused by: java.security.InvalidKeyException: IOException : DER input, Integer tag error
    at sun.security.pkcs.PKCS8Key.decode(PKCS8Key.java:361)
    at sun.security.pkcs.PKCS8Key.decode(PKCS8Key.java:367)
    at sun.security.rsa.RSAPrivateCrtKeyImpl.<init>(RSAPrivateCrtKeyImpl.java:91)
    at sun.security.rsa.RSAPrivateCrtKeyImpl.newKey(RSAPrivateCrtKeyImpl.java:75)
    at sun.security.rsa.RSAKeyFactory.generatePrivate(RSAKeyFactory.java:316)
    at sun.security.rsa.RSAKeyFactory.engineGeneratePrivate(RSAKeyFactory.java:213)
    ... 3 more
  • Is there a way to give you my key? It was generated just for test purposes so I don't care sharing it ! – BRabbit27 Dec 9 '11 at 19:28
  • Doing some research. It seems that KeyFactory is the one responsible of this exception, 'cause in fact the key is PKCS#8. – BRabbit27 Dec 9 '11 at 20:50
  • I have another question. My private key has a password, but nowhere in the code I put that password, could it be the problem of the exception? – BRabbit27 Dec 9 '11 at 22:48
  • I had the same question. That was the inspiration for this: orbaker.com/java/sslcontext.html – user9284 Apr 22 '12 at 23:49
10

If you have a public key in this form (and not within a certificate), I'd recommend using BouncyCastle's PEMReader. Its readObject() method can read a lot for formats: public keys, certificates, private keys (although you may need to use the method with a password)...

If you don't want to use BouncyCastle, you can read certificates using a CertificateFactory (see examples). With a certificate in PEM format in an InputStream:

CertificateFactory cf = CertificateFactory.getInstance("X.509");
Certificate cert = cf.generateCertificate(inputStream);

For private keys, if your private key is a PKCS#8 structure in DER format, you can read it directly using PKCS8EncodedKeySpec. For example:

KeyFactory kf = KeyFactory.getInstance("RSA");
// Read privateKeyDerByteArray from DER file.
KeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyDerByteArray);
PrivateKey key = kf.generatePrivate(keySpec);

You can convert your private key into PKCS#8 using openssl pkcs8 -topk8 (remember -outform DER, you may also want to check the cipher suites as not all might be commonly supported by both Java and OpenSSL).

  • From a keystore usage point of view:

If you don't want to do much programming for handling the keys, to go between Java and OpenSSL, it's convenient to use the PKCS#12 format.

If the keys and certs you have produced with OpenSSL are not already in a p12 container:

openssl pkcs12 -export -in cert.pem -inkey key.pem -out store.p12

In general, you can make use of the directly, using Java's "PKCS12" keystore type (instead of "JKS" by default).

If needed, you can convert this PKCS12 keystore into another format (e.g. JKS) using keytool (Java 6+):

keytool -importkeystore -srckeystore store.p12 -srcstoretype PKCS12 \
     -destkeystore store.jks -deststoretype JKS

(Essentially, the opposite operation as the one described in this question.)

Either way, whether from using PEMReader or by loading your key/cert from a KeyStore, you should be able to get instances of PrivateKey and Certificate (or PublicKey directly).

You can verify the signature of a Certificate has been done using by the private key matching a given public key using its verify(PublicKey) method.

With them, you can also use the digital signature API. It's a more general API for any document signature, and I wouldn't necessarily verify a certificate signature with it (I'd rather use the certification path API for this, since it will also build the chain).

  • Yep thanks ! And If I don't want to use third party APIs? Is there a native Java API to use private/public RSA keys and certificates? Should I create new keys in PKCS#12 format? How can I check if my keys are in that format? – BRabbit27 Dec 9 '11 at 0:16
  • I've edited my answer for direct usage of the API (but BC makes the whole process a bit easier). I gave you the openssl command to build a p12 file from a cert and key in PEM format (if you have those in .pem or .crt file for example). Extensions are just a convention, so it depends on how you actually created the key/cert. What you've pasted in your question looks like PEM (or a variant thereof), but that's just a public key, not a certificate. – Bruno Dec 9 '11 at 0:45
  • Thanks. I've done a more deep research and actually the key and cert are in DER format, so they are in pkcs8 arent they? So if I understand well the info you gave me I can use PKCS8EncodedKeySpec, am I right? (The key I posted was actually a PEM one but the original file is in DER, and all the other keys and certs are in DER) Thanks I'll try this out ! thanks ! – BRabbit27 Dec 9 '11 at 16:55
  • 1
    @miho, no, I was just talking of ways to read them. PEMReader will try its best to read anything it can. A certificate has more information than just a public key (it binds a public key to an identity and other attributes). – Bruno Mar 30 '14 at 11:19
  • 1
    Mostly concur, but: openssl pkcs8 -topk8 supports several PBE ciphers (not cipher suites) to encrypt PKCS8, but standard Java crypto (non-BC) can't read any encrypted PKCS8, only clear; use -nocrypt for that, or in 1.0.0 up use pkey which defaults to PKCS8 unencrypted. Or as you say instead use PKCS12 as keystore, which Java does handle encrypted; here again there are several PBE options but OpenSSL and Java defaults are compatible. – dave_thompson_085 Sep 16 '16 at 4:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.