piątek, 4 marca 2022

Odczytanie tagów NFC NDEF

W tym poście chciałbym opisać sposób odczytu tagów NFC NDEF wykonanych na karcie Mifare za pomocą programu NFC Tools.


[Źródło: https://github.com/XaviTorello/mifare-classic-toolkit]

Struktura karty:


Do przygotowania tagu NFC wykorzystałem czystą kartę Mifare:


Następnie na karcie zapisałem w formacie tekstowym następującą wiadomość abcdefgh1234567890 czyli 25 bajtów. Do zapisu wykorzystałem wspomniany wcześniej program NFC Tools. Poprawny zapis na danych do karty wymaga aby była ona czysta, bez żadnych danych w sektorach z zabezpieczonymi własnymi kluczami (jeśli karta nie ma domyślnych kluczy dostępu to należy ją sformatować). Informacje zostały zapisane w kodzie ASCII co oznacza, że w sektorze powinny znajdować się bajty:

0x61 (a);  0x62 (b);  0x63 (c);  0x64 (d);  0x65 (e);  0x66 (f); 0x67 (g);  0x68 (h); 
0x31 (1); 0x32 (2); 0x33 (3); 0x34 (4); 0x35 (5); 0x36 (6); 0x37 (7); 0x38 (8); 0x39 (9); 0x30 (0); 

Struktura karty wygląda następująco:


Jak widać powyżej karta sformatowana będzie zawierała sektor MAD, w kolejnych sektorach będą przechowywane wiadomości NDEF.

Powyżej sektor MAD składa się z bajtu CRC, 

Dane z zmodyfikowanego sektora 1:


Jak widać zmianie uległo kilka rzeczy. Zmienione zostały klucze dostępu do wszystkich sektorów. W  tym w sektorze 0 są umieszczone inne klucze niż w pozostałych sektorach. Ponieważ zawiera on MAD1. 

Sektor 0 - A0A1A2A3A4A5 - Klucz standardowy dla sektora MAD
Sektor od 1 - D3F7D3F7D3F7

Nie został jedynie zmodyfikowany sektor 0 blok 0, gdzie zapisany jest numer seryjny karty.

Zmianie uległy także bajty tzw. AcessBits z domyślnych FF078069 na:

787788 C1 -

Bloki danych z konfiguracją C1 - 1, C2 - 0, C3 - 0 (zapis możliwy tylko z użyciem klucza A odczyt z użyciem klucza A lub B)
Sektor trailer C1 - 0, C2 - 1, C3 - 1 (Zapis klucza tylko z użyciem klucza B, odczyt bitów konfiguracyjnych z użyciem klucza A lub B)
C1 jest to wartość General Purpouse Byte, który oznacza, że sektor zawiera MAD. 

7F0788 40 - 

Bloki danych z konfiguracją C1 - 0, C2 - 0, C3 - 0 (wszystkie operacje z użyciem klucza A lub B)
Sektor trailer C1 - 0, C2 - 1, C3 - 1 (Zapis klucza tylko z użyciem klucza B, odczyt bitów konfiguracyjnych z użyciem klucza A lub B)

Kalkulator do obliczenia tych wartości dostępny pod tym linkiem

W celu przechowywania danych na karcie w formacie NDEF, wiadomość musi być zapisana w bloku zwanym TLV 

Dane które chcemy odczytać zostały zapisane w sektorze 1;

  • 0x00 - Rekord 1
  • 0x00 - Rekord 1
  • 0x03 - Rozpoczęcie danych dla Rekord 2. Blok zawiera wiadomość NDEF.
  • 0x19 - Długość danych 25 decymalnie. Bez bajtu końca bloku TLV
  • 0xD1 - Nagłówek wiadomości NDEF 
  • 0x01 - Type Length Długość danych. 
  • 0x15 - długość danych Payload. 21 bajtów dziesiętnie.
  • 0x54 - typ danych. W tym przypadku 'T' czyli tekst. Wartość 0x55 oznacza wiadomość URI. 
  • 0x02 - Informacja o kodowaniu UTF8, tzw. Language Code dwa kolejne bajty. 
  • 0x65, 0x6E - 'e' 'n'. Czyli wiadomość zapisana w języku angielskim.
  • PAYLOAD - 21 bajtów
  • 0xFE -  TLV Terminator, oznaczenie końca bloku TLV.

Aplikacja odczytana za pomocą programu NFC Tools zwraca następujące informacje:


Odczyt danych PN532:

W celu odczytania danych wystarczy pobrać dane z sektorów.

Na samym początku procedura uwierzytelnienia sektora. Wszystkie bloki można odczytać za pomocą klucza A (D3 F7 D3 F7 D3 F7) :

  1. Mifare_StatusTypeDef Mifare_AuthMifare_SectorA(uint8_t tg, uint8_t sector, uint8_t* keyA, uint8_t *uid, uint8_t uidLen, uint16_t timeout){
  2.     uint8_t sendFrame[] = {MIFARE_CMD_AUTH_A, sector*4,
  3.             0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x66, 0xE9, 0xAC, 0xE8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
  4.  
  5.     /* Prepare the frame for send */
  6.     for(uint8_t i=0; i<6; i++)          { sendFrame[2+i] = *(keyA + i); }
  7.     for(uint8_t i=0; i<uidLen; i++ )    { sendFrame[8+i] = *(uid + i); }
  8.  
  9.     if(PN532_InDataExchange_Auth(sendFrame, 8+uidLen, tg, timeout) != PN532_OK) {
  10.         return MIFARE_AUTH_ERROR;
  11.     }
  12.  
  13.     return MIFARE_OK;
  14. }

lub klucza B (FF FF FF FF FF FF):

  1. Mifare_StatusTypeDef Mifare_AuthMifare_SectorB(uint8_t tg, uint8_t sector, uint8_t* keyB, uint8_t *uid, uint8_t uidLen, uint16_t timeout){
  2.     uint8_t sendFrame[] = {MIFARE_CMD_AUTH_B, sector*4,
  3.             0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x66, 0xE9, 0xAC, 0xE8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
  4.  
  5.     /* Prepare the frame for send */
  6.     for(uint8_t i=0; i<6; i++)          { sendFrame[2+i] = *(keyB + i); }
  7.     for(uint8_t i=0; i<uidLen; i++ )    { sendFrame[8+i] = *(uid + i); }
  8.  
  9.     if(PN532_InDataExchange_Auth(sendFrame, 8+uidLen, tg, timeout) != PN532_OK) {
  10.         return MIFARE_AUTH_ERROR;
  11.     }
  12.  
  13.     return MIFARE_OK;
  14. }

Dalej należy odczytać dane z poszczególnych bloków:

  1. //Mifare_ReadBlock(Mifare_CardData_Struct.selectedTgNumber, 1, 0, &Mifare_CardData_Struct.sector_9_1_data[0], 16, 1000);
  2. //Mifare_ReadBlock(Mifare_CardData_Struct.selectedTgNumber, 1, 1, &Mifare_CardData_Struct.sector_10_1_data[0], 16, 1000);
  3. //Mifare_ReadBlock(Mifare_CardData_Struct.selectedTgNumber, 1, 2, &Mifare_CardData_Struct.sector_10_2_data[0], 16, 1000);
  4.  
  5. Mifare_StatusTypeDef Mifare_ReadBlock(uint8_t tg, uint8_t sector, uint8_t blockNumber, uint8_t* dataBuffer, uint8_t length, uint16_t timeout){
  6.     uint8_t sendFrame[] = {MIFARE_CMD_READ, (sector * 4) + blockNumber};
  7.     uint8_t response[255] = {0};
  8.  
  9.     PN532_StatusTypeDef opStatus = PN532_InDataExchange_Read(sendFrame, 2, tg, response, 255, timeout);
  10.  
  11.     if(opStatus != PN532_OK) {
  12.         return MIFARE_PN532_ERROR;
  13.     }
  14.  
  15.     for(uint8_t i=0; i<16; i++) {
  16.         *(dataBuffer + i) = response[i];
  17.     }
  18.  
  19.     return MIFARE_OK;
  20. }
  21.  

Teraz wyświetlam odczytane dane:

  1. standard card type
  2. AUTH OK
  3. serial_number: [0A] [80] [C0] [73]
  4. 1_0 - [00] [00] [03] [19] [d1] [01] [15] [54] [02] [65] [6e] [61] [62] [63] [64] [65]
  5. 1_1 - [66] [67] [68] [31] [32] [33] [34] [35] [36] [37] [38] [39] [30] [fe] [00] [00]
  6. 1_2 - [00] [00] [00] [00] [00] [00] [00] [00] [00] [00] [00] [00] [00] [00] [00] [00]

Dokumentacja: