How to decrypt the first message sent from Mifare Desfire EV1

后端 未结 2 737
南笙
南笙 2020-12-24 11:31

Does anyone have a clue how to decrypt the first message sent from the card? I mean after the authentication success and then you send a command (for example 0x51 (GetRealTa

相关标签:
2条回答
  • 2020-12-24 11:52

    It's not c/c++ section but enter my position, I'm looking at a possible bug from the C developer. I can't proof Java implementation here. But i think @Michael Roland way is not true! Maby! Maby i'm wrong!

    Sry for my English,- its terrible :) but it's not my native language. I'm Russian.

    Check first MSB (7 - bit) of array[0] and then shiffting this to the left. And then XOR if MSB 7 bit was == 1; Or save first MSB bit of array[0] and after shiffting put this bit at the end of array[15] at the end (LSB bit).

    Just proof it's here: https://www.nxp.com/docs/en/application-note/AN10922.pdf

    Try this way:

    Zeros <- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

    SessionKey <- 00 01 02 03 E3 27 64 0C 0C 0D 0E 0F 5C 5D B9 D5

    Data <- 6F 80 00 00 00 00 00 00 00 00 00 00 00 00 00 00

    First u have to encrypt 16 bytes (zeros) with SesionKey;

    enc_aes_128_ecb(Zeros);
    

    And u get EncryptedData.

    EncryptedData <- 3D 08 A2 49 D9 71 58 EA 75 73 18 F2 FA 6A 27 AC

    Check bit 7 [MSB - LSB] of EncryptedData[0] == 1? switch i to true;

     bool i = false;
      if (EncryptedData[0] & 0x80){
        i = true;
      }
    

    Then do Shiffting of all EncryptedData to 1 bit <<.

    ShiftLeft(EncryptedData,16);
    

    And now, when i == true - XOR the last byte [15] with 0x87

    if (i){
        ShiftedEncryptedData[15] ^= 0x87;
      }
    

    7A 11 44 93 B2 E2 B1 D4 EA E6 31 E5 F4 D4 4F 58

    Save it as KEY_1.

    Try bit 7 [MSB - LSB] of ShiftedEncryptedData[0] == 1?

     i = false;
      if (ShiftedEncryptedData[0] & 0x80){
        i = true;
      }
    

    Then do Shiffting of all ShiftedEncryptedData to 1 bit <<.

    ShiftLeft(ShiftedEncryptedData,16);
    

    And now, when i == true - XOR the last byte [15] with 0x87

    if (i){
       ShiftedEncryptedData[15] ^= 0x87;
    }
    

    F4 22 89 27 65 C5 63 A9 D5 CC 63 CB E9 A8 9E B0

    Save it as KEY_2.

    Now we take our Data (6F 80 00 00 00 00 00 00 00 00 00 00 00 00 00 00)

    As Michael say's - pad command with 0x80 0x00...

    XOR Data with KEY_2 - if command was padded, or KEY_1 if don't. If we have more like 16 bytes (32 for example) u have to XOR just last 16 bytes.

    Then encrypt it:

    enc_aes_128_ecb(Data);
    

    Now u have a CMAC.

    CD C0 52 62 6D F6 60 CA 9B C1 09 FF EF 64 1A E3


    Zeros <- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

    SessionKey <- 00 01 02 03 E3 27 64 0C 0C 0D 0E 0F 5C 5D B9 D5

    Key_1 <- 7A 11 44 93 B2 E2 B1 D4 EA E6 31 E5 F4 D4 4F 58

    Key_2 <- F4 22 89 27 65 C5 63 A9 D5 CC 63 CB E9 A8 9E B0

    Data <- 6F 80 00 00 00 00 00 00 00 00 00 00 00 00 00 00

    CMAC <- CD C0 52 62 6D F6 60 CA 9B C1 09 FF EF 64 1A E3

    C/C++ function:

    void ShiftLeft(byte *data, byte dataLen){
      for (int n = 0; n < dataLen - 1; n++) {
       data[n] = ((data[n] << 1) | ((data[n+1] >> 7)&0x01));
      }
      data[dataLen - 1] <<= 1;
    }   
    

    Have a nice day :)

    0 讨论(0)
  • 2020-12-24 12:07

    After authentication, the IV is reset to all-zeros. As you use AES authentication, you then have to calculate the CMAC for every follow-up command (even if CMAC is not actually appended to the command). So the CMAC calculation for your command will lead to correct IV initialization for decoding the response. I.e. the CMAC for the command is equal to the IV for decrypting the response. Similarly, for all further commands, the IV is the last cipher block from the previous encryption/CMAC.


    UPDATE:

    How to calculate CMAC pad XOR value

    • Encrypt one block of zeros (0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00) with session key (using IV of zeros). -> x[0..15]
    • Rotate x[0..15] one bit to the left. -> rx[0..15]
    • If the last bit (bit 0 in rx[15]) is one: xor rx[15] with 0x86.
    • Store rx[0..15] as crc_k1[0..15].
    • Rotate rx[0..15] one bit to the left. -> rrx[0..15]
    • If the last bit (bit 0 in rrx[15]) is one: xor rrx[15] with 0x86.
    • Store rrx[0..15] as crc_k2[0..15].

    How to calculate CMAC

    • You pad the command using 0x80 0x00 0x00 ... to the block size of the cipher (16 bytes for AES). If the command length matches a multiple of the block size, no padding is added.
    • For your command (0x51) this would look like: 0x51 0x80 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
    • If padding was added, xor the last 16 bytes of the padded command with crc_k2[0..15].
    • If no padding was added, xor the last 16 bytes of the command with crc_k1[0..15].
    • Encrypt (in send mode, i.e. enc(IV xor datablock), cipher text of previous block is new IV) the result with the session key.
    • The ciphertext of the last block is the CMAC and the new IV.

    UPDATE 2:

    How to rotate a bit vector to the left for one bit

    public void rotateLeft(byte[] data) {
        byte t = (byte)((data[0] >>> 7) & 0x001);
        for (int i = 0; i < (data.length - 1); ++i) {
            data[i] = (byte)(((data[i] << 1) & 0x0FE) | ((data[i + 1] >>> 7) & 0x001));
        }
        data[data.length - 1] = (byte)(((data[data.length - 1] << 1) & 0x0FE) | t);
    }
    
    0 讨论(0)
提交回复
热议问题