Decifrare un testo cifrato Vigenère


28

Il codice Vigenère era un semplice codice polialfabetico che sostanzialmente applicava uno dei numerosi numeri di Cesare, secondo una chiave. Bascialmente le lettere nella chiave indicano quale alfabeto spostato usare. A tal fine c'era un semplice strumento, chiamato piazza Vigenère:

inserisci qui la descrizione dell'immagine

Qui ogni riga è un alfabeto separato, che inizia con la lettera corrispondente della chiave. Le colonne vengono quindi utilizzate per determinare la lettera cifrata. La decrittazione funziona più o meno allo stesso modo, solo viceversa.

Supponiamo di voler crittografare la stringa CODEGOLF. Abbiamo anche bisogno di una chiave. In questo caso la chiave deve essere FOOBAR. Quando la chiave è più corta del testo in chiaro, la estendiamo ripetutamente, quindi la chiave effettiva che usiamo è FOOBARFO. Ora cerchiamo la prima lettera della chiave, che è quella Fdi trovare l'alfabeto. Comincia, forse non sorprende, con F. Ora troviamo la colonna con la prima lettera del testo in chiaro e la lettera risultante è H. Per la seconda lettera abbiamo Ocome lettera chiave e la lettera di testo semplice, risultante C. Continuando in questo modo finalmente otteniamo HCRFGFQT.

Compito

Il tuo compito ora è decifrare i messaggi, dati una chiave. Tuttavia, poiché abbiamo superato il XVI secolo e disponiamo di computer, dovremmo almeno supportare un alfabeto leggermente più grande:

abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789

La costruzione della piazza Vigenère è ancora più o meno la stessa e la cifra funziona ancora allo stesso modo. È solo un po '... ingombrante dare qui per intero.

Ingresso

L'input viene fornito sull'input standard come due righe di testo separate, ciascuna terminata da un'interruzione di riga. La prima riga contiene la chiave mentre la seconda contiene il testo cifrato.

Produzione

Una riga singola, contenente il messaggio decifrato.

Condizioni vincenti

Poiché la crittografia viene talvolta considerata un'arma, il codice dovrebbe essere breve per facilitare il contrabbando. Più corto è il migliore, in quanto riduce la probabilità di scoperta.

Esempio di input 1

Key
miQ2eEO

Uscita campione 1

Message

Esempio di input 2

ThisIsAKey
CoqKuGRUw29BiDTQmOpJFpBzlMMLiPb8alGruFbu

Uscita campione 2

ThisWorksEquallyWellWithNumbers123894576

È passata una settimana La soluzione attualmente più breve è stata accettata. Per chi fosse interessato, nel nostro concorso abbiamo avuto le seguenti osservazioni e lunghezze:

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

E le nostre soluzioni che non sono state classificate con le altre:

108 - Ruby
139 - PowerShell


Sembra che ciò possa essere utile per stampare la piazza Vigenère.
Erik the Outgolfer,

Risposte:


10

Golfscript - 48 caratteri

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

Nessun trucco in questo!


+1 Sono andato a letto pensando che ci fosse un modo per arrivare a ~ 50, ora vedo che è possibile ma probabilmente non ci sarei riuscito presto
gnibbler

8

File .COM 16 bit MS-DOS - 87 byte

Base64 codificato binario ( seguendo questo collegamento per un decodificatore )

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

Di solito scrivi tu stesso un codice sorgente breve per giocare a golf. Anche se probabilmente non è impossibile, in qualche modo ne dubito.
Joey,

@Joey: Cosa, non hai mai codificato manualmente le istruzioni del codice macchina! Cosa insegnano ai giovani in questi giorni! ;-)
Skizz

Skizz: l'ho fatto. Non in Base64, però;) (qualche anno fa avevamo una lezione in cui dovevamo scrivere programmi per un Siemens 80C167 in assemblatore - e negli esami anche assemblarli in codice macchina. Ho pensato di scavare quella conoscenza per l'Assemblatore Un buon compito, ma non avevamo strutture di output [almeno, variavano]).
Joey,

