Skip to main content
Esta página documenta la implementación del lector por HID para que su exposición de datos pueda auditarse. Para la guía de recuperación de usuario, ve a Modo sin pantalla. El modo hace que el dispositivo teclee el estado actual de la pantalla por USB HID (teclado), línea a línea, para que una unidad con el OLED muerto pueda igualmente desbloquearse y operarse a ciegas. La implementación está en ZerokeyOS/zerokey-utils.cpp (emisor), zerokey-io.cpp (gesto) y zerokey-menu.cpp (conmutador persistente).

Estado y activación

  • Flag en tiempo de ejecución screenReaderMode (zerokey-globals.cpp, por defecto false).
  • Flag persistente en EEPROM en EEPROM_SCREEN_READER_ADDR = 0x0003 (1 = arrancar directamente en modo lector). initScreenReaderMode() lo lee y aplica en el arranque; Ajustes → “Reader: On/Off” (setScreenReaderPersistent) lo escribe y voltea el flag de ejecución para que el cambio surta efecto al instante.
  • Gesto de sesión: mantén Centro 10 s (SCREEN_READER_HOLD_MS = 10000) con la pantalla de PIN visible (PIN_SCREEN/EDITPIN). Una animación de borde se rellena durante los 10 s completos y voltea screenReaderMode justo al completarse.
El gesto se restringe deliberadamente a la pantalla de PIN para que sea accesible antes de desbloquear — el objetivo es rescatar un dispositivo cuya pantalla murió. Soltar antes de los 10 s no hace nada.

Qué emite (mecánica de la línea-eco)

El dispositivo mantiene una línea lógica en el host. announceCurrentScreen():
  • cachea el texto en g_lastEcho y la longitud en g_hidEchoLen;
  • ante un cambio de estado, borra con retroceso el eco anterior y teclea el nuevo (los estados sin cambios no se reteclean → sin parpadeo);
  • pone g_suppressNextAnnounce para saltarse el anuncio automático que si no se duplicaría justo después de teclear una credencial real.
La salida HID usa una cadencia fija (hidTapKey): pulsar, 12 ms, releaseAll, 18 ms; \nKEY_RETURN, \tKEY_TAB.
PantallaLínea emitida
Entrada de PINPIN 125 >7 — dígitos introducidos, luego el dígito seleccionado (>OK = tic de confirmar)
Credencial (sitio)3: google.com
Campos de credencial3: user, 3: password, 3: 2FA
MenúMenu: <elemento seleccionado>
Página de confirmación<título> Hold=OK Left=No
Entrada de PIN a ciegas: Arriba/Abajo cambian el dígito seleccionado (mira >n), Derecha lo añade, Izquierda borra, luego selecciona >OK y Derecha/Centro para desbloquear — la línea tecleada refleja lo que mostraría el OLED. Revelar un valor: pulsar Centro en una credencial borra el eco (typeCredential retrocede g_hidEchoLen) y teclea el valor real (usuario/contraseña) exactamente como lo haría el tecleo HID normal — así puedes leer una contraseña a ciegas en un campo de texto enfocado.

Frontera de exposición de datos (lo relevante para auditar)

El lector teclea dígitos del PIN y, con un Centro explícito, contraseñas en el campo que esté enfocado. Úsalo solo en un campo de texto privado que controles, y bórralo después.
Dos propiedades importan para una auditoría:
  1. Sin canal de salida nuevo. El lector solo emite (a) la única línea de estado que mostraría el OLED, o (b) — con un Centro explícito — el mismo valor que typeCredential ya teclea en uso normal. No expone nada que un usuario con vista no pudiera obtener ya por HID.
  2. La semilla Bitcoin nunca se teclea. El visor de semilla (btcDisplaySeed) dibuja solo en el OLED y no tiene ruta HID; el lector no tiene ninguna rama que emita palabras de semilla ni entropía. Una unidad con la pantalla rota por tanto sigue sin poder filtrar la semilla Bitcoin por USB. (Ver Firmante Bitcoin.)

Cómo auditarlo tú mismo

1

Enumera los emisores

Grepea announceCurrentScreen y hidTypeText/hidTapKey en zerokey-utils.cpp. Confirma que cada punto de llamada corresponde a una pantalla que el OLED ya muestra, y que ninguno lee la página de cartera ZKBW ni las palabras de semilla.
2

Confirma el alcance del gesto

En zerokey-io.cpp, verifica que el conmutador de 10 s está condicionado a programPosition == PIN_SCREEN || EDITPIN y SCREEN_READER_HOLD_MS.
3

Confirma la persistencia

Verifica que el flag persistente es un único byte en EEPROM_SCREEN_READER_ADDR (0x0003) y que solo alterna el mismo comportamiento de ejecución.

Mapa de código

AspectoDónde
Emisor, línea-eco, revelado de credencialZerokeyOS/zerokey-utils.cpp
Gesto de activación de 10 sZerokeyOS/zerokey-io.cpp
Conmutador persistente “Reader: On/Off”ZerokeyOS/zerokey-menu.cpp
Flag de ejecución y persistente, dirección EEPROMZerokeyOS/zerokey-globals.{h,cpp}

Guía de usuario

Activa y usa el modo con la pantalla muerta.

Firmante Bitcoin

Por qué la semilla nunca se expone, ni siquiera aquí.