Si proteges tu firmware con encriptación simétrica (como AES-256), necesitas guardar la contraseña secreta dentro del código del STM32 para que pueda desencriptarlo. Si un hacker avanzado logra hacer un ataque de "Fault Injection" (Inyección de Fallos por láser o voltaje) al procesador y extrae esa contraseña secreta de la memoria, el juego terminó: el hacker podrá firmar sus propios virus usando tu llave secreta y la flota entera los aceptará.
La **Criptografía Asimétrica (RSA o ECDSA)** soluciona esto usando un par de llaves vinculadas matemáticamente:
firmware.bin de 192KB y le calculas un Hash criptográfico (SHA-256). Esto genera una huella digital única de 32 bytes. Luego, encriptas esa huella usando tu Llave Privada RSA. El resultado es la Firma Digital, que se anexa al final del archivo .bin.Librerías Criptográficas en Bare-Metal: Escribir una función RSA o de Curva Elíptica (ECDSA) desde cero es un error fatal; los atacantes analizarán el consumo de corriente de tu chip (*Side-Channel Attack*) para robar la llave. Siempre debes usar librerías criptográficas de grado industrial optimizadas para sistemas embebidos, como mbedTLS o TinyCrypt.
Ejercicio 1: La Compuerta Lógica del Salto. Escribiremos la función C que envuelve la validación Secure Boot en el Bootloader. Asumiremos que el archivo binario FOTA descargado tiene la firma adjunta en los últimos 256 bytes (tamaño típico de una firma RSA-2048).
/**
* @file secure_boot_rsa.c
* @brief Validación Criptográfica Asimétrica del Firmware FOTA (MISRA-C)
*/
#include "stm32f401xe.h"
#include <stdint.h>
#include <stdbool.h>
// Simulación de inclusión de librería criptográfica (ej. mbedTLS)
#include "crypto_mbedtls_port.h"
// =========================================================================
// DEFINICIONES DE DIRECCIONES Y TAMAÑOS
// =========================================================================
#define APP_BASE_ADDRESS (0x08010000U)
#define OTA_MAX_FIRMWARE_SIZE (192U * 1024U) // 192 KB
#define RSA_2048_SIGNATURE_SIZE (256U) // 2048 bits = 256 bytes
#define SHA256_HASH_SIZE (32U) // 256 bits = 32 bytes
// =========================================================================
// LA LLAVE PÚBLICA INCRUSTADA EN EL BOOTLOADER (Solo Lectura)
// =========================================================================
// Esta llave se genera en la computadora del desarrollador y se compila
// directamente en el código del Bootloader (.rodata). No es secreta.
const uint8_t LLAVE_PUBLICA_RSA_2048[] = {
0x30, 0x82, 0x01, 0x22, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86,
// ... [200+ bytes omitidos por brevedad] ...
0x02, 0x03, 0x01, 0x00, 0x01
};
// Funciones Externas (Del Archivo bootloader_jump.c del Día 257)
extern void Ejecutar_Salto_A_Aplicacion(void);
extern void Entrar_Modo_Emergencia_Brick(void);
extern void IAP_Borrar_Slot_Aplicacion(void);
// =========================================================================
// EL MOTOR DEL SECURE BOOT (ZERO-TRUST)
// =========================================================================
/**
* @brief Extrae el firmware, calcula su huella física, desencripta la
* firma con la llave pública y determina si el código es auténtico.
* @param app_address Dirección base de la Aplicación en Flash.
* @param app_size_bytes Tamaño exacto del binario (sin contar la firma).
* @retval bool TRUE si la firma es válida e inquebrantable.
*/
bool SecureBoot_Validar_Autenticidad(uint32_t app_address, uint32_t app_size_bytes) {
// 1. Sanity Checks Básicos
if ((app_size_bytes == 0U) ||
((app_size_bytes + RSA_2048_SIGNATURE_SIZE) > OTA_MAX_FIRMWARE_SIZE)) {
return false;
}
// 2. Extraer los componentes de la memoria Flash
// El firmware es todo el bloque desde el inicio hasta el tamaño indicado.
const uint8_t* p_firmware_data = (const uint8_t*)app_address;
// La firma está anexada exactamente al final del binario
const uint8_t* p_firma_rsa = (const uint8_t*)(app_address + app_size_bytes);
// 3. CALCULAR EL HASH SHA-256 DEL FIRMWARE FÍSICO
uint8_t hash_calculado[SHA256_HASH_SIZE];
// Esta función del motor criptográfico recorre todo el código .bin
// y lo condensa en 32 bytes garantizando que ni un "1" ni un "0" haya cambiado.
if (Crypto_SHA256_Calculate(p_firmware_data, app_size_bytes, hash_calculado) != CRYPTO_OK) {
return false;
}
// 4. VERIFICACIÓN ASIMÉTRICA RSA
// El motor usa la LLAVE PÚBLICA para revertir el algoritmo RSA sobre la firma,
// extrayendo el Hash que el programador encriptó en la nube. Luego lo compara
// internamente contra 'hash_calculado'.
int32_t verificacion = Crypto_RSA_Verify_Signature(
LLAVE_PUBLICA_RSA_2048, sizeof(LLAVE_PUBLICA_RSA_2048),
p_firma_rsa, RSA_2048_SIGNATURE_SIZE,
hash_calculado, SHA256_HASH_SIZE
);
if (verificacion == CRYPTO_SIGNATURE_MATCH) {
return true; // EL CÓDIGO ES DE NUESTRA AUTORÍA Y ESTÁ INTACTO
}
return false; // FRAUDE O CORRUPCIÓN DETECTADA
}
// =========================================================================
// BOOT SEQUENCE PRINCIPAL
// =========================================================================
void Bootloader_Main_Sequence(void) {
// Asumimos que el Header de metadatos nos da el tamaño real del firmware instalado
uint32_t tamano_binario_actual = *(uint32_t*)(APP_BASE_ADDRESS + 0x200);
// EL CERROJO DE CONFIANZA
if (SecureBoot_Validar_Autenticidad(APP_BASE_ADDRESS, tamano_binario_actual)) {
// El código fue verificado matemáticamente. Cedemos el control.
Ejecutar_Salto_A_Aplicacion();
} else {
// ¡CÓDIGO MALICIOSO O CORRUPTO EN LA FLASH!
// No podemos saltar. Acción drástica para proteger la IP y los usuarios:
IAP_Borrar_Slot_Aplicacion(); // Borramos la aplicación entera.
// Levantamos bandera roja en Hardware
Entrar_Modo_Emergencia_Brick();
}
}
Objetivo del día: Autenticación Criptográfica Asimétrica y Filosofía Zero-Trust.
En el Día 268 cerramos la puerta del hardware con un candado RDP para que nadie pueda sacar tu código. Hoy, en el Día 269, pusimos un guardia armado en la puerta de entrada (Bootloader) para que nadie pueda meter código extraño. Si un ciberdelincuente se roba el ESP32 de una de tus máquinas, le inyecta un firmware hackeado que ignora los precios del gas, y usa el cable UART para enviarlo al STM32, tu Bootloader lo recibirá felizmente. Pero justo antes de ejecutar la primera instrucción, el Bootloader exigirá el "Pasaporte Criptográfico" (Firma RSA). Como el hacker no tiene la Llave Privada que está guardada bajo llave en tus servidores de AWS, la firma generada será inválida. El STM32, implacable, borrará el código fraudulento y colgará la máquina, bloqueando el robo físico de hidrocarburos. El Bootloader seguro es la frontera final entre un dispositivo vulnerable y un Activo Crítico Industrial inviolable.