Criptografia CipherSaber

11

Implemente um programa de criptografia CipherSaber , conforme descrito abaixo. Diretrizes:

  • A menor entrada, em bytes, vence.
    • No entanto, ao se afastar das normas do , você pode publicar entradas interessantes, mesmo que não sejam sérias.
  • Uma entrada normalmente seria um programa que pega o texto sem formatação da entrada padrão e grava o texto cifrado na saída padrão, com a chave especificada (pelo usuário) da maneira que você preferir.
    • No entanto, se você deseja implementar isso como um procedimento, tudo bem também.
  • O IV deve vir de um gerador de números pseudoaleatórios criptograficamente seguro. Se o seu idioma não suportar isso, escolha um idioma diferente. ;-)
  • Por favor, não use bibliotecas, chamadas de sistema ou instruções específicas para criptografia (exceto o PRNG, conforme estipulado acima). Obviamente, operações bit a bit de baixo nível genéricas estão bem.

O CipherSaber é uma variante do RC4 / Arcfour, então vou começar descrevendo o último, depois as alterações que o CipherSaber faz nele.

0. RC4 / Arcfour

Arcfour é totalmente especificado em outro lugar , mas para ser completo, eu descreverei aqui. (No caso de discrepâncias entre o rascunho da Internet e essa descrição, o primeiro é normativo.)

Configuração de teclas

Configure duas matrizes Se S2, ambas com comprimento 256, onde k_1é o primeiro byte da chave e k_no último.

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

( S2é preenchido com os bytes da chave, repetidamente, até que todos os 256 bytes sejam preenchidos.)

Em seguida, inicialize jpara 0 e embaralhe 256 vezes:

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

Isso completa a configuração da chave. A S2matriz não é mais usada aqui e pode ser limpa.

Geração de fluxo cifrado

Inicialize ie jpara 0, gere o fluxo de chaves da seguinte maneira:

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

Criptografar / descriptografar dados

  • Para criptografar, XOR a saída do fluxo de chaves com o texto sem formatação
  • Para descriptografar, XOR a saída do fluxo de chaves com o texto cifrado

1. CipherSaber

O CipherSaber (que é o que estamos implementando nesta pergunta) é uma variação do RC4 / Arcfour de duas maneiras:

10 bytes IV / nonce

Ao criptografar uma mensagem, 10 bytes aleatórios devem ser obtidos, como via /dev/urandom, e gravados nos primeiros 10 bytes da saída criptografada. Ao descriptografar uma mensagem, os 10 primeiros bytes da entrada são os IV usados ​​para criptografá-la.

O estágio de configuração da chave RC4 / Arcfour é executado com passphrase || IVa chave, onde passphraseestá a senha especificada pelo usuário, IVé como descrito acima e ||é concatenação. Então, uma senha de "Olá, mundo!" e um IV de "supercalif" (por mais improvável que seja :-P) resultaria em uma chave de "Hello, world! supercalif".

Várias iterações da configuração da chave

Para ajudar a evitar a vulnerabilidade que quebrou completamente a criptografia WEP, o ciclo de embaralhamento do estágio de configuração de chave do RC4 é executado um número de vezes especificado pelo usuário. O valor de jdeve ser retido entre as iterações.

2. Vetores de teste

Aqui estão alguns vetores de teste que você pode usar para testar seus programas. Além disso, ossifrage melindroso criou uma ferramenta de criptografia e descriptografia CipherSaber que você pode usar para validar seus resultados.

Você só precisa implementar o programa de criptografia. Você não precisa fornecer o programa de descriptografia, mas a saída do programa de criptografia deve retornar corretamente à entrada original quando processada com um programa de descriptografia implementado corretamente, usando a chave correta.

Chris Jester-Young
fonte

Respostas:

7

Pitão, 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 o $comando, que permite executar o código Python. Para impedir a execução de código malicioso no servidor, o comando this está desabilitado no compilador online. Você deve executá-lo com o compilador off-line, que pode ser encontrado aqui .

A entrada está no formato:

secret key
5 (number of repeats)
secret message

O programa gera a sequência criptografada, que pode conter caracteres não imprimíveis. Se você deseja verificá-lo usando a Ferramenta de Criptografia e Descriptografia CipherSaber , pode usar o código a seguir, que converte a string em uma série de dígitos hexadecimais.

$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

O Pyth não suporta números pseudo-aleatórios criptograficamente seguros e a importação deles do Python custa 25 bytes. Um código mais curto, que usa o gerador de números pseudo-aleatórios normar do Pyth / Python e também funciona no compilador on-line é:

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

Experimente on-line: retornando uma sequência ou uma série de dígitos hexadecimais

O código não é nada de especial. Apenas muitas atribuições sujas e reutilizações imediatas de resultados computados e aplicando o dobro do truque de troca de lista .

Explicação:

                                  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
fonte
Aparentemente, as funções Pyth embutidas não têm números pseudo-aleatórios criptograficamente seguros . Você pode manter sua inscrição como está, e ela não se qualificará para o visto verde, ou você pode criar uma versão que use urandom(que pode ser uma entrada separada, se quiser) se você se interessar em "vencer". :-)
Chris Jester-Young
@ ChrisJester-Young Desculpe por isso. Não pensei que o gerador de números aleatórios do Python fosse tão inseguro. Corrigido para um custo de 25 bytes.
Jakube 26/07/2015
4

Python 2 - 373 350 326 317 bytes

Pyth possivelmente virá mais tarde. Define uma função, c(p,d,r,m)que recebe listas de bytes para senha e dados, e int para repetições e modo que criptografa quando 1 e descriptografa quando 0. Isso ocorre porque a única diferença neles é lidar com o IV. Retorna a 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

Aqui estão algumas funções de código de teste / auxiliar:

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
fonte
Você só precisa escrever um programa de criptografia. Então você pode remover a else:v,d=d[:10],d[10:]peça.
Jakube 26/07
3

Ruby - 263 caracteres

Esta é minha resposta do Ruby à pergunta original sobre stackoverflow em 2010! É um codificador e decodificador, tudo em um programa

Os parâmetros são:
e ou d (para codificar ou descodificar)
chave de
número de vezes

$ 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}
mordedor
fonte
2

C, 312 bytes

Aceita uma contagem de iteração de chave e mistura de chaves na linha de comando e, em seguida, criptografa tudo do stdin para o stdout. Isso usa a função de biblioteca BSD / Darwin arc4random(), que é um PRNG baseado no RC4. Ele se propaga automaticamente, para que os resultados sejam sempre diferentes.

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

Versão mais 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]);
  }
}

Exemplo:

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

Python - 266 caracteres

Esta é a minha resposta do Python à pergunta original sobre stackoverflow em 2010! É um codificador e decodificador, tudo em um programa

Os parâmetros são:
e ou d (para codificar ou descodificar)
chave de
número de vezes

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

Esta versão tenta mesclar os 2 loops do rc4 em um (salva 11 bytes até agora ...)

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]))
mordedor
fonte