PEM to PublicKey in Android

9.6k views Asked by At

I've seen a number of similar questions, but nothing has quite worked for me. I am simply trying to convert an RSA public key that's in PEM format that I've retrieved from a server into a PublicKeyin Android. Can anyone point me in the right direction?

EDIT: I've successfully used the following code to convert the PEM into a PublicKey, but upon encoding a message, I get unexpected output...

 public PublicKey getFromString(String keystr) throws Exception
    {
        // Remove the first and last lines

        String pubKeyPEM = keystr.replace("-----BEGIN PUBLIC KEY-----\n", "");
        pubKeyPEM = pubKeyPEM.replace("-----END PUBLIC KEY-----", "");

        // Base64 decode the data

        byte [] encoded = Base64.decode(pubKeyPEM);
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(encoded);
        KeyFactory kf = KeyFactory.getInstance("RSA");
        PublicKey pubkey = kf.generatePublic(keySpec);

        return pubkey;
    }

    public String RSAEncrypt(final String plain) throws NoSuchAlgorithmException, NoSuchPaddingException,
            InvalidKeyException, IllegalBlockSizeException, BadPaddingException, IOException {

        if (pubKey!=null) {
            cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.ENCRYPT_MODE, pubKey);
            encryptedBytes = cipher.doFinal(plain.getBytes());
            Log.d("BYTES", new String(encryptedBytes));
            return Hex.encodeHexString(encryptedBytes);
        }
        else
            return null;
    }

The output looks like this:

b6813f8791d67c0fa82890d005c8ff554b57143b752b34784ad271ec01bfaa9a6a31e7ae08444baef1585a6f78f3f848eecb1706bf7b2868fccefc9d728c30480f3aabc9ac5c3a9b4b3c74c2f7d6f0da235234953ea24b644112e04a2ec619f6bf95306ef30563c4608ec4b53ed7c15736d5f79c7fa1e35f2444beb366ae4c71

when I expect something closer to:

JfoSJGo1qELUbpzH8d4QXtafup+J2F9wLxHCop00BQ4YS0cRdRCKDfHpFPZQYjNeyQj00HwHbz+vj8haTPbpdqT94AHAl+VZ+TPAiUw1U5EXLLyy4tzbmfVI7CwvMm26lwB4REzYUZdedha1caxMEfxQ5duB+x4ol9eRZM/savg=

Is there some formatting or file type that I'm missing?

2

There are 2 answers

2
cph2117 On BEST ANSWER

To answer my own question...The first output is in hex and the second output is in base 64. Just change the return statement to return new String(Base64.encode(encryptedBytes)); and you'll be good!

0
Daniel On

This doesn't answer the question, but I find the content relevant. Posting as an answer because it doesn't fit as a comment.

PEM vs DER

  • PEM basically encapsulates a DER-encoded certificate or key.
  • DER is binary, PEM is text; so PEM can easily be copy-pasted to an email, for example.
  • What PEM does is:
    1. Encode the DER certificate or key using Base64, and
    2. Delimit the result with -----BEGIN <something>----- and -----END <something>-----.
  • The key or certificate is the same, just represented in a different format.

Mostly paraphrasing from ASN.1(wiki).

DER to Android/Java public key

The following is an example of how to use a key factory in order to instantiate a DSA public key from its encoding. Assume Alice has received a digital signature from Bob. Bob also sent her his public key (in encoded format) to verify his signature. Alice then performs the following actions:

X509EncodedKeySpec bobPubKeySpec = new X509EncodedKeySpec(bobEncodedPubKey);
KeyFactory keyFactory = KeyFactory.getInstance("DSA");
PublicKey bobPubKey = keyFactory.generatePublic(bobPubKeySpec);

...

Note that bobEncodedPubKey is DER-encoded in this sample.

https://developer.android.com/reference/java/security/KeyFactory

PEM to Android/Java public key

Similar to what is done for DER, but do the following beforehand:

  1. Remove the BEGIN/END delimitation, and
  2. Decode the content in Base64 to obtain the original DER.

(The question already shows code on how to do this.)