Elderan
0
Ich habe vor hier eine kleine Crypto-Challenge zu veranstalten und hoffe das einige freudig dran teilnehmen.
Es geht in der Crypto-Challenge um die Kryptoanalyse von Magenta, welcher von der Deutschen Telekom als Algorithmus zum Advanced Encryption Standard eingereicht wurde.
Magenta ist eine Feistelchiffre mit einer Blockgröße von 128 Bit und einer Keylänge von 128 bis 256 Bit, wobei wir uns nur die 128 Bit Variante betrachten.
Dann wollen wir mal unsere Chancen zur Kryptoanalyse abschätzen, dazu zuerst ein Paper welches Magenta weiter beschreibt: The MAGENTA Block Cipher Algorithm (Paper muss nicht gelesen werden)
Innerhalb von 20 Minuten, noch während der Präsentation von Magenta, wurde von Eli Biham, Alex Biryukov, Niels Ferguson, Lars Knudsen, Bruce Schneier und Adi Shamir eine eklatante Schwäche in Magenta gefunden, womit der Algorithmus als gebrochen gilt.
(Am Rande: Magenta war außerdem noch einer der langsamsten Algorithmen die eingereicht wurden).
Regeln ? Wichtig!
Es hat keinen Sinn sich bereits fertige Kryptoanalysen von Magenta anzugucken. Hat man diese einmal durchgelesen, gibt es nicht viel mehr zu entdecken womit die Challengen für einen dann beendet wäre.
Auch wenn das 1. Zitat wenig Mut macht, die Kryptoanalyse ist leichter als erwartet und sollte auch von fortgeschrittenen Anfängern zu meistern sein. Irgendwelche abgefahrenen Kentnisse in differentielle/lineare Kryptoanalyse sind nicht notwendig. Grundkenntnisse in Kryptographie sollten ausrecihen.
Ich werde ausreichend Tipps ins spoiler-Tags geben, wobei man sich diese erst angucken sollte, wenn man wirklich nicht mehr weiter weiß.
Sollte Ihr eine Lösung gefunden haben, dann verwendet bitte ebenso Spoiler-Tags.
Reverse Engineering oder ähnliche Verfahren sind nicht erlaubt, allerdings sind alle Angriffstechniken aus der Kryptographie erlaubt.
Woraus besteht die Challenge?
Diese Challenge besteht aus mehreren Teilen, einmal soll man einen Angriff gegen Magenta beschreiben, der natürlich deutlich schneller als Brute Force (2^128) ist.
Dann gibt es auch noch einen Praxis-Teil, ich habe eine reduzierten Magenta-Version geschrieben, die für den selben Angriff anfällig ist wie die orginal Magenta Version.
Diese Version arbeitet mit einer Blockgröße von 64 Bit sowie einer Key Länge von 64 Bit. Ein Brute Force Angriff wäre möglich (2^64 Schritte), aber dennoch zu aufwendig.
Für diesen Algorithmus soll man den Angriff, der auch gegen orginal Magenta klappt, implementieren. Dazu ist im Anhang eine DLL (Magenta64.dll), die einen geheimen Schlüssel enthält und nur ver- und entschlüsseln mit diesem geheimen Key anbietet.
Das Auslesen durch Reverse Engineering ist natürlich nicht erlaubt. Ziel ist es also, mit diesem Angriff den Key in Erfahrung zu bringen.
Zuerst nocheinmal klären, wann ein Algorithmus als gebrochen gilt:
Versucht also nicht irgendwie den Geheimtext statistisch zu untersuchen, sondern verwendet andere Angriffstechniken
1. Teil
(Erst den 1. Teil lesen, dann aber besser mit dem 2. Teil anfangen)
Finde einen Angriff gegen Magenta, welcher deutlich schneller als Brute Force (2^128 ) ist. Welche Voraussetzungen werden benötigt, um diesen Angriff durchzuführen? Welche Komplexilität wird für diesen Angriff benötigt? Von welchen Parametern hängt die Komplexilität ab und mit was für einem Aufwand kann man im aller schlimmsten Fall rechnen? Ist dieser Worst-case realistisch (mit Begründung)?
Kann man aus diesem Angriff evt. noch andere Angriffsarten ableiten? Wenn ja, wie ist deren Aufwand?
Wenn ihr noch Lust habt: Nenne ein nachvollziehbares (also aus der Realität) Beispiel, bei dem dieser Angriff schlimme Folgen haben können.
Magenta ist wie folgt aufgebaut: Wie gewohnt bei Feistelchiffren wird der 128 Bit Klartextblock in einen Linken und einen Rechten teil aufgespalten.
Der 128 Bit-Schlüssel wird ebenso in zwei Teile aufgeteilt, in k1 und k2. Der Schlüssel k1 wird für die ersten beiden Rundenfunktionen und die letzten beiden Rundenfunktionen verwendet, k2 kommt in den beiden mittleren Rundenfunktionen zum Einsatz, als Grafik sieht dies wie folgt aus:
Dabei ist F die Rundenfunktion, dieses Kreuz im dem Kreis bedeutet XOR.
Soviel schon gesagt, dieser entsprechende Angriff funktioniert ohne nähere Details der Rundenfunktion F. Deswegen solltet ihr auch, wenn ihr die modifizierten Magenta Versionen (Magenta64 und Magenta16) betrachten, nicht versuchen irgendwelche Eigenschaften der Rundenfunktion F auszunutzen, sondern das Problem liegt in der Struktur des Magenta-Algorithmus. Als Rundenfunktion könnte auch z.B. ein sicherer Algorithmus wie Rijndael zum Einsatz kommen.
2. Teil
Schreibe ein Programm, welches diesen Angriff auf die Magenta64 Version anwendet. Ermittel damit den geheimen Schlüssel aus der Magenta64.dll (Reverse Engineering nicht erlaubt).
Ermittle den benötigten Aufwand.
------------------------------------------------------------------
Magenta64
Magenta64 hat eine Feistelstruktur mit einer Block- und Keygröße von 64 Bit.
Dabei wird wie beim echten Magenta der Key in zwei Teile mit je 32 Bit aufgeteilt, ebenso der Klartext besteht aus einer linken und einer rechten Hälfte, mit je 32 Bit. Der Ablauf für die Verschlüsselung ist identisch mit der Grafik oben. Für die Entschlüsselung wird die Struktur einfach rückwärts durchlaufen, also man beginnt unten, wobei die Entschlüsselung für den gesuchten Angriff unerheblich ist.
Ich veröffentliche Implementierungen in C und C#. Es ist sehr empfehlenswert eine IDE mit sehr guten Debugger zu verwenden, mit dem man sich die einzelnen Zwischenergebnisse angucken kann.
Die Portierung des Algorithmus in andere Sprachen (z.B. Java) sollte nicht das Problem darstellen, sofern jmd. es schon gemacht hat, kann er es hier gerne veröffentlichen, so dass ich es einbinden kann. Ein Testvektor kann im Anhang gefunden werden.
Die Rundenfunktion F sieht wie folgt aus:
Komplett implementiert sieht es wie folgt aus, wobei die Entschlüsselung einfach nur die Runden von unten nach oben durchläuft:
In Wie programmiere ich einen Algorithmus tauchte als erster Test für einen Algorithmus die statistischen Eigenschaften von diesem auf.
Wie man dem Paper über Magenta entnehmen kann, soll Magenta wohl relativ gute statistische Eigenschaften besitzen. Auch für Magenta64 habe ich ein paar statistische Eigenschaften überprüft, welche alle absolviert wurden.
Dabei wurde z.B. unter einem festen Key (z.B. 000...000) eine aufsteigende Nummer verschlüsselt und mittels der FIPS-PUB-140-1-Testbatterie auf zufälligkeit getestet. Magenta64 hat diese Test soweit soweit bestanden, dennoch kann hier von keinem sicheren Algorithmus gesprochen werden.
Ihr könnt Magenta64 mit dem gleichen Angriff wie orginal Magenta knacken, andere Analysen oder knackversuche sind natürlich herzlich willkommen und vermutlich auch durchaus möglich, da Magenta64 nur ein paar wenige statistische Tests absolviert hat und nicht speziell gegen z.B. lineare/differentielle Kryptoanalyse abgehärtet wurde.
Tipps
Da es vermutlich für die meisten unmöglich ist, von selbst ein Angriffsszenario gegen Magenta zu finden, kommen hier die Tipps.
Dabei sind einige Tipps in spoiler-Tags versteckt, und diese solltet ihr erst lesen, wenn ihr wirklich nicht mehr weiter wisst.
Das finden eines Angriffes ist nicht in 5 Minuten erledigt und man sollte schon sich einige Gedanken machen, bevor man evt. den nächsten Tipp liest.
Wenn man einen Algorithmus kryptoanalysiert, fängt man überlicherweise mit einer reduzierten Variante an, hierfür habe ich zwei Sachen vorbreitet. Direkt zu versuchen Magenta64 zu knacken ist nicht vielversprechend.
Zuerst eine reduzierte Version, dabei fehlen die Runden 5 und 6
Gegen diesen Variante gibt es zwei mögliche Angriffe, wobei die eine Angriffsform relativ offensichtlich ist, diese bringt uns aber nicht richtig weiter.
Weil es außerdem recht unhandlich ist, mit so großen Blockgrößen zu arbeiten, gibt es noch die Magenta16 Variante, gleiche Struktur wie oben, allerdings mit einer Block- und Keygröße von 16 Bit, also 2 mal 8 Bit. Auch die Rundenfunktion wurde etwas reduziert, ändert aber nichts am Angriff.
Magenta64.dll
Die Magenta64.dll ist eine in C geschriebene Implementierung der Magenta64 Version, allerdings mit festen Key.
Diese DLL enthält die Funktionen F, Encrypt und Decrypt und zwar mit folgenden Interface:
Auf diese DLL kann man in C# z.B. wie folgt zugreifen:
Ziel ist es, ohne Reverse Engineering, Speicherdump u.ä., den Key zu extrahieren. Dazu kann man z.B. ein Crack-Programm schreiben, welches aus einem Magenta64-Objekt versucht den Key herrauszufinden.
Die Klasenstruktur kann in C# z.B. so aussehen:
Um eventuelle Probleme mit der .dll unter Linux zu vermeiden ihabe ich noch die Object-Datei Magenta64_dll.o angehängt.
Ich hoffe diese kann soweit Problemlos verwendet werden (es wurde gcc von Dev-C++ zur Überstzung verwendet).
Ansonsten wünsche ich euch viel Spaß und gutes gelingen. Für Fragen und Anmerkungen bin ich immer offen und hoffe dass dieses Challenge soweit lösbar ist.
Es geht in der Crypto-Challenge um die Kryptoanalyse von Magenta, welcher von der Deutschen Telekom als Algorithmus zum Advanced Encryption Standard eingereicht wurde.
Magenta ist eine Feistelchiffre mit einer Blockgröße von 128 Bit und einer Keylänge von 128 bis 256 Bit, wobei wir uns nur die 128 Bit Variante betrachten.
Dann wollen wir mal unsere Chancen zur Kryptoanalyse abschätzen, dazu zuerst ein Paper welches Magenta weiter beschreibt: The MAGENTA Block Cipher Algorithm (Paper muss nicht gelesen werden)
Hört sich erstmal schlecht, allerdings hier kommt die gute Nachricht:To date, no significant security weaknesses are known for the MAGENTA block cipher algorithm. It seems to have sufficient avalanche properties, no statistical weaknesses have been found, and attacks based on differential and linear cryptanalysis do not offer any signifficant improvement over a brute force attack.
Innerhalb von 20 Minuten, noch während der Präsentation von Magenta, wurde von Eli Biham, Alex Biryukov, Niels Ferguson, Lars Knudsen, Bruce Schneier und Adi Shamir eine eklatante Schwäche in Magenta gefunden, womit der Algorithmus als gebrochen gilt.
(Am Rande: Magenta war außerdem noch einer der langsamsten Algorithmen die eingereicht wurden).
Regeln ? Wichtig!
Es hat keinen Sinn sich bereits fertige Kryptoanalysen von Magenta anzugucken. Hat man diese einmal durchgelesen, gibt es nicht viel mehr zu entdecken womit die Challengen für einen dann beendet wäre.
Auch wenn das 1. Zitat wenig Mut macht, die Kryptoanalyse ist leichter als erwartet und sollte auch von fortgeschrittenen Anfängern zu meistern sein. Irgendwelche abgefahrenen Kentnisse in differentielle/lineare Kryptoanalyse sind nicht notwendig. Grundkenntnisse in Kryptographie sollten ausrecihen.
Ich werde ausreichend Tipps ins spoiler-Tags geben, wobei man sich diese erst angucken sollte, wenn man wirklich nicht mehr weiter weiß.
Sollte Ihr eine Lösung gefunden haben, dann verwendet bitte ebenso Spoiler-Tags.
Reverse Engineering oder ähnliche Verfahren sind nicht erlaubt, allerdings sind alle Angriffstechniken aus der Kryptographie erlaubt.
Woraus besteht die Challenge?
Diese Challenge besteht aus mehreren Teilen, einmal soll man einen Angriff gegen Magenta beschreiben, der natürlich deutlich schneller als Brute Force (2^128) ist.
Dann gibt es auch noch einen Praxis-Teil, ich habe eine reduzierten Magenta-Version geschrieben, die für den selben Angriff anfällig ist wie die orginal Magenta Version.
Diese Version arbeitet mit einer Blockgröße von 64 Bit sowie einer Key Länge von 64 Bit. Ein Brute Force Angriff wäre möglich (2^64 Schritte), aber dennoch zu aufwendig.
Für diesen Algorithmus soll man den Angriff, der auch gegen orginal Magenta klappt, implementieren. Dazu ist im Anhang eine DLL (Magenta64.dll), die einen geheimen Schlüssel enthält und nur ver- und entschlüsseln mit diesem geheimen Key anbietet.
Das Auslesen durch Reverse Engineering ist natürlich nicht erlaubt. Ziel ist es also, mit diesem Angriff den Key in Erfahrung zu bringen.
Zuerst nocheinmal klären, wann ein Algorithmus als gebrochen gilt:
Ihr werdet es vermutlich nicht schaffen, nur aus dem Geheimtext den Key zurückzugewinnen, dennoch ist der Angriff so verheerend, dass man Magenta nicht guten gewissens verwenden kann.WHAT DOES IT MEAN TO "BREAK" A CIPHER?
Breaking a cipher doesn't necessarily mean finding a practical way for an eavesdropper to recover the plaintext from just the ciphertext.
In academic cryptography, the rules are relaxed considerably. Breaking a cipher simply means finding a weakness in the cipher that can be exploited with a complexity less than brute-force. Never mind that brute-force might require 2^128 encryptions; an
attack requiring 2^110 encryptions would be considered a break. Breaks might also
require unrealistic amounts of known or chosen plaintext - 2^56 blocks - or unrealistic
amounts of storage: 2^80. Simply put, a break can just be a "certifcational
weakness": evidence that the cipher does not perform as advertised.
Successful cryptanalysis might mean showing a break against a reduced-round
variant of the cipher - 8-round DES versus the full 16-round DES, for example -
or a simplified variant of the cipher. Most breaks start out as cryptanalysis
against reduced-round variants, and are eventually (maybe years later) extended
to the full cipher. In fact, a break on a reduced-round version of a cipher is often
a publishable result.
Self-Study Course in Block Cipher Cryptanalysis
Versucht also nicht irgendwie den Geheimtext statistisch zu untersuchen, sondern verwendet andere Angriffstechniken
1. Teil
(Erst den 1. Teil lesen, dann aber besser mit dem 2. Teil anfangen)
Finde einen Angriff gegen Magenta, welcher deutlich schneller als Brute Force (2^128 ) ist. Welche Voraussetzungen werden benötigt, um diesen Angriff durchzuführen? Welche Komplexilität wird für diesen Angriff benötigt? Von welchen Parametern hängt die Komplexilität ab und mit was für einem Aufwand kann man im aller schlimmsten Fall rechnen? Ist dieser Worst-case realistisch (mit Begründung)?
Kann man aus diesem Angriff evt. noch andere Angriffsarten ableiten? Wenn ja, wie ist deren Aufwand?
Wenn ihr noch Lust habt: Nenne ein nachvollziehbares (also aus der Realität) Beispiel, bei dem dieser Angriff schlimme Folgen haben können.
Magenta ist wie folgt aufgebaut: Wie gewohnt bei Feistelchiffren wird der 128 Bit Klartextblock in einen Linken und einen Rechten teil aufgespalten.
Der 128 Bit-Schlüssel wird ebenso in zwei Teile aufgeteilt, in k1 und k2. Der Schlüssel k1 wird für die ersten beiden Rundenfunktionen und die letzten beiden Rundenfunktionen verwendet, k2 kommt in den beiden mittleren Rundenfunktionen zum Einsatz, als Grafik sieht dies wie folgt aus:

