CipherSaber-Verschlüsselung

11

Implementieren Sie ein CipherSaber- Verschlüsselungsprogramm wie unten beschrieben. Richtlinien:

  • Der kleinste Eintrag in Bytes gewinnt.
    • In Abweichung von den Normen können Sie jedoch gerne interessante Einträge veröffentlichen, auch wenn es sich nicht um ernsthafte Golfeinträge handelt.
  • Ein Eintrag ist normalerweise ein Programm, das den Klartext von der Standardeingabe übernimmt und den Chiffretext in die Standardausgabe schreibt, wobei der Schlüssel (vom Benutzer) auf eine von Ihnen bevorzugte Weise angegeben wird.
    • Wenn Sie dies jedoch als Prozedur implementieren möchten, ist dies ebenfalls in Ordnung.
  • Die IV muss von einem kryptografisch sicheren Pseudozufallszahlengenerator stammen. Wenn Ihre Sprache dies nicht unterstützt, wählen Sie eine andere. ;-);
  • Bitte verwenden Sie keine kryptospezifischen Bibliotheken, Systemaufrufe oder Anweisungen (außer dem PRNG, wie oben angegeben). Generelle bitweise Operationen auf niedriger Ebene sind natürlich in Ordnung.

CipherSaber ist eine Variante von RC4 / Arcfour, daher beschreibe ich zunächst Letzteres und dann die Änderungen, die CipherSaber daran vornimmt.

0. RC4 / Arcfour

Arcfour ist an anderer Stelle vollständig spezifiziert , aber der Vollständigkeit halber werde ich es hier beschreiben. (Bei Abweichungen zwischen dem Internet-Entwurf und dieser Beschreibung ist die erstere normativ.)

Schlüsseleinstellung

Richten Sie zwei Arrays, Sund S2sowohl der Länge 256, wobei k_1das erste Byte des Schlüssels ist, und k_nist das letzte.

S = [0, ..., 255]
S2 = [k_1, ..., k_n, k_1, ...]

( S2wird immer wieder mit den Bytes des Schlüssels gefüllt, bis alle 256 Bytes voll sind.)

Initialisieren Sie dann jauf 0 und mischen Sie 256 Mal:

j = 0
for i in (0 .. 255)
    j = (j + S[i] + S2[i]) mod 256
    swap S[i], S[j]
end

Damit ist die Schlüsseleinrichtung abgeschlossen. Das S2Array wird hier nicht mehr verwendet und kann gesäubert werden.

Erzeugung von Chiffrestreams

Initialisieren Sie iund jauf 0 und generieren Sie dann den Schlüsselstrom wie folgt:

i = 0
j = 0
while true
    i = (i + 1) mod 256
    j = (j + S[i]) mod 256
    swap S[i], S[j]
    k = (S[i] + S[j]) mod 256
    yield S[k]
end

Daten verschlüsseln / entschlüsseln

  • Zum Verschlüsseln XOR die Keystream-Ausgabe mit dem Klartext
  • Zum Entschlüsseln XOR die Schlüsselstromausgabe mit dem Chiffretext

1. CipherSaber

CipherSaber (was wir in dieser Frage implementieren) ist eine Variation von RC4 / Arcfour in zweierlei Hinsicht:

10 Byte IV / Nonce

Beim Verschlüsseln einer Nachricht sollten 10 zufällige Bytes abgerufen werden, z. B. via /dev/urandom, und in die ersten 10 Bytes der verschlüsselten Ausgabe geschrieben werden. Beim Entschlüsseln einer Nachricht sind die ersten 10 Bytes der Eingabe die IV, mit der sie verschlüsselt wird.

Die Einrichtungsphase für RC4 / Arcfour-Schlüssel wird mit passphrase || IVdem Schlüssel ausgeführt, wobei passphrasedie benutzerdefinierte Passphrase IVwie oben beschrieben und ||verkettet ist. Also eine Passphrase von "Hallo Welt!" und eine IV von "Supercalif" (wie unwahrscheinlich das auch sein mag :-P) würde zu einem Schlüssel von "Hallo Welt! Supercalif" führen.

