%% fig-alt: Circuit diagram showing ESP32 connected to four push buttons for simulating different NFC tag types and three LEDs for status indication in the NFC communication lab
%%{init: {'theme': 'base', 'themeVariables': {'primaryColor': '#2C3E50', 'primaryTextColor': '#fff', 'primaryBorderColor': '#16A085', 'lineColor': '#16A085', 'secondaryColor': '#E67E22', 'tertiaryColor': '#7F8C8D'}}}%%
flowchart LR
subgraph ESP32["ESP32 DevKit"]
G12["GPIO 12<br/>(NTAG213)"]
G13["GPIO 13<br/>(NTAG216)"]
G14["GPIO 14<br/>(DESFire)"]
G15["GPIO 15<br/>(Malicious)"]
G25["GPIO 25<br/>(Green LED)"]
G26["GPIO 26<br/>(Red LED)"]
G27["GPIO 27<br/>(Blue LED)"]
GND["GND"]
end
subgraph Buttons["NFC Tag Simulators"]
B1["Button 1<br/>NTAG213"]
B2["Button 2<br/>NTAG216"]
B3["Button 3<br/>DESFire"]
B4["Button 4<br/>Malicious"]
end
subgraph LEDs["Status Indicators"]
LEDG["Green LED<br/>Success"]
LEDR["Red LED<br/>Security Alert"]
LEDB["Blue LED<br/>Processing"]
end
G12 -.->|"Input"| B1
G13 -.->|"Input"| B2
G14 -.->|"Input"| B3
G15 -.->|"Input"| B4
G25 -.->|"Output"| LEDG
G26 -.->|"Output"| LEDR
G27 -.->|"Output"| LEDB
style ESP32 fill:#2C3E50,stroke:#16A085,stroke-width:2px,color:#fff
style Buttons fill:#16A085,stroke:#2C3E50,stroke-width:2px,color:#fff
style LEDs fill:#E67E22,stroke:#2C3E50,stroke-width:2px,color:#fff
881 NFC Hands-On Lab
881.1 Learning Objectives
By completing this lab, you will be able to:
- Understand NFC Tag Structure: Learn how NFC tags store data in memory blocks
- Parse NDEF Messages: Decode the NFC Data Exchange Format structure
- Identify Tag Types: Recognize characteristics of different NFC tag types (Type 1-5)
- Implement Security Checks: Validate tag authenticity and detect tampering
- Simulate P2P Concepts: Understand peer-to-peer communication handshake patterns
881.2 Prerequisites
Before starting this lab, you should have completed:
- NFC Introduction and Basics: Understanding of NFC fundamentals
- NFC Modes and Protocols: Knowledge of operating modes, tag types, and NDEF
- NFC Security and Best Practices: Security considerations and common pitfalls
881.3 NFC Communication Lab
This hands-on lab demonstrates NFC communication concepts using an ESP32-based simulation. Since actual NFC hardware requires specialized modules (like the PN532 or RC522), this lab simulates NFC tag reading, NDEF message parsing, and security concepts to help you understand the underlying principles before working with real hardware.
Real NFC communication requires specialized hardware (PN532, RC522, or smartphone NFC chip). This Wokwi simulation demonstrates the software concepts behind NFC: tag memory structure, NDEF parsing, security validation, and protocol state machines. The same code patterns apply when you transition to real NFC hardware.
881.3.1 Lab Components
| Component | Purpose | Simulation Role |
|---|---|---|
| ESP32 DevKit | Main controller | Simulates NFC reader/writer logic |
| Push Buttons | Tag simulation triggers | Simulate different tag types being “tapped” |
| LEDs | Status indicators | Show read/write/error states |
| Serial Monitor | Output display | Shows NDEF parsing and security analysis |
881.3.2 Wokwi Simulator Environment
Wokwi is a free online simulator for Arduino, ESP32, and other microcontrollers. While it does not simulate actual NFC hardware, we use it to demonstrate the software logic that processes NFC data. The code patterns you learn here directly apply to real NFC development with modules like PN532 or RC522.
Launch the simulator below and copy the provided code to explore NFC concepts interactively.
- Click the + button to add components (search for “Push Button” and “LED”)
- Use the Serial Monitor to see NFC simulation output (115200 baud)
- Press buttons to simulate different NFC tag types being tapped
- The code demonstrates real NDEF parsing logic used in actual NFC applications
881.3.3 Step-by-Step Instructions
881.3.3.1 Step 1: Set Up the Circuit
- Add 4 Push Buttons: Click + and search for “Push Button” - add 4 buttons
- Add 3 LEDs: Click + and search for “LED” - add Red, Green, and Blue LEDs
- Wire the components to ESP32:
- Button 1 (NTAG213 sim) -> GPIO 12
- Button 2 (NTAG216 sim) -> GPIO 13
- Button 3 (DESFire sim) -> GPIO 14
- Button 4 (Malicious tag sim) -> GPIO 15
- Green LED (Success) -> GPIO 25
- Red LED (Error/Security) -> GPIO 26
- Blue LED (Processing) -> GPIO 27
- All button other pins -> GND
- All LED cathodes -> GND (with appropriate resistors)
881.3.3.2 Step 2: Understanding the NFC Simulation Architecture
This lab simulates the key NFC concepts through software:
%% fig-alt: NFC simulation architecture showing how button presses trigger simulated tag reads which are processed through NDEF parser and security validator modules before displaying results
%%{init: {'theme': 'base', 'themeVariables': {'primaryColor': '#2C3E50', 'primaryTextColor': '#fff', 'primaryBorderColor': '#16A085', 'lineColor': '#16A085', 'secondaryColor': '#E67E22', 'tertiaryColor': '#7F8C8D'}}}%%
flowchart TB
subgraph Input["Tag Simulation Input"]
BTN["Button Press"]
SIM["Simulated Tag Data<br/>(Memory blocks, UID, Type)"]
end
subgraph Processing["NFC Processing Logic"]
NDEF["NDEF Parser<br/>- Header decoding<br/>- Record extraction<br/>- Payload parsing"]
SEC["Security Validator<br/>- UID verification<br/>- CMAC check<br/>- Counter validation"]
TYPE["Tag Type Analyzer<br/>- Memory capacity<br/>- Feature detection<br/>- Compatibility check"]
end
subgraph Output["Results"]
SERIAL["Serial Output<br/>Detailed analysis"]
LED["LED Indicators<br/>Visual feedback"]
end
BTN --> SIM
SIM --> NDEF
SIM --> SEC
SIM --> TYPE
NDEF --> SERIAL
SEC --> SERIAL
TYPE --> SERIAL
SEC --> LED
style Input fill:#16A085,stroke:#2C3E50,stroke-width:2px,color:#fff
style Processing fill:#2C3E50,stroke:#16A085,stroke-width:2px,color:#fff
style Output fill:#E67E22,stroke:#2C3E50,stroke-width:2px,color:#fff
881.3.3.3 Step 3: Copy the NFC Communication Lab Code
Copy the following code into the Wokwi code editor. This comprehensive simulation demonstrates NFC tag reading, NDEF parsing, tag type identification, and security validation.
/*
* NFC Communication Lab - ESP32 Simulation
*
* This code demonstrates NFC concepts without requiring actual NFC hardware:
* - NFC tag memory structure and organization
* - NDEF (NFC Data Exchange Format) message parsing
* - Tag type identification (Type 1-5, NTAG, DESFire)
* - Security validation and tamper detection
* - Peer-to-peer communication concepts
*
* Hardware: ESP32 DevKit with buttons and LEDs
* Purpose: Educational simulation of NFC protocols
*
* Button 1 (GPIO 12): Simulate NTAG213 tag (144 bytes, basic)
* Button 2 (GPIO 13): Simulate NTAG216 tag (888 bytes, Smart Poster)
* Button 3 (GPIO 14): Simulate DESFire tag (secure, encrypted)
* Button 4 (GPIO 15): Simulate malicious/tampered tag (security demo)
*
* LEDs:
* - Green (GPIO 25): Successful read/valid tag
* - Red (GPIO 26): Security alert/invalid tag
* - Blue (GPIO 27): Processing/reading
*/
#include <Arduino.h>
// ========== PIN DEFINITIONS ==========
#define BTN_NTAG213 12 // Simulate NTAG213 tag
#define BTN_NTAG216 13 // Simulate NTAG216 tag
#define BTN_DESFIRE 14 // Simulate DESFire secure tag
#define BTN_MALICIOUS 15 // Simulate malicious tag
#define LED_SUCCESS 25 // Green LED - successful operation
#define LED_SECURITY 26 // Red LED - security alert
#define LED_PROCESSING 27 // Blue LED - reading/processing
// ========== NFC TAG TYPE DEFINITIONS ==========
enum NFCTagType {
TAG_TYPE_UNKNOWN = 0,
TAG_TYPE_1, // Topaz (Broadcom) - 96 bytes to 2KB
TAG_TYPE_2, // NTAG/Ultralight - 48 bytes to 2KB
TAG_TYPE_3, // FeliCa - variable, 212/424 Kbps
TAG_TYPE_4, // DESFire, ISO-DEP - 4KB to 32KB
TAG_TYPE_5 // ISO 15693 (ICODE) - 256 bytes to 8KB
};
// ========== NDEF RECORD TYPE DEFINITIONS ==========
#define TNF_EMPTY 0x00
#define TNF_WELL_KNOWN 0x01 // NFC Forum well-known type
#define TNF_MEDIA 0x02 // RFC 2046 media type
#define TNF_ABSOLUTE_URI 0x03 // Absolute URI
#define TNF_EXTERNAL 0x04 // NFC Forum external type
#define TNF_UNKNOWN 0x05
#define TNF_UNCHANGED 0x06
#define TNF_RESERVED 0x07
// URI identifier codes (first byte of URI payload)
const char* URI_PREFIXES[] = {
"", // 0x00 - no prepending
"http://www.", // 0x01
"https://www.", // 0x02
"http://", // 0x03
"https://", // 0x04
"tel:", // 0x05
"mailto:", // 0x06
};
// ========== SIMULATED TAG DATA STRUCTURES ==========
// NTAG213 simulated memory (144 bytes user memory)
struct NTAG213_Simulated {
uint8_t uid[7];
uint8_t capability_container[4];
uint8_t user_memory[144];
} ntag213_tag;
// NTAG216 simulated memory (888 bytes user memory)
struct NTAG216_Simulated {
uint8_t uid[7];
uint8_t capability_container[4];
uint8_t user_memory[888];
uint32_t counter;
} ntag216_tag;
// DESFire simulated structure
struct DESFire_Simulated {
uint8_t uid[7];
uint8_t sak;
bool authenticated;
uint32_t counter;
uint8_t cmac[8];
} desfire_tag;
// ========== GLOBAL VARIABLES ==========
unsigned long lastButtonPress = 0;
const unsigned long DEBOUNCE_DELAY = 300;
int tagsRead = 0;
int securityAlerts = 0;
// ========== HELPER FUNCTIONS ==========
void printHex(const uint8_t* data, size_t len) {
for (size_t i = 0; i < len; i++) {
if (data[i] < 0x10) Serial.print("0");
Serial.print(data[i], HEX);
if (i < len - 1) Serial.print(" ");
}
}
void setLEDs(bool success, bool security, bool processing) {
digitalWrite(LED_SUCCESS, success ? HIGH : LOW);
digitalWrite(LED_SECURITY, security ? HIGH : LOW);
digitalWrite(LED_PROCESSING, processing ? HIGH : LOW);
}
void blinkLED(int pin, int count, int delayMs) {
for (int i = 0; i < count; i++) {
digitalWrite(pin, HIGH);
delay(delayMs);
digitalWrite(pin, LOW);
delay(delayMs);
}
}
void simulateCMAC(const uint8_t* data, size_t len, uint8_t* cmac) {
for (int i = 0; i < 8; i++) {
cmac[i] = 0;
for (size_t j = i; j < len; j += 8) {
cmac[i] ^= data[j];
}
cmac[i] ^= 0xA5;
}
}
const char* getTNFName(uint8_t tnf) {
switch (tnf) {
case TNF_EMPTY: return "Empty";
case TNF_WELL_KNOWN: return "NFC Forum Well-Known";
case TNF_MEDIA: return "Media Type (RFC 2046)";
case TNF_ABSOLUTE_URI: return "Absolute URI";
case TNF_EXTERNAL: return "NFC Forum External";
case TNF_UNKNOWN: return "Unknown";
default: return "Reserved";
}
}
// ========== TAG INITIALIZATION FUNCTIONS ==========
void initNTAG213() {
ntag213_tag.uid[0] = 0x04;
ntag213_tag.uid[1] = 0xA1;
ntag213_tag.uid[2] = 0xB2;
ntag213_tag.uid[3] = 0xC3;
ntag213_tag.uid[4] = 0xD4;
ntag213_tag.uid[5] = 0xE5;
ntag213_tag.uid[6] = 0xF6;
ntag213_tag.capability_container[0] = 0xE1; // NDEF magic
ntag213_tag.capability_container[1] = 0x10; // Version 1.0
ntag213_tag.capability_container[2] = 0x12; // Size: 144 bytes
ntag213_tag.capability_container[3] = 0x00; // Read/write
memset(ntag213_tag.user_memory, 0, sizeof(ntag213_tag.user_memory));
// Write NDEF URL record
int idx = 0;
ntag213_tag.user_memory[idx++] = 0x03; // NDEF TLV
ntag213_tag.user_memory[idx++] = 24; // Length
ntag213_tag.user_memory[idx++] = 0xD1; // MB=1, ME=1, SR=1, TNF=well-known
ntag213_tag.user_memory[idx++] = 0x01; // Type length
ntag213_tag.user_memory[idx++] = 20; // Payload length
ntag213_tag.user_memory[idx++] = 'U'; // Type: URI
ntag213_tag.user_memory[idx++] = 0x04; // https://
const char* url = "example.com/iot";
memcpy(&ntag213_tag.user_memory[idx], url, strlen(url));
idx += strlen(url);
ntag213_tag.user_memory[idx++] = 0xFE; // Terminator
Serial.println("NTAG213 initialized with URL: https://example.com/iot");
}
void initNTAG216() {
ntag216_tag.uid[0] = 0x04;
ntag216_tag.uid[1] = 0x12;
ntag216_tag.uid[2] = 0x34;
ntag216_tag.uid[3] = 0x56;
ntag216_tag.uid[4] = 0x78;
ntag216_tag.uid[5] = 0x9A;
ntag216_tag.uid[6] = 0xBC;
ntag216_tag.capability_container[0] = 0xE1;
ntag216_tag.capability_container[1] = 0x10;
ntag216_tag.capability_container[2] = 0x6D; // ~888 bytes
ntag216_tag.capability_container[3] = 0x00;
ntag216_tag.counter = 42;
memset(ntag216_tag.user_memory, 0, sizeof(ntag216_tag.user_memory));
// Smart Poster NDEF
int idx = 0;
ntag216_tag.user_memory[idx++] = 0x03; // NDEF TLV
ntag216_tag.user_memory[idx++] = 50; // Length
ntag216_tag.user_memory[idx++] = 0xD1; // Header
ntag216_tag.user_memory[idx++] = 0x02; // Type length
ntag216_tag.user_memory[idx++] = 46; // Payload length
ntag216_tag.user_memory[idx++] = 'S'; // Smart Poster
ntag216_tag.user_memory[idx++] = 'p';
// Nested URI
ntag216_tag.user_memory[idx++] = 0x91; // MB=1, ME=0
ntag216_tag.user_memory[idx++] = 0x01;
ntag216_tag.user_memory[idx++] = 20;
ntag216_tag.user_memory[idx++] = 'U';
ntag216_tag.user_memory[idx++] = 0x04;
const char* sp_url = "github.com/iot-lab";
memcpy(&ntag216_tag.user_memory[idx], sp_url, strlen(sp_url));
idx += strlen(sp_url);
ntag216_tag.user_memory[idx++] = 0xFE;
Serial.println("NTAG216 initialized with Smart Poster");
}
void initDESFire() {
desfire_tag.uid[0] = 0x04;
desfire_tag.uid[1] = 0xDE;
desfire_tag.uid[2] = 0x5F;
desfire_tag.uid[3] = 0x1E;
desfire_tag.uid[4] = 0xE0;
desfire_tag.uid[5] = 0x01;
desfire_tag.uid[6] = 0x23;
desfire_tag.sak = 0x20;
desfire_tag.authenticated = true;
desfire_tag.counter = 157;
simulateCMAC(desfire_tag.uid, 7, desfire_tag.cmac);
Serial.println("DESFire EV2 initialized (secure tag simulation)");
}
// ========== TAG READING SIMULATION FUNCTIONS ==========
void simulateReadNTAG213() {
Serial.println("\n========================================");
Serial.println(" NFC TAG DETECTED: NTAG213");
Serial.println("========================================\n");
setLEDs(false, false, true);
delay(200);
Serial.println("--- TAG IDENTIFICATION ---");
Serial.print("Tag Type: NFC Forum Type 2 Tag\n");
Serial.print("IC: NTAG213 (NXP)\n");
Serial.print("UID (7 bytes): ");
printHex(ntag213_tag.uid, 7);
Serial.println();
Serial.println("\n--- MEMORY INFORMATION ---");
Serial.println("Total memory: 180 bytes");
Serial.println("User memory: 144 bytes");
Serial.println("\n--- CAPABILITY CONTAINER ---");
Serial.print("CC Bytes: ");
printHex(ntag213_tag.capability_container, 4);
Serial.println();
Serial.print("NDEF Magic: 0x");
Serial.print(ntag213_tag.capability_container[0], HEX);
Serial.println(ntag213_tag.capability_container[0] == 0xE1 ? " (valid)" : " (invalid!)");
Serial.println("\n--- NDEF MESSAGE ---");
Serial.println("Record Type: URI");
Serial.println("URI: https://example.com/iot");
Serial.println("\n--- SECURITY ANALYSIS ---");
Serial.println("UID Validation: PASS");
Serial.println("Note: NTAG213 has basic security (password protection only)");
setLEDs(true, false, false);
tagsRead++;
Serial.println("\n========================================\n");
}
void simulateReadNTAG216() {
Serial.println("\n========================================");
Serial.println(" NFC TAG DETECTED: NTAG216");
Serial.println("========================================\n");
setLEDs(false, false, true);
delay(250);
ntag216_tag.counter++;
Serial.println("--- TAG IDENTIFICATION ---");
Serial.print("Tag Type: NFC Forum Type 2 Tag (Extended)\n");
Serial.print("IC: NTAG216 (NXP)\n");
Serial.print("UID: ");
printHex(ntag216_tag.uid, 7);
Serial.println();
Serial.println("\n--- MEMORY INFORMATION ---");
Serial.println("User memory: 888 bytes");
Serial.println("\n--- NFC COUNTER ---");
Serial.print("Read counter: ");
Serial.println(ntag216_tag.counter);
Serial.println("Counter increments on each read - helps detect cloning");
Serial.println("\n--- NDEF MESSAGE ---");
Serial.println("Smart Poster detected:");
Serial.println(" URI: https://github.com/iot-lab");
Serial.println("\n--- SECURITY FEATURES ---");
Serial.println(" + NFC counter (anti-clone)");
Serial.println(" + Password protection available");
Serial.println(" - No cryptographic authentication");
setLEDs(true, false, false);
tagsRead++;
Serial.println("\n========================================\n");
}
void simulateReadDESFire() {
Serial.println("\n========================================");
Serial.println(" NFC TAG DETECTED: MIFARE DESFire EV2");
Serial.println("========================================\n");
setLEDs(false, false, true);
delay(300);
desfire_tag.counter++;
simulateCMAC(desfire_tag.uid, 7, desfire_tag.cmac);
Serial.println("--- TAG IDENTIFICATION ---");
Serial.println("Tag Type: NFC Forum Type 4 Tag");
Serial.println("IC: MIFARE DESFire EV2 (NXP)");
Serial.print("UID: ");
printHex(desfire_tag.uid, 7);
Serial.println();
Serial.print("SAK: 0x");
Serial.print(desfire_tag.sak, HEX);
Serial.println(" (ISO 14443-4 compliant)");
Serial.println("\n--- CRYPTOGRAPHIC SECURITY ---");
Serial.println("Encryption: AES-128 CBC");
Serial.println("Authentication: 3-pass mutual authentication");
Serial.print("Session authenticated: ");
Serial.println(desfire_tag.authenticated ? "YES" : "NO");
Serial.print("Transaction counter: ");
Serial.println(desfire_tag.counter);
Serial.print("CMAC: ");
printHex(desfire_tag.cmac, 8);
Serial.println();
Serial.println("\n--- SECURITY FEATURES ---");
Serial.println(" [+] AES-128 encryption");
Serial.println(" [+] Cryptographic authentication");
Serial.println(" [+] Transaction counter");
Serial.println(" [+] CMAC message authentication");
Serial.println(" [+] Anti-cloning protection");
Serial.println("\n--- RECOMMENDED APPLICATIONS ---");
Serial.println(" * Access control badges");
Serial.println(" * Transit ticketing");
Serial.println(" * Product authentication");
setLEDs(true, false, false);
tagsRead++;
Serial.println("\n========================================\n");
}
void simulateMaliciousTag() {
Serial.println("\n========================================");
Serial.println(" !! SECURITY ALERT: SUSPICIOUS TAG !!");
Serial.println("========================================\n");
setLEDs(false, true, true);
delay(100);
int attackType = random(1, 5);
switch (attackType) {
case 1:
Serial.println("ATTACK TYPE: Cloned Tag Detected");
Serial.println("-----------------------------------");
Serial.println("Indicators:");
Serial.println(" [!] Counter value is LOWER than expected");
Serial.println(" Expected: >= 158, Received: 42");
Serial.println(" [!] This suggests tag was cloned");
Serial.println("\nMitigation:");
Serial.println(" - Reject this tag");
Serial.println(" - Investigate security breach");
break;
case 2:
Serial.println("ATTACK TYPE: Malicious URL Injection");
Serial.println("--------------------------------------");
Serial.println("NDEF payload contains suspicious URL:");
Serial.println(" URL: https://secure-bank-login.tk/verify");
Serial.println("\nRed Flags:");
Serial.println(" [!] .tk domain (commonly used for phishing)");
Serial.println(" [!] Contains 'login', 'bank', 'verify' keywords");
Serial.println("\nMitigation:");
Serial.println(" - Block URL from opening");
Serial.println(" - Warn user about phishing attempt");
break;
case 3:
Serial.println("ATTACK TYPE: CMAC Validation Failed");
Serial.println("-------------------------------------");
Serial.println("Cryptographic authentication failed:");
Serial.println(" Expected CMAC: A5 B7 C9 D1 E3 F5 07 19");
Serial.println(" Received CMAC: 00 00 00 00 00 00 00 00");
Serial.println("\nPossible causes:");
Serial.println(" [!] Tag may be counterfeit");
Serial.println(" [!] Replay attack attempted");
Serial.println("\nMitigation:");
Serial.println(" - Reject authentication");
Serial.println(" - Log incident for review");
break;
case 4:
Serial.println("ATTACK TYPE: Invalid UID Format");
Serial.println("---------------------------------");
Serial.println("UID anomalies detected:");
Serial.println(" Received UID: FF FF FF FF FF FF FF");
Serial.println("\nIssues:");
Serial.println(" [!] All bytes are 0xFF (factory default)");
Serial.println(" [!] Likely an emulated/spoofed tag");
Serial.println("\nMitigation:");
Serial.println(" - Reject tag immediately");
Serial.println(" - Use cryptographic challenge-response");
break;
}
Serial.println("\n--- SECURITY RECOMMENDATIONS ---");
Serial.println("1. Never trust NFC tags blindly");
Serial.println("2. Validate URLs before opening");
Serial.println("3. Use cryptographic authentication");
Serial.println("4. Monitor for counter anomalies");
blinkLED(LED_SECURITY, 5, 100);
setLEDs(false, true, false);
securityAlerts++;
Serial.println("\n========================================");
Serial.print("Security alerts this session: ");
Serial.println(securityAlerts);
Serial.println("========================================\n");
}
// ========== MAIN SETUP AND LOOP ==========
void setup() {
Serial.begin(115200);
delay(1000);
Serial.println("\n");
Serial.println("========================================");
Serial.println(" NFC COMMUNICATION LAB");
Serial.println(" ESP32 Simulation");
Serial.println("========================================");
Serial.println("\nThis lab demonstrates NFC concepts:");
Serial.println(" - Tag types and memory structure");
Serial.println(" - NDEF message format parsing");
Serial.println(" - Security validation techniques");
Serial.println("\n----------------------------------------");
Serial.println("CONTROLS:");
Serial.println(" Button 1 (GPIO 12): Read NTAG213");
Serial.println(" Button 2 (GPIO 13): Read NTAG216 (Smart Poster)");
Serial.println(" Button 3 (GPIO 14): Read DESFire (secure)");
Serial.println(" Button 4 (GPIO 15): Malicious tag demo");
Serial.println("----------------------------------------\n");
pinMode(BTN_NTAG213, INPUT_PULLUP);
pinMode(BTN_NTAG216, INPUT_PULLUP);
pinMode(BTN_DESFIRE, INPUT_PULLUP);
pinMode(BTN_MALICIOUS, INPUT_PULLUP);
pinMode(LED_SUCCESS, OUTPUT);
pinMode(LED_SECURITY, OUTPUT);
pinMode(LED_PROCESSING, OUTPUT);
// Startup sequence
for (int i = 0; i < 3; i++) {
setLEDs(true, false, false);
delay(150);
setLEDs(false, true, false);
delay(150);
setLEDs(false, false, true);
delay(150);
}
setLEDs(false, false, false);
initNTAG213();
initNTAG216();
initDESFire();
Serial.println("\nReady! Press a button to simulate NFC tag reading.\n");
}
void loop() {
unsigned long currentTime = millis();
if (currentTime - lastButtonPress < DEBOUNCE_DELAY) {
return;
}
if (digitalRead(BTN_NTAG213) == LOW) {
lastButtonPress = currentTime;
simulateReadNTAG213();
}
else if (digitalRead(BTN_NTAG216) == LOW) {
lastButtonPress = currentTime;
simulateReadNTAG216();
}
else if (digitalRead(BTN_DESFIRE) == LOW) {
lastButtonPress = currentTime;
simulateReadDESFire();
}
else if (digitalRead(BTN_MALICIOUS) == LOW) {
lastButtonPress = currentTime;
simulateMaliciousTag();
}
// Idle LED pulse
static unsigned long lastPulse = 0;
static bool pulseState = false;
if (currentTime - lastPulse > 2000) {
pulseState = !pulseState;
digitalWrite(LED_PROCESSING, pulseState ? HIGH : LOW);
lastPulse = currentTime;
}
}881.3.4 Challenge Exercises
After completing the basic lab, try these advanced challenges:
Modify the NTAG216 initialization to include a Wi-Fi configuration record. The NDEF message should contain: - Network SSID: “IoT-Lab-Network” - Security type: WPA2 - Password: (simulated, not stored in plain text)
Hint: Use the application/vnd.wfa.wsc MIME type for Wi-Fi configuration records.
Add a function that tracks expected counter values for known tags. When a tag is read: 1. Look up the tag’s UID in a stored database 2. Check if the counter value is higher than the last recorded value 3. If the counter is lower or equal, flag as a potential clone 4. Update the stored counter value after successful validation
Real-world application: This technique is used by NTAG424 DNA for product authentication.
Design and implement a simulated NFC application for one of these scenarios: - Museum Guide: Store exhibit information with multiple language support - Business Card: Create a vCard record with contact details - IoT Device Pairing: Implement Bluetooth handover record
Expected output: Parse and display all record fields in a user-friendly format.
Enhance the malicious tag detection to check for: 1. URL shorteners: Detect and expand shortened URLs 2. Domain reputation: Check against a whitelist of trusted domains 3. NDEF format validation: Ensure all records follow proper structure 4. Payload size validation: Detect buffer overflow attempts
Security principle: Never trust user-provided data without validation.
881.3.5 Expected Outcomes
After completing this lab, you should be able to:
| Skill | Demonstration |
|---|---|
| Tag Type Recognition | Identify NTAG213, NTAG216, DESFire by their characteristics |
| NDEF Parsing | Decode URI, Text, and Smart Poster records |
| Security Analysis | Recognize cloned tags, suspicious URLs, and CMAC failures |
| Memory Calculation | Determine if NDEF payload fits in tag memory |
| Protocol Understanding | Explain P2P handshake and handover concepts |
The concepts demonstrated in this simulation directly apply to real NFC development:
| Simulation Component | Real Hardware Equivalent |
|---|---|
| Button triggers | PN532/RC522 tag detection interrupt |
| Simulated tag structs | Actual tag memory read via SPI/I2C |
| NDEF parsing functions | Libraries like NDEF_MFRC522 or ndef-js |
| Security validation | Server-side CMAC verification |
| Serial output | Mobile app or web dashboard |
Recommended hardware for next steps: - PN532 module: Full NFC support (all modes, all tag types) - RC522 module: MIFARE tags only, lower cost - ESP32 + PN532: Complete IoT NFC solution
881.3.6 Knowledge Check
Question 1: In the simulation, NTAG213 has 144 bytes of user memory. If you need to store a Smart Poster with a 50-byte URL, 30-byte title, and icon thumbnail, which tag should you use instead?
Explanation: Smart Posters with multiple nested records (URI + Title + Icon) require more memory than basic NTAG213 provides. NTAG216 with 888 bytes is the appropriate choice for larger payloads. DESFire does not have “unlimited” memory, and Smart Posters do not compress automatically.
Question 2: The DESFire simulation shows CMAC verification. Why is CMAC important for NFC security?
Explanation: CMAC (Cipher-based Message Authentication Code) is a cryptographic mechanism that ensures message integrity and authenticity. It prevents tampering and verifies that the data comes from a legitimate source with the correct cryptographic keys.
Question 3: The malicious tag simulation detected a “counter anomaly” when the counter value was lower than expected. What attack does this indicate?
Explanation: NFC counters increment with each read and cannot be reset. If a tag shows a counter value lower than previously recorded, it indicates the tag was cloned at an earlier point (before the counter reached its current value on the legitimate tag). This is why counters are valuable for anti-cloning protection.
881.4 Summary
This hands-on lab covered:
- Tag Simulation: NTAG213, NTAG216, and DESFire tag characteristics
- NDEF Parsing: Decoding URI, Text, and Smart Poster records
- Security Validation: UID verification, counter checks, CMAC authentication
- Attack Detection: Cloning, phishing URLs, spoofed UIDs
- Real Hardware Transition: Mapping simulation concepts to PN532/RC522 development
881.5 What’s Next
Return to the NFC Fundamentals index for links to related NFC chapters, or explore:
- NFC Security and Comparisons - Advanced security topics
- NFC Applications - Real-world implementations
- RFID Fundamentals - NFC’s parent technology