Lo so, il consiglio generale è "tieni le mani fuori dalla criptografia". E il modo standard per crittografare i dati di backup in modo sicuro sarebbe utilizzare GnuPG. Tuttavia, per un esercizio piuttosto accademico, mi piacerebbe pensare a un protocollo che funzioni solo con gli strumenti standard di OpenSSL (cioè, dgst, enc, rsautl & Co) richiamati da una shell POSIX.
Lo scenario include un sistema più o meno affidabile su e da cui vengono creati i backup - questo potrebbe e. g. essere un mail o un file server. Poi c'è uno storage che non è affidabile al 100% (ad esempio, un cloud storage o un server di backup non completamente sotto il mio controllo). Quindi lo scopo della crittografia è proteggere la riservatezza e l'integrità dei dati mentre sono archiviati nella memoria non sicura. Questa protezione dovrebbe anche funzionare nel caso in cui il sistema di fiducia venga compromesso, almeno per i dati memorizzati prima che il sistema attendibile venisse compromesso.
Quindi ecco una sorta di protocollo che dovrebbe soddisfare i criteri sopra menzionati:
Passaggio 1: coppia di chiavi RSA
Questo passaggio deve essere eseguito solo una volta. È necessaria una coppia di chiavi RSA. Questa coppia di chiavi non deve essere creata sul sistema "fidato", ma su una scatola veramente affidabile (ad esempio una stazione di lavoro affidabile o dovunque ti fidi di mantenere il tuo keyring GPG). Poiché la chiave privata è necessaria solo per il ripristino, non deve mai entrare nei reami del sistema attendibile o della memoria non attendibile. La dimensione della chiave deve essere 4096 bit o superiore (ne parleremo più avanti). OpenSSL di solito offre la generazione e la separazione delle chiavi con questi comandi:
EDIT: switched to PKCS#8 for the keys, being probably more resistant to brute force attacks
openssl genpkey -aes-256-cbc -algorithm RSA -pkeyopt 'rsa_keygen_bits:8192' -out private.key
openssl pkey -in private.key -out public.key -pubout
Passaggio 2: Genera segreti di sessione
Per ogni processo di crittografia, devono essere generati segreti dedicati (chiave, vettore di inizializzazione e sale):
EDIT: removed salt as per Ctulhu's comment
key=$(openssl rand -hex 32)
iv=$(openssl rand -hex 16)
hmacpw=$(openssl rand -base64 48)
Nota: sono consapevole che questo avrà i segreti non protetti nella memoria della macchina affidabile. Tuttavia, se un utente malintenzionato ha accesso alla macchina in modo da poter scremare la memoria del processo di backup, probabilmente ha già accesso ai dati da proteggere con questi segreti.
Passaggio 3: comprimi e crittografa
I dati devono essere compressi prima della crittografia. La compressione è necessaria comunque, quindi ritengo una buona idea farlo prima di crittografare i dati:
EDIT: removed salt as per Ctulhu's comment
data-generator | xz -zc | openssl enc -e -aes-256-ctr -K $key -iv $iv -out message.enc
Passaggio 4: Genera HMAC e impacchetta i tasti
L'ultimo passo sarebbe quello di generare un HMAC dei dati appena crittografati e comprimerlo insieme con i segreti della sessione in un file crittografato RSA, utilizzando la chiave pubblica per la crittografia:
EDIT: removed salt as per Ctulhu's comment
hmac=$(openssl dgst -sha512 -hmac $hmacpw -hex message.enc | sed 's/^.*=[[:space:]]//g')
echo "${key}:${iv}:${hmacpw}:${hmac}" | openssl rsautl -inkey public.key -pubin -encrypt -out message.key
E qui diventa ovvio perché la chiave RSA doveva essere così grande: le cifre esadecimali nelle stringhe di shell sono contate come un byte ciascuna, non mezzo un byte. Pertanto, la dimensione della stringa di tasti riassume (2x32 + 2x16 + 64 + 128 + 5) = 293 byte = 2344 bit.
Ancora una volta, sono consapevole che esporre i segreti su una linea di comando è generalmente una cattiva idea, ma date le circostanze, non vedo come ciò comprometterebbe la riservatezza o l'integrità dei dati che sono disponibili in testo normale su tale sistema, dove un aggressore potrebbe molto più facilmente compromettere la loro privacy o integrità. Tuttavia, se volessi davvero implementarlo, preferirei usare named pipe per evitare che i segreti si presentino nella lista dei processi.
Ora le mie domande:
- Cosa mi sono perso? Vedi qualche difetto o potenziale vettore di attacco che non ho ancora notato?
- Sarebbe più sicuro creare una firma con
openssl dgst -sha512 -sign private.key -out message.sig message.enc
, dato che questo richiederebbe la chiave privata per risiedere sul sistema più o meno affidabile?