ZeroKeyUSB does not rely on the Internet, cloud storage, or companion apps.
Everything — from random number generation to PIN verification — happens inside the device, powered directly through USB.Your passwords never leave the hardware and cannot be accessed remotely, even by the manufacturer.
Security is split across two pieces of silicon so neither one alone can leak the vault:
Chip
Role
SAMD21E18A (MCU)
Runs the application firmware, performs software AES-128 CBC, drives the OLED, USB HID, touch, and I²C bus.
ATECC608A-MAHDA-T (secure element)
Generates true random numbers (TRNG), holds a unique 9-byte chip serial used as PIN salt, and provides a tamper-resistant monotonic hardware counter (Counter0) that gates PIN attempts and cannot be rolled back.
The MCU and ATECC608A share an I²C bus at address 0x60. Neither chip stores the entire secret on its own: the AES master key lives in EEPROM but its entropy comes from the secure element’s TRNG, and the PIN is verified through a hash that mixes the user’s digits with the secure element’s serial.
Crypto model — Camino B (software AES, chip-assisted PIN auth).
The ATECC608A SKU in use (MAHDA-T) ships with the standalone hardware AES command disabled at the factory, so the AES master key cannot live inside the chip. See the trade-off section below.
All sensitive data is stored in the external EEPROM M24C64-WMN6TP, encrypted using AES-128 in CBC mode (software, AESLib on Cortex-M0+).
Element
Source / Location
Cipher
AES-128 CBC — software implementation via AESLib. Manual per-block XOR chaining for full control of IV handling.
AES master key
16 random bytes produced by the ATECC608A TRNG at provisioning. Stored in EEPROM at 0x0028–0x0037. Loaded into a static RAM buffer on first use and cached for the session.
IV (Initialization Vector)
16 random bytes produced by the ATECC608A TRNG at provisioning. Stored in EEPROM at 0x0010–0x001F.
PIN binding
The AES master key is not derived from the PIN. The PIN is verified separately via an EEPROM-stored hash and gates access to the unlock routine.
Credential layout
Each slot holds up to four 32-byte encrypted EEPROM pages: site (p0), username (p1), password (p2), TOTP secret (p3). Each 32-byte page encrypts 16 bytes of plaintext padded to 32 bytes with 0xFF.
cbcEncrypt32 / cbcDecrypt32 process each 32-byte credential in two 16-byte blocks:
Block is XORed with the previous ciphertext (or the device IV for the first block).
The XOR result is fed to AESLib as a single-block ECB operation with a zero IV — this collapses to ECB, but the manual XOR step restores CBC semantics.
The resulting 16-byte ciphertext becomes prev for the next block.
Note: a zero local IV is intentionally used to avoid the AESLib CBC API’s IV-write-back behavior, which would trigger a HardFault on SAMD21 if the IV were flash-resident.
The PIN authorises an unlock cycle; it is never used directly as an encryption key.The verification flow:
The user enters up to 16 digits on the capacitive pads.
The firmware increments Counter0 in the ATECC608A. This counter is monotonic and survives power cycles — it cannot be rolled back by software or by desoldering the MCU.
The firmware reads the attempt threshold from EEPROM (0x0020). If Counter0 ≥ threshold, the device calls eraseAll() (wipes all credential slots) and halts.
Otherwise, the firmware calls derivePinKey(): computes SHA-256(pinArray[16] ∥ chip_serial[9]) to produce the 32-byte PIN hash.
It reads the stored 32-byte hash from EEPROM (0x0038) and runs a constant-time compare (diff |= stored[i] ^ derived[i]).
On match: the threshold is reset to Counter0 + 50, the soft failed-attempt counter is cleared, and the unlock proceeds.
On mismatch: the soft counter increments and the device enforces an exponential backoff delay before the next attempt.
Because the rate-limit counter is in hardware, an attacker who dumps EEPROM still cannot brute-force the PIN against the device — Counter0 keeps marching forward with each attempt and the firmware wipes the vault once the threshold is crossed.
Established at provisioning time and locked permanently:
Slot
Size
Content
Access
9
32 B
SHA-256(PIN_padded ∥ device_serial) — the PIN key
Clear write allowed (IsSecret=0, WriteConfig=Always). Readable over I²C.
8
16 B
AES-128 master key (provisioning path, currently unused by app)
—
Counter 0
monotonic
PIN attempt counter
Increment-only. Read by app before each unlock.
Known trade-off (Slot 9 readable): Slot 9 is not locked as secret because the MAHDA-T SKU rejects clear writes to IsSecret slots. This means an attacker with physical I²C access can read the 32-byte PIN hash and attempt an offline dictionary attack against SHA-256(PIN∥serial). Counter0 hardware lockout limits how fast they can then USE a recovered PIN against the device, but offline hash cracking is unbounded. Short PINs are vulnerable to offline attack if the attacker obtains I²C access.
The IV is generated once during provisioning by the ATECC608A’s TRNG and stored in EEPROM at 0x0010. Two sanity guards protect it:
A read returning all-0x00 or all-0xFF is treated as uninitialised and triggers regeneration from the TRNG.
If EEPROM read fails at unlock time, the firmware attempts TRNG regeneration and re-stores the IV.
Single device-wide IV: all credential pages are chained against the same IV. This keeps the layout simple and auditable. The threat model leans on TRNG quality and Counter0, not on per-record nonces.Regeneration consequence: if the IV is lost or regenerated without re-encrypting credentials, existing slots will decrypt to garbage (the ciphertext was produced under the old IV). The firmware’s self-healing routine (silentEraseAll) is called automatically on first unlock if slot 0 page 0 is still raw 0xFF (EEPROM default), and can be called again manually via generateAndStoreIV().
On the first unlock after provisioning, ZerokeySecurity::unlock() checks whether credential slot 0, page 0 is still at the EEPROM factory default (0xFF across all 32 bytes). If so, it calls silentEraseAll():
Loads the device IV from EEPROM.
For each of the 62 credential slots × 4 pages: encrypts a 32-byte 0xFF blank under AES-128 CBC and writes it to EEPROM.
Clears TOTP metadata for every slot.
This ensures fresh units always have consistent, properly encrypted blank entries before any credential is written.
Splitting fields keeps recognisable plaintext patterns out of the ciphertext stream and limits the blast radius of a corrupt EEPROM page. Padding bytes are 0xFF; trailing 0x20 (space) chars are replaced with 0xFF before encryption to avoid pattern leakage.
The PCB is encapsulated in epoxy resin; opening the device destroys the board and the chip connections.
No wireless interfaces (no Wi-Fi, no Bluetooth, no NFC).
The bootloader region is BOOTPROT-locked in hardware fuses (BOOTPROT = 7, protecting the first 16 KB) — application firmware cannot rewrite or relocate the bootloader.
The bootloader will only jump to ECDSA P-256-signed firmware; an unsigned or tampered image falls into USB-CDC recovery mode instead of executing.
All decrypted credentials live in temporary RAM buffers (currentSite, currentUser, currentPass) that are populated at unlock and overwritten at the next lock or power cycle.
Write-protect pin (EEPROM_WP_PIN = PA01) can be driven high by firmware to hardware-lock EEPROM writes.
Credentials can be exported and imported over the USB CDC serial interface:
Export (backupAllCredentials): decrypts all 62 slots in-device and sends them as comma-delimited plaintext lines over SerialUSB. The host receives credentials in clear — ensure the USB connection is trusted.
Import (loadAllbackupCredentials): receives records from the host, re-encrypts them under the current device IV/master, and writes them to EEPROM. TOTP secrets are parsed and stored in page 3 of each slot.
Security note: backup transmits decrypted credentials in plaintext over USB. Only perform backup/restore on a trusted, air-gapped host.
ZeroKeyUSB’s firmware is fully open-source and available for public audit and verification. Anyone can review:
How the ATECC608A is driven (zerokey-atecc.cpp).
How the AES master, IV, and PIN hash are written and read (zerokey-security.cpp).
How the bootloader hashes and verifies the application (bootloader/src/main.c).
There are no remote update mechanisms: re-flashing requires physical access via SWD pogo pins or the local USB-CDC bootloader, and any new image must be signed by the offline ECDSA key.
How the ATECC-generated master key and IV are used to chain credential pages with software AES-CBC.
PIN Verification
Counter0, the EEPROM-stored SHA-256 hash, and the constant-time compare that gates unlock.
IV Generation
How the ATECC608A TRNG seeds the device-wide IV and how regeneration is handled.
ZeroKeyUSB pairs an MCU with a hardened secure element. The MCU does the cryptographic work; the secure element provides the entropy, the identity (chip serial used as PIN salt), and the rate limit (Counter0) that makes the PIN protection meaningful against online attacks.