Keycard Shell transforms any Keycard into a standalone, air-gapped hardware wallet with built-in keypad, display, camera, and USB (which can be turned off). Fully open-source and EAL6+ certified, it uses ERC-4527 QR codes for secure signing and supports infinite removable backups.
All firmware, hardware designs, and toolchain scripts are fully open source under the MIT license.
Scan and display QR codes (ERC-4527) to sign transactions without ever exposing your keys.
EAL6+ certified secure element for key storage and signing.
Support for an infinite number of Keycard smartcards, each with its own key & PIN.
Works seamlessly with MetaMask, imToken, Rabby, BlueWallet, BlueWallet, Sparrow, Specter, and more.
Powered by a replaceable Nokia BL-4C battery (25 + year expectancy), water & dust resistant.
A second PIN stops bad actors from stealing crypto by physical force
This repo contains everything needed to build a Keycard Shell.
app: the main firmware code. This is what makes everything happen.bootloader: the bootloader. Since it is non-upgradable we kept its complexity to a minimum.cddl: contains definitions for the various CBOR messages defined by the UR standarddeployment: git-ignored folder containing the signing keys and build resultsfreertos: we use FreeRTOS as our task scheduler.hardware: everything hardware related. From schematics up to case designs.json: example json files for abi, token and chain db. These files are unused.stm32: all platform-specific code for the STM32H5 MCU. It also contains the project file for STM32CubeIDE needed to build the firmware.test: the tests firmware we run in the factory on each unit to check it has been properly assembled.tools: some tools used during the build process or during development.zcbor: the library we use to parse CBOR messages.
The build is fully reproducible, although not yet in an automated way.
First, clone the repository and switch to the release tag you want to build:
git clone https://github.com/keycard-tech/keycard-shell.git
cd keycard-shell
git checkout v1.1.1 # use the tag matching the official release you want to verify1. Install STM32CubeIDE
Download and install STM32CubeIDE.
2. Configure the Toolchain
After importing the project, verify you are using GNU Tools for STM32 (14.3.rel1) by checking the Toolchain manager in the IDE settings:
- Go to
Window → Preferences → STM32CubeIDE → Build → Settings - Select
GNU Tools for STM32 (14.3.rel1)as your toolchain
3. Install Python Dependencies
Install the required Python packages:
pip install -r tools/requirements.txtNote: Depending on your platform, you may need additional steps to get Python set up correctly.
4. Set up Signing Keys
In your deployment directory, you need two files:
bootloader-pubkey.txt: Contains the public key the bootloader will use to verify the firmware. The key must be hex-encoded, uncompressed, and without the leading04byte.fw-test-key.txt: Contains a hex-encoded private key (the private part of the key inbootloader-pubkey.txt) used to sign the firmware.
Note: We use this signing method in our internal development units. Shipped units will have different keys and the signing process is handled in a secure environment.
-
Import the Project
- Open STM32CubeIDE
- Go to
File → Import → Existing Projects into Workspace - Select the
stm32directory and import the project
-
Build the Bootloader (BL)
- Select the BL build configuration
- Right-click on the project →
Build Project - The bootloader binary will be generated in
stm32/BL/
-
Build the Release Firmware
- Select the Release build configuration
- Right-click on the project →
Build Project - The firmware binary will be generated in
stm32/Release/
-
(Optional) Build the TestApp
- Select the TestApp build configuration
- Right-click on the project →
Build Project - The test application binary will be generated in
stm32/TestApp/
Build the Release target in STM32CubeIDE, and run:
python3 tools/firmware-hash.py -b stm32/Release/stm32.binDownload the official binary from the GitHub releases page and hash it the same way:
python3 tools/firmware-hash.py -b ~/Downloads/shellos-<date>-<version>.binThe two hashes must match.
Note: Use
-bbefore the file path — it is required by the script.
If you want to generate a full image to load on a device you built yourself, take a look at the tools/create-image.py script.