Key material
The AES master key is a 16-byte random value generated by the ATECC608A TRNG at first boot, written to slot 8 of the chip, and then locked in by the data-zone lock.
Because
IsSecret=1 is enforced before the data zone is locked, even an attacker with physical I²C access cannot read the AES key back from the chip — the Read command refuses to return it.
Why the chip and not the MCU?
The earlier firmware ran software AES on the SAMD21 with the key stored in EEPROM, because theMAHDA-T variant of the ATECC608A ships with the hardware AES command disabled. Enabling it requires:
- Writing the
AES_Enablebit (byte 13, bit 0) of the Config Zone. - Configuring slot 8 with
KeyType=6(AES). - Locking the Config Zone so those settings take effect.
CBC chaining implementation
ThecbcEncrypt32 / cbcDecrypt32 functions in zerokey-security.cpp process each 32-byte credential field as two 16-byte blocks chained against the device IV:
Encryption
Decryption
Wire format of each AES call
For every 16-byte block:
Each call takes ~10 ms including I²C overhead.
Padding
Each credential field (site, username, password) is up to 32 bytes in RAM. Before encryption:- Trailing space characters (
0x20) are replaced with0xFFfrom the end inward. - The field fills the 32-byte page buffer directly; any unused tail is
0xFF.
bufferToString() strips 0xFF bytes and reads until \0 or 0xFF.
Per-operation flow
lock() — encrypt and write credentials
- Replace trailing spaces in
currentSite,currentUser,currentPasswith0xFF. - Load IV from EEPROM (
loadIVfromEEPROM()). - For each of the 3 fields:
- Copy up to 32 bytes into the 32-byte buffer, padding any unused tail with
0xFF. - Call
cbcEncrypt32(iv, plain, encrypted)— two ATECC AES calls under the hood. - Write the 32-byte ciphertext to the correct EEPROM page.
- Copy up to 32 bytes into the 32-byte buffer, padding any unused tail with
unlock() — decrypt and load credentials
- Load IV from EEPROM.
- Self-heal check: if slot 0 page 0 is raw
0xFF, callsilentEraseAll(). - For each of the 3 fields:
- Read the 32-byte ciphertext from EEPROM.
- Call
cbcDecrypt32(iv, encrypted, decrypted)— two ATECC AES calls. - Copy the 32 bytes into
currentSite/currentUser/currentPass.
Error reporting
When an AES round-trip fails, the firmware preserves the chip’s response code and displays it on the OLED instead of a generic error. The format isAES E<n> RC<x> SS<XX> plus a second line LC=<x> LV=<x> KT=<n> showing the chip’s lock and key-type state at the moment of failure:
RC is the driver-level code (-1 wake, -2 I²C, -3 CRC, -4 chip status error, -5 timeout). SS is the raw status byte from the chip (0x0F execution error, 0x03 parse, 0x07 self-test, …). The combination tells you exactly why the chip rejected the call. Locked + KT=1 (instead of 6) means the chip is permanently misconfigured for AES; that’s the only failure mode that can’t be cleared by a reboot.