Creating RSA Public Key From String

35,438

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.

Share:
35,438
raximus
Author by

raximus

Freelance audio engineer and web/android/windows programmer.

Updated on July 21, 2022

Comments

  • raximus
    raximus almost 2 years

    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(); 
                }
    
             }
    
  • Maarten Bodewes
    Maarten Bodewes over 8 years
    Or, if Bouncy Castle doesn't work, you could use Spongy Castle, but in this case that might not be required.
  • raximus
    raximus over 8 years
    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.
  • raximus
    raximus over 8 years
    I only had to change the Base 64 line to get it working. byte[] decoded = Base64.decode(AppKeyPub,0);
  • Maarten Bodewes
    Maarten Bodewes over 7 years
    This expects SubjectPublicKeyInfo which, as I explained in my answer, is incorrect.
  • Lee Dat
    Lee Dat about 5 years
    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.?
  • Maarten Bodewes
    Maarten Bodewes about 5 years
    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.
  • vincent mathew
    vincent mathew over 3 years
    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.
  • Maarten Bodewes
    Maarten Bodewes over 3 years
    @vincentmathew The key in the question is different from the key in this answer. If it works for you you'd have a PKCS#1 encoded public key, not a SubjectPublicKeyInfo. Both are ASN.1 encoded so they may superficially look like each other (starting with "MII" for instance) but a SubjectPublicKeyInfo structure would be larger. Of course, the code in this answer does work, just not for this question.
  • Maarten Bodewes
    Maarten Bodewes over 2 years
    Hmm, I got the comment backwards, the key in the question is PKCS#1, and this works for SubjectPublicKeyInfo, which is part of X.509 certificate specifications, hence the X509EncodedKeySpec.