Cifrado CipherSaber

11

Implemente un programa de cifrado CipherSaber , como se describe a continuación. Pautas:

  • La entrada más pequeña, en bytes, gana.
    • Sin embargo, en una desviación de normas de , puede publicar entradas interesantes, incluso si no son entradas serias de golf.
  • Una entrada normalmente sería un programa que toma el texto sin formato de la entrada estándar y escribe el texto cifrado en la salida estándar, con la clave especificada (por el usuario) de la manera que prefiera.
    • Sin embargo, si desea implementar esto como un procedimiento, también está bien.
  • El IV debe provenir de un generador de números pseudoaleatorios criptográficamente seguro. Si su idioma no es compatible con eso, elija uno diferente. ;-)
  • No utilice ninguna biblioteca específica de cifrado, llamadas al sistema o instrucciones (que no sean PRNG, como se estipula anteriormente). Por supuesto, las operaciones bit a nivel genéricas de bajo nivel están bien.

CipherSaber es una variante de RC4 / Arcfour, por lo que comenzaré describiendo esta última y luego los cambios que CipherSaber realiza.

0. RC4 / Arcfour

Arcfour está completamente especificado en otra parte , pero para completarlo, lo describiré aquí. (En caso de discrepancias entre el borrador de Internet y esta descripción, la primera es normativa).

Configuración clave

Configure dos matrices Sy S2, ambas de longitud 256, donde k_1es el primer byte de la clave y k_nes el último.

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

( S2se llena con los bytes de la clave, una y otra vez, hasta que se llenen los 256 bytes).

Luego, inicialice ja 0 y baraje 256 veces:

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

Esto completa la configuración clave. La S2matriz ya no se usa aquí, y se puede eliminar.

Generación de flujo de cifrado

Inicialice iya j0, luego genere la secuencia de claves de la siguiente manera:

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

Cifrar / descifrar datos

  • Para cifrar, XOR la ​​salida del flujo de claves con el texto sin formato
  • Para descifrar, XOR la ​​salida del flujo de claves con el texto cifrado

1. CipherSaber

CipherSaber (que es lo que estamos implementando en esta pregunta) es una variación de RC4 / Arcfour de dos maneras:

10 bytes IV / nonce

Al cifrar un mensaje, se deben obtener 10 bytes aleatorios, como vía /dev/urandom, y se deben escribir en los primeros 10 bytes de la salida cifrada. Al descifrar un mensaje, los primeros 10 bytes de la entrada son el IV utilizado para cifrarlo.

La etapa de configuración de la clave RC4 / Arcfour se ejecuta con passphrase || IVla clave, donde passphraseestá la frase de contraseña especificada por el usuario, IVes como se describió anteriormente y ||es la concatenación. Entonces, una frase de contraseña de "¡Hola, mundo!" y una IV de "supercalif" (por improbable que sea :-P) resultaría en una clave de "¡Hola, supercalif!".

Múltiples iteraciones de configuración clave

Para ayudar a prevenir la vulnerabilidad que hizo que el cifrado WEP se rompiera por completo, el ciclo de barajado de la etapa de configuración de clave de RC4 se ejecuta un número de veces especificado por el usuario. El valor de jdebe conservarse entre iteraciones.

2. Vectores de prueba

Aquí hay algunos vectores de prueba que puede usar para probar sus programas. Además, ossifrage aprensivo creó una herramienta de cifrado y descifrado CipherSaber que puede usar para validar sus resultados.

Solo necesita implementar el programa de cifrado. No es necesario que suministre el programa de descifrado, pero la salida de su programa de cifrado debe ir correctamente a la entrada original cuando se procesa con un programa de descifrado implementado correctamente utilizando la clave correcta.

Chris Jester-Young
fuente

Respuestas:

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

Este script usa el $comando, que permite ejecutar código Python. Para evitar la ejecución de código malicioso en el servidor, este comando está deshabilitado en el compilador en línea. Tienes que ejecutarlo con el compilador fuera de línea que puedes encontrar aquí .

La entrada está en el formato:

secret key
5 (number of repeats)
secret message

El programa genera la cadena encriptada, que puede contener caracteres no imprimibles. Si desea verificarlo con la herramienta de cifrado y descifrado CipherSaber , puede usar el siguiente código, que convierte la cadena en una serie de dígitos hexadecimales.

$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 no admite números pseudoaleatorios criptográficamente seguros y su importación desde Python cuesta 25 bytes. Un código más corto, que usa el generador de números pseudoaleatorios normar de Pyth / Python y también funciona en el compilador en línea es:

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

Pruébelo en línea: devolver una cadena o una serie de dígitos hexadecimales

El código no es nada especial. Solo muchas tareas sucias y reutilizaciones inmediatas de resultados calculados y aplicar el doble del truco de intercambio de listas .

Explicación:

                                  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
fuente
Aparentemente, las funciones integradas de Pyth no tienen números pseudoaleatorios criptográficamente seguros . Puede mantener su entrada como está, y no calificará para la marca verde, o puede hacer una versión que use urandom(que puede ser una entrada separada si lo desea) si le importa "ganar". :-)
Chris Jester-Young
@ ChrisJester-Young Lo siento por eso. No pensé que el generador de números aleatorios de Python sea tan inseguro. Lo corrigió a un costo de 25 bytes.
Jakube
4

Python 2 - 373 350 326 317 bytes

Pyth posiblemente vendrá más tarde. Define una función, c(p,d,r,m)que toma listas de bytes para frase de contraseña y datos, e int para repeticiones y modo que encripta cuando 1 y desencripta cuando 0. Esto se debe a que la única diferencia en ellos es tratar con el IV. Devuelve la lista de bytes.

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

Aquí hay algunas funciones de código de prueba / ayudante:

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
fuente
Solo necesita escribir un programa de cifrado. Entonces puedes quitar la else:v,d=d[:10],d[10:]parte.
Jakube
3

Ruby - 263 caracteres

¡Esta es mi respuesta de Ruby a la pregunta original sobre stackoverflow en 2010! Es un codificador y decodificador todo en un programa.

Los parámetros son:
eod (
clave de codificación o decodificación)
número de veces

$ 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
fuente
2

C, 312 bytes

Acepta un recuento de iteración de mezcla de clave y clave en la línea de comando, luego encripta todo en stdin a stdout. Utiliza la función de biblioteca BSD / Darwin arc4random(), que es un PRNG basado en RC4. Se siembra automáticamente, por lo que los resultados serán diferentes cada vez.

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

Versión más ordenada:

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

Ejemplo:

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

Python - 266 caracteres

¡Esta es mi respuesta de Python a la pregunta original sobre stackoverflow en 2010! Es un codificador y decodificador todo en un programa.

Los parámetros son:
eod (
clave de codificación o decodificación)
número de veces

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

Esta versión intenta fusionar los 2 bucles del rc4 en uno (ahorra 11 bytes hasta ahora ...)

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
fuente