Hello NFC community, as you may know the The PN7462 family consists of 32-bit Arm® Cortex®-M0-based NFC microcontrollers offering high performance and low power consumption. It has a simple instruction set and memory addressing along with a reduced code size compared to existing architectures. PN7462 family offers an all-in-one-solution, with features such as NFC, supporting all NFC Forum modes, microcontroller, optional contact smart card reader, and software in a single chip. It operates at CPU frequencies of up to 20 MHz. and
MIFARE® Ultralight-based tickets offer an ideal solution for low-cost, high-volume applications such as public transport, loyalty cards and event ticketing. They serve as a perfect contactless replacement for magnetic stripe, barcode, or QR-code systems. The introduction of the contactless MIFARE Ultralight® ICs for limited-use applications can lead to reduced system installation and maintenance costs. As you may know the MIFARE family has the Ultralight C tag which is a contactless IC supporting 3DES cryptography is mostly used in limited use applications such smart ticketing, this tag complies with ISO 14443-3 type A and it is defined as type 2 tag.

In this document I am going to show you how to modify an example that is provided in the NXP Reader Library to authenticate to a not personalized Mifare Ultralight C and perform a Read operation.
Materials:
First we are going to go to NfcrdlibEx4_MIFAREClassic.c, I am going to explain as much as I can with comments in the code and add some information
here we are going to add the following include:
#define MFULC_READ_DATA_SIZE 16
#define MFULC_USER_MEMORY_BEGIN 0x04
#define MFULC_PAGE_SIZE 0x04
#define KEYCOUNT 0x7FU
#define KEYVERSIONS 0x01U
#define RAND_KEY_2K3DES_ADDRESS 0x01U
#define RAND_KEY_2K3DES_VERSION 0x00U
#define UL_C_KEY_ADDRESS 0x02U
#define UL_C_KEY_VERSION 0x00U
#define KEY_POSITION 0x00U
after this in the Global Variable declaration section we will have to add the following:
phCryptoSym_Sw_DataParams_t cryptoEnc;
phCryptoSym_Sw_DataParams_t cryptoSymRng;
phCryptoRng_Sw_DataParams_t cryptoRng;
phKeyStore_Sw_DataParams_t keyStore;
static uint8_t gaUlcKey[] = {0x49, 0x45, 0x4D, 0x4B, 0x41, 0x45, 0x52, 0x42, 0x21, 0x4E, 0x41, 0x43, 0x55, 0x4F, 0x59, 0x46};
phacDiscLoop_Sw_DataParams_t * pDiscLoop;
void *psKeyStore;
void *psalMFUL;
void *ppalMifare;
the variable static uint8_t gaUlcKey[] = {0x49, 0x45, 0x4D, 0x4B, 0x41, 0x45, 0x52, 0x42, 0x21, 0x4E, 0x41, 0x43, 0x55, 0x4F, 0x59, 0x46}; this is the key for default in the Mifare Ultralight c as stated in the datasheet section 7.5.6 this is a reference for the key we should be using.
Then we are going to change the PAL variables
phKeyStore_Sw_KeyEntry_t aKeyEntry[KEYCOUNT];
phKeyStore_Sw_KeyVersionPair_t aKeyVersion[KEYCOUNT * KEYVERSIONS];
phKeyStore_Sw_KUCEntry_t aKeyUsageCounter[KEYCOUNT];
uint8_t bDataBuffer[DATA_BUFFER_LEN];
uint8_t bSak;
uint16_t wAtqa;
then we are going to change this in line 131
psalMFC = phNfcLib_GetDataParams(PH_COMP_AL_MFC);
to
psalMFUL = phNfcLib_GetDataParams(PH_COMP_AL_MFUL);
so this get the MIFARE Ultralight AL-Components, then after this line we are going to add
ppalMifare = phNfcLib_GetDataParams(PH_COMP_PAL_MIFARE);
then we are going to erase the Mifare classic functionality to avoid any kind of error due to Mifare classic not being present in the field.and add the following:
First we are going to proceed with the Authentication part, we are going tu use the API phalMful_UlcAuthenticate(pDataParams, wKeyNumber, wKeyVersion); the first parameter is the structure pointing to the tag that was activated by the discoveryloop, then the key address and last the version of the key. as you can see we do not send the key we only tell the tag where is the key stored and the version if it was updated. to ensure the confidentiality of the communication.
status = phalMful_UlcAuthenticate(psalMFUL, UL_C_KEY_ADDRESS, UL_C_KEY_VERSION);
if ((status & PH_ERR_MASK) != PH_ERR_SUCCESS)
{
DEBUG_PRINTF("\nAuthentication Failed!!!");
DEBUG_PRINTF("\nPlease correct the used key");
DEBUG_PRINTF("\nExecution aborted!!!\n");
break;
}
DEBUG_PRINTF("\nAuthentication Successful");
/*
after this the status should be OK and no error found, if you have an error in this please check that the card you are using was not tampered before and changed the key or if you distributor delivered a configured key please be sure to use the correct key.
then we are going to proceed to the Read operation:
phalMful_Read(pDataParams, bAddress, pData) as you can see the first parameter is the same as authentication because we are still talking to the same tag, the MFULC_USER_MEMORY_BEGIN its value is 04 this is because as you can see in the datasheet section 7.5 Memory organization the user memory starts in page 4 and ends in page 39 so we just want to read the first page of the tag and the bDataBuffer variable will store the received information.
memset(bDataBuffer, '\0', DATA_BUFFER_LEN);
DEBUG_PRINTF("\n\nRead data from page %d, %d, %d, %d", MFULC_USER_MEMORY_BEGIN, MFULC_USER_MEMORY_BEGIN + 1, MFULC_USER_MEMORY_BEGIN + 2, MFULC_USER_MEMORY_BEGIN + 3);
status = phalMful_Read(psalMFUL, MFULC_USER_MEMORY_BEGIN, bDataBuffer);
if (status != PH_ERR_SUCCESS)
{
DEBUG_PRINTF("\nRead operation failed!!!\n");
DEBUG_PRINTF("\nExecution aborted!!!\n\n");
break;
}
DEBUG_PRINTF("\nRead Success");
DEBUG_PRINTF("\nThe content of page %d is:\n", MFULC_USER_MEMORY_BEGIN);
phApp_Print_Buff(&bDataBuffer[0], MFULC_READ_DATA_SIZE);
and that is all of our project, this is a simple project but can help a lot of people to understand how to work with Mifare Ultralight C using the PN7462 and then help people to start doing more complex examples based on this project. if you want to know how to configure a Mifare Ultralight c product using our PEGODA reader please check the document I posted called "Mifare Ultralight C - Changing default password and protecting page address". if you have any questions please let me know.
BR
Jonathan