[Pubblichiamo un estratto da Imparare a programmare con JavaScript. Il valore di un libro come questo sta nell’introdurre in modo accattivante la programmazione anche in ambiti che diventano rapidamente riservati ai professionisti.]
La crittografia
Quando invii un messaggio potresti avere la necessità di mantenerlo segreto. Per fare in modo che un messaggio sia leggibile solo dal destinatario ci sono due possibilità: nascondere il messaggio o nascondere il contenuto del messaggio. Per nascondere il contenuto lo si può codificare, cioè trasformare i simboli dell’alfabeto con cui è scritto in qualcos’altro.
La crittologia è lo studio delle tecniche per nascondere le informazioni e la crittografia (letteralmente “scrittura nascosta”) studia i modi per cifrare i testi.
I cifrari a sostituzione utilizzano una password per codificare il testo (come nella figura qui sopra). Vediamo un sistema a prova di curiosi usato già al tempo dei Romani per comunicare in tempo di guerra.
Cesare e i messaggi nascosti
Nelle campagne di Gallia, Giulio Cesare, sapendo che i messaggeri e con essi i messaggi potevano cadere nelle mani del nemico, aveva escogitato un modo (chiamato ancor oggi “Cifrario di Cesare”) per tenere segrete le comunicazioni. Il metodo prevede di spostare (o shiftare, dall’inglese shift) ogni lettera del testo in avanti nell’alfabeto. Per decifrare il messaggio e capirlo bisogna conoscere sia il metodo, cioè l’algoritmo, utilizzato per cifrarlo sia il numero di posizioni dello spostamento, ovvero la chiave.
Come puoi vedere nella prossima figura, se la chiave è 3 la lettera “a” nel messaggio viene spostata di 3 posizioni, diventando la “d”, la “b” (evidenziata) diventa la “e” e così via. Quando si supera la “z” si riparte, circolarmente, dalla “a”.
Il cifrario di Cesare
Scriviamo un programma per codificare i messaggi secondo il cifrario di Cesare (guarda la figura qui sotto).
Parte del codice HTML per definire la pagina della figura precedente è il seguente.
cifrario_cesare/index.html (elemento body col contenuto della pagina)
<body>
<img src="images/wizard.png" id="character">
<img src="images/speech-bubble-rounded.png" id="speech-bubble">
<span id="msg">
Scrivi un messaggio in chiaro<br>
e lo cripterò<br>
oppure un messaggio cifrato<br>
e lo decripterò
</span>
<div id="input-area">
<label id="label-decrypted-msg" for="decrypted-msg">Testo in chiaro:</label>
<textarea cols="40" rows="2" id="decrypted-msg"></textarea>
<p>
<button onclick="encrypt();" id="encrypt-button">Cripta</button>
<button onclick="decrypt();" id="decrypt-button">Decripta</button>
<label id="label-key" for="key">Chiave:</label>
<input type="text" id="key" value="3">
</p>
<label id="label-encrypted-msg" for="encrypted-msg">Testo cifrato:</label>
<textarea cols="40" rows="2" id="encrypted-msg" value=""></textarea>
</div>
</body>
Vediamo ora come risolvere in JavaScript il problema della cifratura (in inglese encrypt) dei messaggi. La decodifica (decrypt) è analoga.
Suddividiamo il compito in due funzioni: encryptWeb() e encrypt(): nella prima gestiamo l’interfaccia e l’acquisizione dei dati, nella seconda cifriamo la stringa in input.
encryptWeb() è richiamata dall’evento onclick del pulsante encrypt-button e, dopo che sono stati recuperati la stringa da convertire dal campo di tipo textarea decrypted-msg e il valore della chiave dal campo key, richiama la funzione di codifica encrypt() e visualizza il risultato nell’altra textarea (encrypted-msg).
cifrario_cesare/index.js (funzione encryptWeb)
var alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
/* Gestisce l'input/output con la pagina web e richiama encrypt() */
function encryptWeb() {
var msg = $('#decrypted-msg').val(); // Recupera il messaggio in chiaro
var key = parseInt($('#key').val()); // Recupera il valore della chiave
var result = encrypt(msg, key); // Codifica il messaggio
$('#encrypted-msg').val(result); // Mostra il testo nella pagina HTML
}
La funzione di codifica encrypt() riceve in input il testo da cifrare e il valore della chiave. Un ciclo for scorre la stringa di input e, quando incontra una lettera (per semplificare ci limitiamo alle lettere maiuscole), incrementa il codice di quest’ultima del valore della chiave. Se, sommando la chiave al codice del carattere il valore risultante va oltre l’ultima lettera (la Z), sottrae un valore pari alla lunghezza dell’alfabeto (26 lettere) per rimanere nell’intervallo ASCII delle lettere (per farlo si potrebbe anche utilizzare l’operatore modulo).
cifrario_cesare/index.js (funzione encrypt)
/* Restituisce un messaggio codificato con uno spostamento di key posizioni */
function encrypt(msg, key) {
var result = ""; // Inizializza il messaggio criptato
msg = msg.toUpperCase(); // Converte il messaggio in maiuscolo
for (var i = 0; i < msg.length; i++) { // Scorre i caratteri del messaggio
var char = msg.charAt(i); // Carattere i-esimo
if (alphabet.indexOf(char) >= 0) { // Controlla se è una lettera
var index = char.charCodeAt(0) + key; // Indice del carattere cifrato
if (index > 'Z'.charCodeAt(0)) { // Se l'indice va oltre 'Z'
index = index - 26; // Riparti in modo circolare da 'A'
}
result += String.fromCharCode(index); // + carattere calcolato
} else {
result += char; // Copia i caratteri che non sono lettere
}
}
return result;
}
Effettuiamo un test e un controtest (usando l’output del test come input) per verificare che le due funzioni siano effettivamente l’una l’inversa dell’altra. Possiamo farlo anche da console grazie al fatto che abbiamo separato l’interfaccia dalla logica del programma. Dopo aver caricato la pagina index.html, oppure aver fatto un “copia e incolla” del contenuto di index.js nella console, scrivi le seguenti istruzioni:
> var key = 3;
< 3
> var messaggio = "Imparare a programmare con JavaScript è divertente";
< "Imparare a programmare con JavaScript è divertente"
> decrypt(encrypt(messaggio, 3), 3); // Andata e ritorno
< "IMPARARE A PROGRAMMARE CON JAVASCRIPT È DIVERTENTE"
Un modo alternativo per codificare le lettere fa uso dell’operatore modulo nel modo seguente.
// Calcola lo scostamento tra 0 e 25 (cioè, quanto va oltre la 'Z')
var index = (char.charCodeAt(0) + key - 'A'.charCodeAt(0)) % 26;
// e aggiunge il codice della 'A'
index = index + 'A'.charCodeAt(0);
Lo spazio al tempo del latino
Il codice usato da Cesare è piuttosto semplice per i giorni nostri, ma all’epoca era comunque un sistema originale e poco conosciuto. La sua robustezza, inoltre, era aumentata dal fatto che, nel I secolo a. C., ai tempi di Giulio Cesare, nella scrittura di documenti in lingua latina tra le parole non vi erano spazi bianchi o segni di punteggiatura (lo spazio per separare le parole è un’introduzione del latino medievale). Questo richiedeva molta concentrazione nella lettura, che spesso era fatta a voce alta, anche di testi non cifrati!