DES Send and Receive Modes for DESFire Authentication

放肆的年华 提交于 2019-11-28 16:55:17

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");
Jose Manuel

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]);
    }
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!