Die Cäsar Verschlüsselung ist eine der simpelsten Möglichkeiten einen Text zu verschlüsseln. Dabei wird ein Buchstabe um X Stellen verschoben. Setzt man für X beispielsweise die drei, wird z. B. aus dem a ein D, aus b ein E und aus z ein C. Üblicherweise besteht die unverschlüsselte Nachricht nur aus Kleinbuchstaben und die verschlüsselte Geheimschrift aus Großbuchstaben. Sie werden in diesem Kapitel aber auch eine erweiterte Möglichkeit vorgestellt bekommen.
Einfache Cäsar Verschlüsselung
Um diese Verschlüsselung in Java zu implementieren legen Sie sich zuerst eine neue Klasse an.
public class Caesar {
}
Diese Klasse erhält die private Variable switchIt, welche speichert, um wie viele Stellen die Buchstaben verschoben werden sollen. Wir bieten den User zum Setzen dieser Variablen Setter- und Getter-Methoden sowie die optionale Übergabe im Konstruktor an. Wird switchIt nicht im Konstruktor übergeben, setzen Sie den Wert auf „3“. Natürlich darf auch die Methode mit dem eigentlichen Algorithmus nicht fehlen. Diese hat als Parameter einen String (den unverschlüsselten Text) und als Rückgabewert ebenfalls einen String (den verschlüsselten Text).
public class Caesar {
private int switchIt = -1;
public Caesar() {
this(3);
}
public Caesar(int switchIt) {
setSwitchIt(switchIt);
}
public int getSwitchIt() {
return this.switchIt;
}
public void setSwitchIt(int switchIt) {
this.switchIt = switchIt;
}
public String encrypt(String text) {
return null;
}
}
Widmen wir uns jetzt der encrypt-Methode. Sie wissen, dass Sie in Java Buchstaben in Zahlenwerte umwandeln können. Mithilfe einer ASCII-Tabelle erkennen Sie, dass alle Buchstaben hintereinander liegen. Es bietet sich also an den unverschlüsselten Text Zeichen für Zeichen durchzugehen und alle klein geschriebenen Buchstaben um X Stellen zu versetzen.
Die kleinen Buchstaben a-z verbergen sich hinter den ASCII-Zeichen 97-122.
public String encrypt(String text) {
StringBuffer encrypted = new StringBuffer();
for (int i = 0; i < text.length(); i++) { char cur = text.charAt(i); if (cur > 96 && cur < 123) { // Kleiner Buchstabe
cur += getSwitchIt();
encrypted.append(cur);
}
}
return encrypted.toString().toUpperCase();
}
Jetzt können Sie unsere Klasse auch testen. Erstellen Sie sich hierzu eine weitere Klasse mit einer Main-Methode, welche ein neues Objekt der Klasse Caesar erstellt und durch selbige einen String verschlüsseln lässt.
Natürlich sticht bald ins Auge, dass die letzten Buchstaben im Alphabet (je nach Wert von switchIt) nicht richtig verschlüsselt werden. Um dies zu umgehen überprüfen wir, ob das aktuelle Zeichen + die Variable switchIt einen höheren ASCII-Wert ergeben, als der von „z“. Trifft dies zu, ziehen wir vom aktuellen Ergebnis 26 ab (für die 26 Buchstaben im Alphabet).
public String encrypt(String text) {
StringBuffer encrypted = new StringBuffer();
for (int i = 0; i < text.length(); i++) { char cur = text.charAt(i); if (cur > 96 && cur < 123) { cur += getSwitchIt(); if (cur > 'z') {
cur -= 26;
}
encrypted.append(cur);
}
}
return encrypted.toString().toUpperCase();
}
Mehr brauchen Sie nicht für eine einfache Cäsar Verschlüsselung.
Erweiterte Cäsar Verschlüsselung
Natürlich ist es in der heutigen Zeit ärgerlich, wenn wirklich nur Kleinbuchstaben und sonst nichts verwendet werden dürfen. Deshalb erweitern wir unsere Cäsar Verschlüsselung dahingehend, dass beliebige, von uns definierte Zeichen, verschlüsselt werden können. Hierzu speichern wir alle Zeichen, die verschlüsselt werden können, in einem Array vom Typ char. In unserem Beispiel beinhaltet dies das Alphabet in Groß- und Kleinschreibung, das Leerzeichen, alle Zahlen und folgende Sonderzeichen:
!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~
Damit wir das Array nicht von Hand befüllen müssen, nutzen wir wieder unsere ASCII-Tabelle mitsamt Schleifen und erstellen eine entsprechende Methode.
public char[] createArray() {
char[] ch = new char[26 + 26 + 10 + 33 + 6];
int pos = 0;
for (int i = 32; i < 127; i++) {
ch[pos++] = (char)i;
}
ch[pos++] = 'ä';
ch[pos++] = 'ö';
ch[pos++] = 'ü';
ch[pos++] = 'Ä';
ch[pos++] = 'Ö';
ch[pos++] = 'Ü';
return ch;
}
Der Inhalt dieses Arrays sieht nun so aus:
!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~äöüÄÖÜ
und sollte somit so gut wie jede Eingabe verschlüsseln können. Natürlich können Sie auch die Reihenfolge der Zeichen nach Ihren Wünschen anpassen.
Jetzt legen wir uns eine Objektvariable vom Typ char-Array an, in welcher wir das erzeugte Array speichern werden. Im Konstruktor unserer Klasse weißen wir diesem den Rückgabewert unserer createArray-Methode zu, geben der aufrufenden Klasse via Getter- und Setter-Methoden aber die Möglichkeit ein eigenes char-Array zu verwenden.
public class Caesar {
private char[] chArray = null;
...
public Caesar(int switchIt) {
this.chArray = createArray();
...
}
...
public char[] getChArray() {
return this.chArray;
}
public void setChArray(char[] chArray) {
this.chArray = chArray;
}
}
Jetzt muss nur noch die encrypt-Methode angepasst werden. Hierzu gehen wir ähnlich wie mit den ASCII-Zeichen um, nur dass anstelle dieser Zeichen unser Array durchlaufen wird.
public String encrypt(String text) {
StringBuffer encrypted = new StringBuffer();
for (int i = 0; i < text.length(); i++) {
char cur = text.charAt(i);
for (int j = 0; j < this.chArray.length; j++) { if (cur == this.chArray[j]) { int pos = j + getSwitchIt(); if (pos >= this.chArray.length) {
pos -= this.chArray.length;
}
cur = this.chArray[pos];
encrypted.append(cur);
break;
}
}
}
return encrypted.toString().toUpperCase();
}
Jetzt fehlen noch zwei Kleinigkeiten:
- Es macht keinen Sinn mehr nur Großbuchstaben zurückzugeben. Entfernen Sie also die Methode
toUpperCase()beim Rückgabewert. - Sobald sich ein Zeichen im unverschlüsselten Text befindet, das aber nicht in unserem Array steht, wird es einfach gelöscht. Besser wäre es aber es zu ignorieren. Verschieben Sie hierzu die Zeile
encrypted.append(cur);hinter diefor-Schleife.
public String encrypt(String text) {
StringBuffer encrypted = new StringBuffer();
for (int i = 0; i < text.length(); i++) {
char cur = text.charAt(i);
for (int j = 0; j < this.chArray.length; j++) { if (cur == this.chArray[j]) { int pos = j + getSwitchIt(); if (pos >= this.chArray.length) {
pos -= this.chArray.length;
}
cur = this.chArray[pos];
break;
}
}
encrypted.append(cur);
}
return encrypted.toString();
}
Cäsar entschlüsseln
Selbstverständlich sollte der verschlüsselte Text auch wieder entschlüsselt werden können. Beachten Sie aber, dass es hierzu zwingend notwendig ist, dass Sie die Anzahl an Zeichen kennen, um die der verschlüsselte Text verschoben wurde, und natürlich unser char-Array in genau derselben Reihenfolge, mit der verschlüsselt wurde. Deshalb ist es unter Umständen auch günstiger die Zeichen in einer anderen Ordnung im char-Array aufeinander folgen zu lassen. Um die Einfachheit in diesem Beispiel zu wahren und den Code nicht unnötig aufblähen zu müssen, belassen wir es aber bei dieser Reihenfolge.
Das Entschlüsseln funktioniert vermutlich viel einfacher, als Sie es sich momentan vorstellen. Hierzu ist es nämlich einfach nur nötig den Schlüssel umzudrehen. Wurde bspw. mit 3 verschlüsselt, so wird der Text bei einer Verschlüsselung mit -3 wieder entschlüsselt. In unserer decrypt-Methode zum Entschlüsseln negieren wir also einfach den Schlüssel und „verschlüsseln“ nochmal.
public String decrypt(String text) {
setSwitchIt(getSwitchIt() * -1);
text = encrypt(text);
setSwitchIt(getSwitchIt() * -1);
return text;
}
Hierzu muss aber noch eine weitere Gegebenheit in unserer encrypt-Methode abgefangen werden – für den Fall, dass der Wertebereich des Arrays unterschritten wird (für das Überschreiten existiert bereits eine If-Abfrage).
public String encrypt(String text) {
StringBuffer encrypted = new StringBuffer();
for (int i = 0; i < text.length(); i++) {
char cur = text.charAt(i);
for (int j = 0; j < this.chArray.length; j++) { if (cur == this.chArray[j]) { int pos = j + getSwitchIt(); if (pos >= this.chArray.length) {
pos -= this.chArray.length;
}
else if (pos < 0) {
pos += this.chArray.length;
}
cur = this.chArray[pos];
break;
}
}
encrypted.append(cur);
}
return encrypted.toString();
}
Die vollständige und voll funktionsfähige Klasse sieht nun so aus:
public class Caesar {
private int switchIt = -1;
private char[] chArray = null;
public Caesar() {
this(3);
}
public Caesar(int switchIt) {
this.chArray = createArray();
setSwitchIt(switchIt);
}
public int getSwitchIt() {
return this.switchIt;
}
public void setSwitchIt(int switchIt) {
this.switchIt = switchIt;
}
public String decrypt(String text) {
setSwitchIt(getSwitchIt() * -1);
text = encrypt(text);
setSwitchIt(getSwitchIt() * -1);
return text;
}
public String encrypt(String text) {
StringBuffer encrypted = new StringBuffer();
for (int i = 0; i < text.length(); i++) {
char cur = text.charAt(i);
for (int j = 0; j < this.chArray.length; j++) { if (cur == this.chArray[j]) { int pos = j + getSwitchIt(); if (pos >= this.chArray.length) {
pos -= this.chArray.length;
o }
else if (pos < 0) {
pos += this.chArray.length;
}
cur = this.chArray[pos];
break;
}
}
encrypted.append(cur);
}
return encrypted.toString();
}
public char[] createArray() {
char[] ch = new char[26 + 26 + 10 + 33 + 6];
int pos = 0;
for (int i = 32; i < 127; i++) {
ch[pos++] = (char)i;
}
ch[pos++] = 'ä';
ch[pos++] = 'ö';
ch[pos++] = 'ü';
ch[pos++] = 'Ä';
ch[pos++] = 'Ö';
ch[pos++] = 'Ü';
return ch;
}
public char[] getChArray() {
return this.chArray;
}
public void setChArray(char[] chArray) {
this.chArray = chArray;
}
}
