Decifrar um texto cifrado de Vigenère


28

A cifra de Vigenère era uma cifra polialfabética simples que basicamente aplicava uma das várias cifras de César, de acordo com uma chave. Basicamente, as letras na chave indicam qual alfabeto mudou para usar. Para esse fim, havia uma ferramenta simples, chamada praça Vigenère:

insira a descrição da imagem aqui

Aqui cada linha é um alfabeto separado, começando com a letra correspondente da chave. As colunas são usadas para determinar a letra cifrada. A descriptografia funciona da mesma maneira, apenas vice-versa.

Suponha que desejemos criptografar a string CODEGOLF. Também precisamos de uma chave. Nesse caso, a chave deve ser FOOBAR. Quando a chave é mais curta que o texto simples, nós a estendemos por repetição; portanto, a chave real que usamos é FOOBARFO. Agora, procuramos a primeira letra da chave, que é Fencontrar o alfabeto. Começa, talvez sem surpresa, com F. Agora encontramos a coluna com a primeira letra do texto simples e a letra resultante é H. Para a segunda letra, temos Ocomo letra-chave e letra de texto sem formatação, resultando em C. Continuando assim, finalmente chegamos HCRFGFQT.

Tarefa

Sua tarefa agora é decifrar as mensagens, com uma chave. No entanto, como superamos o século XVI e temos computadores, devemos pelo menos suportar um alfabeto um pouco maior:

abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789

A construção da praça Vigenère ainda é praticamente a mesma e a cifra ainda funciona da mesma maneira. É um pouco ... difícil de dar aqui na íntegra.

Entrada

A entrada é fornecida na entrada padrão como duas linhas de texto separadas, cada uma terminada por uma quebra de linha. A primeira linha contém a chave enquanto a segunda contém o texto cifrado.

Saída

Uma única linha, contendo a mensagem decifrada.

Condição vencedora

Como a criptografia às vezes é considerada uma arma, o código deve ser curto para facilitar o contrabando fácil. Quanto menor, melhor, pois reduz a probabilidade de descoberta.

Entrada de amostra 1

Key
miQ2eEO

Saída de amostra 1

Message

Entrada de amostra 2

ThisIsAKey
CoqKuGRUw29BiDTQmOpJFpBzlMMLiPb8alGruFbu

Saída de amostra 2

ThisWorksEquallyWellWithNumbers123894576

Uma semana se passou. A solução mais curta atualmente foi aceita. Para os interessados, em nosso concurso, tivemos os seguintes envios e comprimentos:

130 - Python
146 - Haskell
195 - C
197 - C
267 - VB.NET

E nossas próprias soluções que não foram classificadas com as outras:

108 - Ruby
139 - PowerShell


Parece que isso pode ser útil para imprimir o quadrado de Vigenère.
Erik the Outgolfer

Respostas:


10

Golfscript - 48 caracteres

n%~.,@*\{\(123,97>91,65>+58,48>+:|?@|?\-|=}%\0<+

Não há truques neste!


+1 fui para a cama pensando que deve haver uma maneira de obter esse baixo para ~ 50, e agora vejo que é possível, mas eu provavelmente não teria conseguido isso em breve
gnibbler

8

Arquivo .COM de 16 bits do MS-DOS - 87 bytes

Binário codificado em Base64 ( seguindo este link para um decodificador )

v1cBi8/oQACJ/ovv6DkAi9msitAqF3MDgMI+gMJhgPp6dguA6jqA+lp2A4DqK80hO/d0IkM563TW69YsYXMIBCB9AgQrBBqqtAHNITwNdev+xLIKzSHD

Normalmente você escreve um código-fonte curto para jogar golfe. Embora provavelmente não seja impossível, de alguma forma duvido disso.
JoeyFev

@ Joey: O que, você nunca entregou instruções de código de máquina codificadas à mão! O que eles ensinam aos jovens hoje em dia! ;-)
Skizz 14/02

Skizz: eu fiz. Porém, não na Base64;) (tivemos uma aula, há alguns anos, em que tivemos que escrever programas para um Siemens 80C167 em assembler - e nos exames também montá-los em código de máquina. Pensei em descobrir esse conhecimento para o Assembler Quine task, mas não tínhamos instalações de saída [pelo menos, elas variavam]).
Joey

@ Joey: O Base64 é apenas uma conveniência para os outros usuários deste site, é fácil decodificar e salvar como um arquivo binário (o link na resposta tem essa opção).
Skizz

Aah, desculpe. Eu pensei que você teria dado o comprimento da Base64. Bem, Chris uma vez incluiu caracteres arbitrários em uma solução e apenas deu um hexdump além de sua resposta. Fiz semelhante na previsão do tempo.
Joey

8

APL (45)

