Anwendung des Vigenère-Chiffres in Java

In diesem Artikel möchte ich dir gerne zeigen, wie du das Vigenère-Verschlüsselungsverfahren in Java anwenden kannst.

Was ist der Vigenère-Chiffre?

Bei Vigenère handelt es sich um ein einfaches Verschlüsselungsverfahren, bei dem eine Nachricht mit einem Schlüsselwort verschlüsselt wird, sodass diese nur mit dem Schlüsselwort auf Anhieb entschlüsselt werden kann.

Vorgehen

Bei dem Algorithmus wird dann in einer Tabelle, in der jeweils die Buchstaben von A bis Z in jeder Zeile stehen, jeweils um einen Buchstaben mehr versetzt, nach der entsprechenden Spalte für den zu verschlüsselnden Buchstaben gesucht. In dieser Spalte wird dann der zum in der linken Spalte stehenden Schlüsselbuchstaben zugehörige Buchstabe abgelesen und in die verschlüsselte Nachricht eingefügt. Zum Entschlüsseln wird dieses Verfahren genau rückwärts wieder ausgeführt.

Wie sicher ist Vigenère?

Natürlich solltest du mit dem Vigenère-Chiffre nicht deine Passwörter oder sonstige Daten verschlüsseln. Es handelt sich dabei um ein altes/traditionelles Verfahren, welches mit sehr wenig Aufwand durch pures Ausprobieren (sogenanntes Brute-Force) geknackt werden kann.

Wie nutze ich Vigenère in Java? (Quellcode)

Mit dem folgenden Quellcode kannst du eine einfache Klasse mit den Methoden encodiere und decodiere nutzen. Im Konstruktor befindet sich direkt auch schon ein Testaufruf dieser Methoden, um den Algorithmus gleich testen zu können. Mit der Methode bruteForce lassen sich alle möglichen Schlüssel und entschlüsselten Nachrichten ermitteln, um eine Nachricht ohne den dazugehörigen Schlüssel zu entschlüsseln.

Der Quellcode ist ausführlich kommentiert. Solltest du noch Fragen dazu haben, kannst du natürlich gerne einen Kommentar hinterlassen.

/**
 * Klasse zur Anwendung des Vigenère-Chiffres
 * Achtung: die Schlüssel und Nachrichten dürfen jeweils nur aus Buchstaben bestehen, keine Umlaute oder Sonderzeichen. Die Groß- und Kleinschreibung ist dabei egal. 
 * @author Bloggingwelt.de
 * © Copyright 2021 Bloggingwelt.de
 */
public class Vigenere {
	
	//Erstellung der Buchstaben-Arrays
	public char[] buchstaben = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'};
	public char[][] buchstabentabelle = new char[buchstaben.length][buchstaben.length];
	
	public static void main(String[] args) {
		new Vigenere();
	}
	
	public Vigenere() {

		//Befüllen der Buchstabentabelle (zweidimensionales Array)
		buchstabentabelle = erstelleBuchstabentabelle();

		//Testaufrufe
		System.out.println(encodiere("HAL", "ich habe hunger"));
		System.out.println(decodiere("HAL", encodiere("HAL", "ich habe hunger")));
		System.out.println(bruteForce(encodiere("HAL", "ich habe hunger"), 3, true));
	}
	
	/**
	 * Klasse für eine Nachricht
	 */
	private class Nachricht {
		private String nachricht;
		private String schluessel;
		
		public Nachricht(String pNachricht, String pSchluessel) {
			this.nachricht = pNachricht;
			this.schluessel = pSchluessel;
		}
		
		public Nachricht(String pSchluessel) {
			this.nachricht = "";
			this.schluessel = pSchluessel;
		}
		
		public String getNachricht() {
			return this.nachricht;
		}
		
		public void setNachricht(String pNachricht) {
			this.nachricht = pNachricht;
		}
		
		public String getSchluessel() {
			return this.schluessel;
		}
	}