Dabei ist F die Rundenfunktion, dieses Kreuz im dem Kreis bedeutet XOR.
Soviel schon gesagt, dieser entsprechende Angriff funktioniert ohne nähere Details der Rundenfunktion F. Deswegen solltet ihr auch, wenn ihr die modifizierten Magenta Versionen (Magenta64 und Magenta16) betrachten, nicht versuchen irgendwelche Eigenschaften der Rundenfunktion F auszunutzen, sondern das Problem liegt in der Struktur des Magenta-Algorithmus. Als Rundenfunktion könnte auch z.B. ein sicherer Algorithmus wie Rijndael zum Einsatz kommen.
2. Teil
Schreibe ein Programm, welches diesen Angriff auf die Magenta64 Version anwendet. Ermittel damit den geheimen Schlüssel aus der Magenta64.dll (Reverse Engineering nicht erlaubt).
Ermittle den benötigten Aufwand.
------------------------------------------------------------------
Magenta64
Magenta64 hat eine Feistelstruktur mit einer Block- und Keygröße von 64 Bit.
Dabei wird wie beim echten Magenta der Key in zwei Teile mit je 32 Bit aufgeteilt, ebenso der Klartext besteht aus einer linken und einer rechten Hälfte, mit je 32 Bit. Der Ablauf für die Verschlüsselung ist identisch mit der Grafik oben. Für die Entschlüsselung wird die Struktur einfach rückwärts durchlaufen, also man beginnt unten, wobei die Entschlüsselung für den gesuchten Angriff unerheblich ist.
Ich veröffentliche Implementierungen in C und C#. Es ist sehr empfehlenswert eine IDE mit sehr guten Debugger zu verwenden, mit dem man sich die einzelnen Zwischenergebnisse angucken kann.
Die Portierung des Algorithmus in andere Sprachen (z.B. Java) sollte nicht das Problem darstellen, sofern jmd. es schon gemacht hat, kann er es hier gerne veröffentlichen, so dass ich es einbinden kann. Ein Testvektor kann im Anhang gefunden werden.
Die Rundenfunktion F sieht wie folgt aus:
Code:
// k = Key
unsigned int F(unsigned int input, unsigned int k) {
//Rotate left 3:
input = input << 3 | input >> 29;
//Input + shifted Const
input += 0x7A8E7B86U << (int)( (input ^ k) & 7) | (0x7A8E7B86U << (int)(32 - ( (input ^ k) & 7)));
//Rotate left 4:
input = input << 4 | input >> 28;
//Input XOR Key
input ^= k;
//Input + shifted Const
int leftShift = (int)( (unsigned int)((input ^ k) & 0xF0000000) >> 28);
input += 0xCF9C5DFC << leftShift | 0xCF9C5DFC >> (32-leftShift);
return input;
}
Code:
//k = Key
public UInt32 F(UInt32 input, UInt32 k)
{
//Rotate Left 3:
input = input << 3 | input >> 29;
//Input + shifted Const
input += 0x7A8E7B86U << (int)( (input ^ k) & 7) | (0x7A8E7B86U << (int)(32 - ( (input ^ k) & 7)));
//Rotate Left 4:
input = input << 4 | input >> 28;
//Input XOR Key
input ^= k;
//Input + shifted Const
int leftShift = (int)( (uint)((input ^ k) & 0xF0000000) >> 28);
input += 0xCF9C5DFC << leftShift | 0xCF9C5DFC >> (32-leftShift);
return input;
}
Komplett implementiert sieht es wie folgt aus, wobei die Entschlüsselung einfach nur die Runden von unten nach oben durchläuft:
Code:
// k = Key
unsigned int F(unsigned int input, unsigned int k) {
//Rotate left 3:
input = input << 3 | input >> 29;
//Input + shifted Const
input += 0x7A8E7B86U << (int)( (input ^ k) & 7) | (0x7A8E7B86U << (int)(32 - ( (input ^ k) & 7)));
//Rotate left 4:
input = input << 4 | input >> 28;
//Input XOR Key
input ^= k;
//Input + shifted Const
int leftShift = (int)( (unsigned int)((input ^ k) & 0xF0000000) >> 28);
input += 0xCF9C5DFC << leftShift | 0xCF9C5DFC >> (32-leftShift);
return input;
}
//Verschluesselt left und right mit den Keys k1 und k2, Ausgabe wird in leftOut/rightOut abgelegt
void Encrypt(unsigned int left, unsigned int right, unsigned int k1, unsigned int k2, unsigned int* leftOut, unsigned int* rightOut)
{
//1. Round
left ^= F(right, k1);
//2. Round
right ^= F(left, k1);
//3. Round
left ^= F(right, k2);
//4. Round
right ^= F(left, k2);
//5. Round
left ^= F(right, k1);
//6. Round
right ^= F(left, k1);
*leftOut = left;
*rightOut = right;
}
void Decrypt(unsigned int left, unsigned int right, unsigned int k1, unsigned int k2 , unsigned int* leftOut, unsigned int* rightOut)
{
//6. Round
right ^= F(left, k1);
//5. Round
left ^= F(right, k1);
//4. Round
right ^= F(left, k2);
//3. Round
left ^= F(right, k2);
//2. Round
right ^= F(left, k1);
//1. Round
left ^= F(right, k1);
*leftOut = left;
*rightOut = right;
}
//Beispiel wie man diese Implementierung verwendet
int main() {
unsigned int left=0x11223344, right=0xAABBCCDD;
unsigned int k1= 0x01234567, k2=0x89ABCDEF;
Encrypt(left, right, k1, k2 , &left, &right);
printf("Encrypted: %X %X \n",left, right);
Decrypt(left, right, k1, k2, &left, &right);
printf("Decrypted: %x %x",left, right);
getchar();
}
Code:
class Magenta64
{
private UInt32 k1, k2;
public Magenta64()
: this(0, 0)
{
}
public Magenta64(UInt32 k1, UInt32 k2)
{
this.k1 = k1;
this.k2 = k2;
}
//Die Funktion F
public virtual UInt32 F(UInt32 input, UInt32 k)
{
//Rotate Left 3:
input = input << 3 | input >> 29;
//Input + shifted Const
input += 0x7A8E7B86U << (int)( (input ^ k) & 7) | (0x7A8E7B86U << (int)(32 - ( (input ^ k) & 7)));
//Rotate Left 4:
input = input << 4 | input >> 28;
//Input XOR Key
input ^= k;
//Input + shifted Const
int leftShift = (int)( (uint)((input ^ k) & 0xF0000000) >> 28);
input += 0xCF9C5DFC << leftShift | 0xCF9C5DFC >> (32-leftShift);
return input;
}
//Encrypt mit this.k1 und this.k2
public virtual UInt32[] Encrypt(UInt32 left, UInt32 right)
{
return Encrypt(left, right, k1, k2);
}
public UInt32[] Encrypt(UInt32 left, UInt32 right, UInt32 k1, UInt32 k2)
{
//1. Round
left ^= F(right, k1);
//2. Round
right ^= F(left, k1);
//3. Round
left ^= F(right, k2);
//4. Round
right ^= F(left, k2);
//5. Round
left ^= F(right, k1);
//6. Round
right ^= F(left, k1);
return new UInt32[] { left, right };
}
public virtual UInt32[] Decrypt(UInt32 left, UInt32 right)
{
return Decrypt(left, right, k1, k2);
}
public UInt32[] Decrypt(UInt32 left, UInt32 right, UInt32 k1, UInt32 k2)
{
//6. Round
right ^= F(left, k1);
//5. Round
left ^= F(right, k1);
//4. Round
right ^= F(left, k2);
//3. Round
left ^= F(right, k2);
//2. Round
right ^= F(left, k1);
//1. Round
left ^= F(right, k1);
return new UInt32[] { left, right };
}
}
In Wie programmiere ich einen Algorithmus tauchte als erster Test für einen Algorithmus die statistischen Eigenschaften von diesem auf.
Wie man dem Paper über Magenta entnehmen kann, soll Magenta wohl relativ gute statistische Eigenschaften besitzen. Auch für Magenta64 habe ich ein paar statistische Eigenschaften überprüft, welche alle absolviert wurden.
Dabei wurde z.B. unter einem festen Key (z.B. 000...000) eine aufsteigende Nummer verschlüsselt und mittels der FIPS-PUB-140-1-Testbatterie auf zufälligkeit getestet. Magenta64 hat diese Test soweit soweit bestanden, dennoch kann hier von keinem sicheren Algorithmus gesprochen werden.
Ihr könnt Magenta64 mit dem gleichen Angriff wie orginal Magenta knacken, andere Analysen oder knackversuche sind natürlich herzlich willkommen und vermutlich auch durchaus möglich, da Magenta64 nur ein paar wenige statistische Tests absolviert hat und nicht speziell gegen z.B. lineare/differentielle Kryptoanalyse abgehärtet wurde.
Tipps
Da es vermutlich für die meisten unmöglich ist, von selbst ein Angriffsszenario gegen Magenta zu finden, kommen hier die Tipps.
Dabei sind einige Tipps in spoiler-Tags versteckt, und diese solltet ihr erst lesen, wenn ihr wirklich nicht mehr weiter wisst.
Das finden eines Angriffes ist nicht in 5 Minuten erledigt und man sollte schon sich einige Gedanken machen, bevor man evt. den nächsten Tipp liest.
Wenn man einen Algorithmus kryptoanalysiert, fängt man überlicherweise mit einer reduzierten Variante an, hierfür habe ich zwei Sachen vorbreitet. Direkt zu versuchen Magenta64 zu knacken ist nicht vielversprechend.
Zuerst eine reduzierte Version, dabei fehlen die Runden 5 und 6