Mehrere Iterationen der Schlüsselkonfiguration

Um die Sicherheitsanfälligkeit zu vermeiden, durch die die WEP-Verschlüsselung vollständig beschädigt wurde, wird die Mischschleife der Schlüssel-Setup-Phase von RC4 eine benutzerdefinierte Anzahl von Malen ausgeführt. Der Wert von jsollte zwischen den Iterationen beibehalten werden.

2. Testvektoren

Hier sind einige Testvektoren, mit denen Sie Ihre Programme testen können. Darüber hinaus hat squeamish ossifrage ein CipherSaber-Verschlüsselungs- und Entschlüsselungstool erstellt , mit dem Sie Ihre Ergebnisse validieren können.

Sie müssen nur das Verschlüsselungsprogramm implementieren. Sie müssen das Entschlüsselungsprogramm nicht angeben, aber die Ausgabe Ihres Verschlüsselungsprogramms muss korrekt zur ursprünglichen Eingabe zurückkehren, wenn sie mit einem korrekt implementierten Entschlüsselungsprogramm unter Verwendung des richtigen Schlüssels verarbeitet wird.

Chris Jester-Young
quelle

Antworten:

7

Pyth, 100 Bytes

$import os$KsM$os.urandom(10)$JuuXN@LN,T=+Z+@NT@+CMzKT)bGQU=b256=Z0sCM+K.exCb@=XJ=N@LJ,hk=+Z@Jhk)sNw

Dieses Skript verwendet den $Befehl, mit dem Python-Code ausgeführt werden kann. Um zu verhindern, dass schädlicher Code auf dem Server ausgeführt wird, ist dieser Befehl im Online-Compiler deaktiviert. Sie müssen es mit dem Offline-Compiler ausführen, den Sie hier finden .

Die Eingabe hat das folgende Format:

secret key
5 (number of repeats)
secret message

Das Programm gibt die verschlüsselte Zeichenfolge aus, die möglicherweise nicht druckbare Zeichen enthält. Wenn Sie es mit dem CipherSaber Encryption & Decryption Tool überprüfen möchten , können Sie den folgenden Code verwenden, der die Zeichenfolge in eine Reihe von hexadezimalen Ziffern konvertiert.

