20

I've generated this test public key using 1024 RSA and then encoded it to DER and Base64 in another coding platform. I copied the key into a string in Android/Eclipse and I am trying to turn it into a public key using KeyFactory. It just keeps giving me an InvalidKeySpecException no matter what I try. Any advice at all would be appreciated.

     private void prepKeys() {
         String AppKeyPub = "MIGHAoGBAOX+TFdFVIKYyCVxWlnbGYbmgkkmHmEv2qStZzAFt6NVqKPLK989Ow0RcqcDTZaZBfO5" +
"5JSVHNIKoqULELruACfqtGoATfgwBp4Owfww8M891gKNSlI/M0yzDQHns5CKwPE01jD6qGZ8/2IZ" +
"OjLJNH6qC9At8iMCbPe9GeXIPFWRAgER";

        // create the key factory          
            try {
                KeyFactory kFactory = KeyFactory.getInstance("RSA");  
                // decode base64 of your key
                byte yourKey[] =  Base64.decode(AppKeyPub,0);
                // generate the public key
                X509EncodedKeySpec spec =  new X509EncodedKeySpec(yourKey);
                PublicKey publicKey = (PublicKey) kFactory.generatePublic(spec);

            System.out.println("Public Key: " + publicKey);  

            } catch (Exception e) {
                // TODO Auto-generated catch block  
                e.printStackTrace(); 
            }

         }
2
  • X509EncodedKeySpec expects a key in the SubjectPublicKeyInfo format (see RFC 5280). Your key is in the simpler RSAPublicKey format which Java does not support. Solution: encode your key in the correct Java supported format. Commented Oct 29, 2015 at 22:12
  • Ok I'm not sure I can generate a key in the other platform that way but I certainly appreciate the information and will give it a try. Thanks. Commented Oct 29, 2015 at 22:21

2 Answers 2

25

The key you have is in PKCS#1 format instead of SubjectPublicKeyInfo structure that Java accepts. PKCS#1 is the encoding of the RSA parameters only and lacks things such as an algorithm identifier. SubjectPublicKeyInfo uses PKCS#1 internally - for RSA public keys anyway.

As the PKCS#1 public key is at the end of the SubjectPublicKeyInfo structure it is possible to simply prefix the bytes so that they become an RSA SubjectPublicKeyInfo. That solution is easier to perform without additional libraries such as Bouncy Castle. So if you need to go without an external library then you may have a look at my answer here.


Alternatively a simple BER decoder could be written to decode the structure into the two BigInteger values. The structure itself is not that complicated but the BER/DER length encoding takes some getting used to.

However, you can also use Bouncy Castle (lightweight API) to solve your issues:

String publicKeyB64 = "MIGHAoGBAOX+TFdFVIKYyCVxWlnbGYbmgkkmHmEv2qStZzAFt6NVqKPLK989Ow0RcqcDTZaZBfO5"
        + "5JSVHNIKoqULELruACfqtGoATfgwBp4Owfww8M891gKNSlI/M0yzDQHns5CKwPE01jD6qGZ8/2IZ"
        + "OjLJNH6qC9At8iMCbPe9GeXIPFWRAgER";
// ok, you may need to use the Base64 decoder of bouncy or Android instead
byte[] decoded = Base64.getDecoder().decode(publicKeyB64);
org.bouncycastle.asn1.pkcs.RSAPublicKey pkcs1PublicKey = org.bouncycastle.asn1.pkcs.RSAPublicKey.getInstance(decoded);
BigInteger modulus = pkcs1PublicKey.getModulus();
BigInteger publicExponent = pkcs1PublicKey.getPublicExponent();
RSAPublicKeySpec keySpec = new RSAPublicKeySpec(modulus, publicExponent);
KeyFactory kf = KeyFactory.getInstance("RSA");
PublicKey generatedPublic = kf.generatePublic(keySpec);
System.out.printf("Modulus: %X%n", modulus);
System.out.printf("Public exponent: %d ... 17? Why?%n", publicExponent); // 17? OK.
System.out.printf("See, Java class result: %s, is RSAPublicKey: %b%n", generatedPublic.getClass().getName(), generatedPublic instanceof RSAPublicKey);

As you can see it actually only requires a single class as interface, although that is of course backed up with the entire ASN.1/BER decoder functionality within Bouncy Castle.


Note that it may be required to change the Base 64 decoder to the Android specific one (android.util.Base64). This code was tested on an equivalent Java runtime.

Sign up to request clarification or add additional context in comments.

5 Comments

Or, if Bouncy Castle doesn't work, you could use Spongy Castle, but in this case that might not be required.
I actually spent the past hour getting Bouncy Castle working in eclipse and was testing some code to try and convert an RSA key into SubjectPublicKeyInfo format. I tried this code and it indeed creates a key. I don't know if it will work yet with my other platform but it's a start. Thank you.
I only had to change the Base 64 line to get it working. byte[] decoded = Base64.decode(AppKeyPub,0);
Hi, I copied that code and apply to my public key. I got an error like this when using bouncycastle with the public key: Exception in thread "main" java.lang.IllegalArgumentException: Bad sequence size: 9. Do you have any ideas to resolve.?
Not from that description. Better create a separate question including the code and test key material in base 64 or hexadecimals. It may be that your key is badly encoded, but that's just guess work.
-2

For those who dont want to use Bouncy Castle

public class RSAKeySeperation {


public static void main(String[] args) throws InvalidKeySpecException, NoSuchAlgorithmException {
    String publicKeyB64 = "MIIBITANBgkqhkiG9w0BAQEFAAOCAQ4AMIIBCQKCAQBV8xakN/wOsB6qHpyMigk/5PrSxxd6tKTJsyMIq5f9npzZue0mI4H2o8toYImtRk6VHhcldo0t7UwsQXmFMk7D"
            + "i3C53Xwfk7yEFSkXGpdtp/7fbqNnjVoJl/EPcgoDsTPrHYF/HgtmbhzuYvYeY1zpV0d2uYpFxAuqkE9FreuuH0iI8xODFe5NzRevXH116elwdCGINeAecHKgiWe"
            + "bGpRPml0lagrfi0qoQvNScmi/WIN2nFcI3sQFCq3HNYDBKDhO0AEKPB2FjvoEheJJwTs5URCYsJglYyxEUon3w6KuhVa+hzYJUAgNTCsrAhQCUlX4+5LOGlwI5gonm1DYvJJZAgMBAAEB";
    byte[] decoded = Base64.getDecoder().decode(publicKeyB64);
    X509EncodedKeySpec spec =
            new X509EncodedKeySpec(decoded);
    KeyFactory kf = KeyFactory.getInstance("RSA");
    RSAPublicKey generatePublic = (RSAPublicKey) kf.generatePublic(spec);
    BigInteger modulus = generatePublic.getModulus();
    System.out.println(modulus);
    BigInteger exponent = generatePublic.getPublicExponent();
    System.out.println(exponent);
}

}

3 Comments

This expects SubjectPublicKeyInfo which, as I explained in my answer, is incorrect.
Don't what @MaartenBodewes is referring to, but the code does work for me and resulting public key is able to decode JWT token for me.
X509EncodedKeySpec is used for SubjectPublicKeyInfo structures, not for PKCS#1 structures as the one displayed in the question. PKCS#1 is not directly supported by Java, SPKI is. Of course, if have a string I'd first try SPKI as well, PKCS#1 is used much less frequently.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.