Skip to main content
Olivier Bontron
Associate II
October 2, 2019
Solved

NFC0541 read Mifare Classic 1K

  • October 2, 2019
  • 24 replies
  • 9773 views

I’m using NFC05A1 and the STMF4xx-Nucle-Polling project.

I’d like to interact with  a Mifare classic card 1K.

I am aware Stm won’t provide any code that would deal with encryption and this is not what I’m asking for.

The issue I encounter is about the first step after SELECT : this is a clear text message, starting with 30 then the sector number. What I expect is the card answering with a nonce.

The issue I encounter is I receive a ‘framing problem’ or ‘timeout’ error message.

Here are the first four requests, which are working fine I think, the fifth one does not.

* Request 1:

Answer to rfalISO14443ATransceiveShortFrame  (with RFAL_14443A_SHORTFRAME_CMD_REQA as a command) is : 04 00.

* Request 2:

Then there is another rfalISO14443ATransceiveShortFrame   instruction this time with RFAL_14443A_SHORTFRAME_CMD_WUPA

*Request 3:

Then a rfalNfcaSelReq  structure is set :

selReq (rfalNfcaSelReq  structure)

selReq.selCmd = 93

selReq.selPar =20

rfalNfcaTxRetry( ret, rfalISO14443ATransceiveAnticollisionFrame( (uint8_t*)&selReq, &bytesTxRx, &bitsTxRx, &bytesRx, RFAL_NFCA_FDTMIN ), ((devLimit==0)?RFAL_NFCA_N_RETRANS:0), RFAL_NFCA_T_RETRANS );

Request answer : the request result consists in

the card Uid  D0 74 CC A4, (correct uid)

and the bcc CC

*Request 4:

Then another request is a SELECT.

selReq.selCmd =93;

selReq.selPar= 70;

selReq.nfcid1[0]= D0

selReq.nfcid1[1]=74;

selReq.nfcid1[2]=CC;

selReq.nfcid1[3]=A4;

selReq.bcc=CC;

       rfalNfcaTxRetry( ret, rfalTransceiveBlockingTxRx( (uint8_t*)&selReq, sizeof(rfalNfcaSelReq), (uint8_t*)selRes, sizeof(rfalNfcaSelRes), &bytesRx, RFAL_TXRX_FLAGS_DEFAULT, RFAL_NFCA_FDTMIN ), ((devLimit==0)?RFAL_NFCA_N_RETRANS:0), RFAL_NFCA_T_RETRANS );

Its results can be found within selRes :

Sak:  08

So far, the device is a Mifare Classic (sak 08) , this device is device[0] and its uid is known.

*Request 5 : this is where there is an issue.

Ask the card to access sector 00.

As Mr Michael Roland suggested in this post :

https://stackoverflow.com/questions/56334836/is-there-any-function-for-reading-nfc-a-iso14443a-tag-with-x-nucleo-nfc05a1

lenTx = 0;

bufferTx[lenTx++] = 0x30;

bufferTx[lenTx++] = 0x00; // sector

lenRxMax = 16;

lenRx = 0;

status = rfalTransceiveBlockingTxRx(&bufferTx[0], lenTx, &bufferRx[0], lenRxMax, &lenRx, RFAL_TXRX_FLAGS_DEFAULT, rfalConvMsTo1fc(5));

Answer

status value :  9

Another attempt with different flags.

status = rfalTransceiveBlockingTxRx(&bufferTx[0], lenTx, &bufferRx[0], lenRxMax, &lenRx,

RFAL_TXRX_FLAGS_CRC_TX_AUTO | RFAL_TXRX_FLAGS_CRC_RX_REMV | RFAL_TXRX_FLAGS_NFCIP1_OFF | RFAL_TXRX_FLAGS_AGC_ON | RFAL_TXRX_FLAGS_PAR_RX_REMV | RFAL_TXRX_FLAGS_PAR_TX_AUTO | RFAL_TXRX_FLAGS_NFCV_FLAG_AUTO, RFAL_NFCA_T_RETRANS);

Same answer

status value :  9

ERR_FRAMING                          = 9, /*!< Framing error */

I’ve added some logs within rfalTransceiveBlockingRx to have a look at the states :

platformLog("gRFAL.state %d\r\n", gRFAL.state);