$import os$KsM$os.urandom(10)$JuuXN@LN,T=+Z+@NT@+CMzKT)bGQU=b256=Z0         
jdm.[2.HCd`0
sCM+K.exCb@=XJ=N@LJ,hk=+Z@Jhk)sNw

Pyth unterstützt keine kryptografisch sicheren Pseudozufallszahlen und der Import aus Python kostet 25 Byte. Ein kürzerer Code, der den normarischen Pseudozufallszahlengenerator von Pyth / Python verwendet und auch im Online-Compiler funktioniert, ist:

KmO=b256TJuuXN@LN,T=+Z+@NT@+CMzKT)bGQUb=Z0sCM+K.exCb@=XJ=N@LJ,hk=+Z@Jhk)sNw

Probieren Sie es online aus: Geben Sie eine Zeichenfolge oder eine Reihe von hexadezimalen Ziffern zurück

Der Code ist nichts Besonderes. Nur eine Menge schmutziger Aufgaben und die sofortige Wiederverwendung berechneter Ergebnisse und die doppelte Anwendung des List-Swap- Tricks.

Erläuterung:

                                  implicit: z = 1st input (= key string)
                                  Q = 2nd input (number of repetitions)
$import os$KsM$os.urandom(10)$
$import os$                       import Python's os module
              $os.urandom(10)$    create 10 cryptographically secure 
                                  pseudo-random bytes
            sM                    convert them to ints
           K                      store them in K

JuuXN@LN,T=+Z+@NT@+CMzKT)bGQU=b256
                             =b256assign b with 256
 u                         QUb    start with G = [0, 1, ..., 255], 
                                  evaluate the following expression Q times and
                                  update G with the result each time:
  u                      bG         start with N = G, 
                                    for each T in [0, 1, ..., 255] evaluate the
                                    following expression and update N each time:
                   CMz                convert key to list of ints
                  +   K               extend it with K
                 @     T              take the Tth element (modulo length)
              @NT                     take the Tth element of N
             +                        add these two values
           +Z                         add Z (with is initially 0)
          =                           and update Z with the result
        ,T  Z                         make the pair of indices [T, Z] 
     @LN                              look-up their values in N
   XN                   )             and switch these two values in N
J                                 assign the result (the key setup) to J

=Z0                               set Z to 0

sCM+K.exCb@=XJ=N@LJ,hk=+Z@Jhk)sNw 
                                w read a string from input (message)
     .e                           map each index k, char b in message to:
                         @Jhk       look-up the (k+1)th element in J
                      =+Z           add it to Z and update Z
                   ,hk  Z           make the pair of indices [k+1,Z]
                @LJ                 look-up their values in J
              =N                    assign the result to N
            XJ N             )      swap these values in J
           =                        and update J with the result
          @  J                sN    take the sum(N)th element of J
        Cb                          convert b to int
       x                            bitwise xor of these two elements
   +K                             insert K at the beginning
 CM                               convert each element to char
s                                 sum them (generate a string)
                                  implicitly print
Jakube
quelle
Anscheinend haben eingebaute Pyth-Funktionen keine kryptografisch sicheren Pseudozufallszahlen . Sie können Ihren Eintrag so lassen, wie er ist, und er qualifiziert sich nicht für das grüne Häkchen, oder Sie können eine Version urandomerstellen , die verwendet (was ein separater Eintrag sein kann, wenn Sie möchten), wenn Sie sich für "Gewinnen" interessieren. :-)
Chris Jester-Young
@ ChrisJester-Young Tut mir leid. Ich hätte nicht gedacht, dass Pythons Zufallszahlengenerator so unsicher ist. Es wurde auf Kosten von 25 Bytes korrigiert.
Jakube
4

Python 2 - 373 350 326 317 Bytes

Pyth kommt möglicherweise später. Definiert eine Funktion, c(p,d,r,m)die Bytelisten für Passphrase und Daten verwendet, und int für Wiederholungen und den Modus, der bei 1 verschlüsselt und bei 0 entschlüsselt. Dies liegt daran, dass der einzige Unterschied darin besteht, dass es sich um die IV handelt. Gibt die Byteliste zurück.

import os
B=256
def c(p,d,r,m):
    if m:v=map(ord,os.urandom(10))
    else:v,d=d[:10],d[10:]
    p+=v;S=range(B);T=(p*B)[:B];j=0;exec"for i in range(B):j=(j+S[i]+T[i])%B;S[i],S[j]=S[j],S[i]\n"*r;o=[];i=j=0
    for b in d:i=-~i%B;j=(j+S[i])%B;S[i],S[j]=S[j],S[i];k=(S[i]+S[j])%B;o+=[S[k]^b]
    return v+o if m else o

Hier sind einige Testcode- / Hilfsfunktionen:

phrase = "hello"
text = "Mary had a little lamb, little lamb, little lamb"
N = 5

def make_bytes(string):
    return map(ord, string)

def make_string(bytes):
    return "".join(map(chr, bytes))

def make_hex(bytes):
    return " ".join("%02x" % i for i in bytes)

def from_hex(hex_str):
    return [int(i, 16) for i in hex_str.split()]

cipher = c(make_bytes(phrase), make_bytes(text), N, 1)
print make_hex(cipher)
plain = c(make_bytes(phrase), cipher, N, 0)
print make_string(plain)
Maltysen
quelle
Sie müssen nur ein Verschlüsselungsprogramm schreiben. So können Sie das else:v,d=d[:10],d[10:]Teil entfernen .
Jakube
3

Ruby - 263 Zeichen

Dies ist meine Ruby-Antwort auf die ursprüngliche Frage zum Stackoverflow im Jahr 2010! Es ist ein Codierer und Decodierer in einem Programm

Parameter sind:
e oder d (zum Codieren oder Decodieren)
Schlüssel
wie oft

$ ruby saber.rb e gnibbler 10 < in.txt | ruby saber.rb d gnibbler 10

o,k,l=ARGV;print o<'e'?(v=STDIN.read(10))*0:v=(0..9).map{rand(256).chr}.join;j=0;E=255
S=Array 0..255;(S*l.to_i).each{|i|j=j+S[i]+((k+v)*E)[i].ord&E;S[i],S[j]=S[j],S[i]};i=j=0
STDIN.each_byte{|c|i=i+1&E;j=j+S[i]&E;S[i],S[j]=S[j],S[i];print (c^S[S[i]+S[j]&E]).chr}
Gnibbler
quelle
2

C 312 Bytes

Akzeptiert eine Anzahl von Schlüssel- und Schlüsselmischungsiterationen in der Befehlszeile und verschlüsselt dann alles auf stdin in stdout. Dies verwendet die BSD / Darwin-Bibliotheksfunktion arc4random(), bei der es sich um ein auf RC4 basierendes PRNG handelt. Es sät sich automatisch selbst, sodass die Ergebnisse jedes Mal anders sind.

unsigned char n,i,j,q,x,t,s[256],k[256];main(int c,char**v){for(strcpy(k,v[1]),n=strlen(k);x<10;x++)putchar(k[n++]=arc4random());do{s[i]=i;}while(++i);for(x=atoi(v[2]);x--;)do{t=s[i];s[i]=s[j+=s[i]+k[i%n]];s[j]=t;}while(++i);for(;(c=getchar())>0;){q+=s[++i];t=s[i];s[i]=s[q];s[q]=t;t=s[i]+s[q];putchar(c^s[t]);}}

Ordentlichere Version:

unsigned char n,i,j,q,x,t,s[256],k[256];
main(int c,char**v) {
  for (strcpy(k,v[1]),n=strlen(k);x<10;x++) putchar(k[n++]=arc4random());
  do {
    s[i]=i;
  }
  while(++i);
  for (x=atoi(v[2]);x--;) do {
    t=s[i];
    s[i]=s[j+=s[i]+k[i%n]];
    s[j]=t;
  }
  while (++i);
  for (;(c=getchar())>0;) {
    q+=s[++i];
    t=s[i];
    s[i]=s[q];
    s[q]=t;
    t=s[i]+s[q];
    putchar(c^s[t]);
  }
}

Beispiel:

$ echo -n 'Ciphersaber' | ./csgolf 'hello' 20 | xxd -p
0f6257c330e5e01c3eab07bc9cb4ee4c3eaa514a85
r3mainer
quelle
1

Python - 266 Zeichen

Dies ist meine Python-Antwort auf die ursprüngliche Frage zum Stackoverflow im Jahr 2010! Es ist ein Codierer und Decodierer in einem Programm

Parameter sind:
e oder d (zum Codieren oder Decodieren)
Schlüssel
wie oft

$ python saber.py e gnibbler 10 < in.txt | python saber.py d gnibbler 10

Diese Version versucht, die 2 Schleifen des rc4 zu einer zusammenzuführen (spart bisher 11 Bytes ...)

import os,sys;X,Y=sys.stdin.read,os.write;_,o,k,l=sys.argv;p='d'<o
V=(X,os.urandom)[p](10);Y(1,V*p);E,S=255,range(256)
for q in S*int(l),X():
 t=q<'';j=0;i=-t
 for c in q:i=i+1&E;j=j+S[i]+t*ord(((k+V)*E)[i])&E;S[i],S[j]=S[j],S[i];t or Y(1,chr(ord(c)^S[S[i]+S[j]&E]))
Gnibbler
quelle