∆[⍙⍳⍨¨⌽∘∆¨(⍴⍙←⍞)⍴1-⍨⍞⍳⍨∆←⎕D,⍨⎕A,⍨⎕UCS 96+⍳26]

Explicação:

  • ∆←⎕D,⍨⎕A,⍨⎕UCS 96+⍳26: gera o alfabeto (números ( ⎕D) seguem letras ( ⎕A) seguem letras minúsculas ( ⎕UCS 96+⍳26, os valores unicode de 97 a 122).

  • 1-⍨⍞⍳⍨∆: leia uma linha (a tecla), encontre a posição de cada caractere no alfabeto e subtraia uma (as matrizes são baseadas em uma por padrão, portanto, mudar esses valores diretamente mudaria o alfabeto muito longe).

  • (⍴⍙←⍞)⍴: leia outra linha (a mensagem) e repita os índices da tecla para que ela tenha o tamanho da mensagem.
  • ⌽∘∆¨: gire o alfabeto pelos índices pertencentes à tecla
  • ⍙⍳⍨¨: procure cada caractere na mensagem no alfabeto deslocado correspondente
  • ∆[... ]: procure os índices fornecidos no alfabeto normal, fornecendo os caracteres correspondentes.

6

Ruby - 132 127 122 109 100 caracteres

a,b=*$<
c=*?a..?z,*?A..?Z,*?0..?9
(b.size-1).times{|i|$><<c[c.index(b[i])-c.index(a[i%(a.size-1)])]}

Use em *$<vez de $<.to_ae inline o lambda para salvar mais alguns bytes. - Ventero 5 mins atrás
Joey

Obrigado @Joey, eu peguei aquele lambda para salvar os personagens e de alguma forma perdi que ele realmente custa mais.
Nemo157

5

Python - 122 caracteres

from string import*
L=letters+digits
R=raw_input
K,T=R(),R()
F=L.find
print"".join(L[F(i)-F(j)]for i,j in zip(T,K*len(T)))

5

J, 65 caracteres

v=:4 : 'a{~x(62|[:-/"1 a i.[,.#@[$])y[a=.a.{~62{.;97 65 48+/i.26'

Não atende completamente às especificações, pois é definido como um verbo em vez de receber informações, mas estou publicando de qualquer maneira com a intenção de mexer com elas posteriormente.

Uso:

   'miQ2eEO' v 'Key'
Message
   'CoqKuGRUw29BiDTQmOpJFpBzlMMLiPb8alGruFbu' v 'ThisIsAKey'
ThisWorksEquallyWellWithNumbers123894576

4

Perl, 95 caracteres

Perl 5.010, executado com perl -E:

%a=map{$_,$n++}@a=(a..z,A..Z,0..9);@k=<>=~/./g;
$_=<>;s/./$a[($a{$&}-$a{$k[$i++%@k]})%62]/ge;say

3

Python - 144 143 140 136 125 caracteres

Provavelmente não é o melhor, mas ei:

from string import*
l=letters+digits
r=l.find
q=raw_input
k=q()
print"".join(l[(r(j)-r(k[i%len(k)]))%62]for i,j in enumerate(q()))

Huh, eu estava prestes a postar algo assim. Você pode atribuir raw_input a uma variável, 3 ou mais caracteres.
Juan

3

Golfscript - 65 caracteres

Ainda precisa ser jogado mais. Por enquanto, T é o texto, K é a chave, L é a lista de letras

n%):T,\~*:K;''26,{97+}%+.{32^}%10,{48+}%++:L;T{L\?K(L\?\:K;-L\=}%

3

K, 81 61

k:0:0;,/$(m!+(`$'m)!+{(1_x),1#x}\m:,/.Q`a`A`n)[(#v)#k]?'v:0:0

.

k)k:0:0;,/$(m!+(`$'m)!+{(1_x),1#x}\m:,/.Q`a`A`n)[(#v)#k]?'v:0:0
ThisIsAKey
CoqKuGRUw29BiDTQmOpJFpBzlMMLiPb8alGruFbu
"ThisWorksEquallyWellWithNumbers123894576"

2

Perl, 115 caracteres

$a=join'',@A=(a..z,A..Z,0..9);$_=<>;chop;@K=split//;$_=<>;s/./$A[(index($a,$&)-index($a,$K[$-[0]%@K]))%@A]/ge;print

2

Golfscript - 92 caracteres

n%~\.,:l;{0\{1$+\)\}%\;}:&;26'a'*&26'A'*&+10'0'*&+\@.,,{.l%3$=4$?\2$=4$?\- 62%3$\>1<}%\;\;\;

Provavelmente muito mais tempo do que precisa. Ainda estou tentando entender GS.

Heres a versão "ungolfed" e comentada

n%~\.,:l;
{0\{1$+\)\}%\;}:&; # This would be sortof an equivalent for range applied to strings
26'a'*&26'A'*&+10'0'*&+\@., # This mess generates the dictionary string,
# l = len(key)
# 0 dictionary (letters + digits)
# 1 key
# 2 text
{
    # 3 index
    .   #+1 Duplicate the index

    # Find the index of the key letter
    l%  #+1 Indice modulo key
    3$  #+2 Duplicate the key
    =   #+1 Get the key letter
    4$? #+1 Search the letters index

    # Find the index of the text letter
    \   #+1 Get the index
    2$  #+2 Get the text
    =   #+1 Get the text letter
    4$? #+0 Search the letters index

    # 3 key index
    # 4 letter index

    \-   #+1 get the index of the new letter

    62% #+1 wrap the index around the dictionary

    3$ #+2 Get the dictionary

    \> #+1 remove the first part of the dict around the target letter

    1< #+1 remove everythin after 
}%
\;
\;
\;

2

VBA, 288

Não supera a pontuação listada no VB.NET (mas estou chegando perto):

Sub h(k,s)
v=Chr(0)
Z=Split(StrConv("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789",64),v)
a=Split(StrConv(s,64),v):b=Split(StrConv(k,64),v)
For l=0 To Len(s)-1
j=l Mod Len(k)
g=0
For i=0 To 62:g=g+i*((Z(i)=b(j))-(Z(i)=a(l))):Next
x=x &Z(IIf(g<0,g+62,g))
Next
s=x
End Sub

Uso:

Sub test()
k = "ThisIsAKey"
s = "CoqKuGRUw29BiDTQmOpJFpBzlMMLiPb8alGruFbu"
h k, s
MsgBox s
End Sub

Obrigado a Joey pela dica!


g=g+IIf(Z(i)=c,i,0)-IIf(Z(i)=d,i,0)seria um candidato que eu pudesse identificar. Além de tentar descobrir se as terminações de linha LF são entendidas pelo VBA. Pelo menos um espaço também x=x & Z(g)poderia ser deixado de fora, eu acho.
Joey #

Outra maneira de escrever a linha: g=g+i*((Z(i)=d)-(Z(i)=c)) (porque Trueé -1 em VB). Pode ser que funcione.
Joey

Obrigado pelo feedback, @Joey. Vou procurar quaisquer outras melhorias e acrescentar que no.
Gaffi

2

C, 186

Um pouco tarde, mas ... (linhas quebradas para evitar a barra de rolagem horizontal).

char a[99],*s,*t;k,j;main(int m,char**v)
{for(;j<26;++j)a[j]=32|(a[j+26]=65+j),
a[52+j]=48+j;while(*v[2])
putchar(a[s=strchr(a,v[1][k++%strlen(v[1])])
,t=strchr(a,*v[2]++),s>t?t-s+62:t-s]);}

Linhas não quebradas

char a[99],*s,*t;k,j;main(int m,char**v){for(;j<26;++j)a[j]=32|(a[j+26]=65+j),a[52+j]=48+j;while(*v[2])putchar(a[s=strchr(a,v[1][k++%strlen(v[1])]),t=strchr(a,*v[2]++),s>t?t-s+62:t-s]);}

Uma discussão sobre o processo de golfe deste código pode ser encontrada aqui: http://prob-slv.blogspot.com/2013/04/code-golf.html


2

JavaScript 248

var v= 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
function d(k,c){var a,b,o,x
a=k.charAt(0)
x=v.indexOf(a)
b=v.substr(x)+v.substring(0,x)
o= v.charAt(b.indexOf(c.charAt(0)))
k=k.substr(1)+a
c=c.substr(1)
return (c)?o+d(k,c):o}

1

Haskell (169)

import List
main=do c<-y;t<-y;putStrLn$map((k!!).(`mod`62))$zipWith(-)(g t)(cycle$g c)
k=['a'..'z']++['A'..'Z']++['0'..'9']
y=getLine
f(Just x)=x
g=map$f.(`elemIndex`k)

1

J: 91 caracteres

[:{&{.&t({&t"0&(({.t=.1|.^:(i.62)a.{~(97+i.26),(65+i.26),48+i.10)&i.)"0@:$~#)|:@(i."1.,"0)]

Por exemplo:

    g=:[:{&{.&t({&t"0&(({.t=.1|.^:(i.62)a.{~(97+i.26),(65+i.26),48+i.10)&i.)"0@:$~#)|:@(i."1.,"0)]
    'ThisIsAKey' g 'CoqKuGRUw29BiDTQmOpJFpBzlMMLiPb8alGruFbu'
ThisWorksEquallyWellWithNumbers123894576
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.