Visão geral
Seu objetivo é implementar a criptografia RC4. A criptografia RC4, inventada por Ron Rivest (da RSA), foi projetada para ser segura, mas simples o suficiente para ser implementada da memória por soldados militares no campo de batalha. Hoje, existem vários ataques ao RC4, mas ainda é usado em muitos lugares hoje.
Seu programa deve aceitar uma única string com uma chave e alguns dados. Será apresentado neste formato.
\x0Dthis is a keythis is some data to encrypt
O primeiro byte representa quanto tempo a chave é. Pode-se supor que a chave não tenha mais que 255 bytes e menos que 1 byte. Os dados podem ser arbitrariamente longos.
Seu programa deve processar a chave e, em seguida, retornar os dados criptografados. A criptografia e descriptografia RC4 são idênticas; portanto, usando a mesma chave para "criptografar" o texto cifrado deve retornar o texto sem formatação original.
Como funciona o RC4
Inicialização
A inicialização do RC4 é bastante simples. Uma matriz de estado de 256 bytes é inicializada para todos os bytes de 0 a 255.
S = [0, 1, 2, 3, ..., 253, 254, 255]
Processamento de chaves
Os valores no estado são trocados com base na chave.
j = 0
for i from 0 to 255
j = (j + S[i] + key[i mod keylength]) mod 256
swap S[i] and S[j]
Criptografia
A criptografia é realizada usando o estado para gerar bytes pseudo-aleatórios, que são então armazenados em XOR nos dados. Os valores no estado são trocados constantemente.
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
Entradas e saídas esperadas
Caracteres não imprimíveis serão mostrados em \xAB
formato.
Entrada: \x01\x00\x00\x00\x00\x00\x00
Saída: \xde\x18\x89A\xa3
Saída (hex):de188941a3
Entrada: \x0Dthis is a keythis is some data to encrypt
Saída: \xb5\xdb?i\x1f\x92\x96\x96e!\xf3\xae(!\xf3\xeaC\xd4\x9fS\xbd?d\x82\x84{\xcdN
Saída (hex):b5db3f691f9296966521f3ae2821f3ea43d49f53bd3f6482847bcd4e
Entrada: \x0dthis is a key\xb5\xdb?i\x1f\x92\x96\x96e!\xf3\xae(!\xf3\xeaC\xd4\x9fS\xbd?d\x82\x84{\xcdN
Entrada (hex): 0d746869732069732061206b6579b5db3f691f9296966521f3ae2821f3ea43d49f53bd3f6482847bcd4e
Saída:this is some data to encrypt
Entrada: 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
Saída: \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
Saída (hex):961f2c8fa3259ba3665b6d6bdfbcac8b8efafe96423d21fc3b13606316710411d886ee07
fonte
\xde
, ele deve ter 1 byte de comprimento e convertê-lo em um número (através de pythonord()
ou javascript.charCodeAt(0)
) deve retornar 222 (0xDE).Respostas:
JavaScript (ES6),
169168 bytesRecebe a entrada como uma matriz de bytes. Retorna outra matriz de bytes.
Quão?
Esta é essencialmente uma implementação literal da especificação.
Primeiro, dividimos a matriz de entrada em l (comprimento da chave) es (dados de carga útil: chave + mensagem). Então, em ordem de execução:
Inicializamos a matriz de estados S e definimos m = 255, que é repetidamente usado posteriormente como uma máscara de bit.
Nós embaralhamos a matriz de estados. Os índices I e J que são inicializados aqui são realmente usados na próxima etapa.
Nós aplicamos a criptografia.
Casos de teste
Mostrar snippet de código
fonte
138 bytes, código de máquina (x86 de 16 bits)
Em execução: salve em codegolf.com, dosbox:
codegolf.com < input.bin
Não sei se isso vai contar como uma entrada, mas decidi fazê-lo manualmente usando editores hexadecimais. Nenhum compilador foi usado para fazer isso.
o editor ht realmente tem assembler, mas sinceramente eu não sabia disso até que terminei ¯ \ _ (ツ) _ / ¯
Porque como
Motivo: principalmente porque eu queria verificar se sou capaz de fazer isso.
Como: eu comecei a criar byte preenchido com
NOP
s e a seguir com uma parte simples: tentando escrever o primeiro loop que preencheS
valores 0..255. Eu mudei para python e escrevi rapidamente a versão python, apenas para ter algo para testar. Em seguida, simplifiquei o código python em pseudo código / pseudo assembly. Então eu estava tentando escrever pequenos pedaços. Decidi que seria mais fácil ler do stdin, então comecei com algo pequeno que leria um byte e adicionei a leitura de senha e a inicialização de chaves. Descobrir o que registrar para pegar levou algum tempo.Embora a adição do loop de / encryption seja fácil, primeiro obtive a decodificação de byte único e adicionei o loop inteiro posteriormente.
O último passo foi livrar-me dos adicionais
nops
que eu deixei entre as instruções ao escrevê-lo (ofc que também exigia a correção de saltos).Você pode ver uma pequena galeria que tentei fazer enquanto progredia aqui .
Dissecação
O programa depende de alguns valores iniciais após a inicialização (consulte os recursos abaixo).
preencher Estado (em 0x200)
ler comprimento, ler senha, armazenar senha no ds: 0x300
inicialize o estado com uma chave (
BP
é usada para atravessar a chave,SI
é usada para atravessar o estado)gerar valor pseudo-aleatório (em
DL
,DH
é 0 thx a xor em 0x140)SI
- ints não tocará neleBX
)DX
)PS: Isso provavelmente pode ser ainda mais curto, mas isso levou quatro noites, por isso não tenho certeza se eu quero passar outro ...
Ferramentas e recursos
fonte
C (gcc) ,
193 188 182 178 178 171172 bytesExperimente online!
Editar: agora funciona com chaves maiores que 127 bytes.
Edit2: Adicionado testcase com chave de 129 bytes ao link TIO.
Versão ligeiramente menos golfe
fonte
Conjunto de instruções da CPU x86, 133 bytes
A7D-9F8 = 85h = 133 bytes, mas não sei se o cálculo está correto porque o número precedente de bytes da mesma função resulta em 130 bytes ... O primeiro argumento da função que eu nomeio "cript" é a string, o segundo argumento é o comprimento da string (primeiro byte + comprimento da chave + comprimento da mensagem). Abaixo, há o arquivo de linguagem assembly para obter essas rotinas de criptografia:
abaixo do arquivo C para verificar os resultados:
os resultados:
fonte
JavaScript (ES6), 262 bytes
Eu considerei usar apenas funções encadeadas, mas optei por golfificar o algoritmo fornecido aqui: https://gist.github.com/farhadi/2185197 .
Menos Golfe
Mostrar snippet de código
fonte
Python 2 , 203 bytes
Experimente online!
f
é um gerador (iterável) de strings.Ungolfed:
fonte
Ruby, 234 bytes
Não testado.
fonte
C, 181 bytes
graças ao ceilingcat por alguns bytes a menos:
f (a, n) em "a" haveria a matriz de caracteres 1Byte len + key + message; em n existe o tamanho de toda a matriz de "a" sem contar o último '\ 0'. o código para teste e resultado seria o usado para a função de montagem.
fonte
APL (NARS), 329 caracteres, 658 bytes
como sempre, a verificação de erro seria exigida para outra pessoa ... Isso parece estar correto na entrada e na saída, teste:
Sim, tudo pode ser reduzido ... mas, por exemplo, tornar mais pequena a função xor pode significar torná-la menos geral ...
fonte
Ferrugem 348
Isso é terrivelmente grande, espero que talvez alguém possa fornecer algumas sugestões.
ungolfed: no parque infantil play.rust-lang.org
fonte
k
vez dekey
e emm
vez demsg
e emfoo&255
vez de(foo)%256