Gegen diesen Variante gibt es zwei mögliche Angriffe, wobei die eine Angriffsform relativ offensichtlich ist, diese bringt uns aber nicht richtig weiter.
Gegen die reduzierte Variante ist ein Meet-in-the-middle attack möglich, welcher bei einer Keygröße von 128 Bit nur 2^65 Rechenschritte benötigen würde.
Dieser Angriff hilft aber nicht unbedingt weiter. Viel mehr sollte man die Besonderheit der Strucktur verwenden.
Dieser Angriff hilft aber nicht unbedingt weiter. Viel mehr sollte man die Besonderheit der Strucktur verwenden.
Schaut mal bei der Magenta16 Version wie die Zwischenergebnisse während der Verschlüsselung aussehen. Wichtig ist festzustellen, von was die einzelnen Zwischenschritte abhängen
Es ist empfehlenswert die Magenta16-Variante mal schrittweise durchzugehen und die einzelnen Ergebnisse (natürlich im Hex-Format) entsprechend in das Diagramm einzutragen. Natürlich kann man hier auch wieder mit der reduzierten Variante anfangen. Kann man evt. bestimmte Teile des Schlüssels leicht überprüfen?
Es ist empfehlenswert die Magenta16-Variante mal schrittweise durchzugehen und die einzelnen Ergebnisse (natürlich im Hex-Format) entsprechend in das Diagramm einzutragen. Natürlich kann man hier auch wieder mit der reduzierten Variante anfangen. Kann man evt. bestimmte Teile des Schlüssels leicht überprüfen?
Weil es außerdem recht unhandlich ist, mit so großen Blockgrößen zu arbeiten, gibt es noch die Magenta16 Variante, gleiche Struktur wie oben, allerdings mit einer Block- und Keygröße von 16 Bit, also 2 mal 8 Bit. Auch die Rundenfunktion wurde etwas reduziert, ändert aber nichts am Angriff.
Code:
//Magenta-Variante mit Block/Keygröße von 2 mal 8 Bit.
#include<stdio.h>
unsigned char F(unsigned char input, unsigned char k) {
//Input + Const
input += 0x5C;
//Rotate Left 2:
input = (unsigned char)(((unsigned char)input << 2) | ((unsigned char)input >> 6));
//Input XOR Key
input ^= k;
//Input + Const
input += 0xA4;
return input;
}
void Encrypt(unsigned char left, unsigned char right, unsigned char k1, unsigned char k2, unsigned char* leftOut, unsigned char* rightOut)
{
//1. Round
left ^= F(right, k1);
//2. Round
right ^= F(left, k1);
//3. Round
left ^= F(right, k2);
//4. Round
right ^= F(left, k2);
//Fuer die reduzierte Version die naechsten beiden Zeilen einfach auskommentieren
//5. Round
left ^= F(right, k1);
//6. Round
right ^= F(left, k1);
*leftOut = left;
*rightOut = right;
}
void Decrypt(unsigned char left, unsigned char right, unsigned char k1, unsigned char k2 , unsigned char* leftOut, unsigned char* rightOut)
{
// Wenn die reduzierte Version benutzt wird, 6. und 5. Runde auskommentieren
//6. Round
right ^= F(left, k1);
//5. Round
left ^= F(right, k1);
//4. Round
right ^= F(left, k2);
//3. Round
left ^= F(right, k2);
//2. Round
right ^= F(left, k1);
//1. Round
left ^= F(right, k1);
*leftOut = left;
*rightOut = right;
}
//Moegliche Verwendung
int main() {
unsigned char left = 0x11, right = 0xAA;
unsigned char k1 = 0x01, k2 = 0x89;
Encrypt(left, right, k1, k2, &left, &right);
printf("Encrypted: %X %X \n",left, right);
Decrypt(left, right, k1, k2, &left, &right);
printf("Decrypted: %x %x",left, right);
getchar();
}
Code:
//Magenta-Variante mit Block/Keygröße von 2 mal 8 Bit.
//In C# ist byte ohne Vorzeichen unsigned
class Magenta16
{
private byte k1, k2;
public Magenta16() : this(0,0)
{
}
public Magenta16(byte k1, byte k2)
{
this.k1 = k1;
this.k2 = k2;
}
//Reduzierte Rundenfunktion, aendert nichts am Angriff
public byte F(byte input, byte k)
{
//Input + Const
input += 0x5C;
//Rotate Left 2:
input = (byte)(((byte)input << 2) | ((byte)input >> 6));
//Input XOR Key
input ^= k;
//Input + Const
input += 0xA4;
return input;
}
public byte[] Encrypt(byte left, byte right)
{
return Encrypt(left, right, k1, k2);
}
public byte[] Encrypt(byte left, byte right, byte k1, byte k2)
{
//1. Round
left ^= F(right, k1);
//2. Round
right ^= F(left, k1);
//3. Round
left ^= F(right, k2);
//4. Round
right ^= F(left, k2);
//Fuer die reduzierte Version die naechsten beiden Zeilen einfach auskommentieren
//5. Round
left ^= F(right, k1);
//6. Round
right ^= F(left, k1);
return new byte[] { left, right };
}
public byte[] Decrypt(byte left, byte right)
{
return Decrypt(left, right, k1, k2);
}
public byte[] Decrypt(byte left, byte right, byte k1, byte k2)
{
//Fuer die reduzierte Variante die Runde 6. und 5. auskommentieren
//6. Round
right ^= F(left, k1);
//5. Round
left ^= F(right, k1);
//4. Round
right ^= F(left, k2);
//3. Round
left ^= F(right, k2);
//2. Round
right ^= F(left, k1);
//1. Round
left ^= F(right, k1);
return new byte[] { left, right };
}
}
Magenta64.dll
Die Magenta64.dll ist eine in C geschriebene Implementierung der Magenta64 Version, allerdings mit festen Key.
Diese DLL enthält die Funktionen F, Encrypt und Decrypt und zwar mit folgenden Interface:
Code:
unsigned int F(unsigned int input, unsigned int k);
void Encrypt(unsigned int left, unsigned int right, unsigned int* leftOut, unsigned int* rightOut);
void Decrypt(unsigned int left, unsigned int right, unsigned int* leftOut, unsigned int* rightOut);
Auf diese DLL kann man in C# z.B. wie folgt zugreifen:
Code:
class Magenta64Dll : Magenta64
{
[DllImport("Magenta64.dll", EntryPoint="Encrypt")]
public static extern void Encrypt_dll(UInt32 left, UInt32 right, out UInt32 leftOut, out UInt32 rightOut);
[DllImport("Magenta64.dll", EntryPoint = "Decrypt")]
public static extern void Decrypt_dll(UInt32 left, UInt32 right, out UInt32 leftOut, out UInt32 rightOut);
//Der Zugriff auf die enthaltene Funktion F ist moeglich,
//aber unnoetig und dauert zu lange
public override uint[] Encrypt(uint left, uint right)
{
UInt32[] c = new UInt32[2];
Encrypt_dll(left, right,out c[0],out c[1]);
return c;
}
public override uint[] Decrypt(uint left, uint right)
{
UInt32[] c = new UInt32[2];
Decrypt_dll(left, right, out c[0], out c[1]);
return c;
}
}
Ziel ist es, ohne Reverse Engineering, Speicherdump u.ä., den Key zu extrahieren. Dazu kann man z.B. ein Crack-Programm schreiben, welches aus einem Magenta64-Objekt versucht den Key herrauszufinden.
Die Klasenstruktur kann in C# z.B. so aussehen:
Code:
class Magenta64Crack
{
public UInt64 steps = 0;
public Magenta64Crack()
{
}
public UInt32[] Crack(Magenta64 mag)
{
//Finde den Key für mag heraus
return new Uint32[] {k1, k2}; //Return Key
}
}
Um eventuelle Probleme mit der .dll unter Linux zu vermeiden ihabe ich noch die Object-Datei Magenta64_dll.o angehängt.
Ich hoffe diese kann soweit Problemlos verwendet werden (es wurde gcc von Dev-C++ zur Überstzung verwendet).
Ansonsten wünsche ich euch viel Spaß und gutes gelingen. Für Fragen und Anmerkungen bin ich immer offen und hoffe dass dieses Challenge soweit lösbar ist.