Search code examples
javaandroidopensslpublic-keypem

PublicKey from PEM file on android, java


Basically I'm trying to verify signature which using openssl looks like this:

openssl dgst -sha256 -verify prime192v1-pub-v1.pem -signature signatureFile.bin < dataFile.bin

... and in order to do that on android I need to create PublicKey object. The method that I'm using throws java.security.spec.InvalidKeySpecException: Unexpected key type at line kf.generatePublic(new X509EncodedKeySpec(encoded)).

import org.spongycastle.util.encoders.Base64;

import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.spec.X509EncodedKeySpec;

public class SO {

    public static PublicKey getPublicKeyFromString(String key) throws IOException, GeneralSecurityException {
        String publicKeyPEM = key;
        publicKeyPEM = publicKeyPEM.replace("-----BEGIN PUBLIC KEY-----\n", "");
        publicKeyPEM = publicKeyPEM.replace("-----END PUBLIC KEY-----", "");
        byte[] encoded = Base64.decode(publicKeyPEM);
        KeyFactory kf = KeyFactory.getInstance("RSA");
        return kf.generatePublic(new X509EncodedKeySpec(encoded));
    }

}

This is how I call the method:

    SO.getPublicKeyFromString(
            "-----BEGIN PUBLIC KEY-----\n" +
            "MEkwEwYHKoZIzj0CAQYIKoZIzj0DAQEDMgAEXMHnQfWiM4oCaLfx296llgz7iaVv\n" +
            "avMPppkzVNZAxtlNLhFlXnNWD0Mw9yzP8/Go\n" +
            "-----END PUBLIC KEY-----"
    );

Anyone knows what I'm doing wrong?


Solution

  • I got it working. The public key is elliptic curve (p192) public key and it should be loaded differently. Having PublicKey I was able to verify signature the same way as using openssl command.

    import org.bouncycastle.jce.provider.BouncyCastleProvider;
    
    import java.io.Reader;
    import java.io.StringReader;
    import java.security.KeyFactory;
    import java.security.PublicKey;
    import java.security.Security;
    import java.security.Signature;
    import java.security.spec.X509EncodedKeySpec;
    
    public class SO {
    
        public PublicKey getPublicKey() throws Exception {
            Security.addProvider(new BouncyCastleProvider());
            Reader rdr = new StringReader(
                    "-----BEGIN PUBLIC KEY-----\n" +
                            "MEkwEwYHKoZIzj0CAQYIKoZIzj0DAQEDMgAEXMHnQfWiM4oCaLfx296llgz7iaVv\n" +
                            "avMPppkzVNZAxtlNLhFlXnNWD0Mw9yzP8/Go\n" +
                            "-----END PUBLIC KEY-----\n"
            ); // or from file etc.
    
            org.bouncycastle.util.io.pem.PemObject spki = new org.bouncycastle.util.io.pem.PemReader(rdr).readPemObject();
            PublicKey key = KeyFactory.getInstance("EC", "BC").generatePublic(new X509EncodedKeySpec(spki.getContent()));
            return key;
        }
    
        public static boolean verify(byte[] data, byte[] signatureBytes, PublicKey publicKey) throws Exception {
            Signature signature = Signature.getInstance("SHA256withECDSA", "BC");
            signature.initVerify(publicKey);
            signature.update(data);
            return signature.verify(signatureBytes);
        }
    
    }