Das Alphabet-Shuffling-Modul dient dem zusätzlichen Schutz geheimer Informationen, die über einen Kommunikationskanal übertragen werden. Obwohl die RC4-Stream-Verschlüsselung, die wir in Extra Systems Cypher Net verwenden, in unserer Implementierung keine Schwachstellen aufweist, bleibt die theoretische Möglichkeit der Schlüsselaufzählung mit anschließender lexikalischer Analyse von Versuchen zur Entschlüsselung der übertragenen Informationen bestehen. Wir sprechen natürlich nicht über die Möglichkeiten, die die Menschheit heute hat. Bei modernen Systemen ist die Zeit für die Suche nach RC4-Schlüsseln in unserem Fall um viele Größenordnungen länger als die Lebensdauer des Universums. Wir sprechen über die hypothetischen Möglichkeiten, die in der Zukunft auftauchen könnten. Mit der Absicht, uns gegen alle denkbaren Optionen abzusichern, haben wir Extra Systems Cypher Net um dieses Alphabet-Shuffling-Modul erweitert, das eine lexikalische Analyse von Entschlüsselungsversuchen grundsätzlich unmöglich macht und somit einem Angreifer jede Möglichkeit nimmt, dieses verschlüsselte Kommunikationssystem zu knacken.
Der Kern dieser Methode besteht darin, dass die Codes von 256 Zeichen (die Anzahl der Optionen für ein Byte von acht Bits) völlig zufällig in der Tabelle verschoben werden, sodass der Text in jeder Sprache zu völligem Kauderwelsch wird, der aus gedruckten und nicht druckbaren Zeichen besteht, die auf völlig unvorhersehbare Weise vermischt werden. Infolgedessen verliert die Methode des Knackens von Verschlüsselungskennwörtern durch Brute-Force-Aufzählung, deren Kern darin besteht, nach Optionen zu suchen, wenn der Chiffretext in eine Reihe bestimmter gedruckter Zeichen umgewandelt wird, vollständig ihre Gültigkeit, da das richtige Kennwort mit unserem hier beschriebenen Ansatz, wie bereits angedeutet, in Abrakadabra umgewandelt wird, das in keiner Weise mit normalem Text verwechselt werden kann.
Daher ist der Extra Systems Cypher Net-Cracker nicht in der Lage, das Passwort zu erraten, sondern konzentriert sich darauf, einen aussagekräftigen Text zu erhalten.
Zunächst erstellt das System eine Tabelle, die der Identitätstransformation entspricht (d. h. es unternimmt nichts – die Zeichenkodierungsinformationen werden nicht geändert). Das Modul shuffle_init macht Folgendes:
int main(void) { int i,file_handle; unsigned char data[256]; for (i=0; i<256; i++) data[i] = i; file_handle = creat("shuffle.encrypt", S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); write(file_handle, data, sizeof(data)); close(file_handle); return 0; }
Dann werden die Informationen in dieser Tabelle zufällig gemischt (dieser Vorgang kann und sollte sogar mehr als einmal durchgeführt werden). Dies erledigt das Modul shuffle_randomize:
int main(void) { unsigned char src, dst; unsigned char shuffle_encrypt_data[256]; unsigned char random_src[256], random_dst[256]; int i, file_handle; file_handle = open("shuffle.encrypt", O_RDONLY); read(file_handle, shuffle_encrypt_data, sizeof(shuffle_encrypt_data)); close(file_handle); fill_random_buffer(random_src, sizeof(random_src)); fill_random_buffer(random_dst, sizeof(random_dst)); for(i = 0; i < 256; i++) { src = shuffle_encrypt_data[random_src[i]]; dst = shuffle_encrypt_data[random_dst[i]]; shuffle_encrypt_data[random_src[i]] = dst; shuffle_encrypt_data[random_dst[i]] = src; } file_handle = creat("shuffle.encrypt", S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); write(file_handle, shuffle_encrypt_data, sizeof(shuffle_encrypt_data)); close(file_handle); return 0; }
Es sollte besonders betont werden, dass die Funktion fill_random_buffer (die in diesem und einer Reihe anderer Module dieses Systems verwendet wird) immer eine kryptografisch starke Folge von Zufallsbytes zurückgibt. In verschiedenen Betriebssystemen basiert es auf Aufrufen verschiedener speziell entwickelter und offiziell dokumentierter Systemdienste (speziell entwickelte und offiziell als solche deklarierte Dienste, die dazu dienen, kryptografisch starke Folgen zufälliger Bytes zu erzeugen). In jedem der von uns unterstützten Betriebssysteme leitet die Funktion fill_random_buffer tatsächlich nur einen Aufruf an eine solche Systemfunktion weiter (und gibt die Ergebnisse ihrer Arbeit einfach an ihren Client zurück).
Die Anwendung dieses Schlüssels im Extra Systems Cypher Net-System wird vom Shuffle-Modul verwaltet (beachten Sie, dass shuffle_decrypt_data „on the fly“ basierend auf shuffle_encrypt_data unmittelbar nach dem Laden erstellt wird – diese Tatsache stellt automatisch die vollständige Konsistenz zwischen den Kodierungs- und Dekodierungsalgorithmen der übertragenen Informationen sicher), dessen Code in C wie folgt lautet:
unsigned char shuffle_encrypt_data[256], shuffle_decrypt_data[256]; int load_shuffle_data(void) { unsigned char src; int i, file_handle; if((file_handle = open("shuffle.encrypt", O_RDONLY)) == -1) return 0; read(file_handle, shuffle_encrypt_data, sizeof(shuffle_encrypt_data)); close(file_handle); for(i = 0; i < 256; i++) { src = shuffle_encrypt_data[i]; shuffle_decrypt_data[src] = i; } return 1; } void shuffle_rotate_l(unsigned char *buffer_ptr, int buffer_len) { int i; unsigned char x; if (!buffer_len) return; x = buffer_ptr[0]; for(i = 0; i < (buffer_len - 1); i++) buffer_ptr[i] = (buffer_ptr[i] << 4) | (buffer_ptr[i + 1] >> 4); buffer_ptr[buffer_len - 1] = (buffer_ptr[buffer_len - 1] << 4) | (x >> 4); } void shuffle_rotate_r(unsigned char *buffer_ptr, int buffer_len) { int i; unsigned char x; if (!buffer_len) return; x = buffer_ptr[buffer_len - 1]; for(i = (buffer_len - 1); i > 0; i--) buffer_ptr[i] = (buffer_ptr[i] >> 4) | (buffer_ptr[i - 1] << 4); buffer_ptr[0] = (buffer_ptr[0] >> 4) | (x << 4); } void shuffle_twist(unsigned char *buffer_ptr, int buffer_len) { int i; unsigned char x, y; if (buffer_len < 2) return; for(i = 1; i < buffer_len; i++) { x = buffer_ptr[i - 1]; y = buffer_ptr[i]; buffer_ptr[i - 1] = (x & 0xF0) | (y >> 4); buffer_ptr[i] = (y & 0xF) | (x << 4); } } void shuffle_buffer(unsigned char *buffer_ptr, int buffer_len, unsigned char *shuffle_data) { short counter; for(counter = 0; counter < buffer_len; counter++) buffer_ptr[counter] = shuffle_data[buffer_ptr[counter]]; } void shuffle_swap_l(unsigned char *buffer_ptr, int buffer_len, unsigned char swap_old) { int i; unsigned char x, y, swap_new; if (buffer_len < 2) return; swap_new = ~swap_old; for(i = 1; i < buffer_len; i++) { x = buffer_ptr[i - 1]; y = buffer_ptr[i]; buffer_ptr[i - 1] = (x & swap_old) | (y & swap_new); buffer_ptr[i] = (y & swap_old) | (x & swap_new); } } void shuffle_swap_r(unsigned char *buffer_ptr, int buffer_len, unsigned char swap_old) { int i; unsigned char x, y, swap_new; if (buffer_len < 2) return; swap_new = ~swap_old; for(i = (buffer_len - 1); i > 0; i--) { x = buffer_ptr[i - 1]; y = buffer_ptr[i]; buffer_ptr[i - 1] = (x & swap_old) | (y & swap_new); buffer_ptr[i] = (y & swap_old) | (x & swap_new); } } unsigned char i_shuffle_rol(unsigned char x, unsigned char y) { unsigned char a, b; a = ((x >> 1) & 0xF0) | ((y << 3) & 0x80); b = ((x << 1) & 0x0F) | ((y >> 3) & 0x01); return a | b; } void shuffle_rol(unsigned char *buffer_ptr, int buffer_len) { int i; unsigned char x, y; if (buffer_len < 2) return; for(i = 1; i < buffer_len; i++) { x = buffer_ptr[i - 1]; y = buffer_ptr[i]; buffer_ptr[i - 1] = i_shuffle_rol(x, y); buffer_ptr[i] = i_shuffle_rol(y, x); } } unsigned char i_shuffle_ror(unsigned char x, unsigned char y) { unsigned char a, b; a = ((x & 0xF0) << 1) | ((y >> 3) & 0x10); b = ((x & 0x0F) >> 1) | ((y << 3) & 0x08); return a | b; } void shuffle_ror(unsigned char *buffer_ptr, int buffer_len) { int i; unsigned char x, y; if (buffer_len < 2) return; for(i = (buffer_len - 1); i > 0; i--) { x = buffer_ptr[i - 1]; y = buffer_ptr[i]; buffer_ptr[i - 1] = i_shuffle_ror(x, y); buffer_ptr[i] = i_shuffle_ror(y, x); } } void shuffle_encrypt_buffer(unsigned char *buffer_ptr, int buffer_len) { shuffle_buffer(buffer_ptr, buffer_len, shuffle_encrypt_data); shuffle_rol(buffer_ptr, buffer_len); shuffle_buffer(buffer_ptr, buffer_len, shuffle_encrypt_data); shuffle_swap_l(buffer_ptr, buffer_len, SHUFFLE_SWAP_STEP_1); shuffle_buffer(buffer_ptr, buffer_len, shuffle_encrypt_data); shuffle_rotate_l(buffer_ptr, buffer_len); shuffle_buffer(buffer_ptr, buffer_len, shuffle_encrypt_data); shuffle_twist(buffer_ptr, buffer_len); shuffle_buffer(buffer_ptr, buffer_len, shuffle_encrypt_data); shuffle_rotate_l(buffer_ptr, buffer_len); shuffle_buffer(buffer_ptr, buffer_len, shuffle_encrypt_data); shuffle_swap_l(buffer_ptr, buffer_len, SHUFFLE_SWAP_STEP_2); shuffle_buffer(buffer_ptr, buffer_len, shuffle_encrypt_data); shuffle_rol(buffer_ptr, buffer_len); shuffle_buffer(buffer_ptr, buffer_len, shuffle_encrypt_data); } void shuffle_decrypt_buffer(unsigned char *buffer_ptr, int buffer_len) { shuffle_buffer(buffer_ptr, buffer_len, shuffle_decrypt_data); shuffle_ror(buffer_ptr, buffer_len); shuffle_buffer(buffer_ptr, buffer_len, shuffle_decrypt_data); shuffle_swap_r(buffer_ptr, buffer_len, SHUFFLE_SWAP_STEP_2); shuffle_buffer(buffer_ptr, buffer_len, shuffle_decrypt_data); shuffle_rotate_r(buffer_ptr, buffer_len); shuffle_buffer(buffer_ptr, buffer_len, shuffle_decrypt_data); shuffle_twist(buffer_ptr, buffer_len); shuffle_buffer(buffer_ptr, buffer_len, shuffle_decrypt_data); shuffle_rotate_r(buffer_ptr, buffer_len); shuffle_buffer(buffer_ptr, buffer_len, shuffle_decrypt_data); shuffle_swap_r(buffer_ptr, buffer_len, SHUFFLE_SWAP_STEP_1); shuffle_buffer(buffer_ptr, buffer_len, shuffle_decrypt_data); shuffle_ror(buffer_ptr, buffer_len); shuffle_buffer(buffer_ptr, buffer_len, shuffle_decrypt_data); }
Dank dieser chaotischen Neuanordnung der Buchstaben wird dem Angreifer die Möglichkeit genommen, den Text, den er erhält, wenn er versucht, ihn mit der Brute-Force-Methode zu entschlüsseln, vollständig zu analysieren. Die Datei „shuffle.encrypt“ wird für jeden Client unterschiedlich erstellt, außerdem ist jeder Client auf Wunsch mit dem Programm shuffle_randomize ausgestattet, mit dessen Hilfe er beliebig viele weitere Permutationen in dieser Schlüsseldatei vornehmen kann.
Der Zweck der Prozeduren shuffle_rotate_l und shuffle_rotate_r besteht darin, regelmäßige Wiederholungen von Schlüsselbytes der UTF8-Kodierung zu eliminieren (die bei der Verwendung aller Sprachen außer Englisch auftreten – und dies ist besonders typisch für das kyrillische Alphabet) – da dieser Umstand als Anhaltspunkt für die Auswahl der RC4-Taste mithilfe der „Brute-Force“-Methode dienen könnte. Durch den Einsatz dieser Verfahren in diesem Modul wird eine solche Gefahr in unserem Produkt vollständig beseitigt.
Die Prozedur shuffle_swap löst ein ähnliches Problem – ihre Aufgabe besteht darin, Bits in benachbarten Bytes gemäß einer bestimmten Maske (SHUFFLE_SWAP_STEP) auszutauschen. Wir wählen den spezifischen Typ dieser Maske basierend auf dem Kriterium aus, den maximalen Entropiegrad der endgültigen Bytefolge (zuvor von diesem Modul verschlüsselt) zu erreichen. Wir verwenden unterschiedliche Masken für verschiedene Sprachen. Ihre Effizienz liegt typischerweise bei über 7,9 Bit Entropie pro Byte. Wir veröffentlichen die spezifischen Werte dieser Bitmasken nicht, da dies keinen Einfluss auf die kryptografische Stärke unseres Systems hat. Unsere Entscheidung verstößt nicht gegen das Kerkhoffs-Prinzip, da die Codes der Algorithmen hier vollständig veröffentlicht sind und sich die spezifischen Werte von SHUFFLE_SWAP_STEP nicht auf Codes, sondern auf Schlüsseldaten beziehen, deren Geheimhaltung das Kerkhoffs-Prinzip niemandem verbietet.
Was das shuffle_rol-Verfahren betrifft (seine Umkehrbarkeit wird durch shuffle_ror sichergestellt), so wurde es der Pavlenko-Chiffre hinzugefügt, weil man optimale Parameter für die Erhöhung der Entropie einer abstrakten Bytefolge in jeder europäischen Sprache finden musste. Unsere vorläufigen Untersuchungen ergaben eine Reihe optimaler Werte von SHUFFLE_SWAP_STEP_1 und SHUFFLE_SWAP_STEP_2, die je nach Sprache die höchsten Entropiewerte für den resultierenden Text (unterliegt der Pavlenko-Chiffre) ergaben. Aber die Parameter, die für eine Sprache optimal waren, waren für eine andere nicht optimal. Um dieses Problem zu lösen, haben wir unserem Algorithmus diese Prozeduren (shuffle_rol und shuffle_ror) hinzugefügt. Als Ergebnis lag die endgültige Entropie eines beliebigen Textes in einer beliebigen Sprache (nach der Verarbeitung mit der Pavlenko-Chiffre) mit allen für eine andere Sprache optimalen Parametern deutlich über dem Wert von 7,9 Bits pro Byte (was praktisch identisch mit einer rein zufälligen Sequenz ist). Und in dieser Situation wurde nach dem Hinzufügen dieser Verfahren klar, dass die praktische Bedeutung der Auswahl sprachspezifischer Werte für die Parameter SHUFFLE_SWAP_STEP_1 und SHUFFLE_SWAP_STEP_2 keine praktische Bedeutung mehr hat. Insbesondere funktionieren die Werte, die wir zuvor für die englische Sprache ausgewählt haben, hervorragend für alle anderen europäischen Sprachen, einschließlich Kyrillisch (Russisch und Ukrainisch).
Wer die Funktionsweise dieses Algorithmus testen möchte, kann beispielsweise folgende Werte von SHUFFLE_SWAP_STEP_1 und SHUFFLE_SWAP_STEP_2 verwenden: 0xC3 und 0x3C. In unseren Experimenten ergaben diese (rein zufälligen und keineswegs optimalen) Parameter eine Entropie von 7,97 Bits pro Byte für Texte in allen Sprachen dieser Site (Russisch, Ukrainisch, Englisch usw.) und eine Standardabweichung von weniger als 7 für 8192 Bytes langen Text (die durchschnittliche Häufigkeit des Auftretens von Bytes beträgt in diesem Fall 8192:256=32). Man kann dies wirklich als die Umwandlung eines bedeutungsvollen Textes in einer beliebigen europäischen Sprache in eine Folge völlig zufälliger Symbole bezeichnen.
Natürlich muss jedes Paar (oder Unternehmen) von Abonnenten, die über Extra Systems Cypher Net miteinander kommunizieren, über eine identische „shuffle.encrypt“-Datei verfügen. Abonnenten erhalten diese Dateien zunächst von uns, können sie aber, wie oben erwähnt, selbst erstellen und zusätzlich mischen. Wichtig ist nur, dass sie in diesem Fall zur Sicherstellung der Identität aller Sets diese physisch an ihre Partner übergeben (bei einem persönlichen Treffen oder durch einen vertrauenswürdigen Kurier).
Der Inhalt dieser Seite ist auch in Englisch, Französisch, Portugiesisch, Spanisch, Italienisch, Ukrainisch und Russisch verfügbar.
© Extra Systems, 2024 |
|