do{

    rfalWorker();

    platformLog("gRFAL.TxRx.state %d\r\n", gRFAL.TxRx.state);

  }

Logs for the successful requests (REQA, SEL) are :

gRFAL.state 3

gRFAL.TxRx.state 83 (RFAL_TXRX_STATE_RX_WAIT_RXS)

gRFAL.TxRx.state 90 (RFAL_TXRX_STATE_RX_FAIL)

gRFAL.TxRx.state 0 (RFAL_TXRX_STATE_IDLE)

status is 0 ERR_NONE            

Logs for the last read request are :

gRFAL.state 3

gRFAL.TxRx.state 83(RFAL_TXRX_STATE_RX_WAIT_RXS)

gRFAL.TxRx.state 84 (RFAL_TXRX_STATE_RX_WAIT_RXE)

gRFAL.TxRx.state 84

gRFAL.TxRx.state 84

gRFAL.TxRx.state 84

gRFAL.TxRx.state 84

gRFAL.TxRx.state 84

gRFAL.TxRx.state 90(RFAL_TXRX_STATE_RX_FAIL)

gRFAL.TxRx.state 0(RFAL_TXRX_STATE_IDLE)

status is 9 ERR_FRAMING /*!< Framing error */

Many thanks in advance,

Olivier

    This topic has been closed for replies.
    Best answer by Olivier Bontron

    Dear Ulysses,

    Thank you so much for your invaluable answer.

    I went through your template and managed to get how you went from 'a2 0f' … to 'a2 1e' …

    Despite I’m not at ‘write’stage but still in the ‘authentication’ process, I guess the rationale is alike and if so the template you sent will definitely  help a lot.

    The answer the reader should send back to the card for authentication is made of :

    8 bytes + 1 parity bit on each byte + 2 bytes CRC (on these 8 bytes) + 1 parity bit on CRC bytes (as you said 'Also the CRC bytes again will have a parity'.).

    Once reshifted the way the template is, the size stays unchanged : it makes

    8 * 8 bits + 8 * 1 bit + 2 * 8 bits + 1 bit = 89 bits.

    This is the situation you described with the 36 bits example, which requires to be sent in raw mode, isn'it?

    Could you tell me how to opt for raw mode please ?

    Thanks in advance

    Olivier Bontron

    24 replies

    Olivier Bontron
    Associate II
    October 8, 2019

    Dear Brian,

    Fwt : modified to rfalConvMsTo1fc(100) (N°1 below) and back to RFAL_NFCA_FDTMIN set to 16200 instead of 1620 (N°2 below).

    Flags : used these flags that are not default flags :

        status = rfalTransceiveBlockingTxRx(&bufferTx[0],

    lenTx, &bufferRx[0], lenRxMax, &lenRx, RFAL_TXRX_FLAGS_PAR_TX_AUTO

    | RFAL_TXRX_FLAGS_CRC_TX_AUTO | RFAL_TXRX_FLAGS_CRC_RX_REMV | RFAL_TXRX_FLAGS_PAR_RX_KEEP,

    rfalConvMsTo1fc(100));

        status = rfalTransceiveBlockingTxRx(&bufferTx[0],

    lenTx, &bufferRx[0], lenRxMax, &lenRx, RFAL_TXRX_FLAGS_PAR_TX_AUTO

    | RFAL_TXRX_FLAGS_CRC_TX_AUTO | RFAL_TXRX_FLAGS_CRC_RX_REMV | RFAL_TXRX_FLAGS_PAR_RX_KEEP,

    RFAL_NFCA_FDTMIN);

    In both cases, the log tells :

    ERR_INCOMPLETE_BYTE                  =

    40, /*!< Incomplete byte

    rcvd        */

    The reason why I set the flag to RFAL_TXRX_FLAGS_CRC_RX_REMV

    is that the former Log was    ERR_CRC                              =

    21, /*!< crc error */

    I already mentioned this log and you said in your former post that this

    error refered to Rx, not Tx, so I tried to sort this out this way.

    The situation now seems to be :

    When the RX CRC is being kept : error since it is a wrong CRC

    When the RX CRC is being removed (REMV) : error since byte is incomplete.

    Any thought?

    Thanks in advance

    Best regards,

    Olivier

    Ulysses HERNIOSUS
    Technical Moderator
    October 9, 2019

    Hi Olivier,

    ERR_INCOMPLETE_BYTE does only mean that the data was not coming in 8-bit chunks and that the last byte which the user gets in his buffer contains less than 8 bits from RF. If you keep the parity then you will get one more bit per byte. It is natural to get incomplete bytes.

    If you really want to support these tags then you need to read information about these tags and you will understand the reason for receiving with CRC and parity and in a further step you need also to move into sending user-defined parity and CRC.

    Please keep in mind even though this protocol is broken and not highly secure it is not simple to support like apply an XOR-operation on some received bytes.

    Regards, Ulysses

    Olivier Bontron
    Associate II
    November 4, 2019

    Hi Ulysses,

    The card sends a card nonce to the reader.

    Then, the reader sends a message, including, as you suggested :

    User-defined parity :

    This what is being sent:

    Since there is a parity bit for every byte of data, the Tx looks like this : AA 80 BB 00 ....

    So basically the tag receives 80 (10000000) or 00 (00000000) and only reads the first bit which is the parity bit of the former sent byte.

    All in all, there are 8 bytes content + 8 bytes parity = 16 bytes ... plus the CRC :

    user-defined CRC

    then to this 16 bytes, 2 more bytes are being added.

    CRC, calculated on the 8 bytes content only, (parity bytes are excluded from the calculation).

        status = rfalTransceiveBlockingTxRx(&tobesentTx[0], lentobesentTx, &bufferRx[0], lenRxMax, &lenRx, RFAL_TXRX_FLAGS_PAR_TX_NONE | RFAL_TXRX_FLAGS_CRC_TX_MANUAL | RFAL_TXRX_FLAGS_CRC_RX_KEEP | RFAL_TXRX_FLAGS_PAR_RX_KEEP , rfalConvMsTo1fc(100));

    Error message is

      ERR_BUSY               = 2 (several times)

    then

      ERR_TIMEOUT              = 4

    You said "timeout just means no response from the card. Absolutely normal if the card did not understand the reader request"

    Any clue about why the reader request can't be understood ?

    Many thanks in advance,

    Olivier Bontron

    Ulysses HERNIOSUS
    Technical Moderator
    November 4, 2019

    Hi Olivier,

    yes, you need to pack the bits into an 8 byte stream. Unless it is completely well-formed with proper parity and CRC the card won't respond. Also the CRC bytes again will have a parity.

    Regards, Ulysses.

    Ulysses HERNIOSUS
    Technical Moderator
    November 4, 2019

    Hi,

     

    giving you a template for this.

    Say you want to send a2 0f 00 00 00 00 (T2T write page 15 with 00 00 00 00).

    with CRC the frame is: a2 0f 00 00 00 00 db d5 (8bytes). Adding one bit per byte makes this 9 bytes and with some shifting: a2 1e 02 04 08 10 e0 f6 6a. If you transfer these 9 bytes with CRC_TX_MANUAL and PAR_TX_NONE you will get exactly the same RF frame as with the chip automatics and it will write 00 00 00 00.

     

    Of course if you want to transfer 4 bytes (including CRC) you will need to send in the end 36 bits ( 4bytes + 4 bits) in raw mode.

     

    Regards, Ulysses

     

    Olivier Bontron
    Olivier BontronAuthorBest answer
    Associate II
    November 6, 2019

    Dear Ulysses,

    Thank you so much for your invaluable answer.

    I went through your template and managed to get how you went from 'a2 0f' … to 'a2 1e' …

    Despite I’m not at ‘write’stage but still in the ‘authentication’ process, I guess the rationale is alike and if so the template you sent will definitely  help a lot.

    The answer the reader should send back to the card for authentication is made of :

    8 bytes + 1 parity bit on each byte + 2 bytes CRC (on these 8 bytes) + 1 parity bit on CRC bytes (as you said 'Also the CRC bytes again will have a parity'.).

    Once reshifted the way the template is, the size stays unchanged : it makes

    8 * 8 bits + 8 * 1 bit + 2 * 8 bits + 1 bit = 89 bits.

    This is the situation you described with the 36 bits example, which requires to be sent in raw mode, isn'it?

    Could you tell me how to opt for raw mode please ?

    Thanks in advance

    Olivier Bontron

    Ulysses HERNIOSUS
    Technical Moderator
    November 6, 2019

    Hi Olivier,

    raw mode for sending: RFAL_TXRX_FLAGS_PAR_TX_NONE | RFAL_TXRX_FLAGS_CRC_TX_MANUAL

    raw mode for receiving: RFAL_TXRX_FLAGS_CRC_RX_KEEP | RFAL_TXRX_FLAGS_PAR_RX_KEEP

    In your example it would be 90 bits as CRC is two bytes. However please carefully check the CRC and parity requirements for the frames. The DS indicates authentication frames are performed without CRC but probably with parity.

    Regards, Ulysses

    Olivier Bontron
    Associate II
    November 8, 2019

    Hi Ulysses,

    Great, there is some progress.

    There is an answer, so the card handled the message that was sent to her, thanks a lot for your template.

    Answer is an error message (but at least it's an answer):

    Status is now 9, framing error.

    lenRx=0

    bufferRx[0] 09

    then 00...

    Is it related to the 'raw mode for receiving'?

    A lenRx=0 and a bufferRx with a content, does the raw mode explain it?

    Regards,

    Olivier Bontron

    Ulysses HERNIOSUS
    Technical Moderator
    November 11, 2019

    Hi Olivier,

    the convenience functions rfalTransceiveBlockingTxRx() always assume a byte oriented interface. In the end you need to move to rfalStartTransceive(), rfalGetTransceiveStatus(), rfalWorker() usage to get the actual number of received bits.

    This does not really explain the lenRx=0. Even in the case of a 4-bit ACK/NAK it should indicate a length of 1 byte. Alternatively I could imagine an overwrite of the buffer on the stack?! bufferRx[0] == Status == 9, ... maybe the lenRxMax=16 bytes does not match the allocated buffer.

    Regards, Ulysses

    Olivier Bontron
    Associate II
    November 11, 2019

    Thanks for answering,

    I am expecting uint8_t as a result from the card, so it should be byte-oriented.

    lenRxMax=16 bytes;

    uint8_t bufferRx[16];

    I went through the processes of rfalStartTransceive(), rfalGetTransceiveStatus(), rfalWorker().

    Logs tell :

    From rfalWorker -> rfalTransceiveRx.

    Within rfal_rfst25r3911.c / rfalTransceiveRx, there is a condition which is met (see below).

    I think this is where the gRFAL.TxRx.status is set to 'ERR_FRAMING', which the '9'.

    /*******************************************************************************/

    static void rfalTransceiveRx( void )

    {

    ...

        case RFAL_TXRX_STATE_RX_WAIT_RXE:

          irqs = st25r3911GetInterrupt( (ST25R3911_IRQ_MASK_RXE | ST25R3911_IRQ_MASK_FWL | ST25R3911_IRQ_MASK_EOF) );

          if( irqs == ST25R3911_IRQ_MASK_NONE )

          {

            /*******************************************************************************/

            /* REMARK: Silicon workaround ST25R3911B Errata #1.1              */

            /* ST25R3911 may indicate RXS without RXE afterwards, this happens rarely on  */

            /* corrupted frames.                              */

            /* SW timer is used to timeout upon a missing RXE               */

            if( rfalTimerisExpired( gRFAL.tmr.RXE ) )

            {

              gRFAL.TxRx.status = ERR_FRAMING;

              gRFAL.TxRx.state = RFAL_TXRX_STATE_RX_FAIL;

            }

            /*******************************************************************************/

               

            break; /* No interrupt to process */

          }

    The logs tell this condition is met.

    Besides, when status and state values are asked for, the answer are:

    status is 9

    state is 90

    Any thought?

    Thanks in advance.

    Olivier Bontron

    Ulysses HERNIOSUS
    Technical Moderator
    November 12, 2019

    Hi Olivier,

    this now sounds more low-level. You shouldn't be hitting this timeout.

    Please try the method in https://community.st.com/s/question/0D50X0000AlgXJWSQ2/st25tb-tag-not-recognized-by-xnucleonfc05a1-but-recognized-by-st25r3911bdisco.

    If it does not help, then please provide logic analyzer traces of this issue.

    Regards, Ulysses

    Olivier Bontron
    Associate II
    November 12, 2019

    Hi Ulysses,

    Thanks, it sure makes a change.

    Now status i 40 and LenRx is 1.

    I'll dig a bit more and come back to you with the logs I get.

    Regards,

    Olivier