Nublodeveloper Nublodeveloper - 1 year ago 109
Java Question

javax.crypto.Cipher working differently since Android 6 Marshmallow

I've been successfully using javax.crypto.Cipher.getInstance("DESede/CBC/NoPadding") to Authenticate with DESFire cards on Android (following the example here: It's been working on several devices from Android 4 to 5, but stopped working on my Nexus 7 updated to 6 Marshmallow (and 6.0.1). It had been working on the same device before updating.

It seems Cipher is working differently, giving different results for the same key and data. Running the following code...

public static void testCipher() throws Exception
byte[] KEY =
new byte[]{
(byte) 0x0C, (byte) 0x09, (byte) 0x03, (byte) 0x0E,
(byte) 0x05, (byte) 0x0A, (byte) 0x0D, (byte) 0x02,
(byte) 0x03, (byte) 0x0A, (byte) 0x09, (byte) 0x0B,
(byte) 0x06, (byte) 0x10, (byte) 0x04, (byte) 0x10

byte[] DATA =
new byte[]{
(byte) 0x29, (byte) 0xDA, (byte) 0xC0, (byte) 0xC4,
(byte) 0xB8, (byte) 0x47, (byte) 0x13, (byte) 0xA2};

byte[] newByte8 = new byte[8]; //Zeroes

android.util.Log.d("TEST", "KEY : " + bin2hex(KEY));
android.util.Log.d("TEST", "DATA: " + bin2hex(DATA));
android.util.Log.d("TEST", "IVPS: " + bin2hex(newByte8));
android.util.Log.d("TEST", "----");

javax.crypto.Cipher cipher =

new javax.crypto.spec.SecretKeySpec(KEY, "DESede"),
new javax.crypto.spec.IvParameterSpec(newByte8));

byte[] result = cipher.doFinal(DATA);

android.util.Log.d("TEST", "RSLT: " + bin2hex(result));

public static String bin2hex(byte[] data) {
return String.format("%0" + (data.length * 2) + "X", new java.math.BigInteger(1, data));

... gives me the following output:

KEY : 0C09030E050A0D02030A090B06100410
DATA: 29DAC0C4B84713A2
IVPS: 0000000000000000
RSLT: 47BC415065B8155E

Normal value, what it should be, always worked and card ends up authenticating correctly, so it's doing it the way the card expects. As a said I tried on several devices (Android 4 and 5) and they give the same result.

But on my Nexus 7 now with Marshmallow I get something else (and the authentication ends up failing)

RSLT: F3ADA5969FA9369C

Has something changed in the libraries?

Answer Source

It seems they changed the default provider in Marshmallow.

A simple:


Shows "AndroidOpenSSL" for Marshmallow, where it was "BC" (BouncyCastle I suppose) before.

Using the other getInstance overload...

 javax.crypto.Cipher cipher =
            javax.crypto.Cipher.getInstance("DESede/CBC/NoPadding","BC"); me the expected result on my Nexus with Marshmallow.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download