	/**
	 * @param nachricht die Nachricht, die entschlüsselt werden soll
	 * @param laengeSchluessel die Länge des Schlüssels, bis zu der ausprobiert werden soll
	 * @param legt fest, ob die Liste aller Nachrichten und Schlüssel in der Konsole ausgegeben werden soll oder nicht
	 * @return entschlüsselte Nachrichten in einer Liste
	 */
	public List<Nachricht> bruteForce(String nachricht, int laengeSchluessel, boolean listeAusgeben) {
		List<Nachricht> loesungen = moeglicheSchluessel(laengeSchluessel);
		if(listeAusgeben == true) {
			loesungen.toFirst();
			while(loesungen.hasAccess()) {
				loesungen.getContent().setNachricht(decodiere(loesungen.getContent().getSchluessel(), nachricht));
				System.out.println("Nachricht: " + loesungen.getContent().getNachricht() + ", Schlüssel: " + loesungen.getContent().getSchluessel());
				loesungen.next();
			}
		}
		return loesungen;
	}
	
	/**
	 * Nachricht mit der Übergabe eines Schlüssels und der Nachricht, die verschlüsselt zurückgegeben werden soll
	 * @param String schluessel Schlüssel zum Codieren
	 * @param String nachricht Nachricht, die codiert werden soll
	 * @return verschlüsselte Nachricht
	 */
	public String encodiere(String schluessel, String nachricht) {

		//Schlüssel und Nachricht in Char-Array verwandeln, nachdem alle Leerzeichen entfernt wurden und es in Großbuchstaben umgewandelt wurde
		char[] schluesselArray = schluessel.replaceAll("\\s+","").toUpperCase().toCharArray();
		char[] nachrichtenArray = nachricht.replaceAll("\\s+","").toUpperCase().toCharArray();

		String verschluesselteNachricht = "";

		//Durchlaufen der kompletten Nachricht
		for(int i = 0; i < nachrichtenArray.length; i++) {

			//Teilung der Nachricht in 5er-Blöcke
			if(i != 0 && i % 5 == 0) {
				verschluesselteNachricht += " ";
			}

			int j = 0;

			//"Verlängerung" des Schlüssels auf die Nachrichtenlänge
			if(i >= schluesselArray.length){
				j = i - (i / schluesselArray.length) * schluesselArray.length;
			} else {
				j = i;
			}

			//Heraussuchen des entsprechenden Buchstabens aus der Tabelle und Anfügen an die Nachricht
			verschluesselteNachricht += buchstabentabelle[buchstabenPosition(nachrichtenArray[i])][buchstabenPosition(schluesselArray[j])];
		}

		//Rückgabe der verschlüsselten Nachricht
		return verschluesselteNachricht;
	}
	
	/**
	 * Nachricht mit der Übergabe eines Schlüssels und der entschlüsselten Nachricht als Rückgabe
	 * @param schluessel Schlüssel zum Decodieren
	 * @param nachricht Nachricht, die decodiert werden soll
	 * @return entschlüsselte Nachricht
	 */
	public String decodiere(String schluessel, String nachricht) {

		//Schlüssel und Nachricht in Char-Array verwandeln, nachdem alle Leerzeichen entfernt wurden und es in Großbuchstaben umgewandelt wurde
		char[] schluesselArray = schluessel.replaceAll("\\s+","").toUpperCase().toCharArray();
		char[] nachrichtenArray = nachricht.replaceAll("\\s+","").toUpperCase().toCharArray();

		String entschluesselteNachricht = "";

		//Durchlaufen der kompletten Nachricht
		for(int i = 0; i < nachrichtenArray.length; i++) {

			//Teilung der Nachricht in 5er-Blöcke
			if(i != 0 && i % 5 == 0) {
				entschluesselteNachricht += " ";
			}

			int j = 0;

			//"Verlängerung" des Schlüssels auf die Nachrichtenlänge
			if(i >= schluesselArray.length){
				j = i - (i / schluesselArray.length) * schluesselArray.length;
			} else {
				j = i;
			}

			//Suchen nach der Buchstabenposition in der entsprechenden Spalte des Lösungswortes
			int buchstabenPositionSpalte = -1;
			for(int p = 0; p < buchstaben.length; p++) {
				if(buchstabentabelle[buchstabenPosition(schluesselArray[j])][p] == nachrichtenArray[i]){
					buchstabenPositionSpalte = p;
				}
			}

			//Heraussuchen des entsprechenden Buchstabens aus der ganz linken Spalte der Tabelle und Anfügen an die Nachricht
			entschluesselteNachricht += buchstabentabelle[0][buchstabenPositionSpalte];
		}

		//Rückgabe der entschlüsselten Nachricht
		return entschluesselteNachricht;
	}
	
