Überblick
Ihr Ziel ist die Implementierung der RC4-Verschlüsselung. Die von Ron Rivest (RSA) erfundene RC4-Verschlüsselung sollte sicher und dennoch einfach genug sein, um von Militärsoldaten auf dem Schlachtfeld aus dem Gedächtnis implementiert zu werden. Heute gibt es mehrere Angriffe auf RC4, aber es wird noch heute an vielen Orten eingesetzt.
Ihr Programm sollte eine einzelne Zeichenfolge mit einem Schlüssel und einigen Daten akzeptieren. Es wird in diesem Format präsentiert.
\x0Dthis is a keythis is some data to encrypt
Das erste Byte gibt an, wie lang der Schlüssel ist. Es kann davon ausgegangen werden, dass der Schlüssel nicht länger als 255 Byte und nicht kürzer als 1 Byte ist. Die Daten können beliebig lang sein.
Ihr Programm sollte den Schlüssel verarbeiten und dann die verschlüsselten Daten zurückgeben. RC4-Verschlüsselung und -Entschlüsselung sind identisch. Wenn Sie also denselben Schlüssel zum "Verschlüsseln" des Chiffretexts verwenden, wird der ursprüngliche Klartext zurückgegeben.
Wie RC4 funktioniert
Initialisierung
Die Initialisierung von RC4 ist ganz einfach. Ein Zustandsarray von 256 Bytes wird für alle Bytes von 0 bis 255 initialisiert.
S = [0, 1, 2, 3, ..., 253, 254, 255]
Schlüsselverarbeitung
Die Werte im Status werden basierend auf dem Schlüssel vertauscht.
j = 0
for i from 0 to 255
j = (j + S[i] + key[i mod keylength]) mod 256
swap S[i] and S[j]
Verschlüsselung
Die Verschlüsselung wird mithilfe des Status durchgeführt, um pseudozufällige Bytes zu generieren, die dann XOR-verknüpft werden. Werte im Staat werden ständig ausgetauscht.
i = j = 0
for each byte B in data
i = (i + 1) mod 256
j = (j + S[i]) mod 256
swap S[i] and S[j]
K = S[(S[i] + S[j]) mod 256]
output K XOR B
Erwartete Ein- und Ausgänge
Nicht druckbare Zeichen werden im \xAB
Format angezeigt .
Eingabe: \x01\x00\x00\x00\x00\x00\x00
Ausgabe: \xde\x18\x89A\xa3
Ausgabe (hex):de188941a3
Eingabe: \x0Dthis is a keythis is some data to encrypt
Ausgabe: \xb5\xdb?i\x1f\x92\x96\x96e!\xf3\xae(!\xf3\xeaC\xd4\x9fS\xbd?d\x82\x84{\xcdN
Ausgabe (hex):b5db3f691f9296966521f3ae2821f3ea43d49f53bd3f6482847bcd4e
Eingabe: \x0dthis is a key\xb5\xdb?i\x1f\x92\x96\x96e!\xf3\xae(!\xf3\xeaC\xd4\x9fS\xbd?d\x82\x84{\xcdN
Eingabe (hex): 0d746869732069732061206b6579b5db3f691f9296966521f3ae2821f3ea43d49f53bd3f6482847bcd4e
Ausgabe:this is some data to encrypt
Eingabe: Sthis is a rather long key because the value of S is 83 so the key length must matchand this is the data to be encrypted
Ausgabe: \x96\x1f,\x8f\xa3%\x9b\xa3f[mk\xdf\xbc\xac\x8b\x8e\xfa\xfe\x96B=!\xfc;\x13`c\x16q\x04\x11\xd8\x86\xee\x07
Ausgabe (hex):961f2c8fa3259ba3665b6d6bdfbcac8b8efafe96423d21fc3b13606316710411d886ee07
quelle
\xde
, sollte es 1 Byte lang sein, und die Konvertierung in eine Zahl (über Pythonsord()
oder Javascript.charCodeAt(0)
) sollte 222 (0xDE) zurückgeben.Antworten:
JavaScript (ES6),
169 bis168 ByteNimmt die Eingabe als Array von Bytes. Gibt ein weiteres Array von Bytes zurück.
Wie?
Dies ist im Wesentlichen eine wörtliche Implementierung der Spezifikation.
Wir teilen das Eingabearray zunächst in l (Länge des Schlüssels) und s (Nutzdaten: Schlüssel + Nachricht) auf. Dann in der Reihenfolge der Ausführung:
Wir initialisieren das Zustandsarray S und definieren m = 255, das später wiederholt als Bitmaske verwendet wird.
Wir mischen die Zustandsmatrix. Die hier initialisierten Indizes I und J werden im nächsten Schritt tatsächlich verwendet.
Wir wenden die Verschlüsselung an.
Testfälle
Code-Snippet anzeigen
quelle
138 Bytes, Computercode (16-Bit x86)
Laufen: auf codegolf.com speichern, dosbox:
codegolf.com < input.bin
Ich weiß nicht, ob dies als Eintrag zählt, aber ich habe beschlossen, es manuell mit Hex-Editoren zu machen. Hierzu wurden keine Compiler verwendet.
Der Editor hat zwar Assembler, aber ehrlich gesagt wusste ich nichts davon, bis ich fertig war ¯ \ _ (ツ) _ / ¯
Warum wie
Warum: Hauptsächlich, weil ich überprüfen wollte, ob ich dazu in der Lage bin.
Wie: Ich habe mit der Erstellung eines mit
NOP
s gefüllten Bytes begonnen und mit einem einfachen Teil begonnen: Ich habe versucht, eine erste Schleife zu schreiben, die dasS
Datum mit 0..255-Werten füllt . Ich bin auf Python umgestiegen und habe schnell eine Python-Version geschrieben, nur um etwas zu testen. Als nächstes vereinfachte ich Python-Code in Pseudo-Code / Pseudo-Assembly. Dann habe ich versucht, kleine Stücke zu schreiben. Ich entschied, dass es am einfachsten ist, von stdin zu lesen, also begann ich mit etwas Kleinem, das einzelne Bytes liest, dann fügte ich das Lesen von Passwörtern und die Initialisierung von Schlüsseln hinzu. Ich brauchte einige Zeit, um herauszufinden, welche Register ich auswählen sollte.Ich füge zwar eine De / Encryption-Schleife hinzu, aber zuerst habe ich tatsächlich eine Einzelbyte-Decodierung und danach eine ganze Schleife hinzugefügt.
Der letzte Schritt bestand darin, zusätzliche
nops
Informationen zu entfernen, die ich beim Schreiben zwischen den Anweisungen gelassen habe (von denen auch Korrektursprünge erforderlich waren).Sie können eine kleine Galerie sehen, die ich gemacht habe, als ich hier vorankam .
Präparation
Das Programm stützt sich nach dem Start auf einige Anfangswerte (siehe Ressourcen unten).
Füllen Sie den Status aus (bei 0x200)
Leselänge, Passwort lesen, Passwort speichern unter ds: 0x300
Zustand mit einem Schlüssel initialisieren (
BP
wird zum Durchlaufen des Schlüssels verwendet,SI
wird zum Durchlaufen des Zustands verwendet)Pseudozufallswert generieren (in
DL
,DH
ist 0 thx bis xor bei 0x140)SI
- Ints werden es nicht berühren,BX
)DX
)PS Das könnte wahrscheinlich noch kürzer sein, aber das hat 4 Abende gedauert, also bin ich mir nicht sicher, ob ich noch einen verbringen will ...
Tools und Ressourcen
quelle
C (gcc) ,
193 188 182 178 171172 BytesProbieren Sie es online!
Bearbeiten: Funktioniert jetzt mit Schlüsseln, die länger als 127 Byte sind.
Edit2: Testfall mit 129-Byte-Schlüssel zur TIO-Verbindung hinzugefügt.
Etwas weniger Golf Version
quelle
CPU x86-Befehlssatz, 133 Byte
A7D-9F8 = 85h = 133 Bytes, aber ich weiß nicht, ob die Berechnung in Ordnung ist, weil die vorherige Anzahl von Bytes der gleichen Funktion 130 Bytes ergibt ... Das erste Argument der Funktion, die ich "cript" nenne, ist der String. Das zweite Argument ist die Länge des Strings (erstes Byte + Schlüssellänge + Nachrichtenlänge). Unten finden Sie die Assemblersprachendatei, um diese Cript-Routinen zu erhalten:
Unterhalb der C-Datei finden Sie die Prüfergebnisse:
die Ergebnisse:
quelle
JavaScript (ES6), 262 Byte
Ich überlegte, nur verkettete Funktionen zu verwenden, entschied mich jedoch für den hier angegebenen Algorithmus: https://gist.github.com/farhadi/2185197 .
Weniger Golf
Code-Snippet anzeigen
quelle
Python 2 , 203 Bytes
Probieren Sie es online!
f
ist ein Generator (iterierbar) von Strings.Ungolfed:
quelle
Ruby, 234 Bytes
Ungetestet.
quelle
C, 181 Bytes
dank ceilingcat für ein paar bytes weniger:
f (a, n) in "a" gäbe es das Zeichenfeld 1Byte len + key + message; in n gibt es die Größe des all-Arrays von "a", nicht die letzte "\ 0". Der Code für Test und Ergebnis entspricht dem Code für die Assembly-Funktion.
quelle
APL (NARS), 329 Zeichen, 658 Byte
wie immer würde die fehlerprüfung jemand anderem abverlangt ... dies scheint bei eingabe und ausgabe in ordnung zu sein, teste:
Ja, alles kann reduziert werden ... aber zum Beispiel kann die xor-Funktion bedeuten, dass es weniger allgemein ist ...
quelle
Rust 348
Das ist ziemlich furchtbar groß, ich hoffe, vielleicht könnte jemand ein paar Vorschläge machen.
ungolfed: auf play.rust-lang.org spielplatz
quelle
k
stattkey
undm
stattmsg
und vorfoo&255
anstelle von(foo)%256