Cryptoanalyse - Known Plaintext

Es folgt der versprochene Beitrag zur Crypto-Analyse eines Usernet Account-Checkers. Dieser erlaubt es, den Account-Status per BB-Code in andere Seiten grafisch einzubinden. Klingt eigentlich nach einer netten Sache… Wenn dabei nur nicht die Account-Daten übergeben werden! Denn das PHP-Skript, welches das Bild erzeugt nimmt Usenet Username und Passwort als GET-Parameter entgegen. Um zu verhindern, dass die Accountdaten ausgelesen werden, wird der Accountname verschlüsselt.

usenetcheck

Ein solcher Include-Link sieht folgendermaßen aus:

usenext-check/image.php?a=vLjWqt+jvNGWm9S54bU==&p=dGVzdA==

Mit dem scharfen Kryptoanalyse-Blick stellt man fest, dass a (der Accountname) und p (das Passwort) Base64 encodiert sind. Während das Passwort einfach ASCII-Encoded ist, bekommt man beim Decoden von Parameter a zunächst Probleme. Denn es hängt ein Gleichheitszeichen zu viel hinten dran! Wenn man dieses überflüssige Zeichen entfernt lassen sich die Daten zwar encodieren, aber es handelt sich nicht um einen ASCII-String. Anscheinend ist der Accountname verschlüsselt.

Nun haben wir den großen Vorteil zu einem Accountnamen den Chiptertext generieren können. Also haben wir eine Known-Plaintext-Attack und kommen mit etwas Glück auf den Key. Füttern wir den Account-Checker mit ein paar Werten und schauen uns das Resultat an. Vielleicht stellen wir ja Gesetzmäsigkeiten fest…

Ein Accountname von 20x “a” erzeugt den verschlüsselten Text “uqfWqNWXuNGUmcal1KKWk5myt8M=”. Da sich der decodierte ASCII String “º§Ö¨Õ—¸Ñ”™Æ¥Ô¢–“™²·Ã” nicht schön darstellen lässt, wird in Zukunft mit eine Hexdump-Darstellung gearbeitet.

00000000   BA A7 D6 A8 D5 97 B8 D1 94 99 C6 A5 D4 A2 96 93
00000010   99 B2 B7 C3

Da dieser Hexdump wenig erhellend ist, schauen wir welche Daten bei 40x “a” erzeugt werden: (= uqfWqNWXuNGUmcal1KKWk5myt8O6p9ao1Ze40ZSZxqXUopaTmbK3ww==)

00000000   BA A7 D6 A8 D5 97 B8 D1  94 99 C6 A5 D4 A2 96 93 
00000010   99 B2 B7 C3 BA A7 D6 A8  D5 97 B8 D1 94 99 C6 A5
00000020   D4 A2 96 93 99 B2 B7 C3

Anscheinend findet nach 20 Zeichen eine Wiederholung der Daten statt! Diese Information lässt auf einen 20 Zeichen Key schließen, sowie dass die vorherigen Daten nicht in die folgenden Daten beeinflussen. Letzteres wäre der Fall bei CBC Mode , bei welchem die vorherigen Daten mit dem Key für den nächsten Block XORed werden.

Was passiert, wenn wir nun anstatt von “a”s ein paar “b”s senden? Hier die Ausgabe von “aaaaabbbbb” (uqfWqNWYudKVmg==)

00000000   BA A7 D6 A8 D5 98 B9 D2  95 9A

Während die ersten 5 Zeichen (wie zu erwarten) gleich bleiben, sind die nächsten 5 Zeichen (unsere “b”s) um exakt eine 1 größer. Das tollte ist, dass b in der ASCII-Tabelle auch um eine 1 größer ist wie a. Diese Information ist sehr wertvoll, denn anscheinend werden die Account-Daten mit einem Shift verschlüsselt (Wenn jemand eine genaue Bezeichung für diese Art von “Verschlüsselung” kennt, darf gerne einen Kommentar hinterlassen). Wer sich das noch nicht vorstellen kann, hat hier nochmal eine Visualisierung:

Plaintext: "abcdef"
In ASCII: 0x61 0x62 0x63 0x64 0x65 0x66
Shift Key: 0x10 0x20 0x30
Chiptertext: (0x61 + 0x10) (0x62 + 0x20) (0x63 + 0x30) (0x64 + 0x10) (0x65 + 0x20) (0x66 + 0x30) = 0x71 0x82 0x93 0x74 0x85 0x96

Somit haben wir De-Facto die Verschlüsselung gebrochen, denn wir kennen die Keylänge und die Verschlüsselungsart. Fehlt nur noch das wichtigste, der Key! Diesen sollten wir errechnen können, indem wir die obere Rechnung umdrehen. Da sich der verschlüsselte Buchstabe i aus “Chipter[i] = Key[i] + Buchstabe[i]“ zusammensetzt, ergibt sich nach Adams Riese: “Key[i] = Chipter[i] - Buchstabe[i]“. Fangen wir mit dem ersten Buchstaben des Keys an:

Buchstabe[0] = 0x61 (= a)
Chipter[0] = 0xBA
0xBA = Key[0] + 0x61
=> Key[0] = 0xBA - 0x61 = 0x59 = "Y"

Da wir zu faul sind diese Rechnungen einzeln durchzuführen, schreiben wir uns ein C# Skript was uns die Arbeit abnimmt:

// Chipter Data für "aaaaaaaaaaaaaaaaaaaa"
byte[] chipterData = new byte[] {0xBA, 0xA7, 0xD6, 0xA8, 0xD5, 0x97, 0xB8, 0xD1, 0x94, 0x99, 0xC6, 0xA5, 0xD4, 0xA2, 0x96, 0x93, 0x99, 0xB2, 0xB7, 0xC3};
 
// ASCII Daten für "aaaaaaaaaaaaaaaaaaaa"
byte[] letterData = Encoding.ASCII.GetBytes("aaaaaaaaaaaaaaaaaaaa");
 
// Bisher leere Key-Daten
byte[] keyData = new byte[20];
// Key[i] = Chipter[i] - Letter[i]
for (int i = 0; i < 20; i++)
{
     keyData[i] = (byte)(chipterData[i] - letterData[i]);
}
 
String asciiEncodedKey = Encoding.ASCII.GetString(keyData);

Damit ist der ASCII-Decodierte Key sogar richtig hübsch: YFuGt6Wp38eDsA528QVb

Mit dieser Information lässt sich auch der oben angegebene Account-Name entschlüsseln. Diese kleine Aufgabe überlasse ich dem Leser. Als Tipp: Die Formel “Chipter[i] = Key[i] + Buchstabe[i]” muss etwas umgestellt werden ;)

Ich hoffe ihr habt bei diesem sehr einfachen Beispiel der Crypto-Analyse etwas lernen können. Ich selbst stehe erst am Anfang von Crypto-Aufgaben, finde das Thema aber sehr spannend. Und wenn man ein “reales Beispiel” knackt, ist die Freude nochmal größter!

9 people like this post.
    • dsfsdfs
    • 22. Mai. 2015 4:50am

    Affine Chiffre ist das Stichwort ;)

    • li0nsar3c00l
    • 5. Jul. 2015 12:23pm

    interessanter ansatz, wüsste nich ob ich auf die idee gekommen wäre, das so zu decrypten. Respekt!

  1. Noch keine TrackBacks.