ZeroKeyUSB guarda todos los secretos dentro de una EEPROM externa ST M24C64-WMN6TP (64 Kbit = 8 KB). El firmware gestiona lecturas y escrituras con cuidado, respetando los límites de página y manteniendo todos los datos de credenciales cifrados en reposo.Documentation Index
Fetch the complete documentation index at: https://docs.zerokeyusb.com/llms.txt
Use this file to discover all available pages before exploring further.
Mapa de memoria
La EEPROM está organizada en una zona de configuración (primeros ~220 bytes) y una zona de credenciales (resto):| Dirección | Tamaño | Contenido | Fuente en código |
|---|---|---|---|
0x0000 | 1 B | Flag del asistente de config (0x42 = hecho) | zerokey-setup.cpp |
0x0001 | 1 B | Orientación de pantalla (0 = normal, 1 = invertida) | EEPROM_SCREEN_MODE_ADDR |
0x0002 | 1 B | Contador soft de intentos fallidos (backoff UX) | FAILED_ATTEMPTS_ADDR |
0x0010–0x001F | 16 B | Vector de inicialización AES-CBC | EEPROM_IV_ADDR |
0x0020–0x0023 | 4 B | Umbral de intentos de PIN (LE uint32) | EEPROM_THRESHOLD_ADDR |
0x0024 | 1 B | Flag de aprovisionamiento (0xA5 = aprovisionado) | EEPROM_PROVISION_FLAG |
0x0028–0x0037 | 16 B | Reservado. Contenía la clave maestra AES en firmware anteriores; la clave ahora vive en el slot 8 del ATECC y nunca toca la EEPROM. | — |
0x003E | 1 B | Selector de layout de teclado (0–8) | EEPROM_LAYOUT_ADDR |
0x0040–0x0047 | 8 B | Último epoch TOTP (big-endian) | EEPROM_LAST_TOTP_EPOCH_ADDR |
0x0048–0x0067 | 32 B | Hash de PIN: SHA-256(PIN ∥ serial) | EEPROM_PIN_HASH |
0x0068–0x00E3 | 124 B | Metadatos TOTP: 2 B × 62 slots (algoritmo + secret_len) | CONFIG_TOTP_META_START |
0x0100–0x1FFF | 7 936 B | 62 slots de credenciales (128 B cada uno = 4 páginas × 32 B) | EEPROM_CREDENTIAL_BASE |
Estructura del slot de credencial
Cada uno de los 62 slots de credenciales ocupa 4 páginas consecutivas de 32 bytes en EEPROM (128 bytes en total): Cada página de 32 bytes contiene:- 16 bytes de texto plano (rellenados con
0xFF) cifrados como dos bloques AES-128 CBC - El cifrado usa el IV global del dispositivo más la clave maestra AES que vive dentro del slot 8 del ATECC — las rondas del cifrador corren en el chip, nunca en el MCU.
status o CRC separado por página. Los slots vacíos se escriben como blancos 0xFF cifrados durante silentEraseAll().
Cálculo de dirección de página
FIRST_CREDENTIAL_PAGEse calcula a partir deCONFIG_TOTP_META_ENDredondeado al siguiente límite de 32 bytes.slotIndexva de 0 a 61.pageIndexva de 0 (sitio) a 3 (TOTP).
Secuencia de escritura
La funciónwriteEepromPage() escribe 32 bytes en una dirección alineada a página:
- Comprueba la presencia de EEPROM vía
Wire.beginTransmission()+ test de ACK. - Envía la dirección de 2 bytes (MSB primero) seguida de 32 bytes de datos.
- Espera 10 ms para el ciclo de escritura interno de la EEPROM.
- Devuelve
truesiWire.endTransmission()no reportó error.
eepromWriteRaw() en zerokey-security.cpp divide los datos en los límites de 32 bytes para evitar el comportamiento de wrap-around de direcciones del M24C64.
Secuencia de lectura
readEepromPage() lee exactamente 32 bytes:
- Envía la dirección de 2 bytes vía escritura I²C.
- Emite
Wire.requestFrom(eepromAddress, 32). - Lee todos los bytes disponibles al buffer de salida.
- Rellena con ceros los bytes no recibidos (lectura parcial = error).
Metadatos TOTP
Cada slot de credencial tiene una entrada de metadatos TOTP de 2 bytes en la zona de configuración:| Byte | Contenido |
|---|---|
| 0 | Código de algoritmo: 0 = ninguno, 1 = SHA-1, 2 = SHA-256, 3 = SHA-512 |
| 1 | Longitud del secreto en bytes crudos (antes de codificar en Base32) |
Características de desgaste
- La M24C64-WMN6TP soporta >1 millón de ciclos de escritura por página (garantía del datasheet).
- Las páginas de credenciales solo se reescriben cuando el usuario edita un campo o importa datos.
- Las páginas de la zona de configuración (IV, hash de PIN, umbral) se escriben durante el aprovisionamiento y cambios de PIN — eventos infrecuentes.
- El epoch TOTP en
0x0040se actualiza cada vez que el usuario sincroniza la hora o genera un código — es la ubicación más escrita. - Como las credenciales suelen ser estáticas, la vida útil esperada de la EEPROM supera las décadas de uso normal.
Resolución de problemas
| Síntoma | Causa | Solución |
|---|---|---|
EEPROM not found | Conexión I²C rota | Comprueba las soldaduras; verifica los pull-ups en SDA/SCL |
EEPROM write 0xNNN | Escritura fallida en la dirección | Reintenta; si persiste, la EEPROM puede estar dañada |
| Credenciales corruptas | IV o clave AES cambió sin re-cifrar | Reset de fábrica + re-aprovisionar; restaurar desde backup |
| El slot aparece en blanco tras importar | Parsing del secreto TOTP falló | Verifica codificación Base32; verifica soporte del algoritmo |
Ninguna credencial descifrada toca memoria persistente sin acción explícita del usuario. El texto plano solo existe en SRAM durante la sesión activa.