edutecnica

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.

import java.util.Scanner;
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