Search code examples
encryptionjava-mebouncycastle

Problem transmiting a RSA public key, javaME , bouncy castle


I'm working on the porting of an instance messaging application from Java to JavaME ,that also implements cryptography. The problem is that I want to send my public key to the server. The desktop client has this code for this job:

byte[] encoded_public_key=publick_key.getEncoded();

And the server has this code to retrieve the key:

EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(encoded_public_key);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey puKey = keyFactory.generatePublic(publicKeySpec);

Now I've looked the API for the getEncoded and it says that it returns the DER-encoded form of the key as a byte array (http://www.docjar.com/docs/api/sun/s...tml#getEncoded)

My implementation for that in JavaME was this:

RSAPublicKeyStructure public_key_JAVAME=new RSAPublicKeyStructure(modulus,exponent);
byte[] DER_encoded_public_key_JAVAME=public_key_JAVAME.getDEREncoded();

//the getEncoded functions returns exact the same byte array.

However when I try to retrieve the JavaME created DER encoded key with the server code ,in other words when I try this:

EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(DER_encoded_public_key_JAVAME);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey puKey = keyFactory.generatePublic(publicKeySpec);

I get

java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: IOException: algid parse error, not a sequence
at sun.security.rsa.RSAKeyFactory.engineGeneratePublic(RSAKeyFactory.java:188)
at java.security.KeyFactory.generatePublic(KeyFactory.java:304)

Caused by: java.security.InvalidKeyException: IOException: algid parse error, not a sequence
at sun.security.x509.X509Key.decode(X509Key.java:380)
at sun.security.x509.X509Key.decode(X509Key.java:386)
at sun.security.rsa.RSAPublicKeyImpl.<init>(RSAPublicKeyImpl.java:66)
at sun.security.rsa.RSAKeyFactory.generatePublic(RSAKeyFactory.java:281)
at sun.security.rsa.RSAKeyFactory.engineGeneratePublic(RSAKeyFactory.java:184)

Interesting point : The DER encoded key from the normal Java (using the getencoded() function) is a byte array is 162 bytes long while the SAME key DER encoded in JavaME using bouncy castle is 140 bytes long. Shouldn't these 2 DER encoded key be of the same lenght?I mean it's the same key in DER encoded format so they should be the same.

What am I doing wrong?


True I didn't notice that.Problem is do you know how to create a subjectPublickeyInfo object from a PublicKey in bouncyCastle? I've tried:

ByteArrayInputStream bIn = new ByteArrayInputStream(RSApublickey.toString().getbytes()); SubjectPublicKeyInfo info = new SubjectPublicKeyInfo((ASN1Sequence)new ASN1InputStream(bIn).readObject());

But it didn't work. I also tried :

ByteArrayInputStream(RSApublicKeyStructure.getEncoded()); SubjectPublicKeyInfo info = new SubjectPublicKeyInfo((ASN1Sequence)new ASN1InputStream(bIn).readObject());

Actually I did expect that not to work , but well I had to try it . So how can I create a Subjectpublickeyinfo from RSAkeyparameters?( This is one of the points where the obscurity of bouncy's castle API really shines I guess)

Again thank you for your response you've been of great help.You've put me on the right track.


Solution

  • DER-encoding is just a standard for encoding. Saying that a key is DER-encoded is equivalent to saying it is XML-encoded: you need to agree on how it is DER-/XML-encoded to be able to decode it.

    In this case your RSAPublicKeyStructure.getEncoded() returns the key as the DER-encoding of an ASN.1 RSAPublicKey:

    RSAPublicKey ::= SEQUENCE {
      modulus INTEGER, -- n
      publicExponent INTEGER -- e 
    }
    

    The X509EncodedKeySpec on the other hand expects to be handed the DER-encoding of an ASN.1 PublicKeyInfo:

    PublicKeyInfo ::= SEQUENCE {
      algorithm AlgorithmIdentifier,
      PublicKey BIT STRING
    }
    

    To create a PublicKeyInfo using BouncyCastle do this (courtesy of GregS):

    RSAPublicKeyStructure rsaPublicKey = /* ... */
    AlgorithmIdentifier rsaEncryption = new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE); 
    SubjectPublicKeyInfo publicKeyInfo = new SubjectPublicKeyInfo(rsaEncryption, rsaPublicKey);
    byte[] encodedPublicKeyInfo = publicKeyInfo.getEncoded();