Material de clave
La clave maestra AES es un valor aleatorio de 16 bytes generado por el TRNG del ATECC608A al primer arranque, escrito al slot 8 del chip, y luego bloqueado por el lock de la zona de datos.
Como
IsSecret=1 se aplica antes de bloquear la zona de datos, incluso un atacante con acceso físico I²C no puede leer la clave AES del chip — el comando Read se niega a devolverla.
¿Por qué el chip y no el MCU?
El firmware anterior corría AES software en el SAMD21 con la clave guardada en EEPROM, porque la varianteMAHDA-T del ATECC608A se entrega con el comando AES hardware deshabilitado. Habilitarlo requiere:
- Escribir el bit
AES_Enable(byte 13, bit 0) de la Config Zone. - Configurar el slot 8 con
KeyType=6(AES). - Bloquear la Config Zone para que esos ajustes tomen efecto.
Implementación del encadenamiento CBC
Las funcionescbcEncrypt32 / cbcDecrypt32 en zerokey-security.cpp procesan cada campo de credencial de 32 bytes como dos bloques de 16 bytes encadenados contra el IV del dispositivo:
Cifrado
Descifrado
Formato wire de cada llamada AES
Para cada bloque de 16 bytes:
Cada llamada tarda ~10 ms incluyendo el overhead I²C.
Padding
Cada campo de credencial (sitio, usuario, contraseña) son hasta 32 bytes en RAM. Antes del cifrado:- Los caracteres espacio (
0x20) finales se reemplazan con0xFFdesde el final hacia dentro. - El campo llena directamente el buffer de página de 32 bytes; cualquier cola sin usar queda en
0xFF.
bufferToString() quita los bytes 0xFF y lee hasta \0 o 0xFF.
Flujo por operación
lock() — cifrar y escribir credenciales
- Reemplazar espacios finales en
currentSite,currentUser,currentPasscon0xFF. - Cargar el IV desde EEPROM (
loadIVfromEEPROM()). - Para cada uno de los 3 campos:
- Copiar hasta 32 bytes al buffer de 32 bytes, rellenando cualquier cola sin usar con
0xFF. - Llamar a
cbcEncrypt32(iv, plain, encrypted)— dos llamadas AES al ATECC por debajo. - Escribir el ciphertext de 32 bytes a la página correcta de EEPROM.
- Copiar hasta 32 bytes al buffer de 32 bytes, rellenando cualquier cola sin usar con
unlock() — descifrar y cargar credenciales
- Cargar el IV desde EEPROM.
- Comprobación de auto-curación: si el slot 0 página 0 es
0xFFcrudo, llamar asilentEraseAll(). - Para cada uno de los 3 campos:
- Leer el ciphertext de 32 bytes desde EEPROM.
- Llamar a
cbcDecrypt32(iv, encrypted, decrypted)— dos llamadas AES al ATECC. - Copiar los 32 bytes a
currentSite/currentUser/currentPass.
Reporte de errores
Cuando un round-trip AES falla, el firmware preserva el código de respuesta del chip y lo muestra en el OLED en lugar de un error genérico. El formato esAES E<n> RC<x> SS<XX> más una segunda línea LC=<x> LV=<x> KT=<n> que muestra el estado de lock y key-type del chip en el momento del fallo:
RC es el código de nivel driver (-1 wake, -2 I²C, -3 CRC, -4 chip status error, -5 timeout). SS es el byte de status crudo del chip (0x0F execution error, 0x03 parse, 0x07 self-test, …). La combinación te dice exactamente por qué el chip rechazó la llamada. Locked + KT=1 (en lugar de 6) significa que el chip está permanentemente mal configurado para AES; ese es el único modo de fallo que no se puede limpiar con un reinicio.