Il nostro obiettivo di oggi è criptare un file proteggendolo con una password in Python.
Anzitutto abbiamo bisogno della libreria cryptography. Per installarla utilizziamo come al solito PIP:
pip install cryptography
Per i neofiti basta aprire il Terminale su Windows (WIN+R e digitare cmd
) ed eseguire il comando.
Quello che andremo a realizzare sarà un semplice programma da Terminale, dove ci siano due opzioni, una per criptare e una per decriptare il file. Il programma dovrà comportarsi più o meno in questo modo:
Anzitutto cominciamo col creare la base del nostro programma, che si svolgerà tutto in un ciclo while infinito. Dobbiamo prevedere 3 opzioni: crittare il file, decrittare il file e un’opzione per uscire/terminare il programma (questa è la prima opzione che implementeremo, per evitare di restare bloccati nell’esecuzione infinita):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
while True: print("-- programma di crittografia dei file --") print("1. critta file") print("2. decritta file") print("0. esci") try: scelta = int(input("scelta: ")) except: print("ERRORE! Scelta non valida!") scelta = -1 if scelta == 0: break |
Dalla libreria cryptography
importeremo Fernet
per la crittografia simmetrica, le caratteristiche salienti del sistema Fernet
sono:
- Crittografia simmetrica: Utilizzo della medesima chiave per cifrare e decifrare i dati
- Sicurezza: gli algoritmi di cifratura utilizzati sono del tipo AES in modalità CBC con una chiave da 128 bit
- Autenticazione dei dati: include HMAC per garantire, laddove necessario, l’integrità e l’autenticità dei dati cifrati
La più blanda implementazione di questo algoritmo potrebbe essere fatta nel modo seguente:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
from cryptography.fernet import Fernet # generiamo una chiave chiave = Fernet.generate_key() # inizializziamo Fernet con la chiave generata fernet = Fernet(chiave) # testo da cifrare messaggio = "Presto sarà primavera. E i frutteti saranno in fiore. E gli uccelli nidieranno nel boschetto di nocciole. E l'orzo estivo sarà seminato nei campi a valle. E si mangeranno le prime fragole con la panna. Vi ricordate il sapore delle fragole?" # cifriamo il messaggio messaggio_cifrato = fernet.encrypt(messaggio.encode()) # stampiamo il messaggio cifrato print(f"Messaggio cifrato: {messaggio_cifrato.decode()}") |
Il risultato sarà qualcosa del genere:
In questo caso, faccio notare, abbiamo usato una chiave generata direttamente dal programma, mentre quello che vogliamo fare in questo esercizio è usare una password come chiave di crittografia.
A tale scopo implementiamo una funzione di creazione della chiave a partire da una password data dall’utente:
1 2 3 4 5 6 |
import base64, hashlib def crea_password(pswd): hlib = hashlib.md5() hlib.update(pswd.encode("utf-8")) return base64.urlsafe_b64encode(hlib.hexdigest().encode('utf8')) |
A questo punto possiamo passare all’implementazione del resto del programma.
Anzitutto gestiamo la scelta 1, dove chiederemo all’utente di darci il percorso del file e una password da usare per la crittazione.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
if scelta == 1: file = input("file: ") pswd = getpass.getpass("password: ") if os.path.isfile(file): with open(file,"rb") as fp: dati = fp.read() chiave = crea_password(pswd) fernet = Fernet(chiave) dati_crittati = fernet.encrypt(dati) with open(file,"wb") as fp: fp.write(dati_crittati) print("File criptato con successo!") else: print("ERRORE! Impossibile trovare il file") |
Faccio notare come in questa parte richiediamo in input
un percorso per il file e usiamo getpass
per acquisire la password (funzionerà sul Terminale, mentre sull’IDLE Shell la password sarà esposta in chiaro!).
Una volta acquisito il nome/percorso del file, verifichiamo se effettivamente esiste, in tal caso lo apriamo in lettura con l’opzione rb (per leggere in modo binario), creiamo la chiave a partire dalla password e cifriamo il file.
Per la decrittazione l’operazione sarà analoga, ma alla rovescia:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
if scelta == 2: file = input("file: ") pswd = getpass.getpass("password: ") if os.path.isfile(file): with open(file,"rb") as fp: dati = fp.read() chiave = crea_password(pswd) fernet = Fernet(chiave) dati_decrittati = fernet.decrypt(dati) with open(file,"wb") as fp: fp.write(dati_decrittati) print("File decriptato con successo!") else: print("ERRORE! Impossibile trovare il file") |
Il codice complessivo sarà così:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
from cryptography.fernet import Fernet import base64, hashlib import getpass import os def crea_password(pswd): hlib = hashlib.md5() hlib.update(pswd.encode("utf-8")) return base64.urlsafe_b64encode(hlib.hexdigest().encode('utf8')) while True: print("-- programma di crittografia dei file --") print("1. critta file") print("2. decritta file") print("0. esci") try: scelta = int(input("scelta: ")) except: print("ERRORE! Scelta non valida!") scelta = -1 if scelta == 0: break if scelta == 1: file = input("file: ") pswd = getpass.getpass("password: ") if os.path.isfile(file): with open(file,"rb") as fp: dati = fp.read() chiave = crea_password(pswd) fernet = Fernet(chiave) dati_crittati = fernet.encrypt(dati) with open(file,"wb") as fp: fp.write(dati_crittati) print("File criptato con successo!") else: print("ERRORE! Impossibile trovare il file") if scelta == 2: file = input("file: ") pswd = getpass.getpass("password: ") if os.path.isfile(file): with open(file,"rb") as fp: dati = fp.read() chiave = crea_password(pswd) fernet = Fernet(chiave) dati_decrittati = fernet.decrypt(dati) with open(file,"wb") as fp: fp.write(dati_decrittati) print("File decriptato con successo!") else: print("ERRORE! Impossibile trovare il file") |