Kleidos Security Overview#
Kleidos is a hardware BLE password manager. This document is the entry point for
two audiences: a user who wants a plain-language answer to "how safe is this?",
and an auditor or developer who needs to navigate the full set of technical
security documents.
How safe is Kleidos, and why?#
Your passwords never leave the device as plain text. The vault — the encrypted
database on the device — can only be opened with your PIN, and the PIN never
travels over any radio or wire.
Encryption on the device. Every credential is encrypted with AES-256 before
being written to storage. A wrong PIN produces a completely different key, so
there is no way to guess whether a PIN attempt was "close". Every encrypted file
also carries an authentication tag that is checked before any decryption happens,
so a physically tampered device is detected and rejected.
PIN and escalating lockout. PIN failures are counted in persistent storage so
they survive power cycles and deep sleep. After four consecutive wrong PINs the
device locks for 30 seconds. From the seventh wrong attempt the lockout extends to
5 minutes. After ten wrong PINs the vault is permanently wiped. There is no way to
bypass these lockouts without physically re-flashing the device — and a re-flash
wipes the vault too.
BLE that types, not broadcasts. The device does not permanently broadcast over
Bluetooth. BLE is activated only after you unlock the device and select a
credential. Pairing requires Numeric Comparison — you confirm a six-digit code on
both sides — so a nearby attacker cannot intercept the link silently. After typing
the credential, BLE shuts down.
Admin WiFi when you need it. WiFi is only active in admin mode, which you
enter deliberately. The admin WiFi access point uses WPA3 and requires PMF
(Protected Management Frames); the password is random and exists only for the
duration of the session. BLE is always turned off before admin WiFi starts.
Production hardware locks down further. Devices built with the _secure
build target add Secure Boot v2 (the bootloader is signed and verified on every
power-on), Flash Encryption (storage is encrypted at the chip level), and NVS
encryption. On ESP32-S3 boards the vault key is also bound to a secret burned into
the chip's eFuse — even if someone reads the flash chips off the board, they
cannot guess PINs offline without that chip. JTAG debug access is disabled.
Deep sleep by default. When the device is not in use it enters deep sleep,
drawing less than 20 µA. Every subsystem — BLE, WiFi, display backlight — must be
fully shut down before sleep. Missing a shutdown path is treated as a bug, not a
warning.
Security controls at a glance#
| Control |
What it protects |
Where documented |
| AES-256-CBC + HMAC-SHA256, encrypt-then-MAC |
Vault data at rest; tamper detection |
vault-encryption.md |
| PBKDF2-SHA256 (175 000 iters on S3; 40 000 on classic ESP32) |
Key derivation from PIN; GPU brute-force resistance |
vault-encryption.md |
| Verify-before-decrypt, constant-time compare |
Padding-oracle prevention; timing side-channel |
vault-encryption.md |
Sub-key domain separation (kleidos-enc / kleidos-mac / kleidos-pin) |
Cross-key confusion |
vault-encryption.md |
HKDF-SHA256 device binding (_secure only) |
Offline PIN brute force after ciphertext exfiltration |
vault-encryption.md |
| Escalating lockout (4 → 30 s; 7 → 5 min; 10 → wipe) |
Online PIN guessing |
pin-and-bruteforce.md |
| NVS-persisted attempt counter + BM8563 RTC lockout expiry |
Lockout survives power cycle and deep sleep |
pin-and-bruteforce.md |
| LE Secure Connections, Numeric Comparison, MITM, bonding |
BLE eavesdropping and MITM |
ble.md |
| Randomized Private Address (RPA) + filter-accept-list |
BLE tracking and unauthorized connections |
ble.md |
| CVE-2025-62235 re-pair confirmation |
Silent bond-overwrite attack |
ble.md |
| BLE/WiFi mutual exclusion |
Simultaneous radio exposure during OTA |
ble.md, wifi.md |
| WPA3-SAE-only SoftAP, PMF required |
WiFi downgrade and deauth attacks |
wifi.md |
| Constant-time session token; rate limiting; idle timeout |
Admin portal credential attacks |
wifi-admin-portal.md |
esp_ota_ops app update + rollback guard |
Malicious firmware, failed update bricking |
ota-and-boot.md |
| Passphrase-encrypted backup (KEXP: PBKDF2-SHA256 600k + AES-256-CBC + HMAC-SHA256 encrypt-then-MAC; device-shown diceware or HW-RNG passphrase; entropy floor against truncated wordlist; universal web restore for all device classes) |
Credential confidentiality on stolen backup media; cross-device vault migration |
vault-encryption.md |
mbedtls_platform_zeroize() / psa_destroy_key() |
Key material in RAM after use |
key-material-and-logging.md |
crypto_hw::ScopedLock (commit 5600ebaf) |
HW-SHA/I2S race causing intermittent MAC failures |
key-material-and-logging.md |
SecureAllocator — dynamic zeroizing ArduinoJson allocator (fail-closed on OOM, no fixed cap) |
Credential plaintext pool in freed heap after export/import |
key-material-and-logging.md |
| Credential material excluded from all log paths |
Credential leakage via debug output |
key-material-and-logging.md |
| Secure Boot v2, Flash Encryption, NVS enc, JTAG disabled |
Physical flash readout; code injection |
flash-and-production.md |
| Structured audit event log |
Traceability of unlock, BLE, admin, OTA events |
audit-log.md |
Navigation map#
Crypto and vault#
| Document |
What it covers |
| vault-encryption.md |
AES-256-CBC envelope design, PBKDF2 key derivation, HKDF device binding, encrypt-then-MAC ordering, sub-key labels, anti-rollback generation counters, crypto_hw::ScopedLock, encrypted backup/restore (KEXP passphrase envelope — PBKDF2 600k iters, AES-256-CBC + HMAC-SHA256, cross-device re-key restore) |
PIN and lockout#
| Document |
What it covers |
| pin-and-bruteforce.md |
Timing Arc UX, NVS-persisted failure counter, BM8563 RTC lockout expiry, escalating lockout thresholds (4 / 7 / 10), vault wipe |
BLE#
| Document |
What it covers |
| ble.md |
NimBLE SM configuration (LE SC, Numeric Comparison, MITM, bonding), RPA privacy, filter-accept-list, CVE-2025-62235 re-pair confirmation, connection-parameter policy, HID service GATT security, BLE QA harness |
WiFi and admin portal#
| Document |
What it covers |
| wifi.md |
WPA3-SAE SoftAP, AES-CCMP pairwise cipher, PMF, transition-disable, per-session random AP password |
| wifi-admin-portal.md |
Session token generation and constant-time comparison, rate limiting, idle timeout, authenticated OTA route, secret wiping on shutdown |
OTA and boot#
| Document |
What it covers |
| ota-and-boot.md |
esp_ota_ops app update flow, esp_ota_mark_app_valid_cancel_rollback(), rollback guard, signed firmware images, BLE-before-WiFi teardown ordering |
Key material and logging#
| Document |
What it covers |
| key-material-and-logging.md |
mbedtls_platform_zeroize() and psa_destroy_key() call sites, crypto_hw::ScopedLock HW-SHA/I2S race fix, credential exclusion from log paths, debug and QA path policy |
Production and flash#
| Document |
What it covers |
| flash-and-production.md |
Secure Boot v2 (RSA-3072), Flash Encryption (DEV mode), NVS encryption, JTAG disable, _secure env target, secure partition table, secure_upload_guard.py |
Audit log#
| Document |
What it covers |
| audit-log.md |
Structured on-device event log: unlock, BLE session, admin portal, OTA, lockout, vault wipe events; retention and read-out policy |
Threat model#
| Document |
What it covers |
| threat-model.md |
Asset inventory, trust boundaries, in-scope threat taxonomy (T1–T17), out-of-scope clarifications (T-OOS1–6), cross-reference to each control document |
CVE register#
| Document |
What it covers |
| cve-register.md |
10 tracked CVE entries against direct and transitive dependencies; mitigated / not-applicable status for each |
Release checklist#
| Document |
What it covers |
| checklist.md |
Release-preparation and security-review checklist: per-target verification steps, eFuse-burn gates, and final sign-off items |
Audit dossier#
| Document |
What it covers |
| audit-dossier.md |
Control matrix mapping every threat ID to code evidence (file:line), governing standard, and the test/QA command that verifies the control is active |
For auditors#
Start with threat-model.md to understand the asset inventory,
trust boundaries, and the complete threat taxonomy (T1–T17). Each subordinate
document maps back to one or more threat IDs and contains an Auditor Checklist
section with mechanically verifiable assertions and file:line anchors.
The Audit Dossier — audit-dossier.md — is the companion
control matrix: it maps every threat ID to code evidence (file:line), the governing
standard, and the specific test/QA command that verifies the control is active.
Architecture diagram#
flowchart LR
User[User] -->|Timing Arc PIN| PinEntry[PIN entry]
PinEntry -->|PBKDF2-SHA256| MasterKey[Master key in RAM]
MasterKey --> Vault[Encrypted LittleFS vault\nAES-256-CBC + HMAC-SHA256]
MasterKey --> AdminMode[Admin mode]
Vault -->|selected credential| BLE[BLE HID session\nLE SC + Numeric Comparison]
BLE --> Host[Paired host]
AdminMode -->|WPA3 SoftAP| Portal[Admin portal\nWPA3 + session token]
Portal -->|esp_ota_ops| OTA[App OTA + rollback guard]
classDef sensitive fill:#ffe8e8,stroke:#b00020,color:#111;
class MasterKey,Vault sensitive;
The key rule is that sensitive material is accessible only in a narrow unlocked
session. BLE, WiFi, display backlight, LittleFS, and key buffers each have an
explicit shutdown or wipe path before lock or deep sleep. Missing a shutdown path
is a bug, not a warning.