{"id":51702805,"url":"https://github.com/TheMaxMur/RS-Key","last_synced_at":"2026-07-21T11:00:53.227Z","repository":{"id":364338658,"uuid":"1266469959","full_name":"TheMaxMur/RS-Key","owner":"TheMaxMur","description":"Open-source FIDO2, OpenPGP, PIV and OATH security-key firmware for RP2350, written in Rust","archived":false,"fork":false,"pushed_at":"2026-07-19T22:09:40.000Z","size":8146,"stargazers_count":110,"open_issues_count":6,"forks_count":15,"subscribers_count":4,"default_branch":"main","last_synced_at":"2026-07-20T01:00:13.100Z","etag":null,"topics":["authenticator","ccid","cryptography","embedded-rust","fido","fido-u2f","fido2","firmware","opengpg","passkeys","pgp","piv","post-quantum-cryptography","pqc","raspberry-pi-pico","rp2350","security-key","smart-card","webauthn"],"latest_commit_sha":null,"homepage":"https://themaxmur.github.io/RS-Key/","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"agpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/TheMaxMur.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":"NOTICE","maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-06-11T16:40:09.000Z","updated_at":"2026-07-19T22:08:48.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/TheMaxMur/RS-Key","commit_stats":null,"previous_names":["themaxmur/rs-key"],"tags_count":21,"template":false,"template_full_name":null,"purl":"pkg:github/TheMaxMur/RS-Key","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TheMaxMur%2FRS-Key","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TheMaxMur%2FRS-Key/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TheMaxMur%2FRS-Key/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TheMaxMur%2FRS-Key/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/TheMaxMur","download_url":"https://codeload.github.com/TheMaxMur/RS-Key/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TheMaxMur%2FRS-Key/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35669289,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-19T02:00:06.923Z","response_time":112,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["authenticator","ccid","cryptography","embedded-rust","fido","fido-u2f","fido2","firmware","opengpg","passkeys","pgp","piv","post-quantum-cryptography","pqc","raspberry-pi-pico","rp2350","security-key","smart-card","webauthn"],"created_at":"2026-07-16T13:00:25.535Z","updated_at":"2026-07-21T11:00:53.216Z","avatar_url":"https://github.com/TheMaxMur.png","language":"Rust","funding_links":[],"categories":["Firmware projects","Software Authenticators"],"sub_categories":["WIP"],"readme":"# RS-Key\n\n[![ci](https://github.com/TheMaxMur/RS-Key/actions/workflows/ci.yml/badge.svg)](https://github.com/TheMaxMur/RS-Key/actions/workflows/ci.yml)\n[![deep-checks](https://github.com/TheMaxMur/RS-Key/actions/workflows/deep-checks.yml/badge.svg)](https://github.com/TheMaxMur/RS-Key/actions/workflows/deep-checks.yml)\n[![docs](https://github.com/TheMaxMur/RS-Key/actions/workflows/pages.yml/badge.svg)](https://themaxmur.github.io/RS-Key/)\n\n\u003ctable align=\"center\"\u003e\n  \u003ctr\u003e\n    \u003ctd align=\"center\" valign=\"top\"\u003e\u003cimg src=\"assets/hero-boards.jpg\" height=\"440\" alt=\"Three RS-Key boards on a blueprint background: a bare RP2350 USB stick, the trusted-display variant showing its Home \u0026quot;Ready\u0026quot; screen (USB connected, Device PIN set, 2 passkeys), and a Waveshare RP2350-One\"\u003e\u003c/td\u003e\n    \u003ctd align=\"center\" valign=\"top\"\u003e\u003cimg src=\"assets/webauthn-demo.gif\" height=\"440\" alt=\"Registering a passkey on webauthn.io with the trusted-display build: the device screen shows a Device PIN pad, then an Approve / Save-passkey prompt, and the browser confirms you are logged in — the PIN and the approval both happen on the device's own screen\"\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd align=\"center\"\u003e\u003csub\u003eThree boards, one firmware — stick · trusted display · RP2350-One\u003c/sub\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003csub\u003eRegistering a passkey — the PIN \u0026amp; Approve/Deny happen on the device's own screen\u003c/sub\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\nRS-Key (RSK, *Raspberry Security Key* — also a nod to its being written in Rust)\nis open-source security-key firmware for the Raspberry Pi **RP2350**. It makes an\nRP2350 board behave like a USB authenticator and ships the host tooling to drive\nit. It is written in Rust (`no_std`, [embassy](https://embassy.dev)) and is meant\nfor development, research, and controlled experiments — **not** as a drop-in\nreplacement for an audited commercial key.\n\n\u003e **This project is experimental.** It has had no external security audit, the\n\u003e RP2350 is not a secure element, and a stolen board is only as strong as the\n\u003e optional OTP / secure-boot hardening you have applied to it. Don't use it to\n\u003e guard credentials you can't afford to lose or have stolen. Read the\n\u003e [threat model](docs/threat-model.md) and [limitations](docs/limitations.md)\n\u003e before trusting it with anything real.\n\n## Documentation\n\nThe docs live in [docs/](docs/) and are published as a site:\n**\u003chttps://themaxmur.github.io/RS-Key/\u003e**.\n\n| | |\n|---|---|\n| [Quick start](docs/quickstart.md) | flash, enroll, first login |\n| [Hardware](docs/hardware.md) | supported boards and build knobs |\n| [Build options](docs/build.md) | every flag: VID/PID presets, version, touch, PQC, FIPS profile |\n| [Production setup](docs/production.md) | OTP fuses + secure boot, step by step (**irreversible**) |\n| [Feature guides](docs/guides/) | FIDO2, SSH, OpenPGP, PIV, OATH, OTP, backup, soft-lock, LED, audit, … |\n| [Threat model](docs/threat-model.md) · [Limitations](docs/limitations.md) | what it protects against, and what it does not |\n| [Architecture](docs/architecture.md) · [`unsafe` audit](docs/unsafe.md) | how it's built; every `unsafe` site |\n| [Testing](docs/testing.md) · [Interop](docs/interop.md) | host tests, fuzzing; real-tool results |\n| [Linux setup](docs/linux.md) · [Motivation](docs/motivation.md) | pcscd/udev/polkit; why this exists |\n\n## What it supports\n\n- **FIDO2 / WebAuthn / U2F** — passkeys, two-factor logins, `ssh ed25519-sk`\n- **OpenPGP card 3.4** — `gpg` signing, decryption, authentication (EC + RSA)\n- **PIV** — X.509 smart-card via PKCS#11 (or `ykman piv`, which needs the opt-in `VIDPID=Yubikey5` build)\n- **OATH** — TOTP / HOTP codes (`ykman oath`, Yubico Authenticator — both need the opt-in `VIDPID=Yubikey5` build)\n- **Yubico-style OTP** — four slots, plus a USB-keyboard interface that types the code\n- **Seed backup** — export the FIDO master seed as BIP-39 / SLIP-39 words\n- **At-rest soft-lock** — keep the FIDO seed in flash encrypted to a key only you hold\n- **On-device audit journal** and **enterprise (org-provisioned) attestation**\n- **Post-quantum FIDO2 (experimental)** — implements the ML-DSA-44 (COSE −48)\n  and ML-DSA-65 (−49) schemes; ML-DSA-65 uses an in-tree, stack-optimized FIPS\n  204 implementation so it fits the RP2350. Advertising them in getInfo is off\n  by default because some shipped browsers reject an unknown algorithm id. This\n  is not a FIPS-validated module.\n\nCapacities are flash-bound and generous (e.g. up to 256 resident passkeys,\n255 OATH accounts, 24 PIV slots, 4 OTP slots); details are in the\n[feature guides](docs/guides/) and [build options](docs/build.md).\n\n```mermaid\nflowchart TD\n    host[\"Host software\u003cbr/\u003ebrowser · ssh · gpg · ykman · rsk / rsk-tui\"]\n    host --\u003e|USB| usb[\"Composite USB device\"]\n    usb --\u003e fido[\"FIDO HID\"]\n    usb --\u003e ccid[\"CCID (smart-card)\"]\n    usb --\u003e kbd[\"Keyboard (OTP typing)\"]\n    fido \u0026 ccid \u0026 kbd --\u003e applets[\"Applets: FIDO2/U2F · OpenPGP · PIV · OATH · OTP · mgmt\"]\n    applets --\u003e core[\"Master seed · TRNG · flash store\"]\n    core --\u003e rp[\"RP2350 (no secure element)\"]\n```\n\n## What it does not protect against\n\n- **Physical / lab attacks** — decapping, microprobing, fault injection beyond\n  the on-chip glitch detectors, power/EM side channels, and flash-emulation\n  TOCTOU. The RP2350 is not a secure element; if your threat model includes a\n  funded lab, buy a certified key.\n- **A compromised host with the device unlocked** — like any security key, it\n  will perform operations you have authorized while plugged in and unlocked.\n- **Loss of secrets without the optional hardening** — at-rest protection only\n  becomes meaningful after you fuse the OTP master key (see Production, below).\n\nFull reasoning: [docs/threat-model.md](docs/threat-model.md).\n\n## Hardware\n\nAny RP2350 board with USB. Developed and tested on the **Waveshare RP2350-One**\n(WS2812 status LED on GPIO16; boards without an LED run fine). A different flash\nsize, LED pin, or presence-button GPIO is a one-line build knob. Details:\n[docs/hardware.md](docs/hardware.md).\n\n## Quick start\n\n```sh\ngit clone https://github.com/TheMaxMur/RS-Key \u0026\u0026 cd RS-Key\nnix develop                       # toolchain, picotool, host tools — everything\n\ncargo build --release -p firmware\npicotool uf2 convert target/thumbv8m.main-none-eabihf/release/firmware -t elf firmware.uf2\n\n# hold BOOTSEL, plug the board in, then flash — either way:\ncp firmware.uf2 /Volumes/RP2350/                    # macOS drag-and-drop; Linux: the mounted RP2350 volume\npicotool load -v firmware.uf2 \u0026\u0026 picotool reboot    # more robust; verifies the write (use if cp flakes)\n```\n\nRe-plug the board and it enumerates as a composite USB authenticator. The default\nbuild requires a **physical touch** (the BOOTSEL button) for FIDO operations;\nbuild with `--features no-touch` for a no-touch build (the automated test\nsuites need it). Full walkthrough: [docs/quickstart.md](docs/quickstart.md).\nOn Linux, the CCID half needs a little host setup: [docs/linux.md](docs/linux.md).\n\n## Development setup\n\n`nix develop` is the whole setup — Rust with the `thumbv8m.main-none-eabihf`\ntarget, `picotool`, the Python host stack, and the security tooling. One command\nis the merge gate, and CI runs exactly the same script:\n\n```sh\nnix develop -c ./scripts/check.sh   # fmt, clippy, host tests, firmware builds, audit, deny, gitleaks\n```\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md) and [docs/testing.md](docs/testing.md).\n\n## Production / secure boot (irreversible — read first)\n\nBy default the firmware flashes by drag-and-drop and roots its at-rest\nencryption in a key derived on the device. An optional, opt-in path hardens\nthat: it fuses a random master key into RP2350 OTP and enables secure boot so\nthe board runs only images you sign.\n\n```mermaid\nflowchart LR\n    subgraph dev[\"Default (development)\"]\n      d1[\"drag-and-drop UF2\"] --\u003e d2[\"flash-derived key\"] --\u003e d3[\"boots any image\"]\n    end\n    subgraph prod[\"Production (opt-in)\"]\n      p1[\"sign UF2\u003cbr/\u003epicotool seal\"] --\u003e p2{{\"burn OTP fuses\u003cbr/\u003eIRREVERSIBLE\"}} --\u003e p3[\"secure boot:\u003cbr/\u003eonly your signed images\"]\n    end\n```\n\nThese steps **burn one-time-programmable fuses**: they cannot be undone, they\nchange your reflash workflow forever (signed images only), and a mistake can\nbrick the board. They are also what makes a stolen board's flash dump useless.\nRead [docs/production.md](docs/production.md) end to end before running anything.\n\n## Host tools\n\nInside the dev shell two commands are on `PATH`:\n\n- **`rsk`** — the device CLI (Python): `rsk status`, `rsk backup`, `rsk lock`,\n  `rsk secure-boot`, `rsk otp`, `rsk fido`, `rsk led`, `rsk reboot`, … (`rsk --help`)\n- **`rsk-tui`** — a terminal dashboard for day-to-day reads and a few in-band\n  actions ([guide](docs/guides/tui.md); `rsk-tui --demo` needs no hardware)\n\nWithout the dev shell, `rsk` also runs on a plain Python ≥ 3.9 toolchain via\n[uv](https://docs.astral.sh/uv/) or pip — `uvx --from ./tools rsk status`,\n`uv tool install ./tools`, or `pipx install ./tools`. Details and the native-lib\nnotes are in [tools/README.md](tools/README.md).\n\nSeparately, **`rsk-wipe`** is a RAM-only flash-erase *image* you flash\ndeliberately to wipe a board for clean-slate testing — it is built and flashed\nlike firmware, not run from `PATH` ([rsk-wipe/README.md](rsk-wipe/README.md)).\n\n## Limitations (short list)\n\n- **No secure element.** OTP + secure boot is real hardening, but physical\n  attacks are out of scope.\n- **Seed backup covers the deterministic identity only** — resident passkeys,\n  OpenPGP and PIV keys do not survive a board swap.\n- **No Brainpool / X448 / Ed448** OpenPGP curves (no mature `no_std` Rust\n  implementations).\n- The default USB identity is **RS-Key's own** pid.codes id `0x1209:0x0001`;\n  the YubiKey USB identity that `ykman` / Yubico Authenticator auto-recognize is\n  the opt-in `VIDPID=Yubikey5` build, not for distribution.\n\nDetails and reasoning: [docs/limitations.md](docs/limitations.md).\n\n## License\n\n**AGPL-3.0-only** — see [LICENSE](LICENSE), [NOTICE](NOTICE), and\n[COMPLIANCE.md](COMPLIANCE.md). RS-Key is a from-scratch Rust reimplementation of\nthe AGPL-3.0-**only** [pico-keys](https://github.com/polhenarejos) firmware\nfamily (pico-fido / pico-openpgp / pico-keys-sdk) by Pol Henarejos; the upstream\ngrant is version-3-only, so RS-Key inherits it and so must forks. Not affiliated\nwith or endorsed by Yubico, Nitrokey, or Raspberry Pi. See [motivation](docs/motivation.md).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FTheMaxMur%2FRS-Key","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FTheMaxMur%2FRS-Key","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FTheMaxMur%2FRS-Key/lists"}