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

Cifrario di Cesare in Python: cifrare e decifrare un testo passo per passo

Costruisci un cifrario di Cesare in Python, provalo con unittest e vedi perché questo cifrario a scorrimento non dà alcuna vera segretezza.

Base5 min di letturaDi NotHoly

Che cosa costruirai

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?.

Prima di cominciare

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.

Passo 1: le lettere come numeri

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:

bash
python -I -c "print(ord('A'), chr(65))"

Output:

text
65 A

Il 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:

python
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:

bash
python -I -c "print((0 - 3) % 26)"

Output:

text
23

Zero meno tre riparte dal fondo dell'alfabeto e dà 23, che è la posizione di X.

Passo 2: scrivi il cifrario

Salva questo codice come caesar_cipher.py. È lo stesso codice del file del lab.

python
"""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:

bash
python -I caesar_cipher.py

Output:

text
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.

Passo 3: esegui i test

Il lab include anche test_caesar_cipher.py. Apri un terminale nella cartella che contiene entrambi i file ed esegui:

bash
python -I -m unittest discover -p 'test_*.py' -v

Output:

text
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

OK

Ogni 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.

Passo 4: capisci il limite

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.

Facoltativo: fai rivedere il codice a un modello di IA

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é.

Prossimo passo

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.

Fonti

Fonti

  1. Python built-in functions (ord, chr)
  2. Python unittest documentation
  3. Python command-line options (-I)
  4. OWASP Cryptographic Storage Cheat Sheet

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