I\'m trying to authenticate DESFire card with my android application. I use the example in this link to decypher the bytes I got from the card. For that, I ruled out padding
OK I got the solution. My mistake was that I was sending
3DES(randA + randB')
But I should send
3DES(randA) + 3DES(randB' XOR 3DES(randA))
Here's the authentication code for Android/Java (it's so sad that this is the only one that can be found on the net currently!):
The actual authentication code:
// send initial authentication request
byte[] result = idTag.transceive(Utils.wrapMessage((byte)0x0a, new byte[]{(byte)0x0}));
// get encrypted(randB) from the response
byte[] b0 = new byte[8];
for(int i = 0; i < 8; i++) {
b0[i] = result[i];
}
// 16 bytes default key
byte[] key = new byte[] {(byte)0x0,(byte)0x0,(byte)0x0,(byte)0x0,
(byte)0x0,(byte)0x0,(byte)0x0,(byte)0x0,
(byte)0x0,(byte)0x0,(byte)0x0,(byte)0x0,
(byte)0x0,(byte)0x0,(byte)0x0,(byte)0x0 };
// keys for TripleDes
byte[][] keys = new byte[3][];
keys[0] = key; keys[1] = key; keys[2] = key;
// decrypt encoded(randB)
byte[] r0 = DES.TripleDES_Decrypt(b0, keys);
// generate randA (integer 0-7 for trying, should randomize for real-life use)
byte[] nr = new byte[8];
for(int i = 0; i < 8; i++) {
nr[i] = Byte.parseByte(Integer.toString(i), 16);
}
// decrypt randA, should XOR with IV, but IV is all 0's, not necessary
byte[] b1 = DES.TripleDES_Decrypt(nr, keys);
// shift randB one byte left and get randB'
byte[] r1 =new byte[8];
for(int i = 0; i < 7; i++) {
r1[i] = r0[i + 1];
}
r1[7]=r0[0];
// xor randB' with randA and decrypt
byte[] b2 = new byte[8];
for(int i = 0; i < 8; i++) {
b2[i] = (byte) (b1[i] ^ r1[i]);
}
b2 = DES.TripleDES_Decrypt(b2, keys);
// concat (randA + randB')
byte[] b1b2 = new byte[16];
for (int i = 0; i < b1b2.length; i++) {
if(i <= 7) {
b1b2[i] = b1[i];
} else {
b1b2[i]=b2[i-8];
}
}
result = idTag.transceive(Utils.wrapMessage((byte)0xaf, b1b2));
TripleDes is the one in the question. wrapMessage function:
public static byte[] wrapMessage (byte command, byte[] parameters) throws Exception {
ByteArrayOutputStream stream = new ByteArrayOutputStream();
stream.write((byte) 0x90);
stream.write(command);
stream.write((byte) 0x00);
stream.write((byte) 0x00);
if (parameters != null) {
stream.write((byte) parameters.length);
stream.write(parameters);
}
stream.write((byte) 0x00);
return stream.toByteArray();
}
EDIT: Thanks to VGe0rge, we found out the reason why this authentication doesn't work from time to time. Instead of calling the 3DES function in the question, just call:
Cipher.getInstance("DESede/CBC/NoPadding");
Ismat, did you try to write data to the DESFIRE files?
As you explained, when sending data to the card: The PCD uses DES “send mode” when sending data (xor before DES), and the card uses DES “recieve mode” when recieving data (xor after DES)
So I can't get the proper code in order to implement the TDES with the XOR before..I need to do all the crypt-decrypt-crypt and the process is to slow for my application:
res = criptoTransformDec.TransformBlock(datosEscribir, 0, 8, datosEscribir, 0);
res = criptoTransformEnc.TransformBlock(datosEscribir, 0, 8, datosEscribir, 0);
res = criptoTransformDec1.TransformBlock(datosEscribir, 0, 8, datosEscribir, 0);
int l_iAux = 0;
while (l_iAux < (datosEscribir.Length - 8))
{
criptoTransformDec2 = desDec.CreateDecryptor(claveSes1, tdesInitialVector);
//desEnc2 = new DESCryptoServiceProvider();
criptoTransformEnc2 = desEnc.CreateEncryptor(claveSes2, tdesInitialVector);
//desDec3 = new DESCryptoServiceProvider();
criptoTransformDec3 = desDec.CreateDecryptor(claveSes1, tdesInitialVector);
Array.Copy(datosEscribir, 8 + l_iAux, aux1, 0, 8);
Array.Copy(datosEscribir, l_iAux, aux2, 0, 8);
DesfireBarik.XorStr(ref aux1, ref aux2, 8);
res = criptoTransformDec2.TransformBlock(aux1, 0, 8, datosEscribir, 8 + l_iAux);
res = criptoTransformEnc2.TransformBlock(datosEscribir, 8 + l_iAux, 8, datosEscribir, 8 + l_iAux);
res = criptoTransformDec3.TransformBlock(datosEscribir, 8 + l_iAux, 8, datosEscribir, 8 + l_iAux);
l_iAux += 8;
}
private static void XorStr (ref byte[] str1, ref byte[] str2, int qty )
{
int i = 0;
for (i = 0; i < qty; i++ )
str1[i] = (byte)(str1[i] ^ str2[i]);
}