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.
Costruisci un cifrario di Cesare in Python, provalo con unittest e vedi perché questo cifrario a scorrimento non dà alcuna vera segretezza.
Scriverai una funzione caesar(). Fa scorrere le lettere inglesi di un certo numero di posizioni, lascia invariato ogni altro carattere e inverte lo scorrimento quando le passi un numero negativo. Poi eseguirai una piccola suite di test e leggerai che cosa controlla.
Ti serve Python 3 e nient'altro. Se l'idea di cifrario a scorrimento ti è nuova, leggi prima Che cos'è il cifrario di Cesare?.
Installa Python 3 da python.org. Il codice usa solo la libreria standard, quindi non c'è nulla da installare con pip. Crea una cartella per il lab e salva lì i file.
L'output di questo articolo viene da Python 3.12.10 su Windows 11. Non ho provato altre versioni.
La funzione ord() di Python restituisce il code point Unicode di un carattere. chr() fa il contrario e riconverte un code point in un carattere. Per la lettera maiuscola A, il code point è 65.
Esegui questo comando in un terminale:
python -I -c "print(ord('A'), chr(65))"Output:
65 AIl flag -I esegue Python in modalità isolata. Le variabili d'ambiente che iniziano con PYTHON vengono ignorate, e la cartella corrente non entra nel percorso di ricerca dei moduli. Usalo quando esegui codice da una cartella il cui contenuto non hai scritto tu.
Lo scorrimento lavora su una posizione che parte da zero. Sottrarre 65 trasforma A in 0 e Z in 25. Il passaggio % 26 riporta il risultato dentro l'alfabeto, e aggiungere 65 ripristina l'intervallo delle maiuscole:
chr((ord(letter) - 65 + shift) % 26 + 65)Le lettere minuscole partono da 97, quindi la stessa idea usa 97 al posto di 65.
L'operatore % di Python non restituisce mai un numero negativo quando il divisore è positivo. Per questo uno scorrimento negativo funziona senza codice aggiuntivo:
python -I -c "print((0 - 3) % 26)"Output:
23Zero meno tre riparte dal fondo dell'alfabeto e dà 23, che è la posizione di X.
Salva questo codice come caesar_cipher.py. È lo stesso codice del file del lab.
"""Educational Caesar cipher only. NOT secure encryption.
Shift ASCII English A-Z/a-z; preserve every other Unicode character as-is.
"""
def caesar(text: str, shift: int) -> str:
shift %= 26
result = []
for character in text:
if 'A' <= character <= 'Z':
result.append(chr((ord(character) - 65 + shift) % 26 + 65))
elif 'a' <= character <= 'z':
result.append(chr((ord(character) - 97 + shift) % 26 + 97))
else:
result.append(character)
return ''.join(result)
if __name__ == '__main__':
print(caesar('HELLO, World!', 3)) # KHOOR, Zruog!
print(caesar('KHOOR, Zruog!', -3)) # HELLO, World!La prima riga, shift %= 26, riduce qualsiasi scorrimento all'intervallo da 0 a 25. Uno scorrimento di 29 si comporta come uno di 3, e uno scorrimento di -3 diventa 23.
Esegui il file:
python -I caesar_cipher.pyOutput:
KHOOR, Zruog!
HELLO, World!La funzione cambia solo le lettere dalla A alla Z e dalla a alla z. Cifre, spazi, punteggiatura e lettere accentate passano invariati. Così il codice resta breve. Un cifrario che gestisse le lettere accentate avrebbe bisogno di una regola per ognuna, e questo lab non ne definisce.
Il lab include anche test_caesar_cipher.py. Apri un terminale nella cartella che contiene entrambi i file ed esegui:
python -I -m unittest discover -p 'test_*.py' -vOutput:
test_large_shift (test_caesar_cipher.CaesarCipherTest.test_large_shift) ... ok
test_lower (test_caesar_cipher.CaesarCipherTest.test_lower) ... ok
test_negative (test_caesar_cipher.CaesarCipherTest.test_negative) ... ok
test_roundtrip (test_caesar_cipher.CaesarCipherTest.test_roundtrip) ... ok
test_upper (test_caesar_cipher.CaesarCipherTest.test_upper) ... ok
test_wrap (test_caesar_cipher.CaesarCipherTest.test_wrap) ... ok
----------------------------------------------------------------------
Ran 6 tests in 0.001s
OKOgni test controlla un comportamento:
test_upper e test_lower confermano che HELLO diventa KHOOR e attack diventa dwwdfn.test_wrap conferma che Z avanza fino a C, cosa possibile solo se il ritorno all'inizio dell'alfabeto è corretto.test_large_shift conferma che uno scorrimento di 29 dà lo stesso risultato di uno di 3.test_negative controlla la decifratura facendo scorrere DEF di -3.test_roundtrip cifra un testo con uno scorrimento di 7, lo decifra con -7 e si aspetta di riavere l'originale. Il testo di esempio include punteggiatura, una cifra e á, quindi controlla anche che i caratteri non alfabetici sopravvivano.Se modifichi il codice e un test fallisce, il messaggio di errore mostra l'input, il valore atteso e il valore reale. Leggi quel messaggio prima di cambiare qualsiasi altra cosa.
Un cifrario di Cesare ha solo 25 scorrimenti utili. Lo scorrimento 0 e lo scorrimento 26 restituiscono entrambi il testo originale. Una persona può provare ogni scorrimento a mano, e un programma li prova tutti in un istante.
L'analisi delle frequenze è un secondo problema. In inglese, lettere come E e T compaiono più spesso di Q o Z. In un messaggio più lungo, le lettere più comuni del testo cifrato spesso indicano le lettere più comuni del testo in chiaro.
Questo cifrario, quindi, non dà nessuna vera riservatezza. Non usarlo per password, dati dei clienti, token o qualsiasi altra cosa importante. Se ti serve una cifratura vera, usa una libreria ben collaudata e un algoritmo standard. L'OWASP Cryptographic Storage Cheat Sheet elenca le regole di base per proteggere i dati salvati.
Prendi questo esercizio come un modo per imparare l'aritmetica modulare, i codici dei caratteri e la differenza tra una trasformazione giocattolo e un vero cifrario.
Quando i test passano, puoi chiedere a un modello linguistico di spiegare la riga del modulo, proporre casi limite o scrivere altri test. Un prompt utile dichiara i limiti fin dall'inizio:
Rivedi questo cifrario di Cesare didattico. Che cosa succede con scorrimenti negativi, caratteri accentati e testo non latino? Non descriverlo come cifratura sicura.
Esegui ogni test proposto dal modello prima di accettarlo. I modelli sbagliano, e un test che fallisce ti dice di più di una spiegazione sicura di sé.
Quando il lab funziona, tieni la cartella sotto controllo di versione così puoi seguire le modifiche. Il prossimo articolo, Che cos'è GitHub?, spiega come fare.
Crittografia
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.
Crittografia
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.
Crittografia
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.