	/**
	 * Hilfsmethode zur Bestimmung einer Buchstabenposition im Alphabet
	 * @param buchstabe der zu suchende Buchstabe
	 * @return gesuchte Position oder -1, wenn er nicht gefunden wurde
	 */
	public int buchstabenPosition(char buchstabe) {
		for(int i = 0; i < buchstaben.length; i++) {
			if(buchstaben[i] == buchstabe) {
				return i;
			}
		}
		return -1;
	}

	/**
	 * Hilfsmethode zur Erstellung aller möglichen Schlüsseln einer Länge
	 * @param laenge des zu suchenden Schlüssels
	 * @return Liste aller möglicher Schlüssel und Nachrichten der definierten Länge
	 */
	public List<Nachricht> moeglicheSchluessel(int laenge) {
		List<Nachricht> schluessel = new List<Nachricht>();
		List<Nachricht> schluesselTemp = new List<Nachricht>();
		schluessel.append(new Nachricht(""));
		for(int j = 0; j < laenge; j++) {
			schluessel.toFirst();
			while(schluessel.hasAccess()) {
				for(int i = 0; i < buchstaben.length; i++) {
					schluesselTemp.append(new Nachricht(schluessel.getContent().getSchluessel() + Character.toString(buchstaben[i])));
				}
				schluessel.next();
			}
			schluessel.concat(schluesselTemp);
			schluesselTemp.toFirst();
			while(schluesselTemp.hasAccess()) {
				schluesselTemp.remove();
				schluesselTemp.next();
			}
		}
		schluessel.toFirst();
		schluessel.remove();
		
		return schluessel;
	}	
	
	/**
	 * Hilfsmethode zur verschobenen Befüllung der Buchstabentabelle
	 * @return gefüllte Buchstabentabelle
	 */
	public char[][] erstelleBuchstabentabelle() {
		char[][] tabelle = new char[buchstaben.length][buchstaben.length];;
		int verschiebung = 0;
		for(int i = 0; i < buchstaben.length; i++) {
			for(int j = 0; j <  26; j++) {
				verschiebung = j+i;
				if(verschiebung >= buchstaben.length) {
					verschiebung = verschiebung - buchstaben.length;
				}
				tabelle[i][j] = buchstaben[verschiebung];
			}
		}
		return tabelle;
	}

}Code-Sprache: Java (java)

Viel Spaß beim Ver- und Entschlüsseln ;-)!

Hinweis: Mit Sternchen (*) markierte Links auf dieser Seite sind Werbelinks. Beim Kauf darüber erhalte ich eine kleine Provision, der Preis bleibt für dich aber gleich. Damit unterstützt du mich, sodass ich weiterhin kostenlosen Inhalt auf diesem Blog anbieten kann ;-).

Du hast noch Fragen zum Quellcode oder zum Algorithmus? Dann keine Zeit verlieren und einfach einen Kommentar schreiben!

Bitte bedenke, dass alle Kommentare manuell freigeschaltet werden müssen. Das kann teilweise ein bisschen dauern, du kannst dich aber mit der unten aufgeführten Funktion benachrichtigen lassen, wenn er beantwortet wurde. Das heißt auch, dass Beleidigungen, Spam oder pure Werbung keine Chance haben, auf die Website zu kommen. Deine Email-Adresse wird selbstverständlich nicht veröffentlicht. Erforderliche Felder sind mit * oder (erforderlich) markiert.