Skip to content

Security: SWPSCO/nockster

Security

docs/security.md

Nockster device security

Nockster is a hardware signer built around the ESP32-S3. A production device uses several independent protections so that losing the device, copying its flash, or connecting it to hostile USB hardware does not immediately expose a wallet seed or authorize a signature.

Security model

The seed remains on the device. Hosts can request public information and submit transactions for review, but private-key operations happen inside the signer. Sensitive actions require confirmation on the device's own display, so malware on the connected computer cannot silently approve what the user did not see.

The design addresses four common attack paths:

  • A lost or stolen device is protected by its PIN, attempt limiting, and device-bound storage key.
  • A copied or desoldered flash chip contains encrypted data rather than a usable seed database.
  • Modified firmware cannot boot unless it carries an authorized Secure Boot signature.
  • Physical debug, ROM download, and fault-injection surfaces are disabled on a production device.

These controls raise the cost of physical attacks; they do not claim to make the chip invulnerable to invasive semiconductor analysis or every possible side-channel technique.

Seed and private-key storage

Each seed is encrypted independently with AES-256-GCM. Its record contains a random salt and nonce plus authenticated ciphertext. Authentication is important: changing stored bytes causes decryption to fail instead of producing corrupted key material that might be used unknowingly.

The PIN is never stored. It is processed with PBKDF2-HMAC-SHA256 and mixed with a secret generated by the ESP32-S3 HMAC peripheral. That HMAC secret lives in a read-protected, purpose-bound hardware key slot: firmware can ask the peripheral to calculate an HMAC, but neither firmware nor a connected host can read the underlying key.

If a production device doesn't have a hardware secret generated at provisioning, the device generates it locally from the hardware random-number generator, assigns it exclusively to HMAC use, and immediately makes the key unreadable and immutable. This recovery is allowed only before wallet storage has been initialized; an existing wallet is never silently rebound to a new hardware key.

Conceptually, the storage key is derived as:

pin_key = PBKDF2-HMAC-SHA256(pin, salt, rounds)
pepper = HMAC-SHA256(device_secret, domain || salt || device_identity)
storage_key = SHA256(domain || pin_key || pepper)

This binds encrypted storage to one physical chip. Copying both the flash and its public salts to another machine is insufficient to test PINs offline, because the second machine does not possess the device's HMAC secret.

Cleartext seeds and derived keys exist only in the unlocked in-memory session. They are zeroized when the device locks, resets, replaces a seed, or deletes a seed. Salts, encryption nonces, and device-generated seeds use the ESP32-S3 hardware random-number generator.

PIN protection

The PIN gates access to decrypted wallet material. Failed attempts are tracked persistently rather than only in RAM, so unplugging or resetting the device does not restore an unlimited number of guesses. PIN changes re-encrypt storage under newly derived key material.

The PIN is one layer rather than the sole protection. Its derivation is tied to the hardware HMAC secret, and the underlying flash is also encrypted by the chip.

Secure Boot and firmware integrity

Secure Boot allows the ESP32-S3 to execute only firmware signed by the authorized release key. This prevents an attacker from replacing Nockster with firmware designed to reveal the seed, bypass confirmations, or record the PIN.

The bootloader, application, and update path share this integrity boundary. A valid data connection alone does not grant permission to install arbitrary code.

Signed firmware updates

Firmware updates are transported over USB HID and installed into an inactive OTA slot. Before activation, the device verifies:

  • The update manifest is signed by the pinned Nockster release key.
  • The bundle targets the correct hardware and protocol.
  • Its release counter advances beyond the installed release.
  • The streamed firmware bytes match the signed digest.
  • The application image carries the signature required by Secure Boot.

The device boots the new slot and confirms it only after its boot-time security checks succeed. An update cannot weaken the hardware lockdown: production OTA firmware verifies the lockdown state on every boot and repairs any still-writable missing setting before accepting the new image.

Signed OTA remains available after lockdown and is the supported firmware recovery mechanism. ROM serial flashing and unsigned recovery images are not.

Flash encryption

ESP32-S3 flash encryption protects the entire external flash with a key held by the chip. Reading or desoldering the flash therefore yields ciphertext.

Seed records remain protected by their own authenticated AES-256-GCM layer as well. The layers serve different purposes:

  • Flash encryption protects firmware, metadata, and storage against raw flash extraction.
  • Record encryption binds wallet data to the PIN and the device HMAC secret and detects tampering.

Neither flash-encryption keys nor the HMAC storage secret are exported through the device protocol.

Immutable device identity

Each device has an immutable factory MAC stored on-chip. Provisioned devices also use their protected production serial; devices without that optional serial use the factory MAC as their USB identity. Either identity survives firmware updates and cannot be replaced by rewriting external flash. It gives host software and operators a stable way to identify the physical signer they are communicating with.

The device identity participates in domain separation for storage derivation; it is not itself a secret.

Hardware lockdown

A production device permanently closes the ESP32-S3's development and ROM recovery interfaces:

  • Pad JTAG, USB JTAG, software-controlled JTAG, and USB Serial/JTAG are disabled.
  • ROM download entry through the available serial and USB paths is disabled.
  • Direct boot and ROM USB debug printing are disabled.
  • Power/clock glitch protection is enabled.

Disabling JTAG prevents debug access to live memory and CPU state. Disabling ROM download paths prevents an attacker from bypassing the signed OTA mechanism to reflash or interrogate the chip. Disabling ROM printing removes an unnecessary pre-application information channel. Glitch protection resets the chip when it detects abnormal conditions associated with fault-injection attempts.

These settings are permanent. They do not disable normal Nockster USB HID operation or signed OTA updates; they remove the lower-level routes that are used for development.

On-device transaction approval

Firmware parses signing requests and shows the relevant transaction details on the trusted device display. Approval is collected locally, including hold-to- confirm behavior for sensitive actions. The connected computer transports the request but does not control the device's confirmation result.

Users should still verify recipients, amounts, fees, and warnings on the device itself. Secure storage cannot make a user-approved malicious transaction safe.

Checking a device

The security check is read-only:

nockster-cli security --port hid

It reports the storage schema, hardware-bound HMAC key, Secure Boot, flash encryption, debug/download lockdown, and glitch-protection state. It exits with an error and lists every missing requirement if the device is not fully secured.

The repository also provides a combined read-only acceptance check:

make validate-device-state VALIDATE_STAGE=production VALIDATE_PORT=hid

A production device should pass the complete assertion. A missing requirement is a security failure, not an optional feature downgrade.

There aren't any published security advisories