1

i'm developing an android app. Unfortunately i have a compatibility problem. My source code works with firmware 4.1, but crashes with devices with firmware 2.2. The error seems to be a "ClassNotFoundException" caused by the ObjectInputStream.

My sourcecode for the encryption and decryption:

private Key getPublicKey() {
    try {
        InputStream fis = activity.getResources().openRawResource(R.raw.publick);
        ObjectInputStream ois = new ObjectInputStream(fis);
        Key RSApublicKey = (Key) ois.readObject();
        return RSApublicKey;
    }
    catch (FileNotFoundException e) {
        e.printStackTrace();
    }
    catch (IOException e) {
        e.printStackTrace();
    }
    catch (ClassNotFoundException e) {
        e.printStackTrace();
    }
    return null;
}

private Key getPrivateKey() {
    try {
        InputStream fis = activity.getResources().openRawResource(R.raw.privatek);
        ObjectInputStream ois = new ObjectInputStream(fis);
        Key RSAprivateKey = (Key) ois.readObject();
        return RSAprivateKey;
    }
    catch (FileNotFoundException e) {
        e.printStackTrace();
    }
    catch (IOException e) {
        e.printStackTrace();
    }
    catch (ClassNotFoundException e) {
        Log.e("error", "Error: " + e);
        e.printStackTrace();
    }
    return null;
}

public byte[] encrypt(String data) {
    byte[] encrypted = null;
    try {
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.ENCRYPT_MODE, getPublicKey());
        encrypted = cipher.doFinal(data.getBytes());
    }
    catch (IllegalBlockSizeException e) {
            e.printStackTrace();
    }
    catch (BadPaddingException e) {
        e.printStackTrace();
    }
    catch (InvalidKeyException e) {
        e.printStackTrace();
    }
    catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    }
    catch (NoSuchPaddingException e) {
        e.printStackTrace();
    }
    catch (NoSuchProviderException e) {
        e.printStackTrace();
    }
    return encrypted;
}

public String decrypt(byte[] encrypted) {
    byte[] decrypted = null;
    try {
        Cipher cipher;
        cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.DECRYPT_MODE, getPrivateKey());
        decrypted = cipher.doFinal(encrypted);
    }
    catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    }
    catch (NoSuchPaddingException e) {
        e.printStackTrace();
    }
    catch (InvalidKeyException e) {
        e.printStackTrace();
    }
    catch (IllegalBlockSizeException e) {
        e.printStackTrace();
    }
    catch (BadPaddingException e) {
        e.printStackTrace();
    }
    catch (NoSuchProviderException e) {
        e.printStackTrace();
    }
    return new String(decrypted);
}

The error in logcat:

03-23 10:13:19.706: E/Error(427): Error: java.lang.ClassNotFoundException: com.android.org.bouncycastle.jce.provider.JCERSAPrivateCrtKey

Do you have any ideas, how i could get it work with android 2.2?

JavaForAndroid
  • 1,111
  • 2
  • 20
  • 42
  • [You've already asked this question](http://stackoverflow.com/questions/15501592/problems-outsourcing-rsa-encryption-and-decryption). You should edit your original question rather than posting a new question. – Duncan Jones Mar 23 '13 at 23:01
  • @DuncanJones Hmm, that question does leave a lot of information out, and as it does not have any answers it's probably better to do the reverse. I do agree that one of them probably has to go, unless these are different issues (but I don't think they are). – Maarten Bodewes Mar 24 '13 at 16:38

2 Answers2

0

Well, if it works on 4.1+ but not on 2.2, I guess it's a class from android that has been included after 2.2. You can test this by trying to compile with android 2.2 a project that uses this class and see if you can. If this is the case just find it and include it in your project.

crios
  • 609
  • 6
  • 6
  • I have already changed the line target=android-15 to target=android-8 in the project.properties File. But i have to set the build target to 4.0 because i use the Sherlock Action Bar. Changing the build target only shows an "R cannot be resolved" error. This is because of the ActionBar, which causes errors in the xml Layout Files. – JavaForAndroid Mar 23 '13 at 12:37
  • Ok, create a new Android Project with the target 8 and try access that class. – crios Mar 23 '13 at 12:47
  • I can never access this class. Also not with build target 15. – JavaForAndroid Mar 23 '13 at 13:15
  • So it was introduced in 16. Try google the problem class's package/jar and if you find it add it to your project and it should work regardless of android version :) – crios Mar 23 '13 at 13:26
  • That is the problem. I can't find this class. And I guess it is another error, because I never used this class. Are there differences between JRE6 and JRE7? I just found out that the path to this class might be org.bouncycastle.jce.provider.JCERSAPrivateKey. – JavaForAndroid Mar 23 '13 at 13:30
  • I believe what you are looking for is the bcprov jar from [here](http://www.bouncycastle.org/latest_releases.html) or if you don't trust the content of the jars you can download the code and build it or add to your project from [here](https://code.google.com/p/android-source-browsing/source/browse/src/main/java/org/bouncycastle/jce/provider/?repo=platform--external--bouncycastle&name=ics-mr1-release) – crios Mar 23 '13 at 13:42
  • I tried this as well. But it does not change anything. – JavaForAndroid Mar 23 '13 at 14:17
  • Then, pretty sure you are doing something wrong, note that if you are using eclipse, after you add the jar to build path you should also check it from the "order and export" tab and clean the project and rebuild. Also you can try change the compiler compliance level(maybe it does matter). And yes, the path to the class is org.bouncycastle.jce.provider.JCERSAPrivateKey since you do not want to use it from the framework anymore. – crios Mar 23 '13 at 18:49
  • I tried this but the app still crashes with the same error. Do you need more information about the logcat? – JavaForAndroid Mar 24 '13 at 15:47
  • No, sorry don't have more ideas, but this is pretty interesting... – crios Mar 24 '13 at 17:23
  • Thank you for your help. Maybe i will still find the error. It is really interesting, what might cause such an error. – JavaForAndroid Mar 24 '13 at 18:31
0

You are better off using the Key.getEncoded() method to serialize the key. The Key.getFormat() already hints that RSA private keys should default to PKCS#8 encoding.

You can then use the PKCS8EncodedKeySpec class and an instance of an "RSA" KeyFactory to deserialize the resulting byte array.

The serialized keys may not work correctly over different implementations of PrivateKey (as you've already found out by now), and PKCS#8 is a well defined and often used standard.

Maarten Bodewes
  • 90,524
  • 13
  • 150
  • 263
  • From my mobile phone, I will amend the answer this evening. – Maarten Bodewes Mar 23 '13 at 16:17
  • Can you tell me how it works? I only know my method. Or is it easier to write own classes for RSA encryption? It sounds interesting. – JavaForAndroid Mar 24 '13 at 15:32
  • A simple search for `PKCS8EncodedKeySpec` should suffice, e.g. http://stackoverflow.com/questions/7216969/getting-rsa-private-key-from-pem-base64-encoded-private-key-file uses this method to build a private key. back from the encoded byte array. So you serialize/deserialize the byte array instead of the class itself. – Maarten Bodewes Mar 24 '13 at 16:36
  • I tried this way. But i do not know how i can get access to the File with the key. I only get an InputStream, but not Path as a String. How can i solve this problem? The file is in raw folder. – JavaForAndroid Mar 24 '13 at 17:10
  • 1
    I checked the format and it returns PKCS#8. It works on the following firmwares: 3.0, 3.1, 4.0, 4.0.3, 4.1.2, 4.2 (tested) – JavaForAndroid Mar 29 '13 at 20:01