@Joey: Base64 è solo una comodità per gli altri utenti su questo sito, è facile da decodificare e salvare come file binario (il collegamento nella risposta ha questa opzione).
Skizz,

Aah, scusa. Pensavo avresti dato la lunghezza della Base64. Bene, Chris una volta ha incluso personaggi arbitrari in una soluzione e ha appena dato un hexdump oltre alla sua risposta. Ho fatto simile nelle previsioni del tempo.
Joey,

8

APL (45)

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

Spiegazione:

  • ∆←⎕D,⍨⎕A,⍨⎕UCS 96+⍳26: genera l'alfabeto (numeri ( ⎕D) segui le lettere ( ⎕A) segui le lettere minuscole ( ⎕UCS 96+⍳26, i valori unicode da 97 a 122).

  • 1-⍨⍞⍳⍨∆: leggi una riga (la chiave), trova la posizione di ciascun carattere nell'alfabeto e sottragga uno (le matrici sono basate su una di default, quindi spostando direttamente quei valori si sposterebbe l'alfabeto troppo lontano).

  • (⍴⍙←⍞)⍴: leggi un'altra riga (il messaggio) e ripeti gli indici della chiave in modo che abbia la lunghezza del messaggio.
  • ⌽∘∆¨: ruota l'alfabeto in base agli indici appartenenti alla chiave
  • ⍙⍳⍨¨: cerca ogni carattere nel messaggio nell'alfabeto spostato corrispondente
  • ∆[... ]: cerca gli indici indicati nell'alfabeto normale, dando i caratteri corrispondenti.

6

Rubino - 132 127 122 109 100 caratteri

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

Utilizzare *$<invece $<.to_ae inline lambda per salvare altri pochi byte. - Ventero 5 minuti fa
Joey

Grazie @Joey, ho tirato fuori quel lambda per salvare i personaggi e in qualche modo mi è mancato il costo in realtà.
Nemo157,

5

Python - 122 caratteri

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 caratteri

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

Non soddisfa completamente le specifiche poiché è definito come un verbo piuttosto che prendere input, ma lo sto pubblicando comunque con l'intenzione di giocherellare con esso in un secondo momento.

Uso:

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

4

Perl, 95 caratteri

Perl 5.010, gestito con 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 caratteri

Probabilmente non il migliore, ma hey:

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, stavo per pubblicare qualcosa del genere. È possibile assegnare raw_input a una variabile, circa 3 caratteri.
Juan,

3

Golfscript - 65 caratteri

Deve ancora essere golfato di più. Per ora, T è il testo, K è la chiave, L è l'elenco di lettere

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 caratteri

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

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

Probabilmente molto più a lungo di quanto debba essere. Sto ancora cercando di farmi girare la testa per GS.

Ecco la versione "ungolfed" e commentata

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

Non batte del tutto il punteggio VB.NET elencato (ma mi sto avvicinando):

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

Grazie a Joey per l'informazione!


g=g+IIf(Z(i)=c,i,0)-IIf(Z(i)=d,i,0)sarebbe un candidato che posso individuare. Oltre a provare se le terminazioni di linea LF sono comprese da VBA. Almeno uno spazio x=x & Z(g)potrebbe anche essere lasciato fuori, immagino.
Joey,

Un altro modo di scrivere la riga: g=g+i*((Z(i)=d)-(Z(i)=c)) (perché Trueè -1 in VB). Potrebbe essere che funzioni.
Joey,

Grazie per il feedback, @Joey. Cercherò altri miglioramenti e lo aggiungerò.
Gaffi,

2

C, 186

Un po 'in ritardo ma ... (linee spezzate per evitare la barra di scorrimento orizzontale).

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

Linee non interrotte

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

Una discussione sul processo di golf questo codice è disponibile qui: 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 caratteri

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

Per esempio:

    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
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.