0

I'm migrating my native Android game to libGDX. So I can't access the Android libraries anymore and I'm trying to replace android.util.Base64 by org.apache.commons.codec.binary.Base64. (I need Base64's encodeToString and decode methods.)

Unfortunately, with the new package I get this error: java.security.InvalidKeyException: Illegal key size (using the same 24-character-key as I did before).

Here at stackoverflow they say it's probably because "Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files 7" are missing. But if I use them, the users of my app have to install them, too.

Is there any easier solution? Why did it work before?

EDIT:

This is the code that leads to the InvalidKeyException:

javax.crypto.Cipher writer = Cipher.getInstance("AES/CBC/PKCS5Padding");

String keyOf24Chars = "abcdefghijklmnopqrstuvwx";

IvParameterSpec ivSpec = getIv();

MessageDigest md = MessageDigest.getInstance("SHA-256");
md.reset();
byte[] keyBytes = md.digest(keyOf24Chars.getBytes("UTF-8"));

SecretKeySpec secretKey = new SecretKeySpec(keyBytes, "AES/CBC/PKCS5Padding");

// secretKey.getAlgorithm(): "AES/CBC/PKCS5Padding"
// secretKey.getFormat(): "RAW"
// secretKey.getEncoded().length: 32

writer.init(Cipher.ENCRYPT_MODE, secretKey, ivSpec); // java.security.InvalidKeyException: Illegal key size

EDIT 2:

As explained in Maarten Bodewes' comment, Android has it's own implementation of the java and javax classes which apparently have no problem with 32 byte keys. After I have installed the "JCE Unlimited Strength Jurisdiction Policy Files 7" we are coming to the code that uses Base64 and causes this error: java.lang.NoSuchMethodError: org.apache.commons.codec.binary.Base64.encodeToString:

String valueToEncode = "xyz";
byte[] secureValue;
try {
    secureValue = writer.doFinal(valueToEncode.getBytes("UTF-8"));
} catch (Exception e) {
    throw new SecurePreferencesException(e);
}
Base64 base64 = new Base64();
String secureValueEncoded = base64.encodeToString(secureValue);

But this method does exist (in BaseNCodec which Base64 extends):

public String encodeToString(final byte[] pArray) {
    return StringUtils.newStringUtf8(encode(pArray));
}

How can I make Android use this method?

EDIT 3:

Finally I solved my problem by writing an interface and then using my old Android code (when compiling for Android). Check this example for libGDX: Interfacing with platform specific code.

Community
  • 1
  • 1
MaxGyver
  • 428
  • 7
  • 21
  • How many bytes are you seeing after decoding? I've answered but I did make a few assumptions... There is no such thing as a 24 character key; keys consist of bits / bytes. – Maarten Bodewes May 03 '15 at 15:51
  • I have added some code. So the key length is 32 bytes. – MaxGyver May 03 '15 at 16:43
  • Where is the base 64? Are you now on Java SE? – Maarten Bodewes May 03 '15 at 16:54
  • Oops! Good point. The game crashes in the constructor method and the Base64 class is not being used there. Strange. So maybe there is another problem. I use `Java(TM) SE Runtime Environment (build 1.7.0_65-b17)`. – MaxGyver May 03 '15 at 17:14
  • Yeah, OK, but in that case my answer is doubly valid. Please rewrite your question to reflect the fact that this is not about base 64. Note that you may want to be precise and include the fact that you go from Android to Java SE in the title, otherwise it will be closed as a dupe... – Maarten Bodewes May 03 '15 at 17:31
  • But I already used only java/javax classes before (except `android.util.Base64`). And I still compile for Android (using the libGDX framework but in my actual problem there are no libGDX functions involved). I'm confused. What do you recommend as a new title? – MaxGyver May 03 '15 at 17:48
  • Android has a different implementation of the `java` and `javax` classes. It just uses the same API. – Maarten Bodewes May 03 '15 at 18:37

1 Answers1

2

No, there isn't an easier solution. You could use 3DES instead of AES (which I presume you are using) but you would be downgrading your security, and still be incompatible with the previous code. Downgrading security of AES to 128 is a better idea, but the incompatibility issue won't go away.

If you are not using the encryption/decryption in a third party library (e.g. JSSE for SSL or XML encryption) then you could directly use the Bouncy Castle or Spongy Castle API's. So that means directly using AESBlockCipher + a mode of encryption. Bouncy Castle doesn't have these kind of limitations - they are part of the Oracle Cipher implementation.

It was working before because Android doesn't have these kind of restrictions while Java 7/8 SE does.

Maarten Bodewes
  • 90,524
  • 13
  • 150
  • 263