RSA-PSS sign, verify, and batch-flash Raspberry Pi HAT+ EEPROM binaries via I2CDriver
Project description
eeprom_sign - RSA-PSS sign/verify/flash tool for HAT+ EEPROMs
Sign, verify, and batch-flash Raspberry Pi HAT+ EEPROM binaries.
Supports single-device and production batch workflows via an
I2CDriver USB-to-I²C bridge.
Summary
- Requirements
- Subcommands
- Supported EEPROM models
- EEPROM image format
- Signature scheme
- Typical production workflow
Installation
Via homebrew (macOS ARM/Linux)
brew tap fred-corp/tap
brew install eeprom-sign
or
brew install fred-corp/tap/eeprom-sign
Via pip
pip install eeprom-sign
Requirements
pip install cryptography i2cdriver
Python 3.10 or later (uses X | Y union type hints).
Subcommands
| Subcommand | What it does |
|---|---|
keygen |
Generate an RSA key pair |
sign |
Sign a single EEPROM binary file |
verify |
Verify the signature in a binary file |
strip |
Remove the signature atom from a binary file |
batch |
Batch sign + flash loop via I2CDriver |
readback |
Read one EEPROM over I²C and verify its signature |
batch-readback |
Batch read + verify loop via I2CDriver |
keygen - Generate an RSA key pair
eeprom-sign keygen --private FILE --public FILE [--bits BITS]
Generates a new RSA private/public key pair and writes both as PEM files. Keep the private key secret; distribute the public key to anyone who needs to verify signatures.
Arguments
| Argument | Required | Default | Description |
|---|---|---|---|
--private FILE |
yes | - | Output path for the private key PEM |
--public FILE |
yes | - | Output path for the public key PEM |
--bits BITS |
no | 2048 |
Key size: 2048, 3072, or 4096 |
Example
eeprom-sign keygen \
--private hat_private.pem \
--public hat_public.pem
sign - Sign a single EEPROM binary
eeprom-sign sign INPUT --serial STRING --private FILE --output FILE
Takes an existing HAT+ EEPROM binary, embeds a serial number atom (SNUM), patches the vendor info atom with a fresh UUID, signs the result with RSA-PSS / SHA-256, and writes the signed image to a new file.
If the input already contains a RSIG or SNUM atom, both are stripped first so the operation is always idempotent.
Arguments
| Argument | Required | Description |
|---|---|---|
INPUT |
yes | Base (unsigned) EEPROM .bin file |
--serial STRING |
yes | Serial number to embed, e.g. YOTA0001 |
--private FILE |
yes | RSA private key PEM file |
--output FILE |
yes | Output path for the signed binary |
Example
eeprom-sign sign eeprom_base.bin \
--serial YOTA0001 \
--private hat_private.pem \
--output eeprom_signed.bin
verify - Verify a signed EEPROM binary file
eeprom-sign verify INPUT --public FILE
Locates the RSIG atom in the binary, reconstructs the exact byte sequence that was signed, and verifies the RSA-PSS signature. Exits with a non-zero status and an error message if verification fails.
Arguments
| Argument | Required | Description |
|---|---|---|
INPUT |
yes | Signed EEPROM .bin file |
--public FILE |
yes | RSA public key PEM file |
Example
eeprom-sign verify eeprom_signed.bin \
--public hat_public.pem
strip - Remove the signature atom
eeprom-sign strip INPUT --output FILE
Removes the RSIG atom and updates the EEPROM header (numatoms, eeplen)
so the result is a valid unsigned image ready for re-signing.
Arguments
| Argument | Required | Description |
|---|---|---|
INPUT |
yes | Signed EEPROM .bin file |
--output FILE |
yes | Output path for the stripped binary |
Example
eeprom-sign strip eeprom_signed.bin \
--output eeprom_base.bin
batch - Batch sign + flash loop
eeprom-sign batch INPUT \
--serial STRING --private FILE \
[--public FILE] [--eeprom MODEL] [--port PORT] \
[--output-dir DIR] [--no-verify] [--auto-detect]
Interactive production loop. For each board it:
- Waits for the operator (Enter key) or for the EEPROM to appear on the
bus (
--auto-detect). - Detects the EEPROM at I²C address
0x50(falls back to a full scan of0x50–0x57if nothing responds there). - Generates a fresh UUID (patched into the vendor info atom) and an incremented serial number.
- Signs the image with RSA-PSS / SHA-256.
- Flashes the EEPROM using page-aligned writes with ACK-poll completion.
- Verifies the readback byte-for-byte. Optionally also verifies the RSA
signature in memory if
--publicis supplied. - Optionally saves the signed binary to
--output-dir. - Advances the serial counter and loops.
Press Ctrl+C to stop. The last flashed serial and the next one to use are printed on exit.
Arguments
| Argument | Required | Default | Description |
|---|---|---|---|
INPUT |
yes | - | Base (unsigned) EEPROM .bin image |
--serial STRING |
yes | - | Starting serial, e.g. YOTA0001. The trailing digits are incremented for each board; the width and prefix are preserved. |
--private FILE |
yes | - | RSA private key PEM file |
--public FILE |
no | - | RSA public key PEM file. If supplied, a full crypto verify is run after each flash in addition to the byte-for-byte readback check. |
--eeprom MODEL |
no | 24c256 |
EEPROM model. See Supported EEPROM models. |
--port PORT |
no | /dev/ttyUSB0 |
Serial port of the I2CDriver. macOS example: /dev/tty.usbserial-DM02V7KY. Windows example: COM3. |
--output-dir DIR |
no | - | Save each signed .bin as <serial>.bin in this directory. |
--no-verify |
no | off | Skip the post-flash crypto signature verification (byte-for-byte readback is always performed). |
--auto-detect |
no | off | Flash automatically when a board is inserted - no Enter needed. Useful on pogo-pin fixtures. |
Examples
# Manual mode (press Enter per board), save signed binaries
eeprom-sign batch eeprom_base.bin \
--serial YOTA0001 \
--private hat_private.pem \
--public hat_public.pem \
--eeprom 24c256 \
--port /dev/tty.usbserial-DM02V7KY \
--output-dir ./signed_images
# Auto-detect mode, no file saving, no crypto re-verify
eeprom-sign batch eeprom_base.bin \
--serial YOTA0001 \
--private hat_private.pem \
--eeprom 24c256 \
--port /dev/tty.usbserial-DM02V7KY \
--auto-detect \
--no-verify
readback - Read one EEPROM and verify its signature
eeprom-sign readback \
--public FILE [--eeprom MODEL] [--port PORT] [--output FILE]
Reads the EEPROM contents over I²C, prints the vendor/product strings, UUID, and serial number found in the atoms, then verifies the RSA-PSS signature. Optionally saves the raw binary.
The tool reads only as many bytes as eeplen in the HAT+ header specifies,
so it is fast regardless of chip capacity.
Arguments
| Argument | Required | Default | Description |
|---|---|---|---|
--public FILE |
yes | - | RSA public key PEM file |
--eeprom MODEL |
no | 24c256 |
EEPROM model |
--port PORT |
no | /dev/ttyUSB0 |
I2CDriver serial port |
--output FILE |
no | - | Save the raw binary read from the chip |
Examples
eeprom-sign readback \
--public hat_public.pem \
--eeprom 24c256 \
--port /dev/tty.usbserial-DM02V7KY \
--output readback.bin
Sample output
[i2c] Connected to I2CDriver on /dev/tty.usbserial-DM02V7KY
[readback] Detecting EEPROM…
[readback] Found EEPROM at 0x50
[readback] Reading 412 bytes…
[readback] 4 atom(s) found
Vendor : ACME Ltd
Product : Sensor HAT
UUID : 3f2a1b4c-…
Serial : BATCH0003
[verify] ✓ Signature VALID - tmp_xxxx.bin
RSA-2048 / SHA-256 / PSS
batch-readback - Batch read + verify loop
eeprom-sign batch-readback \
--public FILE [--eeprom MODEL] [--port PORT] \
[--output-dir DIR] [--auto-detect]
Read and verify multiple boards in sequence. Mirrors the batch workflow
but is read-only - useful for post-flash QC or incoming inspection.
Arguments
| Argument | Required | Default | Description |
|---|---|---|---|
--public FILE |
yes | - | RSA public key PEM file |
--eeprom MODEL |
no | 24c256 |
EEPROM model |
--port PORT |
no | /dev/ttyUSB0 |
I2CDriver serial port |
--output-dir DIR |
no | - | Save each readback as readback_NNNN.bin |
--auto-detect |
no | off | Trigger read on board insertion (no Enter needed) |
Examples
# Manual mode
eeprom-sign batch-readback \
--public hat_public.pem \
--eeprom 24c256 \
--port /dev/tty.usbserial-DM02V7KY
# Auto-detect, save all readbacks
eeprom-sign batch-readback \
--public hat_public.pem \
--eeprom 24c256 \
--port /dev/tty.usbserial-DM02V7KY \
--auto-detect \
--output-dir ./qc_readbacks
Supported EEPROM models
--eeprom value |
Capacity | Page size | Notes |
|---|---|---|---|
24c32 |
4 KiB | 32 B | |
24c64 |
8 KiB | 32 B | |
24c128 |
16 KiB | 64 B | |
24c256 |
32 KiB | 64 B | Default |
24c512 |
64 KiB | 128 B | |
24c1024 |
128 KiB | 128 B |
All models use I²C address 0x50 when address pins A2/A1/A0 are
tied to GND, which is standard on HAT+ boards. The tool probes 0x50
first and falls back to a full scan of 0x50–0x57 if needed.
EEPROM image format
The tool follows the HAT+ EEPROM specification.
File header (12 bytes)
| Offset | Size | Field. | Value |
|---|---|---|---|
| 0 | 4 | Magic | 0x69502d52 ("R-Pi") |
| 4 | 1 | Version | |
| 5 | 1 | Reserved | |
| 6 | 2 | numatoms |
atom count (LE uint16) |
| 8 | 4 | eeplen |
total image size in bytes (LE uint32) |
Atom layout
| Offset | Size | Field |
|---|---|---|
| 0 | 2 | type (LE uint16) |
| 2 | 2 | count (atom index, LE uint16) |
| 4 | 4 | dlen (data + CRC length, LE uint32) |
| 8 | dlen−2 | data |
| 8+dlen−2 | 2 | CRC-16/ARC over header+data |
Atom types used by this tool
| Type | Name | Description |
|---|---|---|
0x0001 |
Vendor info | UUID, PID, version, vendor/product strings. The 16-byte UUID field is overwritten with a fresh uuid4() on every sign operation. |
0x0004 + magic RSIG |
Signature | RSA-PSS / SHA-256 signature (256 bytes for RSA-2048). |
0x0004 + magic SNUM |
Serial number | ASCII serial string embedded by sign and batch. |
Signature scheme
- Algorithm: RSA-PSS with MGF1-SHA-256 and maximum salt length.
- Signed payload: every byte of the image from offset 0 up to (but not
including) the RSIG atom header, with
numatomsandeeplenin the file header already reflecting the final atom count and total size. This means the UUID, serial number, and all standard HAT+ atoms are all covered by the signature. - Verification: the verifier reconstructs the same byte range from the
image on disk (or read from the chip) and calls
public_key.verify(…, PSS(…), SHA256()).
Typical production workflow
┌─────────────────────────────────┐
│ 1. keygen (once, off-line) │
│ hat_private.pem │
│ hat_public.pem │
└──────────────┬──────────────────┘
│
┌──────────────▼──────────────────┐
│ 2. batch │
│ Base image + private key │
│ → unique UUID + serial │
│ → sign → flash → verify │
└──────────────┬──────────────────┘
│
┌──────────────▼──────────────────┐
│ 3. batch-readback (QC) │
│ Public key only │
│ → read → verify signature │
└─────────────────────────────────┘
License & Acknowledgements
Made with ❤️, lots of ☕️, and lack of 🛌
Published under CreativeCommons BY-SA 4.0
This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file eeprom_sign-1.1.0.tar.gz.
File metadata
- Download URL: eeprom_sign-1.1.0.tar.gz
- Upload date:
- Size: 26.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6441c6ec3b672d12d626830433330b08e9df877538569278cc1064da1efac582
|
|
| MD5 |
b0c99ac18b98e24fbd815bf4590acf94
|
|
| BLAKE2b-256 |
43045b844699931f075219cf7eaeef7a7d045d7e151e3120271a0f8bc009759e
|
Provenance
The following attestation bundles were made for eeprom_sign-1.1.0.tar.gz:
Publisher:
release.yml on fred-corp/eeprom-sign
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
eeprom_sign-1.1.0.tar.gz -
Subject digest:
6441c6ec3b672d12d626830433330b08e9df877538569278cc1064da1efac582 - Sigstore transparency entry: 1442504605
- Sigstore integration time:
-
Permalink:
fred-corp/eeprom-sign@39baf67b7911c0691efbd8b2fb4fcdf392a41955 -
Branch / Tag:
refs/tags/v1.1.0 - Owner: https://github.com/fred-corp
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@39baf67b7911c0691efbd8b2fb4fcdf392a41955 -
Trigger Event:
push
-
Statement type:
File details
Details for the file eeprom_sign-1.1.0-py3-none-any.whl.
File metadata
- Download URL: eeprom_sign-1.1.0-py3-none-any.whl
- Upload date:
- Size: 24.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
da1c54c3440f5b0626c204e8aaaf821f8c75e74f06b20a29a9877e7238e31043
|
|
| MD5 |
6849b945b1d812e025e3b782dc62711a
|
|
| BLAKE2b-256 |
9bab147c53f53f703701c72ed8af1ee706fa39718a14f09ac4f07eeac216f005
|
Provenance
The following attestation bundles were made for eeprom_sign-1.1.0-py3-none-any.whl:
Publisher:
release.yml on fred-corp/eeprom-sign
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
eeprom_sign-1.1.0-py3-none-any.whl -
Subject digest:
da1c54c3440f5b0626c204e8aaaf821f8c75e74f06b20a29a9877e7238e31043 - Sigstore transparency entry: 1442504679
- Sigstore integration time:
-
Permalink:
fred-corp/eeprom-sign@39baf67b7911c0691efbd8b2fb4fcdf392a41955 -
Branch / Tag:
refs/tags/v1.1.0 - Owner: https://github.com/fred-corp
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@39baf67b7911c0691efbd8b2fb4fcdf392a41955 -
Trigger Event:
push
-
Statement type: