Vai al contenuto
New

DeepSeek V4.1 Flash free for 7 days: 10M tokens a day after a top-up of $10 or more. Until Nov 30.

How it works

Chiavi pubbliche e private spiegate: firme che puoi verificare

Chiavi pubbliche e private da zero: cosa dimostra una firma, perché la chiave privata resta segreta e un lab con Ed25519 in cui un file modificato non passa la verifica.

Base10 min di letturaDi NotHoly

La crittografia a chiave pubblica risolve un problema che i segreti condivisi non possono risolvere. Due parti che non si sono mai incontrate possono concordare un segreto su una rete che chiunque può leggere. Qualcuno può anche dimostrare di aver scritto un file, senza condividere alcun segreto con chi lo controlla. Entrambe le cose funzionano perché una coppia di chiavi ha due metà legate matematicamente. La metà pubblica si può condividere liberamente. La metà privata resta in mano al proprietario.

Se hai usato TLS o SSH, ti sei già affidato a questa idea. Il lucchetto del browser e la richiesta di fingerprint del client SSH dipendono entrambi dalle chiavi pubbliche. Questo articolo spiega l'idea che sta sotto quegli strumenti. Genererai una coppia di chiavi Ed25519 con OpenSSL, firmerai un file, verificherai la firma, poi cambierai una riga del file e vedrai fallire la verifica. Le release software firmate usano lo stesso meccanismo, ed è la base delle chiavi SSH trattate nel prossimo articolo.

Che cos'è una coppia di chiavi

Una coppia di chiavi è formata da due valori generati insieme. La chiave privata è segreta. La chiave pubblica si può copiare in un file, inviare per email o incollare nella configurazione di un server. Le due sono legate da una matematica che funziona in una sola direzione. Ricavare la chiave pubblica da quella privata è facile. Lo schema è progettato perché risalire alla chiave privata da quella pubblica sia impraticabile.

I crittografi la chiamano crittografia asimmetrica perché le due parti usano chiavi diverse. La cifratura simmetrica, come AES, usa un solo segreto per entrambe le direzioni. Uno schema asimmetrico divide il lavoro: una chiave esegue un'operazione e l'altra la inverte o la controlla.

Un'immagine approssimativa aiuta. Pensa alla chiave pubblica come alla fessura di una cassetta delle lettere. Chiunque può infilarci una lettera, e solo il proprietario ha la chiave che apre la cassetta. Per le firme i ruoli si invertono. Il proprietario appone su un documento un sigillo che solo lui può fare, e chiunque abbia il riferimento pubblico può controllare il sigillo. L'immagine è imperfetta, perché le chiavi sono numeri e non ottone. Da ricordare è la direzione di ogni operazione.

Cifratura e firme fanno lavori opposti

Si confondono di continuo, quindi tienile separate.

La cifratura verso una chiave pubblica permette a chiunque abbia la tua chiave pubblica di creare un messaggio che solo la tua chiave privata può aprire. L'obiettivo è la riservatezza. Chiunque può scriverti, e solo tu puoi leggere quello che ha scritto.

Una firma è un valore che chi possiede la chiave privata calcola su determinati dati. Chiunque abbia la chiave pubblica può controllarla. L'obiettivo è autenticità e integrità: i dati vengono dal titolare della chiave e nessuno li ha modificati dopo la firma. Una firma non nasconde nulla. Un file firmato resta del tutto leggibile da chi lo possiede.

Ed25519, l'algoritmo di questo lab, è solo uno schema di firma. Non può cifrare un messaggio. La cifratura a chiave pubblica usa altre costruzioni, come RSA-OAEP o un accordo di chiavi su curve ellittiche seguito da un cifrario simmetrico. Per questo "chiave pubblica" indica una forma di chiave più che un compito. Impara prima il compito, poi l'algoritmo.

TLS usa entrambi i compiti. In un handshake TLS 1.3, il server firma dei dati con la chiave privata che corrisponde alla chiave pubblica del suo certificato, e così dimostra di controllare quella chiave. Un accordo di chiavi separato ricava poi le chiavi simmetriche che cifrano la sessione. SSH segue la stessa divisione. Una host key firma parte dell'handshake e una user key firma una sfida di autenticazione. Una volta separati i due compiti, i protocolli diventano più facili da leggere.

Perché la chiave privata non deve mai lasciare il suo proprietario

La chiave privata è la prova. Chi la possiede può produrre firme che risultano valide per quell'identità e può decifrare i messaggi cifrati verso di essa. Chi verifica non vede la tua faccia né il tuo nome. Controlla una firma rispetto alla chiave pubblica di cui si fida. Se qualcuno copia la tua chiave privata, ogni verificatore che si fida della tua chiave pubblica accetta la copia come se fossi tu.

Ne seguono quattro regole pratiche:

  • Genera la chiave privata sulla macchina che la userà, o su un token hardware costruito per questo. Non scaricare una chiave privata da un sito web e non riceverne una in chat.
  • Restringi i permessi del file. Proteggi la chiave con una passphrase quando lo strumento lo permette, o tienila in uno store con supporto hardware.
  • Tienila fuori da Git, ticket, screenshot e richieste di assistenza. Gli scanner di segreti cercano le intestazioni PEM. Una volta che una chiave arriva nella cronologia di un repository, considerala esposta, anche dopo aver cancellato il file.
  • Se sospetti un'esposizione, ritira quella chiave. Crea una nuova coppia, pubblica la nuova chiave pubblica attraverso un canale di cui i verificatori si fidano e revoca quella vecchia. Cancellare il file locale non rimuove le copie già uscite dalla tua macchina.

Condividere la chiave pubblica è sicuro per progetto. Il problema più difficile va nella direzione opposta. Chi verifica deve sapere che una chiave pubblica appartiene davvero alla persona o al progetto che indica. Le autorità di certificazione, le chiavi di release fissate e i fingerprint degli host SSH esistono per risolvere proprio questo problema. Una firma valida dimostra che il titolare della chiave ha firmato quei byte. Non dimostra che il titolare della chiave sia chi ti aspettavi.

Come funzionano firma e verifica, passo per passo

La sequenza per una release firmata è questa:

  1. Chi pubblica la release genera una coppia di chiavi una sola volta e tiene segreta la chiave privata.
  2. Condivide la chiave pubblica attraverso un canale di cui chi verifica si fida, come una pagina già considerata attendibile, un fingerprint pubblicato in un secondo posto o una chiave verificata in precedenza.
  3. Per ogni release, firma con la chiave privata i byte esatti del file. Una firma Ed25519 è lunga 64 byte.
  4. Distribuisce insieme il file e la sua firma.
  5. Chi verifica esegue il controllo usando i byte del file, la firma e la chiave pubblica fidata. La risposta è valida o non valida.

Due dettagli contano più di quanto sembri. Il primo: una firma copre byte esatti. Uno spazio in più, un fine riga diverso o un archivio ricompresso sono un messaggio diverso, e la verifica fallisce. Il secondo: la firma Ed25519 di RFC 8032 è deterministica. La stessa chiave e lo stesso messaggio producono sempre la stessa firma, quindi firmare non richiede ogni volta un nuovo numero casuale. Questo elimina una causa comune di errore. FIPS 186-5 elenca EdDSA con ECDSA e RSA tra gli algoritmi di firma digitale approvati.

Lab pratico: firma un file e vedi fallire la verifica

Ti serve OpenSSL 3.x. L'output di questo lab viene da Windows 11 con Git Bash e OpenSSL 3.2.4. Controlla prima la tua versione con openssl version. Le build più vecchie potrebbero non accettare le stesse opzioni.

Usa Git Bash, una shell Linux o il Terminale su macOS. Windows PowerShell 5.1 scrive in UTF-16 quando reindirizzi con >, e questo cambia i byte che firmi. Esegui il lab in una cartella vuota sulla tua macchina. Non contatta alcun server.

Genera la coppia di chiavi

bash
openssl genpkey -algorithm ed25519 -out priv.pem
openssl pkey -in priv.pem -pubout -out pub.pem

Quando riescono, entrambi i comandi non stampano nulla. Controlla i risultati:

bash
ls -l priv.pem pub.pem

Sulla nostra macchina, priv.pem era di 122 byte e pub.pem di 116 byte. Apri pub.pem e vedrai il blocco -----BEGIN PUBLIC KEY-----. Non stampare e non incollare priv.pem. In questo lab è la metà segreta dell'identità, e abituarti a non mostrarla mai ti servirà anche per le chiavi SSH.

Firma il file

bash
echo 'release v1.0' > msg.txt
openssl pkeyutl -sign -inkey priv.pem -rawin -in msg.txt -out msg.sig
ls -l msg.sig

L'opzione -rawin dice a OpenSSL di firmare direttamente il contenuto del file. Ed25519 calcola l'hash dell'input all'interno dell'algoritmo, quindi non devi fare prima l'hash del file. Il comando di firma non stampa nulla. Il nostro msg.sig era di 64 byte.

Verifica con la chiave pubblica

bash
openssl pkeyutl -verify -pubin -inkey pub.pem -rawin -in msg.txt -sigfile msg.sig

Output:

text
Signature Verified Successfully

Il flag -pubin dice che il file della chiave contiene solo la metà pubblica. A chi verifica non serve altro, quindi questo controllo può girare su un'altra macchina che non ha mai visto priv.pem.

Cambia una riga e verifica di nuovo

bash
echo 'release v1.1' > msg.txt
openssl pkeyutl -verify -pubin -inkey pub.pem -rawin -in msg.txt -sigfile msg.sig

Output:

text
Signature Verification Failure

Il comando esce con stato 1. La firma in msg.sig è stata fatta su release v1.0, quindi non può garantire per release v1.1. OpenSSL non dice cosa è cambiato. Riporta solo che byte e firma non concordano. Chi verifica dovrebbe trattare questo risultato come uno stop netto, e non come un avviso da superare con un clic.

Controlla i casi limite

Questi controlli mostrano esattamente cosa copre la firma. Li abbiamo eseguiti tutti sulla stessa macchina, nella stessa cartella.

Firmare due volte lo stesso file dà gli stessi byte:

bash
echo 'release v1.0' > msg.txt
openssl pkeyutl -sign -inkey priv.pem -rawin -in msg.txt -out a.sig
openssl pkeyutl -sign -inkey priv.pem -rawin -in msg.txt -out b.sig
cmp a.sig b.sig && echo "identical"

Output:

text
identical

Un file senza l'a capo finale non passa. echo aggiunge un a capo, quindi questo file è più corto di un byte:

bash
printf 'release v1.0' > nonl.txt
openssl pkeyutl -verify -pubin -inkey pub.pem -rawin -in nonl.txt -sigfile a.sig

Output:

text
Signature Verification Failure

msg.txt è di 13 byte e nonl.txt di 12 byte. La firma riguarda la versione da 13 byte, quindi il file più corto non passa.

Anche una coppia di chiavi diversa non passa, persino sul file originale:

bash
openssl genpkey -algorithm ed25519 -out other.pem
openssl pkey -in other.pem -pubout -out other.pub
openssl pkeyutl -verify -pubin -inkey other.pub -rawin -in msg.txt -sigfile a.sig

Output:

text
Signature Verification Failure

Il file e la firma sono entrambi corretti. La chiave pubblica appartiene a un'altra coppia, quindi il controllo fallisce.

Errori comuni

  • Trattare una firma come cifratura. Un file firmato resta leggibile da chiunque. Se ti serve segretezza, ti serve la cifratura, che è una costruzione separata.
  • Fidarsi di qualsiasi chiave pubblica trovata. Una firma valida dimostra che il titolare della chiave ha firmato i byte. Non dimostra chi sia il titolare della chiave. Confronta i fingerprint attraverso un secondo canale.
  • Verificare byte diversi da quelli firmati. Una pipeline che ricodifica, ricomprime o cambia i fine riga rompe la verifica. Firma l'artefatto finale e verifica quello stesso artefatto.
  • Firmare in una shell che riscrive i byte. Il reindirizzamento di Windows PowerShell 5.1 è un esempio. Gli editor che salvano con una codifica o un fine riga diversi sono un altro.
  • Riusare una sola chiave per tutto. Chiavi separate per firma delle release, login SSH e cifratura limitano il danno quando una chiave trapela.
  • Credere che una chiave cancellata sia sparita. Le copie in backup, cartelle sincronizzate, cronologia della shell o log di chat sopravvivono a una cancellazione locale.
  • Scegliere le primitive dal nome. "RSA" o "ECC" non dicono quale padding, curva o modalità sia in uso. Leggi i parametri nello standard, oltre all'etichetta.

Per andare oltre

Il prossimo articolo, Che cos'è SSH e come funzionano le chiavi SSH?, usa la stessa idea di firma per i login. I tuoi file id_ed25519, se li hai, sono una coppia esattamente di questo tipo. Leggi anche l'articolo sull'hashing delle password, perché password e chiavi risolvono parti diverse dell'autenticazione, ed è utile tenerle distinte.

Per scendere nel dettaglio, leggi RFC 8032 per vedere come Ed25519 struttura le sue firme e perché è deterministico. Leggi FIPS 186-5 per vedere dove si colloca EdDSA tra gli algoritmi di firma approvati. Leggi le pagine man di OpenSSL genpkey e pkeyutl per vedere le altre opzioni, come la scelta del digest per gli algoritmi che ne richiedono uno. Poi verifica una release di un progetto che usi già, con la chiave che il progetto pubblica sul proprio sito. Esegui solo file scaricati dalla fonte ufficiale, e solo dopo averli controllati.

Fonti

Gli standard e le pagine di manuale citati sopra sono i riferimenti primari di questo articolo:

  • RFC 8032, Edwards-Curve Digital Signature Algorithm (EdDSA)
  • FIPS 186-5, Digital Signature Standard (DSS)
  • Documentazione di OpenSSL, openssl-genpkey
  • Documentazione di OpenSSL, openssl-pkeyutl

Fonti

  1. RFC 8032: Edwards-Curve Digital Signature Algorithm (EdDSA)
  2. FIPS 186-5: Digital Signature Standard (DSS)
  3. OpenSSL documentation: openssl-genpkey
  4. OpenSSL documentation: openssl-pkeyutl

Altro su Crittografia

Crittografia

Cifratura, codifica e hashing: che cosa fa ciascuno

Distingui codifica, cifratura e hashing con laboratori su Base64, SHA-256 e OpenSSL. Impara perché Base64 non protegge niente e perché gli hash sono unidirezionali.

Base10 min di lettura

Crittografia

Password e hashing con Argon2id

Perché gli hash veloci non vanno bene per le password, a cosa servono salt e work factor e come calcolare e verificare un hash con Argon2id in Python usando argon2-cffi.

Intermedio10 min di lettura