This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

DLP-7970ABP: Read and update contents of HID iCLASS

Part Number: DLP-7970ABP

Hello,

I followed the guide of "PicoPass 32K(S) Card Operations with the TRF79xxA",and got the sample code of picopass.c,I can get the UID of the card which means command "ACTALL" and the function "calculate crc" are correct. Later, I try to read content with the read command. I also can get the data of block 0 is UID. I continue reading the next block, and I get the data below:

Select command received bytes:0A
iClass UID: [D802E000F7FF12E0]

Block 00 Data: [ D802E000F7FF12E026B8]
Read command received bytes:0A
Block 01 Data: [ 12FFFFFFE97FFF3C9427]
Read command received bytes:0A
Block 02 Data: [ FEFFFFFFFFFFFFFF5574]
Read command received bytes:0A


When I am trying to update some of the blocks, I found the function PicoPass_UPDATE is uncomplete. So I implemented the function. But it can't work. I will attach my code below to figure it out some bug or my iClass card can't update by the sample.

Many thanks for any reply.

                           graph1:iClass wirte and read.                                          graph2:iClass other block data.

Testing card:

HID iCLASS TEST CARD
PART NO. 2004PGGNN
FORMAT: H10301
F/C = 99
ID = 1002

typedef union
{
    uint16_t value;
    struct
    {
        uint8_t lowByte;
        uint8_t highByte;
    };
} crc16_t;

#define CRC_POLYNOME 0x8408
#define CRC_PRESET_VALUE 0xE012
#define CRC_CHECK_VALUE 0x0000

extern uint8_t g_trf_buffer[NFC_FIFO_SIZE];
static volatile trf_status_t m_trf_status;

/**
* This function calculates a crc16 over a uint8_t array
* with LSB first.
*
* @param Datag_trf_buffer Pointer to data to calculate crc16 for.
* @param SizeOfDatag_trf_buffer Length of the data g_trf_bufferfer (Datag_trf_buffer)
* @param polynom Value of the generator polynom.
* 0x8408 is recommended.
* @param Initial_Value Initial value of crc16.
* 0xFFFF is recommended for
* host to reader communication.
* @return Calculated crc16
*/
uint16_t GetCrc(uint8_t *pDatag_trf_buffer, uint8_t g_trf_bufferLen, uint16_t polynom, uint16_t initialValue)
{
    uint16_t crc16 = initialValue;
    uint8_t byteCounter, bitCounter;

    for (byteCounter = 0; byteCounter < g_trf_bufferLen; byteCounter++)
    {
        crc16 ^= pDatag_trf_buffer[byteCounter];
        for (bitCounter = 0; bitCounter < 8; bitCounter++)
        {
            if ((crc16 & 0x0001) == 0)
            {
                crc16 >>= 1;
            }
            else
            {
                crc16 = (crc16 >> 1) ^ polynom;
            }
        }
    }
    return (crc16);
}

//addr is the block to update, p_block_data is the data to be sent,block_size is the size of sent data,p_out_data store the reply of update
uint8_t iclass_cmd_update(uint8_t addr, uint8_t* p_block_data, uint8_t block_size, uint8_t* p_out_data)
{
    //SHELL FOR COMMAND

    uint8_t bTxbuffer[17];
    crc16_t crc16;
    uint8_t ui8Offset = 0;
    uint8_t out_data_len;
    GUAP_Delay_ms(2); //delay
    out_data_len = 0;

    bTxbuffer[ui8Offset++] = 0x8F; // reset FIFO
    bTxbuffer[ui8Offset++] = 0x90; // sending without CRC
    bTxbuffer[ui8Offset++] = 0x3D; // write continuous from 1D
    bTxbuffer[ui8Offset++] = 0x00; // upper and middle nibbles of transmit byte length
    bTxbuffer[ui8Offset++] = 0xC0; // lower and broken nibbles of transmit byte length

    bTxbuffer[ui8Offset++] = 0x27; // UPDATE
    bTxbuffer[ui8Offset++] = addr; // BLOCK #addr
    memcpy(&bTxbuffer[ui8Offset], p_block_data, block_size); // Data to write to tag
    ui8Offset += block_size;

    crc16.value = GetCrc(&bTxbuffer[6], 9, CRC_POLYNOME, CRC_PRESET_VALUE);
    bTxbuffer[ui8Offset++] = crc16.lowByte;
    bTxbuffer[ui8Offset++] = crc16.highByte;

    TRF79xxA_writeRaw(bTxbuffer, ui8Offset); //issuing the READ command

    m_trf_status = TRF79xxA_waitRxData(30, 20); // 30 millisecond TX timeout, 20 millisecond RX timeout

    if (m_trf_status == RX_COMPLETE)
    { // if received block data in g_trf_bufferfer
        uint8_t g_trf_buffer_len = TRF79xxA_getRxBytesReceived();

        if (0 != g_trf_buffer_len && NULL != p_out_data)
        {
            out_data_len = g_trf_buffer_len;
            memcpy(p_out_data, g_trf_buffer, g_trf_buffer_len);
            //Response will be contents written to the block (8 bytes)
        }
    }
    else
    {
        // clear any IRQs
        TRF79xxA_resetIrqStatus();
    }
    return out_data_len;
}

  • Hello Ken,

    currently I'm attending a training and will not be able to work on this post. I will look at it tomorrow, but as I have to catch up on other posts, it might take 1 or 2 days until I can give an answer. Please be patient.

    Best regards,

    Andreas.

  • Hello Ken,

    it seems that the sequence of commands is important. ACS must be performed first, then a SELECT is required and then the Update command can be sent. The implementation of the Update command itself is looking reasonable.

    Best regards,

    Andreas.


  • Hello Andreas,

    I do follow the ACS sequence so that I can get UID. This card only responds back if the commands are right.
    Is any update function's raw data like attach picture? I can't get any response after sending update command. Thanks.

    Best regards,

                          example to test
    Ken.

  • Hi Ken,

    here it is

    Best regards,

    Andreas.

  • Hello Andreas,

    I can't receive anything with update command and crc code if you look back "graph1:iClass wirte and read" in the first post.
    Because the example didn't include block data and crc code.
    I wonder why there is no response with update command. So, if I don't care, the block data has to be written. Only test crc code with brute-force. Maybe I can get some response. I tried this first at read command. It works and shows that the crc code is like an example. But I still can't get any response from update command after brute-force ends.

    Best regards,
    Ken.

    Brute-force Read successed  video (1 minute) : https://youtu.be/Ik_GPUVMfNI

                            5.13 Brute-force write failed.

                                                                function iclass_cmd_test c code

    #define DEBUG_ICLASS_WRITE
    //#define DEBUG_ICLASS_READ
    
    
    void iclass_cmd_test()
    {
    #if defined DEBUG_ICLASS_WRITE
        //update test txbuffer
        uint8_t bTxbuffer[12] = {0x27, 0x03, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x00, 0x00};
        uint8_t m_bRxbuffer[8] = {0};
    #elif defined DEBUG_ICLASS_READ
        //read test txbuffer
        uint8_t bTxbuffer[4] = {0xAC, 0x00, 0x00, 0x00};
        uint8_t m_bRxbuffer[10] = {0};
    
    #endif
    
        uint8_t m_bForFlag = 0;
        uint8_t receive_length = 0;
        uint16_t i, j;
    
    //  read crc is 73 33, 73 = 115 , start from 115 and 0
        for(i = 0; i < 256; i++)
        {
            for(j = 0; j < 256; j++)
            {
    #if defined DEBUG_ICLASS_WRITE
                //update test txbuffer
                bTxbuffer[10] = (uint8_t)i;
                bTxbuffer[11] = (uint8_t)j;
    #elif defined DEBUG_ICLASS_READ
                //read test txbuffer
                bTxbuffer[2] = (uint8_t)i;  //change crc
                bTxbuffer[3] = (uint8_t)j;  //change crc
    #endif
    
    #if defined DEBUG_ICLASS_WRITE
                //update test txbuffer
                if (TRF79xxA_SendCmd(TRF79XXA_TRANSMIT_NO_CRC_CMD, bTxbuffer, 96, 30)) // 96 = 12 * 8 bits
    #elif defined DEBUG_ICLASS_READ
                //read test txbuffer
                if (TRF79xxA_SendCmd(TRF79XXA_TRANSMIT_NO_CRC_CMD, bTxbuffer, 32, 30)) // 32 = 4 * 8 bits
    #endif
                {
                    NDEF_PRINT_BYTE(i);
                    NDEF_PRINT_STRING("\n");
    
    #if defined DEBUG_ICLASS_WRITE
                //update test txbuffer
                    receive_length = TRF79xxA_ReceiveData(m_bRxbuffer, 8, 20);  // FF is timeout, 0x08 is good, only data 8
    #elif defined DEBUG_ICLASS_READ
                //read test txbuffer
                    receive_length = TRF79xxA_ReceiveData(m_bRxbuffer, 10, 20); // FF is timeout, 0x0A is good, data 8 + crc 2 = 10(A)
    #endif
                    if( 0 < receive_length && 0xFF != receive_length)
                    {
                        NDEF_PRINT_STRING("j: ");
                        NDEF_PRINT_BYTE(j);
                        NDEF_PRINT_STRING("\n");
                        DBG_PRINT_BYTE("receive_length:", receive_length);
                        NDEF_PRINT_STRING("find");
                        NDEF_PRINT_STRING("\n");
                        m_bForFlag = 1;
                        break;
                    }
                }
                Delay_Ms(2);  //delay
            }
            if(1 == m_bForFlag)
            {
                break;
            }
        }
        NDEF_PRINT_STRING("end\n");
    }


  • Hello Andreas,

    After I have studied the two papers at reference, I found that it is impossible to write a data without a secret key.
    Your steps for iClass are correct, but do not mention how to generate challenge values in mutual authentication.
    Because the secret key is needed to generate challenge values. And Write command must be sent after authentication.
    I think this question is the end. Thanks for your reply again.

    Best regards,
    Ken.

    Reference:

    1.Dismantling iClass and iClass Elite
        www.cs.bham.ac.uk/.../dismantling.iClass.pdf
    2.Exposing iClass Key Diversification
        www.usenix.org/.../Garcia.pdf