Crittografia CipherSaber


11

Implementare un programma di crittografia CipherSaber , come descritto di seguito. Linee guida:

  • La voce più piccola, in byte, vince.
    • Tuttavia, in deroga norme del , siete invitati a pubblicare voci interessanti, anche se non sono serie voci sul golf.
  • Una voce sarebbe in genere un programma che prende il testo normale dall'input standard e scrive il testo cifrato nell'output standard, con la chiave specificata (dall'utente) nel modo che preferisci.
    • Tuttavia, se si desidera implementare questo come una procedura, va bene lo stesso.
  • L'IV deve provenire da un generatore di numeri pseudocasuali crittograficamente sicuro. Se la tua lingua non lo supporta, scegline una diversa. ;-)
  • Non utilizzare librerie, chiamate di sistema o istruzioni specifiche per criptovalute (diverse dal PRNG, come stipulato sopra). Naturalmente, le operazioni generiche bit a basso livello vanno bene.

CipherSaber è una variante di RC4 / Arcfour, quindi inizierò descrivendo quest'ultimo, quindi le modifiche apportate da CipherSaber.

0. RC4 / Arcfour

Arcfour è completamente specificato altrove , ma per completezza, lo descriverò qui. (In caso di discrepanze tra la bozza di Internet e questa descrizione, la prima è normativa.)

Impostazione chiave

Configurare due array Se S2, entrambi di lunghezza 256, dove si k_1trova il primo byte della chiave ed k_nè l'ultimo.

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

( S2viene riempito con i byte della chiave, ancora e ancora, fino a riempire tutti i 256 byte.)

Quindi, inizializza jsu 0 e mescola 256 volte:

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

Questo completa l'impostazione della chiave. L' S2array non viene più utilizzato qui e può essere rimosso.

Generazione del flusso di cifratura

Inizializza ie jsu 0, quindi genera il flusso di chiavi come segue:

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

Crittografia / decrittografia dei dati

  • Per crittografare, XOR l'output keystream con il testo in chiaro
  • Per decrittografare, XOR l'output keystream con il testo cifrato

1. CipherSaber

CipherSaber (che è ciò che stiamo implementando in questa domanda) è una variante di RC4 / Arcfour in due modi:

10 byte IV / nonce

Quando si crittografa un messaggio, è necessario ottenere 10 byte casuali, ad esempio via /dev/urandom, e scrivere nei primi 10 byte dell'output crittografato. Quando si decodifica un messaggio, i primi 10 byte dell'input sono il IV utilizzato per crittografarlo.

La fase di impostazione della chiave RC4 / Arcfour viene eseguita passphrase || IVcome chiave, dove si passphrasetrova la passphrase specificata dall'utente, IVcome descritto sopra ed ||è concatenazione. Quindi, una passphrase di "Ciao, mondo!" e un IV di "supercalif" (per quanto improbabile sia :-P) si tradurrebbe in una chiave di "Hello, world! supercalif".

Più iterazioni di impostazione chiave

Per aiutare a prevenire la vulnerabilità che ha reso la crittografia WEP completamente rotta, il ciclo di shuffle della fase di impostazione della chiave di RC4 viene eseguito un numero di volte specificato dall'utente. Il valore di jdeve essere mantenuto tra le iterazioni.

2. Test dei vettori

Ecco alcuni vettori di test che puoi utilizzare per testare i tuoi programmi. Inoltre, ossifrage squeamish ha creato uno strumento di crittografia e decrittografia CipherSaber che è possibile utilizzare per convalidare i risultati.

Hai solo bisogno di implementare il programma di crittografia. Non è necessario fornire il programma di decrittografia, ma l'output del programma di crittografia deve essere inviato correttamente all'input originale quando elaborato con un programma di decrittografia correttamente implementato utilizzando la chiave corretta.

Risposte:


7

Pyth, 100 byte

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

Questo script utilizza il $comando, che consente di eseguire il codice Python. Per impedire l'esecuzione di codice dannoso sul server, questo comando è disabilitato nel compilatore online. Devi eseguirlo con il compilatore off-line che puoi trovare qui .

L'input è nel formato:

secret key
5 (number of repeats)
secret message

Il programma genera la stringa crittografata, che potrebbe contenere caratteri non stampabili. Se si desidera verificarlo utilizzando lo strumento di crittografia e decrittografia CipherSaber , è possibile utilizzare il seguente codice, che converte la stringa in una serie di cifre esadecimali.

$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 non supporta numeri pseudocasuali sicuri crittograficamente e importarli da Python costa 25 byte. Un codice più breve, che utilizza il normale generatore di numeri pseudocasuali di Pyth / Python e funziona anche nel compilatore online è:

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

Provalo online: restituisce una stringa o una serie di cifre esadecimali

Il codice non è niente di speciale. Solo un sacco di compiti sporchi e riutilizzi immediati dei risultati calcolati e l'applicazione del doppio del trucco di scambio di lista .

Spiegazione:

                                  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

Apparentemente, le funzioni Pyth integrate non hanno numeri pseudocasuali sicuri dal punto di vista crittografico . Puoi mantenere la tua voce così com'è, e non si qualificherà per il segno di spunta verde, oppure puoi creare una versione che usa urandom(che può essere una voce separata se vuoi) se ti interessa "vincere". :-)
Chris Jester-Young,

@ ChrisJester-Young Mi dispiace per quello. Non pensavo che il generatore di numeri casuali di Python fosse così insicuro. Corretto ad un costo di 25 byte.
Jakube,

4

Python 2 - 373 350 326 317 byte

Pyth probabilmente arriverà più tardi. Definisce una funzione, c(p,d,r,m)che accetta gli elenchi di byte per passphrase e dati e int per le ripetizioni e la modalità che crittografa quando 1 e decrittografa quando 0. Ciò è dovuto al fatto che l'unica differenza è che si occupa del IV. Restituisce l'elenco di byte.

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

Ecco alcuni codici di test / funzioni di supporto:

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)

Devi solo scrivere un programma di crittografia. Quindi puoi rimuovere la else:v,d=d[:10],d[10:]parte.
Jakube,

3

Rubino - 263 caratteri

Questa è la mia risposta di Ruby alla domanda originale su StackOverflow nel 2010! È un codificatore e decodificatore tutto in un programma

I parametri sono:
e o d (per codificare o decodificare) il numero di volte del
tasto

$ 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}

2

C, 312 byte

Accetta una chiave e una chiave che mescolano il conteggio delle iterazioni sulla riga di comando, quindi crittografa tutto su stdin su stdout. Questo utilizza la funzione di libreria BSD / Darwin arc4random(), che è un PRNG basato su RC4. Semina automaticamente se stesso, quindi i risultati saranno sempre diversi.

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]);}}

Versione più ordinata:

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]);
  }
}

Esempio:

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

1

Python - 266 caratteri

Questa è la mia risposta Python alla domanda originale su StackOverflow nel 2010! È un codificatore e decodificatore tutto in un programma

I parametri sono:
e o d (per codificare o decodificare) il numero di volte del
tasto

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

Questa versione tenta di unire i 2 loop di rc4 in uno (salva 11 byte finora ...)

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]))
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.