cancel
Showing results for 
Search instead for 
Did you mean: 

NFC0541 read Mifare Classic 1K

Olivier Bontron
Associate III

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

31 REPLIES 31

Hi Ulysses,

Thanks.

So I'll try to figure out why responses are not recognised as a valid frame and change the transceive flag consequently.

Best regards

Olivier

Olivier Bontron
Associate III

Hi 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 :

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

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

It's not the only possible explanation, maybe another expected content like PAR is missing.

Any thought?

Best regards,

Olivier

Olivier Bontron
Associate III

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
ST Employee

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

Dear Ulysses,

What you were saying in a post that apparently disappeared was that the faulty flag was RFAL_TXRX_FLAGS_PAR_RX_KEEP.

"If you keep the parity then you will get one more bit per byte. It is natural to get incomplete bytes."

I turned it to RFAL_TXRX_FLAGS_PAR_RX_REMV and now the error is back to 21 (CRC) which was the issue I met earlier. Experience curve is steep.

I read in the ST's doc CR95HF DocID018669 Rev 12 page 28/77 about the parity framing : The parity framing mode is compatible with MIFARE® classic requirements.

"If parity framing mode is used (Bit 4 of transmission flag byte is set to ‘1’), then the parity bit must be coded inside the data for each byte to be sent using the send/receive command in transmit mode, and is not decoded by the ST25R95 in receive mode. In Receive mode, each data byte is accompanied by an additional byte which encodes the parity: .

Examples of data received by send / receive in Parity Framing mode: • 80 05 32 80 34 00 00 meaning: if the ST25R95 received 2 data bytes: • 0x32 with parity = ‘1’ (0x80) and 0x34 with parity = ‘0’ (0x0) in parity framing mode."

Is there a specific flag or another mean to activate parity framing ?

Thanks in advance.

Olivier

Addendum

Parity framing

I'm thinking of this flag : RFAL_TXRX_FLAGS_PAR_TX_NONE, so I could have a data byte and immediately following this byte a byte containing a parity bit (for instance 0x80 for a 1 parity).

The block would be : for instance data byte 0x30 followed by the parity byte, let's say 0x80 according to the example, then again a data byte 0x00 (auth to block 0) followed by its parity byte and eventually the CRC bytes, only based on the two data bytes, not the four bytes.

Since this is definitely not the usual way to forge CRC I'll switch to RFAL_TXRX_FLAGS_CRC_TX_MANUAL.

Does it sound to you a plausible way to send an authentication request to the picc ?

Another question is : What kind of parity is used ?

If we look at the example, when a 0x32 data byte is followed by a 0x80 byte containing parity (8 being 1000), then it must have been that Mifare Classic tag require an even parity, isn'it ?

Last question is : I read there is also a start bit. Do you confirm ? How sould I manage with this start bit ?

Thanks in advance

Olivier

Hi Olivier,

hint: Click "More Answers" on the bottom of the thread to recover the "lost" messages. (Kind of s..uboptimal UI).

When you receive ERR_INCOMPLETE_BYTE you actually also receive data bytes. This is what you need to interpret. Just ignore this ERR_INCOMPLETE_BYTE.

Start bit is handled by the hardware. Your software will need to handle all parity and CRC bits.

I fear I am repeating myself but without a deep understanding of the the cryptography of these tags you will not be able to succeed in communicating with them. To understand the parity bit thingy you need to first understand the cryptography and how it is used in these tags.

It will not help you now reading ST25R95HF data sheet when using NFC05 which has ST25R3911B.

Regards, Ulysses

Olivier Bontron
Associate III

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
ST Employee

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
ST Employee

Hi,

giving you a template for this.

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

with CRC the frame is: a2 0f 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