DES Send and Receive Modes for DESFire Authentication

后端 未结 2 690

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

2条回答
  •  不思量自难忘°
    2020-12-13 01:37

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

提交回复
热议问题