Esercizio 6
Scrivi un programma che realizzi il sistema di cifratura a chiave simmetrica di Giulio Cesare. Il programma deve essere in grado di cifrare o decifrare una parola inserita da tastiera.
Come è noto, Giulio Cesare usava, nel corso delle varie
guerre, comunicare attraverso dispacci cifrati.
Il codice usato da Cesare era un semplice cifrario di sostituzione dove
le lettere alfabetiche differivano di una costante (chiave k) dalle lettere
codificate in chiaro secondo lo schema seguente:
dove per ipotesi la chiave k di cifratura vale 3. Ovviamente
il valore della chiave può essere un numero intero arbitrariamente scelto.
l'importante è che il valore della chiave sia nota sia al mittente che al
destinatario del messaggio (chiave simmetrica).
Ora, se questo sistema poteva essere ritenuto valido in un periodo storico
dove era raro trovare una persona in grado di leggere o scrivere un testo
(in chiaro) al giorno d'oggi un cifrario del genere è altamente sconsigliabile
per la sua elevata vulnerabilità.
L'implementazione del sistema di codifica e decodifica, rimane un buon esercizio
per prendere confidenza con stringhe caratteri e numeri e le loro reciproche
conversioni.
Dovendo automatizzare l'operazione al calcolatore bisogna ricordare come
questo memorizza i caratteri con un numero che varia da 0 a 255 per un totale
di 256 caratteri totali; questo perché per memorizzare un carattere ci vuole
1 byte=8 bit e con 8 bit si possono avere 28=256 byte diversi.
Questi codici sono rappresentati nella
tabella dei caratteri ASCII (American Standard Code for Information
Interchange).
Come si nota a ciascun carattere corrisponde un suo numero. Anche se questo
numero viene elaborato in binario dal microprocessore e viene memorizzato
in esadecimale dalla RAM, noi possiamo riferirci ad esso anche in decimale.
Per
realizzare uno scritto che preveda il minimo di righe di istruzione possibile,
dobbiamo osservare la tabella costatando che il lotto delle lettere minuscole
è disgiunto sia da quello delle lettere minuscole che dai numeri interi
(0..9). Decidiamo dunque di operare solo sull'insieme delle lettere maiuscole
che va dal codice ASCII 65='A' fino al 90='Z' usando, dunque, l'alfabeto
inglese di 26 caratteri. Nel nostro esempio usiamo una chiave k=+3 quindi
ogni lettera della frase viene traslata verso destra di 3 posizioni.
Dobbiamo quindi prevenire uno sconfinamento oltre il codice 90 (Z) in fase
di codifica e di evitare di scendere sotto il 65 (A) in fase di decodifica.
Identificando con la variabile p la frase o parola da elaborare, per evitare
malintesi essa viene subito commutata in maiuscolo tramite l'istruzione:
p=p.toUpperCase();
Gli spazi eventuali (spazio=32) vengono anch'essi eliminati dall'istruzione
p=p.replaceAll(" ","" );
Rimane la possibilità che nella frase possano entrare caratteri superiori a 90=Z oppure inferiori al 65=A per risolvere il problema, bisogna preventivamente eseguire una scansione della frase/parola eliminando questi caratteri
for(int i=0;i < p.length();i++)
if(p.charAt(i)<'A' || p.charAt(i)>'Z')
p=p.replaceAll("" +p.charAt(i), "" );
A parte il fatto che le funzioni come charAt(i) o replaceAll("
","" ) o toUpperCase() sono funzioni proprie delle stringhe in Java l'algoritmo
nel suo insieme può essere usato come riferimento per la soluzione dello
stesso problema in altri linguaggi di programmazione.
Le operazioni di codifica e decodifica vengono eseguite da opportuni metodi;
ad esempio .nel caso della codifica ogni lettera deve spostarsi verso destra
di 3 posizioni.
Ciascuna lettera viene convertita nel suo codice ASCII corrispondente che è un numero intero, quindi dobbiamo eseguire una conversione di cast;
j=(int)p.charAt(i)+k;
se sconfiniamo oltre il 90=Z decrementiamo di 26 posizioni.
if(j > 90)j-=26;
la lettera codificata è il carattere corrispondente al numero trovato
c+=(char)j;
che viene inserito nella stringa da restituire.
class cesare{ public static void main (String args []) {
Scanner in=new Scanner(System.in);
int j,k=3;//k è la chiave
String p="";//p:parola da elaborare
System.out.print("inserisci parola:");
p=in.nextLine();//parola da crittare o decrittare
p=p.toUpperCase();
//tutti i caratteri della parola commutati in maiuscolo
p=p.replaceAll(" ","" );//elimina gli eventuali spazi
for(int i=0;i < p.length();i++)
if(p.charAt(i)<'A' || p.charAt(i)>'Z')
p=p.replaceAll(""+p.charAt(i),"" );
System.out.println(p);
System.out.print("codifica(1) o decodifica(2)?:");
j=in.nextInt();
if(j==1)System.out.println(codifica(p,k));
else if(j==2)System.out.println(decodifica(p,k));
else System.out.println("errore digita 1 o 2");
}//fine main
static String codifica(String p,int k){
int j;
String c="";
for(int i=0;i < p.length();i++){
j=(int)p.charAt(i)+k;//nuovo codice ASCII della lettera attuale
if(j > 90)j-=26;//se vado sopra la Z decremento j di 26 posizioni
c+=(char)j;//converto il codice ASCII nella lettera corrispondente
}//fine for
return c;//parola codificata
}//fine codifica
static String decodifica(String p,int k){
int j;
String c="";
for(int i=0;i < p.length();i++){
j=(int)p.charAt(i)-k;//nuovo codice ASCII della lettera attuale
if(j < 65)j+=25;//se vado sotto la A incremento j di 26 posizioni
c+=(char)j;//converto il codice ASCII nella lettera corrispondente
}//fine for
return c;//parola decodificata
}//fine decodifica
}//fine classe