
Login con impronta digitale sul desktop Linux usando un sensore Grow R503 + Arduino + un daemon Rust sostitutivo di fprintd
Un lettore di impronte digitali USB per desktop Linux, assemblato da componenti singoli. Costo totale dei componenti
inferiore a 15 $. Sostituto diretto del progetto upstream fprintd — funzionano PAM, KDE Settings,
GNOME Settings, fprintd-verify, sudo con il dito e sblocco dello schermo
con il dito.
A partire da fw=1.0 / r503d 1.0.0 il collegamento Arduino↔host è autenticato:
ogni comando e ogni risposta trasporta un MAC SipHash-2-4 basato su un
segreto accoppiato tramite TOFU e memorizzato in EEPROM. Gli attacchi di replay e di scambio a caldo
contro il collegamento seriale USB sono bloccati. Vedi SPEC.md §13 per la progettazione completa,
incluso ciò che il modello di minaccia non copre.

vorrei tanto avere una stampante 3D…``` ┌──────────┐ UART ┌─────────────┐ USB-CDC ┌──────────────────┐ │ Grow │ 57600 8N1│ Arduino │ /dev/r503 │ r503d daemon │ │ R503 │◀─────────▶│ (firmware) │◀──────────▶│ net.reactivated │ │ sensor │ 3.3V TTL │ │ framed, │ .Fprint on D-Bus│ └──────────┘ └─────────────┘ MAC'd └──────────────────┘ │ ▼ PAM, KDE, GNOME, fprintd-verify, …
## Perché
I lettori di impronte digitali USB hardware per Linux sono scarsi, costosi, e
quelli che esistono (Validity, Synaptics, ecc.) sono reverse-engineered tramite
driver libfprint instabili che si rompono con gli aggiornamenti del firmware del fornitore. Il
protocollo del Grow R503 è **pubblico**, il lato Arduino è codice tuo,
e il livello di compatibilità libfprint è solo D-Bus.
Ti ritrovi anche con un lettore di impronte digitali di cui puoi leggere il sorgente, dall'inizio
alla fine.
## Distinta dei materiali
| Parte | Note | Costo approssimativo |
|------|-------|------|
| Sensore capacitivo di impronte digitali Grow R503 | Quello rotondo con l'anello RGB | ~$10 |
| Arduino Uno R3 / Nano / Mega / qualsiasi scheda ATmega328 | Qualsiasi cosa che esegua SoftwareSerial | $5–$25 |
| 4–6 fili jumper | Dupont / breadboard | trascurabile |
Questo è tutto. **Niente level shifter, niente partitore di tensione** — vedi [`SPEC.md` §3.1](https://github.com/matpb/linux-fingerprint-r503/blob/main/SPEC.md)
per il motivo (la linea RX dell'R503 è tollerante ai 5V nella pratica; il datasheet mente).
## Cablaggio```
R503 Arduino (Uno R3 / Nano / etc.)
---- ------------------------------
Red (VCC) 3V3
White (3.3VT) 3V3 (touch-IC supply; shares rail with red)
Black (GND) GND
Yellow (TXD) D2 ── SoftwareSerial RX
Brown (RXD) D3 ── SoftwareSerial TX (direct — no divider!)
Blue (WAKEUP) D4 (optional; not used by firmware yet)
Se la tua R503 viene fornita con il connettore JST-SH, taglia un pigtail a 6 pin JST-SH-to-Dupont per separare i fili. Il marrone a volte è verde a seconda del venditore — verifica in base al filo che entra nel pin RXD del connettore JST, non al colore.
Testato su Fedora 44 KDE; dovrebbe funzionare su qualsiasi distro basata su systemd con
fprintd, pam_fprintd e una toolchain Rust recente.
Pacchetti di sistema:
| Distro | Compilazione | Runtime |
|---|---|---|
| Fedora / RHEL | rust cargo arduino-cli tpm2-tss-devel | fprintd pam fprintd-pam tpm2-tss |
| Debian / Ubuntu | rustc cargo arduino-cli libtss2-dev | fprintd libpam-fprintd libtss2-esys-3.0.2-0 |
I pacchetti tss-esapi sono necessari solo se prevedi di usare --pair --seal-tpm
(SPEC §13.12). Altrimenti il demone compila e funziona senza TPM — tss-esapi
è una dipendenza di compilazione obbligatoria ma di runtime facoltativa (il percorso del codice viene seguito solo quando
/var/lib/r503d/key.tpm esiste).
Rust 1.95+, arduino-cli nel tuo $PATH.
Hai un TPM2?```bash ls /dev/tpmrm0 && tpm2_pcrread sha256:7 | head -3
Se entrambi riescono, il tuo host può utilizzare il percorso della chiave sigillata. Se `/dev/tpmrm0` è
assente (hardware più vecchio, TPM disabilitato nel BIOS o una VM senza TPM virtuale),
attieniti al flusso predefinito con chiave in chiaro.
## Compilazione e installazione
### 1. Flash del firmware
Apri `firmware/r503fp/r503fp.ino` nell'IDE Arduino e caricalo. Oppure con
`arduino-cli`:```bash
# Uno R3:
arduino-cli compile --fqbn arduino:avr:uno firmware/r503fp/
arduino-cli upload --fqbn arduino:avr:uno --port /dev/ttyACM0 firmware/r503fp/
# Nano (modern Optiboot, including most Elegoo / WAVGAT clones):
arduino-cli compile --fqbn arduino:avr:nano:cpu=atmega328 firmware/r503fp/
arduino-cli upload --fqbn arduino:avr:nano:cpu=atmega328 --port /dev/ttyUSB0 firmware/r503fp/
# Nano with legacy 57600-baud bootloader (older clones):
# replace `cpu=atmega328` with `cpu=atmega328old`
The firmware uses Adafruit_Fingerprint. The IDE will offer to install it
on first compile.
If arduino-cli upload fails with not in sync: resp=0x7e, your bootloader
is the other variant — swap atmega328 ↔ atmega328old and retry. Both
work; the difference is just bootloader baud rate.
Requires Rust 1.95+.
Traduzione in italiano:
Il firmware utilizza Adafruit_Fingerprint. L'IDE offrirà di installarlo
alla prima compilazione.
Se arduino-cli upload fallisce con not in sync: resp=0x7e, il tuo bootloader
è l'altra variante — scambia atmega328 ↔ atmega328old e riprova. Entrambi
funzionano; la differenza è solo il baud rate del bootloader.
Richiede Rust 1.95+.```bash cd pcside/daemon cargo build --release
### 3. Installazione```bash
sudo bash pcside/daemon/dist/install.sh
Questo script: