A diferencia de las viejas tarjetas de 125 kHz que solo "escupían" un número fijo, las tarjetas Mifare (estándar ISO/IEC 14443A) son computadoras microscópicas con memoria EEPROM y procesadores criptográficos internos.
Tienen 1 Kilobyte de memoria dividido en 16 Sectores. Cada Sector tiene 4 Bloques (de 16 bytes cada uno). La magia ocurre en el último bloque de cada sector (El Bloque Tráiler). Este bloque no guarda datos; guarda dos contraseñas secretas de 48 bits: la Key A y la Key B.
El Sector 0 contiene el UID (Número de Serie único). Este sector NO tiene clave y es público. Por eso, leer el UID es trivial e inseguro.
Para crear un sistema seguro, tu Despachador jamás confiará en el UID. En su lugar, el algoritmo industrial es el siguiente:
Circuito (Módulo RFID vía SPI): Los módulos lectores industriales (como el chip NXP MFRC522 o PN532) se comunican con el STM32 usando el bus SPI (Serial Peripheral Interface). Son 4 líneas de datos (MISO, MOSI, SCK, CS). Sin embargo, la regla de oro del bajo consumo y RTOS es usar el pin de Interrupción (IRQ) del módulo. Nunca hagas *Polling* infinito leyendo el SPI para ver si hay tarjeta; conecta el pin IRQ del lector a un pin de interrupción (EXTI) de tu STM32. Así, el microcontrolador duerme tranquilamente hasta que el hardware de radio detecta una antena acercándose.
Ejercicio 1: Máquina de Estados Criptográfica MISRA-C. Programaremos el proceso de autenticación. Este flujo debe ser estricto: Detección -> Petición Crypto1 -> Lectura de Memoria -> Validación de Datos (Checksum interno).
/**
* @file rfid_mifare_auth.c
* @brief Tarea RTOS de Autenticación Criptográfica RFID (Mifare 1K) - MISRA-C
*/
#include "stm32f401xe.h"
#include "cmsis_os2.h"
#include <stdint.h>
#include <stdbool.h>
// =========================================================================
// DEFINICIONES CRIPTOGRÁFICAS DE FLOTILLA (SECRETO INDUSTRIAL)
// =========================================================================
// Nunca uses la llave por defecto (0xFF 0xFF 0xFF 0xFF 0xFF 0xFF)
// Esta llave debe inyectarse encriptada desde AWS, pero la definimos como constante para el ejemplo.
static const uint8_t LLAVE_A_EMPRESA[6] = {0x4A, 0x9B, 0xC1, 0x33, 0xF2, 0x88};
// Elegimos un sector aleatorio (ej. Sector 4) para guardar los datos.
// El Sector 4 abarca los Bloques 16, 17, 18 y el Trailer 19.
#define SECTOR_FLOTILLA (4U)
#define BLOQUE_DATOS_CLIENTE (16U)
// =========================================================================
// MÁQUINA DE ESTADOS RFID
// =========================================================================
typedef enum {
RFID_ESTADO_DORMIDO = 0U,
RFID_ESTADO_DETECTANDO = 1U,
RFID_ESTADO_AUTENTICANDO= 2U,
RFID_ESTADO_LEYENDO = 3U,
RFID_ESTADO_RECHAZADO = 4U
} RFID_FSM_t;
// Bandera levantada por la interrupción de hardware del chip RC522 (Pin IRQ)
extern osEventFlagsId_t rfid_event_flag;
#define FLAG_TARJETA_PRESENTE (1U << 0)
// =========================================================================
// TAREA RTOS DE CONTROL DE ACCESO
// =========================================================================
void Task_RFID_ControlAcceso(void *argument) {
RFID_FSM_t estado_rfid = RFID_ESTADO_DORMIDO;
uint8_t buffer_lectura[16];
uint8_t uid_tarjeta[4];
// Iniciar Módulo RC522 vía SPI (Configura ganancia de antena e interrupciones)
RC522_Init_SPI();
for(;;) {
switch (estado_rfid) {
case RFID_ESTADO_DORMIDO:
// El procesador bloquea esta tarea hasta que el PIN IRQ del Módulo RFID se active.
// Consumo de CPU: 0%.
osEventFlagsWait(rfid_event_flag, FLAG_TARJETA_PRESENTE, osFlagsWaitAny, osWaitForever);
estado_rfid = RFID_ESTADO_DETECTANDO;
break;
case RFID_ESTADO_DETECTANDO:
// Leemos el UID. No nos importa para la seguridad, pero es necesario
// pasárselo a la función de autenticación criptográfica.
if (RC522_AntiCollision_ReadUID(uid_tarjeta) == MFRC522_STATUS_OK) {
estado_rfid = RFID_ESTADO_AUTENTICANDO;
} else {
estado_rfid = RFID_ESTADO_RECHAZADO; // Tarjeta se alejó muy rápido
}
break;
case RFID_ESTADO_AUTENTICANDO:
// PASO CRÍTICO: Solicitamos al chip RFID que ejecute el algoritmo Crypto1
// intentando abrir el Sector 4 usando nuestra Llave A secreta.
uint8_t status_auth = RC522_Authenticate(
PICC_CMD_MF_AUTH_KEY_A,
BLOQUE_DATOS_CLIENTE,
(uint8_t*)LLAVE_A_EMPRESA,
uid_tarjeta
);
if (status_auth == MFRC522_STATUS_OK) {
estado_rfid = RFID_ESTADO_LEYENDO;
} else {
// La tarjeta es de otra gasolinera, o es un clon "Magic" sin la llave.
estado_rfid = RFID_ESTADO_RECHAZADO;
}
break;
case RFID_ESTADO_LEYENDO:
// Si llegamos aquí, el sector está descifrado y abierto.
if (RC522_ReadBlock(BLOQUE_DATOS_CLIENTE, buffer_lectura) == MFRC522_STATUS_OK) {
// Extraemos los datos (ej. ID de Flotilla, Saldo Prepago)
uint32_t id_cliente_hex = (buffer_lectura[0] << 24) | (buffer_lectura[1] << 16) |
(buffer_lectura[2] << 8) | buffer_lectura[3];
// Autorizamos el Despacho
// Despachador_Habilitar_Venta(id_cliente_hex);
// Imprimimos en Pantalla LCD
// LCD_Mostrar_Mensaje("Acceso Autorizado");
}
// MISRA-C: SIEMPRE detener la sesión criptográfica para que no quede abierta.
RC522_StopCrypto1();
estado_rfid = RFID_ESTADO_DORMIDO;
break;
case RFID_ESTADO_RECHAZADO:
// LCD_Mostrar_Mensaje("Tarjeta Invalida!");
RC522_StopCrypto1(); // Por seguridad
// Un pequeño delay para evitar que pite 10 veces por segundo
osDelay(pdMS_TO_TICKS(1000U));
estado_rfid = RFID_ESTADO_DORMIDO;
break;
default:
estado_rfid = RFID_ESTADO_DORMIDO;
break;
}
}
}
Objetivo del día: Control de Acceso Criptográfico y Gestión de Flotillas (B2B).
El mercado de las gasolineras está saturado. La forma en que las empresas despachadoras ganan millones hoy en día es ofreciendo contratos corporativos (B2B) a empresas con flotillas de camiones repartidores (ej. Bimbo, Coca-Cola). El administrador de la flotilla no quiere darle dinero en efectivo a sus choferes; quiere que lleguen a tu máquina de Gas LP, pongan una tarjeta RFID y carguen gas. Al final del mes, el sistema en la nube factura todo automáticamente.
Si construyes tu máquina leyendo el UID de la tarjeta (el error de los novatos), un chofer malicioso puede clonar su tarjeta con su celular Android (NFC), dársela a sus amigos y robar gas a cuenta de la empresa corporativa. Tú serías el responsable legal del robo por tener un hardware vulnerable. Al implementar **Autenticación de Sectores Criptográficos Mifare (Crypto1/AES)**, fuerzas al lector RFID de la placa a exigir una contraseña oculta que no puede ser clonada copiando el número de serie. Tu diseño de hardware acaba de habilitar un modelo de negocio Multi-Millonario (Gestión de Flotillas) blindado contra fraudes. Ese es el valor de la ingeniería segura.
PICC_HaltA y limpieza del hardware StopCrypto1) para impedir que un atacante "secuestre" el túnel de lectura si no quita la tarjeta.