C) Cäsar Verschlüsselung

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:

  1. Es macht keinen Sinn mehr nur Großbuchstaben zurückzugeben. Entfernen Sie also die Methode toUpperCase() beim Rückgabewert.
  2. 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 die for-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;
	  }
          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;
  }
}

12 Replies to “C) Cäsar Verschlüsselung”

  1. Stefan Kiesel

    OK, das ist zweimal ein Kommentar von der selben IP-Adresse mit unterschiedlichem Namen und kurz hintereinander. Wenn wirklich Hilfe gewünscht ist, dann bitte mit richtigen Namen, etwas geduldiger, und mit konkreter Problembeschreibung: Was genau wird nicht verstanden?

    Gruß
    Stefan

  2. Amelie

    ja wir sahen im computerraum nebeneinander und mussten diese aufgabe in Infomartik machen.
    Wir sollten diese Verschlüsserung selbst herstellen mit java. ja und wir sind java nieten

  3. Stefan Kiesel

    Hallo Amelie,

    das ist ja alles kein Thema. Wir helfen auch gerne, wenn es Probleme gibt. Aber ohne konkrete Frage kann ich euch leider nicht weiterhelfen.

    Gruß
    Stefan

  4. Mentos05
        char[] ch = new char[26+26+10+32+6];
        int pos = 0;
        for (int i = 32; i < 39; i++) {
          ch[pos++] = (char)i;
        }
        for (int i = 40; i < 127; i++) {
          ch[pos++] = (char)i;
        }

    Wieso kann man hier nicht gleich von 32 bis 127 durchgehen? (Array out of bound exception)
    Im Moment geht es doch von 32 nach 39 und von 40 nach 127 wenn ich das richtig verstehe.

    char[] ch = new char[26+26+10+32+6];
    Wieso schreibst du hier nicht 100 hin?
    Oder dient das nur dem Verständnis? (26 kleine Buchstaben, 26 große, etc.)

      public String decrypt(String text) {
        setSwitchIt(getSwitchIt() * -1);
        text = encrypt(text);
        setSwitchIt(getSwitchIt() * -1);
        return text;
      }

    Wieso drehst du das Vorzeichen zwei Mal?
    Der Schlüssel wird doch sowieso bei jedem Aufruf erneut gesetzt, soweit ich das verstehe.

    Bin noch ein Anfänger was Java angeht, von daher bitte nicht lachen, falls ich irgendwo schwere Denkfehler habe. =)

    Des Weiteren, die Entschlüsselungsmethode funktioniert ja nur, wenn man den Schlüssel weiß.
    Ich möchte anhand von Buchstabenhäufigkeitsverteilung (nur die deutsche Sprache), eine Entschlüsselung programmieren, die als Ergebnis den entschlüsselten Text mit Schlüssel ausgibt.
    Hättest du da vielleicht eventuell irgendwelche guten Anlaufpunkte im Web? Beispielscripte sind immer gerne gesehen.
    Das hier ist dennoch ein hervorragendes Grundgerüst zum lernen. Vielen Dank schonmal!

  5. Stefan Kiesel

    Hallo Mentos05,

    danke für deinen Kommentar.

    Dein Denkfehler liegt im Detail. Schleife 1 geht von 32 bis kleiner als 39, also 38. Schleife zwei fängt bei 40 an. Die 39 wird also ausgelassen. Allerdings kann ich dir nicht mehr sagen, warum ich die 39 (entspricht dem Zeichen ‚) ausgelassen habe. Außerdem fehlte noch der Backslash ( \ ) bei den Sonderzeichen. Ich habe den Code dahingehend ausgebessert.

    Ich habe nicht direkt 100 geschrieben (bzw. nach meiner Verbesserung 101), damit die Aufteilung klarer wird. Man kann natürlich auch direkt 100 bzw. 101 schreiben.

    Der Schlüssel wird nur neu gesetzt, wenn die setSwitchIt-Methode aufgerufen, oder eine neue Instanz der Klasse erzeugt wird. Man könnte aber bspw. mehrere Texte mit einer Instanz der Klasse und ohne Aufruf von setSwitchIt ver- und entschlüsseln.

    Bspw.:

      public static void main(String[] args) {
    
        Caesar c = new Caesar();
        String s = "A";
        s = c.encrypt(s);
        System.out.println(s);
        s = c.decrypt(s);
        System.out.println(s);
        s = c.encrypt(s);
        System.out.println(s);
      }

    Wird das Vorzeichen zweimal gedreht, erhält man die korrekte Ausgabe

    D
    A
    D

    Dreht man es nur einmal, erhält man hingegen

    D
    A
    >

    Ich hoffe diesbezüglich ist jetzt alles klar!?

    Wenn du die Häufigkeitsverteilung der Buchstaben kennst, sollte es problemlos möglich sein, so ein Progrämmchen zu bauen. Zumindest auf vorerst einfachem Niveau. Durchsuche den verschlüsselten Text einfach nach den am häufigsten vorkommenden Buchstaben. Daraus kannst du dann ja relativ einfach ermitteln, wie der Schlüssel lauten könnte.

    Einen Link habe ich jedoch nicht für dich.

    Grüße
    Stefan

  6. Stefan Kiesel

    Hallo Ann,

    normalerweise programmiert man nur wiederverwendbare Programmteile (Module) und fügt diese dann zu einem kompletten Programm zusammen. So könnte man bspw. die Verschlüsselung von der Konsole, mit einer GUI oder über einen WebService zur Verfügung stellen. Eine Beispielaufruf mit fest einkodiertem Text findet man in meinem vorherigen Kommentar direkt über Ihren (mit der Nummer 7.).

    Grüße
    Stefan

  7. Michael Noser

    Hab selbst eine lösung gefunden
    Doch es giebt eine fehler
    „X“ ergiebt „{„

Schreibe einen Kommentar

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre mehr darüber, wie deine Kommentardaten verarbeitet werden.