Vigenère cipher/Cryptanalysis: Difference between revisions

From Rosetta Code
Content added Content deleted
(Rename Perl 6 -> Raku, alphabetize, minor clean-up)
m (→‎{{header|Wren}}: Minor tidy)
 
(13 intermediate revisions by 10 users not shown)
Line 1: Line 1:
{{task|Encryption}}
{{task|Encryption}}[[Category:Encryption]]
Given some text you suspect has been encrypted with a Vigenère cipher, extract the key and plaintext. There are several methods for doing this. See [[wp:Vigenère_cipher#Cryptanalysis|the Wikipedia entry]] for more information. Use the following encrypted text:
[[Category:String manipulation]]
<pre>
{{omit from|GUISS|would need to install an application that could do this}}
MOMUD EKAPV TQEFM OEVHP AJMII CDCTI FGYAG JSPXY ALUYM NSMYH
{{omit from|Openscad}}
VUXJE LEPXJ FXGCM JHKDZ RYICU HYPUS PGIGM OIYHF WHTCQ KMLRD
ITLXZ LJFVQ GHOLW CUHLO MDSOE KTALU VYLNZ RFGBX PHVGA LWQIS
FGRPH JOOFW GUBYI LAPLA LCAFA AMKLG CETDW VOELJ IKGJB XPHVG
ALWQC SNWBU BYHCU HKOCE XJEYK BQKVY KIIEH GRLGH XEOLW AWFOJ
ILOVV RHPKD WIHKN ATUHN VRYAQ DIVHX FHRZV QWMWV LGSHN NLVZS
JLAKI FHXUF XJLXM TBLQV RXXHR FZXGV LRAJI EXPRV OSMNP KEPDT
LPRWM JAZPK LQUZA ALGZX GVLKL GJTUI ITDSU REZXJ ERXZS HMPST
MTEOE PAPJH SMFNB YVQUZ AALGA YDNMP AQOWT UHDBV TSMUE UIMVH
QGVRW AEFSP EMPVE PKXZY WLKJA GWALT VYYOB YIXOK IHPDS EVLEV
RVSGB JOGYW FHKBL GLXYA MVKIS KIEHY IMAPX UOISK PVAGN MZHPW
TTZPV XFCCD TUHJH WLAPF YULTB UXJLN SIJVV YOVDJ SOLXG TGRVO
SFRII CTMKO JFCQF KTINQ BWVHG TENLH HOGCS PSFPV GJOKM SIFPR
ZPAAS ATPTZ FTPPD PORRF TAXZP KALQA WMIUD BWNCT LEFKO ZQDLX
BUXJL ASIMR PNMBF ZCYLV WAPVF QRHZV ZGZEF KBYIO OFXYE VOWGB
BXVCB XBAWG LQKCM ICRRX MACUO IKHQU AJEGL OIJHH XPVZW JEWBA
FWAML ZZRXJ EKAHV FASMU LVVUT TGK
</pre>


Letter frequencies for English can be found [[wp:Letter_frequency|here]].
;Task:
Implement a &nbsp; [[wp:Vigen%C3%A8re_cipher|Vigenère cypher]], &nbsp; both encryption and decryption.


Specifics for this task:
The program should handle keys and text of unequal length,
* Take only the ciphertext as input. You can assume it's all capitalized and has no punctuation, but it might have whitespace.
and should capitalize everything and discard non-alphabetic characters. <br>
* Assume the plaintext is written in English.
(If your program handles non-alphabetic characters in another way,
* Find and output the key.
make a note of it.)
* Use that key to decrypt and output the original plaintext. Maintaining the whitespace from the ciphertext is optional.
* The algorithm doesn't have to be perfect (which may not be possible) but it should work when given enough ciphertext. The example above is fairly long, and should be plenty for any algorithm.


=={{header|11l}}==
{{trans|Python}}


<syntaxhighlight lang="11l">-V ascii_uppercase = Array(‘A’..‘Z’)
;Related tasks:
* &nbsp; [[Caesar cipher]]
* &nbsp; [[Rot-13]]
* &nbsp; [[Substitution Cipher]]
<br><br>


F vigenere_decrypt(target_freqs, input)
=={{header|Ada}}==
V nchars = :ascii_uppercase.len
V ordA = ‘A’.code
V sorted_targets = sorted(target_freqs)


F frequency(input)
<lang Ada>WITH Ada.Text_IO, Ada.Characters.Handling;
V result = :ascii_uppercase.map(c -> (c, 0.0))
USE Ada.Text_IO, Ada.Characters.Handling;
L(c) input
result[c - @ordA][1]++
R result


F correlation(input)
PROCEDURE Main IS
SUBTYPE Alpha IS Character RANGE 'A' .. 'Z';
V result = 0.0
V freq = sorted(@frequency(input), key' a -> a[1])
TYPE Ring IS MOD (Alpha'Range_length);
TYPE Seq IS ARRAY (Integer RANGE <>) OF Ring;
FUNCTION "+" (S, Key : Seq) RETURN Seq IS
R : Seq (S'Range);
BEGIN
FOR I IN R'Range LOOP
R (I) := S (I) + Key (Key'First + (I - R'First) MOD Key'Length);
END LOOP;
RETURN R;
END "+";
FUNCTION "-" (S : Seq) RETURN Seq IS
R : Seq (S'Range);
BEGIN
FOR I IN R'Range LOOP
R (I) := - S (I);
END LOOP;
RETURN R;
END "-";
FUNCTION To_Seq (S : String) RETURN Seq IS
R : Seq (S'Range);
I : Integer := R'First;
BEGIN
FOR C OF To_Upper (S) LOOP
IF C IN Alpha THEN
R (I) := Ring'Mod (Alpha'Pos (C) - Alpha'Pos (Alpha'First));
I := I + 1;
END IF;
END LOOP;
RETURN R (R'First .. I - 1);
END To_Seq;
FUNCTION To_String (S : Seq ) RETURN String IS
R : String (S'Range);
BEGIN
FOR I IN R'Range LOOP
R (I) := Alpha'Val ( Integer (S (I)) + Alpha'Pos (Alpha'First));
END LOOP;
RETURN R;
END To_String;
Input : Seq := To_Seq (Get_Line);
Key : Seq := To_Seq (Get_Line);
Crypt : Seq := Input + Key;
BEGIN
Put_Line ("Encrypted: " & To_String (Crypt));
Put_Line ("Decrypted: " & To_String (Crypt + (-Key)));
END Main;


L(f) freq
</lang>
result += f[1] * @sorted_targets[L.index]
R result


V cleaned = input.uppercase().filter(c -> c.is_uppercase()).map(c -> c.code)
{{out}}
V best_len = 0
<pre>Beware the Jabberwock, my son! The jaws that bite, the claws that catch!
V best_corr = -100.0
VIGENERECIPHER
Encrypted: WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY
Decrypted: BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH</pre>


L(i) 2 .< cleaned.len I/ 20
=={{header|ALGOL 68}}==
V pieces = [[Int]()] * i
{{trans|C++}} Note: This specimen retains the original [[Vigenère_Cipher#C++|C++]] coding style.
L(c) cleaned
{{works with|ALGOL 68|Revision 1 - no extensions to language used.}}
pieces[L.index % i].append(c)
{{works with|ALGOL 68G|Any - tested with release [http://sourceforge.net/projects/algol68/files/algol68g/algol68g-1.18.0/algol68g-1.18.0-9h.tiny.el5.centos.fc11.i386.rpm/download 1.18.0-9h.tiny].}}
V corr = -0.5 * i + sum(pieces.map(p -> @correlation(p)))
{{works with|ELLA ALGOL 68|Any (with appropriate job cards) - tested with release [http://sourceforge.net/projects/algol68/files/algol68toc/algol68toc-1.8.8d/algol68toc-1.8-8d.fc9.i386.rpm/download 1.8-8d].}}
<lang algol68>STRING key := "";


I corr > best_corr
PROC vigenere cipher = (REF STRING key)VOID:
best_len = i
(
FOR i FROM LWB key TO UPB key DO
best_corr = corr
IF key[i] >= "A" AND key[i] <= "Z" THEN
key +:= key[i] FI;
IF key[i] >= "a" AND key[i] <= "z" THEN
key +:= REPR(ABS key[i] + ABS"A" - ABS"a") FI
OD
);


I best_len == 0
PROC encrypt = (STRING text)STRING:
R (‘Text is too short to analyze’, ‘’)
(
STRING out := "";


V pieces = [[Int]()] * best_len
INT j := LWB text;
L(c) cleaned
FOR i FROM LWB text TO UPB text DO
pieces[L.index % best_len].append(c)
CHAR c := text[i];


V freqs = pieces.map(p -> @frequency(p))
IF c >= "a" AND c <= "z" THEN
c := REPR(ABS c + (ABS"A" - ABS"a")) FI;
IF c >= "A" AND c <= "Z" THEN
out +:= REPR((ABS c + ABS key[j] - 2*ABS"A") MOD 26 + ABS"A");
j := j MOD UPB key + 1
FI
OD;


V key = ‘’
out
L(fr_) freqs
);
V fr = sorted(fr_, key' a -> a[1], reverse' 1B)
V m = 0
V max_corr = 0.0
L(j) 0 .< nchars
V corr = 0.0
V c = ordA + j
L(frc) fr
V d = (frc[0].code - c + nchars) % nchars
corr += frc[1] * target_freqs[d]


I corr > max_corr
PROC decrypt = (STRING text)STRING:
m = j
(
max_corr = corr
STRING out;


key ‘’= Char(code' m + ordA)
INT j := LWB text;
FOR i FROM LWB text TO UPB text DO
CHAR c := text[i];


V r = (enumerate(cleaned).map((i, c) -> Char(code' (c - @key[i % @best_len].code + @nchars) % @nchars + @ordA)))
IF c >= "a" AND c <= "z" THEN
R (key, r.join(‘’))
c := REPR(ABS c + (ABS"A" - ABS"a")) FI;
IF c >= "A" AND c <= "Z" THEN
out +:= REPR((ABS c - ABS key[j] + 26) MOD 26 + ABS"A");
j := j MOD UPB key + 1
FI
OD;


V encoded = ‘
out
MOMUD EKAPV TQEFM OEVHP AJMII CDCTI FGYAG JSPXY ALUYM NSMYH
);
VUXJE LEPXJ FXGCM JHKDZ RYICU HYPUS PGIGM OIYHF WHTCQ KMLRD
ITLXZ LJFVQ GHOLW CUHLO MDSOE KTALU VYLNZ RFGBX PHVGA LWQIS
FGRPH JOOFW GUBYI LAPLA LCAFA AMKLG CETDW VOELJ IKGJB XPHVG
ALWQC SNWBU BYHCU HKOCE XJEYK BQKVY KIIEH GRLGH XEOLW AWFOJ
ILOVV RHPKD WIHKN ATUHN VRYAQ DIVHX FHRZV QWMWV LGSHN NLVZS
JLAKI FHXUF XJLXM TBLQV RXXHR FZXGV LRAJI EXPRV OSMNP KEPDT
LPRWM JAZPK LQUZA ALGZX GVLKL GJTUI ITDSU REZXJ ERXZS HMPST
MTEOE PAPJH SMFNB YVQUZ AALGA YDNMP AQOWT UHDBV TSMUE UIMVH
QGVRW AEFSP EMPVE PKXZY WLKJA GWALT VYYOB YIXOK IHPDS EVLEV
RVSGB JOGYW FHKBL GLXYA MVKIS KIEHY IMAPX UOISK PVAGN MZHPW
TTZPV XFCCD TUHJH WLAPF YULTB UXJLN SIJVV YOVDJ SOLXG TGRVO
SFRII CTMKO JFCQF KTINQ BWVHG TENLH HOGCS PSFPV GJOKM SIFPR
ZPAAS ATPTZ FTPPD PORRF TAXZP KALQA WMIUD BWNCT LEFKO ZQDLX
BUXJL ASIMR PNMBF ZCYLV WAPVF QRHZV ZGZEF KBYIO OFXYE VOWGB
BXVCB XBAWG LQKCM ICRRX MACUO IKHQU AJEGL OIJHH XPVZW JEWBA
FWAML ZZRXJ EKAHV FASMU LVVUT TGK’


V english_frequences = [
main:
0.08167, 0.01492, 0.02782, 0.04253, 0.12702, 0.02228, 0.02015,
(
0.06094, 0.06966, 0.00153, 0.00772, 0.04025, 0.02406, 0.06749,
vigenere cipher(key:="VIGENERECIPHER");
0.07507, 0.01929, 0.00095, 0.05987, 0.06327, 0.09056, 0.02758,
0.00978, 0.02360, 0.00150, 0.01974, 0.00074]


V (key, decoded) = vigenere_decrypt(english_frequences, encoded)
STRING original := "Beware the Jabberwock, my son! The jaws that bite, the claws that catch!";
print(‘Key: ’key)
STRING encrypted := encrypt(original);
print("\nText: "decoded)</syntaxhighlight>
STRING decrypted := decrypt(encrypted);


print((original, new line));
print(("Encrypted: ", encrypted, new line));
print(("Decrypted: ", decrypted, new line))
)</lang>
{{out}}
{{out}}
<pre>
<pre>
Key: THECHESHIRECAT
Beware the Jabberwock, my son! The jaws that bite, the claws that catch!

Encrypted: WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY
Text: THISWASTHEPOEMTHATALICEREADJABBERWOCKYTWASBRILLIGANDTHESLITHYTOVESDIDGYREANDGIMBLEINTHEWABEALLMIMSYWERETHEBOROGOVE...
Decrypted: BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH
</pre>
</pre>


=={{header|Applesoft BASIC}}==
=={{header|Ada}}==
The program is not fully auto, but makes a small number of suggestions for the right key and plaintext.
Lines <code>340,350,430,440</code> could probably been put into some DEF FN, but it would probably have made it harder to read. The maximum length for a string in AppleSoft BASIC is 255 characters.
<syntaxhighlight lang="ada">with Ada.Text_IO;
I have not used the DEF FN MOD(A) function in line <code>450</code> on purpose, as I still would have had to correct for a possible negative value.
<lang Applesoft BASIC>
100 :
110 REM VIGENERE CIPHER
120 :
200 REM SET-UP
210 K$ = "LEMON": PRINT "KEY: "; K$
220 PT$ = "ATTACK AT DAWN": PRINT "PLAIN TEXT: ";PT$
230 DEF FN MOD(A) = A - INT (A / 26) * 26
300 REM ENCODING
310 K = 1
320 FOR I = 1 TO LEN (PT$)
330 IF ASC ( MID$ (PT$,I,1)) < 65
OR ASC ( MID$ (PT$,I,1)) > 90 THEN NEXT I
340 TV = ASC ( MID$ (PT$,I,1)) - 65
350 KV = ASC ( MID$ (K$,K,1)) - 65
360 CT$ = CT$ + CHR$ ( FN MOD(TV + KV) + 65)
370 K = K + 1: IF K > LEN (K$) THEN K = 1
380 NEXT I
390 PRINT "CIPHER TEXT: ";CT$
400 REM DECODING
410 K = 1
420 FOR I = 1 TO LEN (CT$)
430 TV = ASC ( MID$ (CT$,I,1)) - 65
440 KV = ASC ( MID$ (K$,K,1)) - 65
450 T = TV - KV: IF T < 0 THEN T = T + 26
460 DT$ = DT$ + CHR$ (T + 65)
470 K = K + 1: IF K > LEN (K$) THEN K = 1
480 NEXT I
490 PRINT "DECRYPTED TEXT: ";DT$ </lang>
{{out}}
KEY: LEMON
PLAIN TEXT: ATTACK AT DAWN
CIPHER TEXT: LXFOPVEFRNHR
DECRYPTED TEXT: ATTACKATDAWN


procedure Vignere_Cryptanalysis is
=={{header|AutoHotkey}}==
<lang AutoHotkey>Key = VIGENERECIPHER
Text= Beware the Jabberwock, my son! The jaws that bite, the claws that catch!


subtype Letter is Character range 'A' .. 'Z';
out := "Input =" text "`nkey =" key "`nCiphertext =" (c := VigenereCipher(Text, Key)) "`nDecrypted =" VigenereDecipher(c, key)
MsgBox % clipboard := out


function "+"(X, Y: Letter) return Letter is
VigenereCipher(Text, Key){
begin
StringUpper, Text, Text
return Character'Val( ( (Character'Pos(X)-Character'Pos('A'))
Text := RegExReplace(Text, "[^A-Z]")
+ (Character'Pos(Y)-Character'Pos('A')) ) mod 26
Loop Parse, Text
+ Character'Pos('A'));
{
end;
a := Asc(A_LoopField) - Asc("A")
b := Asc(SubStr(Key, 1+Mod(A_Index-1, StrLen(Key)), 1)) - Asc("A")
out .= Chr(Mod(a+b,26)+Asc("A"))
}
return out
}


function "-"(X, Y: Letter) return Letter is
VigenereDecipher(Text, key){
begin
Loop Parse, key
return Character'Val( ( (Character'Pos(X)-Character'Pos('A'))
decoderKey .= Chr(26-(Asc(A_LoopField)-65)+65)
- (Character'Pos(Y)-Character'Pos('A')) ) mod 26
return VigenereCipher(Text, decoderKey)
+ Character'Pos('A'));
}</lang>
end;
{{out}}
<pre>Input =Beware the Jabberwock, my son! The jaws that bite, the claws that catch!
key =VIGENERECIPHER
Ciphertext =WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY
Decrypted =BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH</pre>


type Frequency_Array is array (Letter) of Float;
=={{header|BBC BASIC}}==
<lang bbcbasic> key$ = "LEMON"
plaintext$ = "ATTACK AT DAWN"
ciphertext$ = FNencrypt(plaintext$, key$)
PRINT "Key = """ key$ """"
PRINT "Plaintext = """ plaintext$ """"
PRINT "Ciphertext = """ ciphertext$ """"
PRINT "Decrypted = """ FNdecrypt(ciphertext$, key$) """"
END
DEF FNencrypt(plain$, key$)
LOCAL i%, k%, n%, o$
plain$ = FNupper(plain$)
key$ = FNupper(key$)
FOR i% = 1 TO LEN(plain$)
n% = ASCMID$(plain$, i%)
IF n% >= 65 IF n% <= 90 THEN
o$ += CHR$(65 + (n% + ASCMID$(key$, k%+1)) MOD 26)
k% = (k% + 1) MOD LEN(key$)
ENDIF
NEXT
= o$
DEF FNdecrypt(cipher$, key$)
LOCAL i%, k%, n%, o$
cipher$ = FNupper(cipher$)
key$ = FNupper(key$)
FOR i% = 1 TO LEN(cipher$)
n% = ASCMID$(cipher$, i%)
o$ += CHR$(65 + (n% + 26 - ASCMID$(key$, k%+1)) MOD 26)
k% = (k% + 1) MOD LEN(key$)
NEXT
= o$
DEF FNupper(A$)
LOCAL A%,C%
FOR A% = 1 TO LEN(A$)
C% = ASCMID$(A$,A%)
IF C% >= 97 IF C% <= 122 MID$(A$,A%,1) = CHR$(C%-32)
NEXT
= A$</lang>
{{out}}
<pre>
Key = "LEMON"
Plaintext = "ATTACK AT DAWN"
Ciphertext = "LXFOPVEFRNHR"
Decrypted = "ATTACKATDAWN"
</pre>


English: Frequency_Array :=
=={{header|Befunge}}==
( 0.08167, 0.01492, 0.02782, 0.04253, 0.12702, 0.02228, 0.02015,
The text to encrypt is read from stdin. The key is the string literal at the start of the program.
0.06094, 0.06966, 0.00153, 0.00772, 0.04025, 0.02406, 0.06749,
0.07507, 0.01929, 0.00095, 0.05987, 0.06327, 0.09056, 0.02758,
0.00978, 0.02360, 0.00150, 0.01974, 0.00074 );


function Get_Frequency(S: String) return Frequency_Array is
<lang befunge>"VIGENERECIPHER">>>>1\:!v>"A"-\:00p0v
Result: Frequency_Array := (others => 0.0);
>>!#:0#-0#1g#,*#<+:v:-1$_^#!:\+1g00p<
Offset: Float := 1.0/Float(S'Length);
\"{"\v>9+2*%"A"+^>$>~>:48*\`#@_::"`"`
begin
*84*`<^4+"4"+g0\_^#!+`*55\`\0::-"A"-*</lang>
for I in S'Range loop
if S(I) in Letter then
Result(S(I)) := Result(S(I)) + Offset;
end if;
end loop;
return Result;
end Get_Frequency;


function Remove_Whitespace(S: String) return String is
{{out}}
begin
<pre>Beware the Jabberwock, my son! The jaws that bite, the claws that catch!
if S="" then
WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY</pre>
return "";
elsif S(S'First) in Letter then
return S(S'First) & Remove_Whitespace(S(S'First+1 .. S'Last));
else
return Remove_Whitespace(S(S'First+1 .. S'Last));
end if;
end Remove_Whitespace;


function Distance(A, B: Frequency_Array;
The decrypter is essentially identical, except for a change of sign on the last line.
Offset: Character := 'A') return Float is
Result: Float := 0.0;
Diff: Float;
begin
for C in A'Range loop
Diff := A(C+Offset) - B(C);
Result := Result + (Diff * Diff);
end loop;
return Result;
end Distance;


function Find_Key(Cryptogram: String; Key_Length: Positive) return String is
<lang befunge>"VIGENERECIPHER">>>>1\:!v>"A"-\:00p0v
>>!#:0#-0#1g#,*#<+:v:-1$_^#!:\+1g00p<
\"{"\v>9+2*%"A"+^>$>~>:48*\`#@_::"`"`
*84*`<^4+"4"-g0\_^#!+`*55\`\0::-"A"-*</lang>


function Find_Caesar_Key(S: String) return Letter is
{{out}}
Frequency: Frequency_Array := Get_Frequency(S);
<pre>WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY
Candidate: Letter := 'A'; -- a fake candidate
BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH</pre>
Candidate_Dist : Float := Distance(Frequency, English, 'A');
New_Dist: Float;


begin
=={{header|C}}==
This program skips non-alphabetical characters, preserves case, and when run with the <code>-d</code> command line flag, decrypts the message rather than encrypting.
<lang C>#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <ctype.h>
#include <getopt.h>


for L in Letter range 'B' .. 'Z' loop
#define NUMLETTERS 26
New_Dist := Distance(Frequency, English, L);
#define BUFSIZE 4096
if New_Dist <= Candidate_Dist then
Candidate_Dist := New_Dist;
Candidate := L;
end if;
end loop;
return Candidate;
end Find_Caesar_Key;


function Get_Slide(S: String; Step: Positive) return String is
char *get_input(void);
begin
if S'Length= 0 then
return "";
else
return S(S'First) & Get_Slide(S(S'First+Step .. S'Last), Step);
end if;
end Get_Slide;


Key: String(1 .. Key_Length);
int main(int argc, char *argv[])
{
char const usage[] = "Usage: vinigere [-d] key";
char sign = 1;
char const plainmsg[] = "Plain text: ";
char const cryptmsg[] = "Cipher text: ";
bool encrypt = true;
int opt;


S: String renames Cryptogram;
while ((opt = getopt(argc, argv, "d")) != -1) {
switch (opt) {
case 'd':
sign = -1;
encrypt = false;
break;
default:
fprintf(stderr, "Unrecogized command line argument:'-%i'\n", opt);
fprintf(stderr, "\n%s\n", usage);
return 1;
}
}


begin
if (argc - optind != 1) {
for I in Key'Range loop
fprintf(stderr, "%s requires one argument and one only\n", argv[0]);
Key(I) := Find_Caesar_Key(Get_Slide(S(S'First+I-1 .. S'Last),
fprintf(stderr, "\n%s\n", usage);
Key_Length));
return 1;
}
end loop;
return Key;
end Find_Key;


function Key_Char(Key: String; Index: Positive) return Letter is
begin
if Index > Key'Last then
return Key_Char(Key, Index-Key'Last);
else
return Key(Index);
end if;
end Key_Char;


Ciphertext: String := Remove_Whitespace(
// Convert argument into array of shifts
"MOMUD EKAPV TQEFM OEVHP AJMII CDCTI FGYAG JSPXY ALUYM NSMYH" &
char const *const restrict key = argv[optind];
"VUXJE LEPXJ FXGCM JHKDZ RYICU HYPUS PGIGM OIYHF WHTCQ KMLRD" &
size_t const keylen = strlen(key);
"ITLXZ LJFVQ GHOLW CUHLO MDSOE KTALU VYLNZ RFGBX PHVGA LWQIS" &
char shifts[keylen];
"FGRPH JOOFW GUBYI LAPLA LCAFA AMKLG CETDW VOELJ IKGJB XPHVG" &
"ALWQC SNWBU BYHCU HKOCE XJEYK BQKVY KIIEH GRLGH XEOLW AWFOJ" &
"ILOVV RHPKD WIHKN ATUHN VRYAQ DIVHX FHRZV QWMWV LGSHN NLVZS" &
"JLAKI FHXUF XJLXM TBLQV RXXHR FZXGV LRAJI EXPRV OSMNP KEPDT" &
"LPRWM JAZPK LQUZA ALGZX GVLKL GJTUI ITDSU REZXJ ERXZS HMPST" &
"MTEOE PAPJH SMFNB YVQUZ AALGA YDNMP AQOWT UHDBV TSMUE UIMVH" &
"QGVRW AEFSP EMPVE PKXZY WLKJA GWALT VYYOB YIXOK IHPDS EVLEV" &
"RVSGB JOGYW FHKBL GLXYA MVKIS KIEHY IMAPX UOISK PVAGN MZHPW" &
"TTZPV XFCCD TUHJH WLAPF YULTB UXJLN SIJVV YOVDJ SOLXG TGRVO" &
"SFRII CTMKO JFCQF KTINQ BWVHG TENLH HOGCS PSFPV GJOKM SIFPR" &
"ZPAAS ATPTZ FTPPD PORRF TAXZP KALQA WMIUD BWNCT LEFKO ZQDLX" &
"BUXJL ASIMR PNMBF ZCYLV WAPVF QRHZV ZGZEF KBYIO OFXYE VOWGB" &
"BXVCB XBAWG LQKCM ICRRX MACUO IKHQU AJEGL OIJHH XPVZW JEWBA" &
"FWAML ZZRXJ EKAHV FASMU LVVUT TGK");


Best_Plain: String := Ciphertext;
char const *restrict plaintext = NULL;
Best_Dist: Float := Distance(English, Get_Frequency(Best_Plain));
for (size_t i = 0; i < keylen; i++) {
Best_Key: String := Ciphertext;
if (!(isalpha(key[i]))) {
Best_Key_L: Natural := 0;
fprintf(stderr, "Invalid key\n");
return 2;
}
char const charcase = (isupper(key[i])) ? 'A' : 'a';
// If decrypting, shifts will be negative.
// This line would turn "bacon" into {1, 0, 2, 14, 13}
shifts[i] = (key[i] - charcase) * sign;
}


begin -- Vignere_Cryptanalysis
do {
for I in 1 .. Ciphertext'Length/10 loop
fflush(stdout);
declare
// Print "Plain text: " if encrypting and "Cipher text: " if
Key: String(1 .. I) := Find_Key(Ciphertext, I);
// decrypting
Plaintext: String(Ciphertext'Range);
printf("%s", (encrypt) ? plainmsg : cryptmsg);
begin
plaintext = get_input();
if (plaintext == NULL) {
for I in Ciphertext'Range loop
fprintf(stderr, "Error getting input\n");
Plaintext(I) := Ciphertext(I) - Key_Char(Key, I);
return 4;
end loop;
if Distance(English, Get_Frequency(Plaintext)) < Best_Dist then
}
Best_Plain := Plaintext;
} while (strcmp(plaintext, "") == 0); // Reprompt if entry is empty
Best_Dist := Distance(English, Get_Frequency(Plaintext));
Best_Key(1 .. I) := Key;
Best_Key_L := I;
if Best_dist < 0.01 then
declare
use Ada.Text_IO;
begin
Put_Line("Key =" & Best_Key(1 .. Best_Key_L));
Put_Line("Distance = " & Float'Image(Best_Dist));
New_Line;
Put_Line("Plaintext =");
Put_Line(Best_Plain);
New_Line; New_Line;
end;
end if;
end if;
end;
end loop;
end Vignere_Cryptanalysis;</syntaxhighlight>


=={{header|C}}==
size_t const plainlen = strlen(plaintext);
This finds the right key (I think, I didn't try to decode it after getting the key). The program is not fully auto, but by its output, the result is pretty obvious.
<syntaxhighlight lang="c">#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <math.h>


const char *encoded =
char* const restrict ciphertext = calloc(plainlen + 1, sizeof *ciphertext);
"MOMUD EKAPV TQEFM OEVHP AJMII CDCTI FGYAG JSPXY ALUYM NSMYH"
if (ciphertext == NULL) {
"VUXJE LEPXJ FXGCM JHKDZ RYICU HYPUS PGIGM OIYHF WHTCQ KMLRD"
fprintf(stderr, "Memory error\n");
"ITLXZ LJFVQ GHOLW CUHLO MDSOE KTALU VYLNZ RFGBX PHVGA LWQIS"
return 5;
"FGRPH JOOFW GUBYI LAPLA LCAFA AMKLG CETDW VOELJ IKGJB XPHVG"
}
"ALWQC SNWBU BYHCU HKOCE XJEYK BQKVY KIIEH GRLGH XEOLW AWFOJ"
"ILOVV RHPKD WIHKN ATUHN VRYAQ DIVHX FHRZV QWMWV LGSHN NLVZS"
"JLAKI FHXUF XJLXM TBLQV RXXHR FZXGV LRAJI EXPRV OSMNP KEPDT"
"LPRWM JAZPK LQUZA ALGZX GVLKL GJTUI ITDSU REZXJ ERXZS HMPST"
"MTEOE PAPJH SMFNB YVQUZ AALGA YDNMP AQOWT UHDBV TSMUE UIMVH"
"QGVRW AEFSP EMPVE PKXZY WLKJA GWALT VYYOB YIXOK IHPDS EVLEV"
"RVSGB JOGYW FHKBL GLXYA MVKIS KIEHY IMAPX UOISK PVAGN MZHPW"
"TTZPV XFCCD TUHJH WLAPF YULTB UXJLN SIJVV YOVDJ SOLXG TGRVO"
"SFRII CTMKO JFCQF KTINQ BWVHG TENLH HOGCS PSFPV GJOKM SIFPR"
"ZPAAS ATPTZ FTPPD PORRF TAXZP KALQA WMIUD BWNCT LEFKO ZQDLX"
"BUXJL ASIMR PNMBF ZCYLV WAPVF QRHZV ZGZEF KBYIO OFXYE VOWGB"
"BXVCB XBAWG LQKCM ICRRX MACUO IKHQU AJEGL OIJHH XPVZW JEWBA"
"FWAML ZZRXJ EKAHV FASMU LVVUT TGK";


const double freq[] = {
for (size_t i = 0, j = 0; i < plainlen; i++) {
0.08167, 0.01492, 0.02782, 0.04253, 0.12702, 0.02228, 0.02015,
// Skip non-alphabetical characters
0.06094, 0.06966, 0.00153, 0.00772, 0.04025, 0.02406, 0.06749,
if (!(isalpha(plaintext[i]))) {
0.07507, 0.01929, 0.00095, 0.05987, 0.06327, 0.09056, 0.02758,
ciphertext[i] = plaintext[i];
0.00978, 0.02360, 0.00150, 0.01974, 0.00074
continue;
};

int best_match(const double *a, const double *b) {
double sum = 0, fit, d, best_fit = 1e100;
int i, rotate, best_rotate = 0;
for (i = 0; i < 26; i++)
sum += a[i];
for (rotate = 0; rotate < 26; rotate++) {
fit = 0;
for (i = 0; i < 26; i++) {
d = a[(i + rotate) % 26] / sum - b[i];
fit += d * d / b[i];
}

if (fit < best_fit) {
best_fit = fit;
best_rotate = rotate;
}
}
// Check case
char const charcase = (isupper(plaintext[i])) ? 'A' : 'a';
// Wrapping conversion algorithm
ciphertext[i] = ((plaintext[i] + shifts[j] - charcase + NUMLETTERS) % NUMLETTERS) + charcase;
j = (j+1) % keylen;
}
}
ciphertext[plainlen] = '\0';
printf("%s%s\n", (encrypt) ? cryptmsg : plainmsg, ciphertext);


free(ciphertext);
return best_rotate;
// Silence warnings about const not being maintained in cast to void*
free((char*) plaintext);
return 0;
}
}
char *get_input(void) {


double freq_every_nth(const int *msg, int len, int interval, char *key) {
char *const restrict buf = malloc(BUFSIZE * sizeof (char));
if (buf == NULL) {
double sum, d, ret;
return NULL;
double out[26], accu[26] = {0};
int i, j, rot;

for (j = 0; j < interval; j++) {
for (i = 0; i < 26; i++)
out[i] = 0;
for (i = j; i < len; i += interval)
out[msg[i]]++;
key[j] = rot = best_match(out, freq);
key[j] += 'A';
for (i = 0; i < 26; i++)
accu[i] += out[(i + rot) % 26];
}
}


for (i = 0, sum = 0; i < 26; i++)
fgets(buf, BUFSIZE, stdin);
sum += accu[i];


for (i = 0, ret = 0; i < 26; i++) {
// Get rid of newline
size_t const len = strlen(buf);
d = accu[i] / sum - freq[i];
if (buf[len - 1] == '\n') buf[len - 1] = '\0';
ret += d * d / freq[i];
}


return buf;
key[interval] = '\0';
return ret;
}</lang>
}


int main() {
{{out}}
int txt[strlen(encoded)];
<pre>$ ./vigenere VIGENERECIPHER
int len = 0, j;
Plain text: Beware the Jabberwock, my son! The jaws that bite, the claws that catch!
char key[100];
Cipher text: Wmceei klg Rpifvmeugx, qp wqv! Ioi avey xuek fkbt, alv xtgaf xyev kpagy!
double fit, best_fit = 1e100;


for (j = 0; encoded[j] != '\0'; j++)
$ ./vigenere -d VIGENERECIPHER
if (isupper(encoded[j]))
Cipher text: Wmceei klg Rpifvmeugx, qp wqv! Ioi avey xuek fkbt, alv xtgaf xyev kpagy!
txt[len++] = encoded[j] - 'A';
Plain text: Beware the Jabberwock, my son! The jaws that bite, the claws that catch!</pre>


for (j = 1; j < 30; j++) {
=={{header|C sharp|C#}}==
fit = freq_every_nth(txt, len, j, key);
<lang csharp>
printf("%f, key length: %2d, %s", fit, j, key);
using System;
if (fit < best_fit) {

best_fit = fit;
namespace VigenereCipher
printf(" <--- best so far");
{
class VCipher
{
public string encrypt(string txt, string pw, int d)
{
int pwi = 0, tmp;
string ns = "";
txt = txt.ToUpper();
pw = pw.ToUpper();
foreach (char t in txt)
{
if (t < 65) continue;
tmp = t - 65 + d * (pw[pwi] - 65);
if (tmp < 0) tmp += 26;
ns += Convert.ToChar(65 + ( tmp % 26) );
if (++pwi == pw.Length) pwi = 0;
}

return ns;
}
};

class Program
{
static void Main(string[] args)
{
VCipher v = new VCipher();

string s0 = "Beware the Jabberwock, my son! The jaws that bite, the claws that catch!",
pw = "VIGENERECIPHER";

Console.WriteLine(s0 + "\n" + pw + "\n");
string s1 = v.encrypt(s0, pw, 1);
Console.WriteLine("Encrypted: " + s1);
s1 = v.encrypt(s1, "VIGENERECIPHER", -1);
Console.WriteLine("Decrypted: " + s1);
Console.WriteLine("\nPress any key to continue...");
Console.ReadKey();
}
}
printf("\n");
}
}
}
</lang>
{{out}}
<pre>
Beware the Jabberwock, my son! The jaws that bite, the claws that catch!
VIGENERECIPHER


return 0;
Encrypted: WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY
}</syntaxhighlight>
Decrypted: BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH
</pre>


=={{header|C++}}==
=={{header|C++}}==
Not guaranteed to give a 100% correct answer, but it works here. Requires C++0x.
<lang cpp>#include <iostream>

<syntaxhighlight lang="cpp">#include <iostream>
#include <string>
#include <string>
#include <vector>
#include <map>
#include <algorithm>
#include <array>
using namespace std;
using namespace std;


typedef array<pair<char, double>, 26> FreqArray;
class Vigenere

class VigenereAnalyser
{
{
private:
public:
array<double, 26> targets;
string key;
array<double, 26> sortedTargets;
FreqArray freq;


// Update the freqs array
Vigenere(string key)
FreqArray& frequency(const string& input)
{
{
for(int i = 0; i < key.size(); ++i)
for (char c = 'A'; c <= 'Z'; ++c)
freq[c - 'A'] = make_pair(c, 0);
{

if(key[i] >= 'A' && key[i] <= 'Z')
for (size_t i = 0; i < input.size(); ++i)
this->key += key[i];
else if(key[i] >= 'a' && key[i] <= 'z')
freq[input[i] - 'A'].second++;

this->key += key[i] + 'A' - 'a';
}
return freq;
}
}


string encrypt(string text)
double correlation(const string& input)
{
{
string out;
double result = 0.0;
frequency(input);


sort(freq.begin(), freq.end(), [](pair<char, double> u, pair<char, double> v)->bool
for(int i = 0, j = 0; i < text.length(); ++i)
{ return u.second < v.second; });
{
char c = text[i];
if(c >= 'a' && c <= 'z')
c += 'A' - 'a';
else if(c < 'A' || c > 'Z')
continue;


out += (c + key[j] - 2*'A') % 26 + 'A';
for (size_t i = 0; i < 26; ++i)
j = (j + 1) % key.length();
result += freq[i].second * sortedTargets[i];
}


return out;
return result;
}
}


public:
string decrypt(string text)
VigenereAnalyser(const array<double, 26>& targetFreqs)
{
{
string out;
targets = targetFreqs;
sortedTargets = targets;
sort(sortedTargets.begin(), sortedTargets.end());
}


pair<string, string> analyze(string input)
for(int i = 0, j = 0; i < text.length(); ++i)
{
string cleaned;
for (size_t i = 0; i < input.size(); ++i)
{
{
char c = text[i];
if (input[i] >= 'A' && input[i] <= 'Z')
cleaned += input[i];
if(c >= 'a' && c <= 'z')
else if (input[i] >= 'a' && input[i] <= 'z')
c += 'A' - 'a';
cleaned += input[i] + 'A' - 'a';
else if(c < 'A' || c > 'Z')
continue;

out += (c - key[j] + 26) % 26 + 'A';
j = (j + 1) % key.length();
}
}


return out;
size_t bestLength = 0;
double bestCorr = -100.0;
}
};


// Assume that if there are less than 20 characters
int main()
// per column, the key's too long to guess
{
for (size_t i = 2; i < cleaned.size() / 20; ++i)
Vigenere cipher("VIGENERECIPHER");
{
vector<string> pieces(i);
for (size_t j = 0; j < cleaned.size(); ++j)
pieces[j % i] += cleaned[j];


// The correlation increases artificially for smaller
string original = "Beware the Jabberwock, my son! The jaws that bite, the claws that catch!";
// pieces/longer keys, so weigh against them a little
string encrypted = cipher.encrypt(original);
double corr = -0.5*i;
string decrypted = cipher.decrypt(encrypted);
for (size_t j = 0; j < i; ++j)
corr += correlation(pieces[j]);


if (corr > bestCorr)
cout << original << endl;
{
cout << "Encrypted: " << encrypted << endl;
bestLength = i;
cout << "Decrypted: " << decrypted << endl;
bestCorr = corr;
}</lang>
}
}


if (bestLength == 0)
{{out}}
return make_pair("Text is too short to analyze", "");
<pre>
Beware the Jabberwock, my son! The jaws that bite, the claws that catch!
Encrypted: WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY
Decrypted: BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH
</pre>


vector<string> pieces(bestLength);
=={{header|Ceylon}}==
for (size_t i = 0; i < cleaned.size(); ++i)
<lang ceylon>shared void run() {
pieces[i % bestLength] += cleaned[i];
function normalize(String text) => text.uppercased.filter(Character.letter);
function crypt(String text, String key, Character(Character, Character) transform) => String {
for ([a, b] in zipPairs(normalize(text), normalize(key).cycled))
transform(a, b)
};
function encrypt(String clearText, String key) =>
crypt(clearText, key, (Character a, Character b) =>
('A'.integer + ((a.integer + b.integer - 130) % 26)).character);


vector<FreqArray> freqs;
function decrypt(String cipherText, String key) =>
for (size_t i = 0; i < bestLength; ++i)
crypt(cipherText, key, (Character a, Character b) =>
freqs.push_back(frequency(pieces[i]));
('A'.integer + ((a.integer - b.integer + 26) % 26)).character);
value key = "VIGENERECIPHER";
value message = "Beware the Jabberwock, my son! The jaws that bite, the claws that catch!";
value encrypted = encrypt(message, key);
value decrypted = decrypt(encrypted, key);
print(encrypted);
print(decrypted);
}</lang>


string key = "";
=={{header|Clojure}}==
for (size_t i = 0; i < bestLength; ++i)
Requires Clojure 1.2.
{
<lang clojure>(ns org.rosettacode.clojure.vigenere
sort(freqs[i].begin(), freqs[i].end(), [](pair<char, double> u, pair<char, double> v)->bool
(:require [clojure.string :as string]))
{ return u.second > v.second; });


size_t m = 0;
; convert letter to offset from \A
double mCorr = 0.0;
(defn to-num [char] (- (int char) (int \A)))
for (size_t j = 0; j < 26; ++j)
{
double corr = 0.0;
char c = 'A' + j;
for (size_t k = 0; k < 26; ++k)
{
int d = (freqs[i][k].first - c + 26) % 26;
corr += freqs[i][k].second * targets[d];
}


if (corr > mCorr)
; convert number to letter, treating it as modulo 26 offset from \A
{
(defn from-num [num] (char (+ (mod num 26) (int \A))))
m = j;
mCorr = corr;
}
}


key += m + 'A';
; Convert a string to a sequence of just the letters as uppercase chars
}
(defn to-normalized-seq [str]
(map #'first (re-seq #"[A-Z]" (string/upper-case str))))
; add (op=+) or subtract (op=-) the numerical value of the key letter from the
; text letter.
(defn crypt1 [op text key]
(from-num (apply op (list (to-num text) (to-num key)))))


string result = "";
(defn crypt [op text key]
for (size_t i = 0; i < cleaned.size(); ++i)
(let [xcrypt1 (partial #'crypt1 op)]
result += (cleaned[i] - key[i % key.length()] + 26) % 26 + 'A';
(apply #'str
(map xcrypt1 (to-normalized-seq text)
(cycle (to-normalized-seq key))))))
; encipher a text
(defn encrypt [plaintext key] (crypt #'+ plaintext key))
; decipher a text
(defn decrypt [ciphertext key] (crypt #'- ciphertext key))</lang>


return make_pair(result, key);
Demonstration code:
}
<lang clojure>(ns org.rosettacode.clojure.test-vigenere
};
(:require [org.rosettacode.clojure.vigenere :as vigenere]))


int main()
(let
{
[ plaintext "Beware the Jabberwock, my son! The jaws that bite, the claws that catch!"
string input =
key "Vigenere cipher"
"MOMUD EKAPV TQEFM OEVHP AJMII CDCTI FGYAG JSPXY ALUYM NSMYH"
ciphertext (vigenere/encrypt plaintext key)
"VUXJE LEPXJ FXGCM JHKDZ RYICU HYPUS PGIGM OIYHF WHTCQ KMLRD"
recovered (vigenere/decrypt ciphertext key) ]
"ITLXZ LJFVQ GHOLW CUHLO MDSOE KTALU VYLNZ RFGBX PHVGA LWQIS"
"FGRPH JOOFW GUBYI LAPLA LCAFA AMKLG CETDW VOELJ IKGJB XPHVG"
"ALWQC SNWBU BYHCU HKOCE XJEYK BQKVY KIIEH GRLGH XEOLW AWFOJ"
"ILOVV RHPKD WIHKN ATUHN VRYAQ DIVHX FHRZV QWMWV LGSHN NLVZS"
"JLAKI FHXUF XJLXM TBLQV RXXHR FZXGV LRAJI EXPRV OSMNP KEPDT"
"LPRWM JAZPK LQUZA ALGZX GVLKL GJTUI ITDSU REZXJ ERXZS HMPST"
"MTEOE PAPJH SMFNB YVQUZ AALGA YDNMP AQOWT UHDBV TSMUE UIMVH"
"QGVRW AEFSP EMPVE PKXZY WLKJA GWALT VYYOB YIXOK IHPDS EVLEV"
"RVSGB JOGYW FHKBL GLXYA MVKIS KIEHY IMAPX UOISK PVAGN MZHPW"
"TTZPV XFCCD TUHJH WLAPF YULTB UXJLN SIJVV YOVDJ SOLXG TGRVO"
"SFRII CTMKO JFCQF KTINQ BWVHG TENLH HOGCS PSFPV GJOKM SIFPR"
"ZPAAS ATPTZ FTPPD PORRF TAXZP KALQA WMIUD BWNCT LEFKO ZQDLX"
"BUXJL ASIMR PNMBF ZCYLV WAPVF QRHZV ZGZEF KBYIO OFXYE VOWGB"
"BXVCB XBAWG LQKCM ICRRX MACUO IKHQU AJEGL OIJHH XPVZW JEWBA"
"FWAML ZZRXJ EKAHV FASMU LVVUT TGK";


array<double, 26> english = {
(doall (map (fn [[k v]] (printf "%9s: %s\n" k v))
0.08167, 0.01492, 0.02782, 0.04253, 0.12702, 0.02228,
[ ["Original" plaintext] ["Key" key] ["Encrypted" ciphertext] ["Decrypted" recovered] ])))
0.02015, 0.06094, 0.06966, 0.00153, 0.00772, 0.04025,
</lang>
0.02406, 0.06749, 0.07507, 0.01929, 0.00095, 0.05987,
0.06327, 0.09056, 0.02758, 0.00978, 0.02360, 0.00150,
0.01974, 0.00074};


VigenereAnalyser va(english);
{{out}}
pair<string, string> output = va.analyze(input);
<pre> Original: Beware the Jabberwock, my son! The jaws that bite, the claws that catch!
Key: Vigenere cipher
Encrypted: WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY
Decrypted: BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH</pre>


cout << "Key: " << output.second << endl << endl;
=={{header|CoffeeScript}}==
cout << "Text: " << output.first << endl;
{{trans|D}}
}</syntaxhighlight>
<lang coffeescript># Simple helper since charCodeAt is quite long to write.
code = (char) -> char.charCodeAt()

encrypt = (text, key) ->
res = []
j = 0
for c in text.toUpperCase()
continue if c < 'A' or c > 'Z'
res.push ((code c) + (code key[j]) - 130) % 26 + 65
j = ++j % key.length
String.fromCharCode res...

decrypt = (text, key) ->
res = []
j = 0
for c in text.toUpperCase()
continue if c < 'A' or c > 'Z'
res.push ((code c) - (code key[j]) + 26) % 26 + 65
j = ++j % key.length
String.fromCharCode res...

# Trying it out
key = "VIGENERECIPHER"
original = "Beware the Jabberwock, my son! The jaws that bite, the claws that catch!"
encrypted = encrypt original, key

console.log "Original : #{original}"
console.log "Encrypted : #{encrypted}"
console.log "Decrypted : #{decrypt encrypted, key}"</lang>
<pre>Original : Beware the Jabberwock, my son! The jaws that bite, the claws that catch!
Encrypted : WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY
Decrypted : BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH</pre>

=={{header|Common Lisp}}==
This doesn't assume anything about character codes other than A-Z being a contiguous block (but still, we could be using EBCDIC. Who knows.)
<lang lisp>(defun strip (s)
(remove-if-not
(lambda (c) (char<= #\A c #\Z))
(string-upcase s)))

(defun vigenère (s key &key decipher
&aux (A (char-code #\A))
(op (if decipher #'- #'+)))
(labels
((to-char (c) (code-char (+ c A)))
(to-code (c) (- (char-code c) A)))
(let ((k (map 'list #'to-code (strip key))))
(setf (cdr (last k)) k)
(map 'string
(lambda (c)
(prog1
(to-char
(mod (funcall op (to-code c) (car k)) 26))
(setf k (cdr k))))
(strip s)))))

(let* ((msg "Beware the Jabberwock... The jaws that... the claws that catch!")
(key "vigenere cipher")
(enc (vigenère msg key))
(dec (vigenère enc key :decipher t)))
(format t "msg: ~a~%enc: ~a~%dec: ~a~%" msg enc dec))</lang>
{{out}}
<pre>msg: Beware the Jabberwock... The jaws that... the claws that catch!
enc: WMCEEIKLGRPIFVMEUGXXYILILZXYVBZLRGCEYAIOEKXIZGU
dec: BEWARETHEJABBERWOCKTHEJAWSTHATTHECLAWSTHATCATCH</pre>


=={{header|D}}==
=={{header|D}}==
{{trans|C++}}
<lang d>import std.stdio, std.string;
<syntaxhighlight lang="d">import std.stdio, std.algorithm, std.typecons, std.string,
std.array, std.numeric, std.ascii;


string encrypt(in string txt, in string key) pure @safe
string[2] vigenereDecrypt(in double[] targetFreqs, in string input) {
enum nAlpha = std.ascii.uppercase.length;
in {
assert(key.removechars("^A-Z") == key);
} body {
string res;
foreach (immutable i, immutable c; txt.toUpper.removechars("^A-Z"))
res ~= (c + key[i % $] - 2 * 'A') % 26 + 'A';
return res;
}


string decrypt(in string txt, in string key) pure @safe
static double correlation(in string txt, in double[] sTargets)
pure nothrow /*@safe*/ @nogc {
in {
uint[nAlpha] charCounts = 0;
assert(key.removechars("^A-Z") == key);
foreach (immutable c; txt)
} body {
charCounts[c - 'A']++;
string res;
return charCounts[].sort().release.dotProduct(sTargets);
foreach (immutable i, immutable c; txt.toUpper.removechars("^A-Z"))
}
res ~= (c - key[i % $] + 26) % 26 + 'A';
return res;
}


static frequency(in string txt) pure nothrow @safe {
void main() {
auto freqs = new Tuple!(char,"c", uint,"d")[nAlpha];
immutable key = "VIGENERECIPHER";
foreach (immutable i, immutable c; std.ascii.uppercase)
immutable original = "Beware the Jabberwock, my son!" ~
" The jaws that bite, the claws that catch!";
freqs[i] = tuple(c, 0);
foreach (immutable c; txt)
immutable encoded = original.encrypt(key);
freqs[c - 'A'].d++;
writeln(encoded, "\n", encoded.decrypt(key));
return freqs;
}</lang>
}
{{out}}
<pre>WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY
BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH</pre>


static string[2] decode(in string cleaned, in string key)
===Alternative Version===
pure nothrow @safe {
{{trans|Perl 6}}
assert(!key.empty);
<lang d>import std.stdio, std.range, std.ascii, std.string, std.algorithm,
std.conv;
string decoded;
foreach (immutable i, immutable c; cleaned)
decoded ~= (c - key[i % $] + nAlpha) % nAlpha + 'A';
return [key, decoded];
}


static size_t findBestLength(in string cleaned,
immutable mod = (in int m, in int n) pure nothrow @safe @nogc =>
in double[] sTargets)
((m % n) + n) % n;
pure nothrow /*@safe*/ {
size_t bestLength;
double bestCorr = -100.0;


// Assume that if there are less than 20 characters
immutable _s2v = (in string s) pure /*nothrow*/ @safe =>
// per column, the key's too long to guess
s.toUpper.removechars("^A-Z").map!q{ a - 'A' };
foreach (immutable i; 2 .. cleaned.length / 20) {
auto pieces = new Appender!string[i];
foreach (immutable j, immutable c; cleaned)
pieces[j % i] ~= c;


// The correlation seems to increase for smaller
string _v2s(R)(R v) pure /*nothrow*/ @safe {
// pieces/longer keys, so weigh against them a little
return v.map!(x => uppercase[x.mod(26)]).text;
double corr = -0.5 * i;
}
foreach (const p; pieces)
corr += correlation(p.data, sTargets);


if (corr > bestCorr) {
immutable encrypt = (in string txt, in string key) pure /*nothrow*/ @safe =>
bestLength = i;
txt._s2v.zip(key._s2v.cycle).map!q{ a[0] + a[1] }._v2s;
bestCorr = corr;
}
}


return bestLength;
immutable decrypt = (in string txt, in string key) pure /*nothrow*/ @safe =>
txt._s2v.zip(key._s2v.cycle).map!q{ a[0] - a[1] }._v2s;

void main() {
immutable key = "Vigenere Cipher!!!";
immutable original = "Beware the Jabberwock, my son!" ~
" The jaws that bite, the claws that catch!";
immutable encoded = original.encrypt(key);
writeln(encoded, "\n", encoded.decrypt(key));
}</lang>
The output is the same.

=={{header|Elena}}==
{{trans|C#}}
ELENA 4.x :
<lang elena>import system'text;
import system'math;
import system'routines;
import extensions;
class VCipher
{
string encrypt(string txt, string pw, int d)
{
auto output := new TextBuilder();
int pwi := 0;
string PW := pw.upperCase();
txt.upperCase().forEach:(t)
{
if(t >= $65)
{
int tmp := t.toInt() - 65 + d * (PW[pwi].toInt() - 65);
if (tmp < 0)
{
tmp += 26
};
output.write((65 + tmp.mod:26).toChar());
pwi += 1;
if (pwi == PW.Length) { pwi := 0 }
}
};
^ output.Value
}
}
}
public program()
{
var v := new VCipher();
var s0 := "Beware the Jabberwock, my son! The jaws that bite, the claws that catch!";
var pw := "VIGENERECIPHER";
console.printLine(s0,newLine,pw,newLine);
var s1 := v.encrypt(s0, pw, 1);
console.printLine("Encrypted:",s1);
s1 := v.encrypt(s1, "VIGENERECIPHER", -1);
console.printLine("Decrypted:",s1);
console.printLine("Press any key to continue..");
console.readChar()
}</lang>
{{out}}
<pre>
Beware the Jabberwock, my son! The jaws that bite, the claws that catch!
VIGENERECIPHER


static string findKey(in string cleaned, in size_t bestLength,
Encrypted:WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY
in double[] targetFreqs) pure nothrow @safe {
Decrypted:BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH
auto pieces = new string[bestLength];
Press any key to continue..
foreach (immutable i, immutable c; cleaned)
</pre>
pieces[i % bestLength] ~= c;


string key;
=={{header|Elixir}}==
foreach (fr; pieces.map!frequency) {
{{trans|Ruby}}
fr.sort!q{ a.d > b.d };
<lang elixir>defmodule VigenereCipher do
@base ?A
@size ?Z - @base + 1
def encrypt(text, key), do: crypt(text, key, 1)
def decrypt(text, key), do: crypt(text, key, -1)
defp crypt(text, key, dir) do
text = String.upcase(text) |> String.replace(~r/[^A-Z]/, "") |> to_char_list
key_iterator = String.upcase(key) |> String.replace(~r/[^A-Z]/, "") |> to_char_list
|> Enum.map(fn c -> (c - @base) * dir end) |> Stream.cycle
Enum.zip(text, key_iterator)
|> Enum.reduce('', fn {char, offset}, ciphertext ->
[rem(char - @base + offset + @size, @size) + @base | ciphertext]
end)
|> Enum.reverse |> List.to_string
end
end


size_t m;
plaintext = "Beware the Jabberwock, my son! The jaws that bite, the claws that catch!"
double maxCorr = 0.0;
key = "Vigenere cipher"
foreach (immutable j, immutable c; uppercase) {
ciphertext = VigenereCipher.encrypt(plaintext, key)
double corr = 0.0;
recovered = VigenereCipher.decrypt(ciphertext, key)
foreach (immutable frc; fr) {
immutable di = (frc.c - c + nAlpha) % nAlpha;
IO.puts "Original: #{plaintext}"
corr += frc.d * targetFreqs[di];
IO.puts "Encrypted: #{ciphertext}"
}
IO.puts "Decrypted: #{recovered}"</lang>


if (corr > maxCorr) {
{{out}}
m = j;
<pre>
maxCorr = corr;
Original: Beware the Jabberwock, my son! The jaws that bite, the claws that catch!
}
Encrypted: WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY
}
Decrypted: BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH
</pre>


key ~= m + 'A';
=={{header|Erlang}}==
}
Erlang is not ideal for string manipulation, but with some utility function definitions it can express this fairly elegantly:
<lang erlang>% Erlang implementation of Vigenère cipher
-module(vigenere).
-export([encrypt/2, decrypt/2]).
-import(lists, [append/2, filter/2, map/2, zipwith/3]).


return key;
% Utility functions for character tests and conversions
}
isupper([C|_]) -> isupper(C);
isupper(C) -> (C >= $A) and (C =< $Z).


immutable cleaned = input.toUpper.removechars("^A-Z");
islower([C|_]) -> islower(C);
islower(C) -> (C >= $a) and (C =< $z).


//immutable sortedTargets = targetFreqs.sorted;
isalpha([C|_]) -> isalpha(C);
immutable sortedTargets = targetFreqs.dup.sort().release.idup;
isalpha(C) -> isupper(C) or islower(C).


immutable bestLength = findBestLength(cleaned, sortedTargets);
toupper(S) when is_list(S) -> lists:map(fun toupper/1, S);
if (bestLength == 0)
toupper(C) when (C >= $a) and (C =< $z) -> C - $a + $A;
throw new Exception("Text is too short to analyze.");
toupper(C) -> C.


immutable string key = findKey(cleaned, bestLength, targetFreqs);
% modulo function that normalizes into positive range for positive divisor
return decode(cleaned, key);
mod(X,Y) -> (X rem Y + Y) rem Y.
}


% convert letter to position in alphabet (A=0,B=1,...,Y=24,Z=25).
to_pos(L) when L >= $A, L =< $Z -> L - $A.


void main() {
% convert position in alphabet back to letter
immutable encoded = "MOMUD EKAPV TQEFM OEVHP AJMII CDCTI FGYAG
from_pos(N) -> mod(N, 26) + $A.
JSPXY ALUYM NSMYH VUXJE LEPXJ FXGCM JHKDZ RYICU HYPUS PGIGM OIYHF
WHTCQ KMLRD ITLXZ LJFVQ GHOLW CUHLO MDSOE KTALU VYLNZ RFGBX PHVGA
LWQIS FGRPH JOOFW GUBYI LAPLA LCAFA AMKLG CETDW VOELJ IKGJB XPHVG
ALWQC SNWBU BYHCU HKOCE XJEYK BQKVY KIIEH GRLGH XEOLW AWFOJ ILOVV
RHPKD WIHKN ATUHN VRYAQ DIVHX FHRZV QWMWV LGSHN NLVZS JLAKI FHXUF
XJLXM TBLQV RXXHR FZXGV LRAJI EXPRV OSMNP KEPDT LPRWM JAZPK LQUZA
ALGZX GVLKL GJTUI ITDSU REZXJ ERXZS HMPST MTEOE PAPJH SMFNB YVQUZ
AALGA YDNMP AQOWT UHDBV TSMUE UIMVH QGVRW AEFSP EMPVE PKXZY WLKJA
GWALT VYYOB YIXOK IHPDS EVLEV RVSGB JOGYW FHKBL GLXYA MVKIS KIEHY
IMAPX UOISK PVAGN MZHPW TTZPV XFCCD TUHJH WLAPF YULTB UXJLN SIJVV
YOVDJ SOLXG TGRVO SFRII CTMKO JFCQF KTINQ BWVHG TENLH HOGCS PSFPV
GJOKM SIFPR ZPAAS ATPTZ FTPPD PORRF TAXZP KALQA WMIUD BWNCT LEFKO
ZQDLX BUXJL ASIMR PNMBF ZCYLV WAPVF QRHZV ZGZEF KBYIO OFXYE VOWGB
BXVCB XBAWG LQKCM ICRRX MACUO IKHQU AJEGL OIJHH XPVZW JEWBA FWAML
ZZRXJ EKAHV FASMU LVVUT TGK";


immutable englishFrequences = [0.08167, 0.01492, 0.02782, 0.04253,
% encode the given letter given the single-letter key
0.12702, 0.02228, 0.02015, 0.06094, 0.06966, 0.00153, 0.00772,
encipher(P, K) -> from_pos(to_pos(P) + to_pos(K)).
0.04025, 0.02406, 0.06749, 0.07507, 0.01929, 0.00095, 0.05987,
0.06327, 0.09056, 0.02758, 0.00978, 0.02360, 0.00150, 0.01974,
0.00074];


immutable key_dec = vigenereDecrypt(englishFrequences, encoded);
% decode the given letter given the single-letter key
writefln("Key: %s\n\nText: %s", key_dec[0], key_dec[1]);
decipher(C, K) -> from_pos(to_pos(C) - to_pos(K)).
}</syntaxhighlight>
{{out|Output (cut)}}
<pre>Key: THECHESHIRECAT


Text: THISWASTHEPOEMTHATALICEREADJABBERWOCKYTWASBRILLIGANDTHESLITHY...</pre>
% extend a list by repeating it until it is at least N elements long
cycle_to(N, List) when length(List) >= N -> List;
cycle_to(N, List) -> append(List, cycle_to(N-length(List), List)).
% Encryption prep: reduce string to only its letters, in uppercase
normalize(Str) -> toupper(filter(fun isalpha/1, Str)).

crypt(RawText, RawKey, Func) ->
PlainText = normalize(RawText),
zipwith(Func, PlainText, cycle_to(length(PlainText), normalize(RawKey))).

encrypt(Text, Key) -> crypt(Text, Key, fun encipher/2).
decrypt(Text, Key) -> crypt(Text, Key, fun decipher/2).</lang>

Demonstration code:
<lang erlang>-module(testvigenere).
-import(vigenere,[encrypt/2, decrypt/2]).
main(_) ->
Key = "Vigenere cipher",
CipherText = encrypt("Beware the Jabberwock, my son! The jaws that bite, the claws that catch!", Key),
RecoveredText = decrypt(CipherText, Key),
io:fwrite("Ciphertext: ~s~nDecrypted: ~s~n", [CipherText, RecoveredText]).</lang>

{{out}}
<pre>Ciphertext: WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY
Decrypted: BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH</pre>

=={{header|F_Sharp|F#}}==
<lang fsharp>
module vigenere =
let keyschedule (key:string) =
let s = key.ToUpper().ToCharArray() |> Array.filter System.Char.IsLetter
let l = Array.length s
(fun n -> int s.[n % l])

let enc k c = ((c + k - 130) % 26) + 65
let dec k c = ((c - k + 130) % 26) + 65
let crypt f key = Array.mapi (fun n c -> f (key n) c |> char)

let encrypt key (plaintext:string) =
plaintext.ToUpper().ToCharArray()
|> Array.filter System.Char.IsLetter
|> Array.map int
|> crypt enc (keyschedule key)
|> (fun a -> new string(a))

let decrypt key (ciphertext:string) =
ciphertext.ToUpper().ToCharArray()
|> Array.map int
|> crypt dec (keyschedule key)
|> (fun a -> new string(a))

let passwd = "Vigenere Cipher"
let cipher = vigenere.encrypt passwd "Beware the Jabberwock, my son! The jaws that bite, the claws that catch!"
let plain = vigenere.decrypt passwd cipher
printfn "%s\n%s" cipher plain
</lang>

<pre>C:\src\fsharp>fsi vigenere.fsx
WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY
BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH
</pre>

=={{header|Factor}}==
<lang>USING: arrays ascii formatting kernel math math.functions
math.order sequences ;
IN: rosetta-code.vigenere-cipher

: mult-pad ( key input -- x )
[ length ] bi@ 2dup < [ swap ] when / ceiling ;
: lengthen-pad ( key input -- rep-key input )
[ mult-pad ] 2keep [ <repetition> concat ] dip
[ length ] keep [ head ] dip ;
: normalize ( str -- only-upper-letters )
>upper [ LETTER? ] filter ;
: vigenere-encrypt ( key input -- ecrypted )
[ normalize ] bi@ lengthen-pad
[ [ CHAR: A - ] map ] bi@ [ + 26 mod CHAR: A + ] 2map ;

: vigenere-decrypt ( key input -- decrypted )
[ normalize ] bi@ lengthen-pad [ [ CHAR: A - ] map ] bi@
[ - 26 - abs 26 mod CHAR: A + ] 2map ;
: main ( -- )
"Vigenere cipher" dup
"Beware the Jabberwock, my son! The jaws that bite, the claws that catch!"
2dup "Key: %s\nInput: %s\n" printf
vigenere-encrypt dup "Encrypted: %s\n" printf
vigenere-decrypt "Decrypted: %s\n" printf ;

MAIN: main</lang>
{{out}}
<pre>
Key: Vigenere cipher
Input: Beware the Jabberwock, my son! The jaws that bite, the claws that catch!
Encrypted: WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY
Decrypted: BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH
</pre>

=={{header|Fortran}}==
{{works with|Fortran|95 and later}}
<lang fortran>program vigenere_cipher
implicit none
character(80) :: plaintext = "Beware the Jabberwock, my son! The jaws that bite, the claws that catch!", &
ciphertext = ""
character(14) :: key = "VIGENERECIPHER"


call encrypt(plaintext, ciphertext, key)
write(*,*) plaintext
write(*,*) ciphertext
call decrypt(ciphertext, plaintext, key)
write(*,*) plaintext

contains

subroutine encrypt(intxt, outtxt, k)
character(*), intent(in) :: intxt, k
character(*), intent(out) :: outtxt
integer :: chrn
integer :: cp = 1, kp = 1
integer :: i
outtxt = ""
do i = 1, len(trim(intxt))
select case(intxt(i:i))
case ("A":"Z", "a":"z")
select case(intxt(i:i))
case("a":"z")
chrn = iachar(intxt(i:i)) - 32
case default
chrn = iachar(intxt(i:i))
end select
outtxt(cp:cp) = achar(modulo(chrn + iachar(k(kp:kp)), 26) + 65)
cp = cp + 1
kp = kp + 1
if(kp > len(k)) kp = kp - len(k)
end select
end do
end subroutine

subroutine decrypt(intxt, outtxt, k)
character(*), intent(in) :: intxt, k
character(*), intent(out) :: outtxt
integer :: chrn
integer :: cp = 1, kp = 1
integer :: i
outtxt = ""
do i = 1, len(trim(intxt))
chrn = iachar(intxt(i:i))
outtxt(cp:cp) = achar(modulo(chrn - iachar(k(kp:kp)), 26) + 65)
cp = cp + 1
kp = kp + 1
if(kp > len(k)) kp = kp - len(k)
end do
end subroutine
end program</lang>
{{out}}
<pre> Beware the Jabberwock, my son! The jaws that bite, the claws that catch!
WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY
BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH</pre>


=={{header|Go}}==
=={{header|Go}}==
{{trans|Kotlin}}
<lang go>package main
<syntaxhighlight lang="go">package main


import "fmt"
import (
"fmt"
"strings"
)


var encoded =
type vkey string
"MOMUD EKAPV TQEFM OEVHP AJMII CDCTI FGYAG JSPXY ALUYM NSMYH" +
"VUXJE LEPXJ FXGCM JHKDZ RYICU HYPUS PGIGM OIYHF WHTCQ KMLRD" +
"ITLXZ LJFVQ GHOLW CUHLO MDSOE KTALU VYLNZ RFGBX PHVGA LWQIS" +
"FGRPH JOOFW GUBYI LAPLA LCAFA AMKLG CETDW VOELJ IKGJB XPHVG" +
"ALWQC SNWBU BYHCU HKOCE XJEYK BQKVY KIIEH GRLGH XEOLW AWFOJ" +
"ILOVV RHPKD WIHKN ATUHN VRYAQ DIVHX FHRZV QWMWV LGSHN NLVZS" +
"JLAKI FHXUF XJLXM TBLQV RXXHR FZXGV LRAJI EXPRV OSMNP KEPDT" +
"LPRWM JAZPK LQUZA ALGZX GVLKL GJTUI ITDSU REZXJ ERXZS HMPST" +
"MTEOE PAPJH SMFNB YVQUZ AALGA YDNMP AQOWT UHDBV TSMUE UIMVH" +
"QGVRW AEFSP EMPVE PKXZY WLKJA GWALT VYYOB YIXOK IHPDS EVLEV" +
"RVSGB JOGYW FHKBL GLXYA MVKIS KIEHY IMAPX UOISK PVAGN MZHPW" +
"TTZPV XFCCD TUHJH WLAPF YULTB UXJLN SIJVV YOVDJ SOLXG TGRVO" +
"SFRII CTMKO JFCQF KTINQ BWVHG TENLH HOGCS PSFPV GJOKM SIFPR" +
"ZPAAS ATPTZ FTPPD PORRF TAXZP KALQA WMIUD BWNCT LEFKO ZQDLX" +
"BUXJL ASIMR PNMBF ZCYLV WAPVF QRHZV ZGZEF KBYIO OFXYE VOWGB" +
"BXVCB XBAWG LQKCM ICRRX MACUO IKHQU AJEGL OIJHH XPVZW JEWBA" +
"FWAML ZZRXJ EKAHV FASMU LVVUT TGK"


var freq = [26]float64{
func newVigenère(key string) (vkey, bool) {
0.08167, 0.01492, 0.02782, 0.04253, 0.12702, 0.02228, 0.02015,
v := vkey(upperOnly(key))
0.06094, 0.06966, 0.00153, 0.00772, 0.04025, 0.02406, 0.06749,
return v, len(v) > 0 // key length 0 invalid
0.07507, 0.01929, 0.00095, 0.05987, 0.06327, 0.09056, 0.02758,
0.00978, 0.02360, 0.00150, 0.01974, 0.00074,
}
}


func (k vkey) encipher(pt string) string {
func sum(a []float64) (sum float64) {
ct := upperOnly(pt)
for _, f := range a {
for i, c := range ct {
sum += f
ct[i] = 'A' + (c-'A'+k[i%len(k)]-'A')%26
}
}
return string(ct)
return
}
}


func bestMatch(a []float64) int {
func (k vkey) decipher(ct string) (string, bool) {
pt := make([]byte, len(ct))
sum := sum(a)
for i := range pt {
bestFit, bestRotate := 1e100, 0
c := ct[i]
for rotate := 0; rotate < 26; rotate++ {
if c < 'A' || c > 'Z' {
fit := 0.0
return "", false // invalid ciphertext
for i := 0; i < 26; i++ {
d := a[(i+rotate)%26]/sum - freq[i]
fit += d * d / freq[i]
}
if fit < bestFit {
bestFit, bestRotate = fit, rotate
}
}
pt[i] = 'A' + (c-k[i%len(k)]+26)%26
}
}
return string(pt), true
return bestRotate
}
}


func freqEveryNth(msg []int, key []byte) float64 {
// upperOnly extracts letters A-Z, a-z from a string and
l := len(msg)
// returns them all upper case in a byte slice.
interval := len(key)
// Useful for vkey constructor and encipher function.
out := make([]float64, 26)
func upperOnly(s string) []byte {
u := make([]byte, 0, len(s))
accu := make([]float64, 26)
for i := 0; i < len(s); i++ {
for j := 0; j < interval; j++ {
c := s[i]
for k := 0; k < 26; k++ {
if c >= 'A' && c <= 'Z' {
out[k] = 0.0
u = append(u, c)
}
} else if c >= 'a' && c <= 'z' {
for i := j; i < l; i += interval {
u = append(u, c-32)
out[msg[i]]++
}
rot := bestMatch(out)
key[j] = byte(rot + 65)
for i := 0; i < 26; i++ {
accu[i] += out[(i+rot)%26]
}
}
}
}
return u
sum := sum(accu)
ret := 0.0
for i := 0; i < 26; i++ {
d := accu[i]/sum - freq[i]
ret += d * d / freq[i]
}
return ret
}
}


func decrypt(text, key string) string {
const testKey = "Vigenère Cipher"
var sb strings.Builder
const testPT = `Beware the Jabberwock, my son!
ki := 0
The jaws that bite, the claws that catch!`
for _, c := range text {
if c < 'A' || c > 'Z' {
continue
}
ci := (c - rune(key[ki]) + 26) % 26
sb.WriteRune(ci + 65)
ki = (ki + 1) % len(key)
}
return sb.String()
}


func main() {
func main() {
fmt.Println("Supplied key: ", testKey)
enc := strings.Replace(encoded, " ", "", -1)
v, ok := newVigenère(testKey)
txt := make([]int, len(enc))
for i := 0; i < len(txt); i++ {
if !ok {
fmt.Println("Invalid key")
txt[i] = int(enc[i] - 'A')
return
}
}
bestFit, bestKey := 1e100, ""
fmt.Println("Effective key:", v)
fmt.Println("Plain text:", testPT)
fmt.Println(" Fit Length Key")
ct := v.encipher(testPT)
for j := 1; j <= 26; j++ {
key := make([]byte, j)
fmt.Println("Enciphered:", ct)
dt, ok := v.decipher(ct)
fit := freqEveryNth(txt, key)
sKey := string(key)
if !ok {
fmt.Println("Invalid ciphertext")
fmt.Printf("%f %2d %s", fit, j, sKey)
return
if fit < bestFit {
bestFit, bestKey = fit, sKey
fmt.Print(" <--- best so far")
}
fmt.Println()
}
}
fmt.Println("Deciphered:", dt)
fmt.Println("\nBest key :", bestKey)
fmt.Printf("\nDecrypted text:\n%s\n", decrypt(enc, bestKey))
}</lang>
}</syntaxhighlight>

{{out}}
{{out}}
Note: carriage returns inserted into decrypted text after every 80 characters to make it more readable.
<pre>
<pre>
Fit Length Key
Supplied key: Vigenère Cipher
2.984348 1 E <--- best so far
Effective key: VIGENRECIPHER
2.483684 2 EC <--- best so far
Plain text: Beware the Jabberwock, my son!
2.642487 3 TEE
The jaws that bite, the claws that catch!
1.976651 4 THEC <--- best so far
Enciphered: WMCEEVXJMYHFSZZCSPBQAADUXYZRGAFKLCBQPXVOPKGYRAUBWHXTVBIL
2.356881 5 EEEPU
Deciphered: BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH
2.203129 6 TCECEC
1.051163 7 THECSAS <--- best so far
1.645763 8 TJQGAHET
2.001380 9 VEIZSEGNT
1.824476 10 ECEGAWQTDS
1.623083 11 TNLUSRXPTAJ
1.253527 12 XLECTHQGTHEC
1.399037 13 LJJTDGFNOTENR
0.152370 14 THECHESHIRECAT <--- best so far
1.533951 15 JNTOOEEXFTGQTNH
1.068182 16 TJTSAEETEXHPXHNE
1.034093 17 AZRAXUHEJLREEXIEE
1.443345 18 VNIZQPALEPTSXSEXUC
1.090977 19 FUCAITCSLVTEZDUDEHS
0.979868 20 EQXGAHWTTQECEWUGXHPI
0.789410 21 HVRCSAFTHEBDLSTAERSES
0.881380 22 TVIJTCIGKAQPELECRXPTNC
0.952456 23 KKEQXGPWTCQEELIEHXUWASV
0.715968 24 ELAIXHQTTIEDXJETTNTGAEPC
0.891258 25 OTJUUEGERDNQTUQEAGWUTIEOA
0.852784 26 IGITEGECAGAVUNLJAHASAVTETW

Best key : THECHESHIRECAT

Decrypted text:
THISWASTHEPOEMTHATALICEREADJABBERWOCKYTWASBRILLIGANDTHESLITHYTOVESDIDGYREANDGIMB
LEINTHEWABEALLMIMSYWERETHEBOROGOVESANDTHEMOMERATHSOUTGRABEBEWARETHEJABBERWOCKMYS
ONTHEJAWSTHATBITETHECLAWSTHATCATCHBEWARETHEJUBJUBBIRDANDSHUNTHEFRUMIOUSBANDERSNA
TCHHETOOKHISVORPALSWORDINHANDLONGTIMETHEMANXOMEFOEHESOUGHTSORESTEDHEBYTHETUMTUMT
REEANDSTOODAWHILEINTHOUGHTANDASINUFFISHTHOUGHTHESTOODTHEJABBERWOCKWITHEYESOFFLAM
ECAMEWHIFFLINGTHROUGHTHETULGEYWOODANDBURBLEDASITCAMEONETWOONETWOANDTHROUGHANDTHR
OUGHTHEVORPALBLADEWENTSNICKERSNACKHELEFTITDEADANDWITHITSHEADHEWENTGALUMPHINGBACK
ANDHASTTHOUSLAINTHEJABBERWOCKCOMETOMYARMSMYBEAMISHBOYOFRABJOUSDAYCALLOOHCALLAYHE
CHORTLEDINHISJOYTWASBRILLIGANDTHESLITHYTOVESDIDGYREANDGIMBLEINTHEWABEALLMIMSYWER
ETHEBOROGOVESANDTHEMOMERATHSOUTGRABEITSEEMSVERYPRETTYSHESAIDWHENSHEHADFINISHEDIT
BUTITSRATHERHARDTOUNDERSTAND
</pre>
</pre>


=={{header|Haskell}}==
=={{header|Haskell}}==
<syntaxhighlight lang="haskell">{-# LANGUAGE TupleSections #-}
<lang haskell>import Data.Char
import Data.List(transpose, nub, sort, maximumBy)
import Text.Printf
import Data.Ord (comparing)
import Data.Char (ord)
import Data.Map (Map, fromListWith, toList, findWithDefault)


average :: Fractional a => [a] -> a
-- Perform encryption or decryption, depending on f.
average as = sum as / fromIntegral (length as)
crypt f key = map toLetter . zipWith f (cycle key)
where toLetter = chr . (+) (ord 'A')


-- Create a map from each entry in list to the number of occurrences of
-- Encrypt or decrypt one letter.
-- that entry in the list.
enc k c = (ord k + ord c) `mod` 26
countEntries :: Ord a => [a] -> Map a Int
dec k c = (ord c - ord k) `mod` 26
countEntries = fromListWith (+) . fmap (,1)


-- Given a key, encrypt or decrypt an input string.
-- Break a string up into substrings of n chars.
breakup :: Int -> [a] -> [[a]]
encrypt = crypt enc
breakup _ [] = []
decrypt = crypt dec
breakup n as =
let (h, r) = splitAt n as
in h:breakup n r


-- Convert a string to have only upper case letters.
-- Dole out elements of a string over a n element distribution.
distribute :: [a] -> Int -> [[a]]
convert = map toUpper . filter isLetter
distribute as n = transpose $ breakup n as

-- The probability that members of a pair of characters taken randomly
-- from a given string are equal.
coincidence :: (Ord a, Fractional b) => [a] -> b
coincidence str =
let charCounts = snd <$> toList (countEntries str)
strln = length str
d = fromIntegral $ strln * (strln - 1)
n = fromIntegral $ sum $ fmap (\cc -> cc * (cc-1)) charCounts
in n / d

-- Use the average probablity of coincidence for all the members of
-- a distribution to rate the distribution - the higher the better.
-- The correlation increases artificially for smaller
-- pieces/longer keys, so weigh against them a little
rate :: (Ord a, Fractional b) => [[a]] -> b
rate d = average (fmap coincidence d) - fromIntegral (length d) / 3000.0

-- Multiply elements of lists together and add up the results.
dot :: Num a => [a] -> [a] -> a
dot v0 v1 = sum $ zipWith (*) v0 v1

-- Given two lists of floats, rotate one of them by the number of
-- characters indicated by letter and then 'dot' them together.
rotateAndDot :: Num a => [a] -> [a] -> Char -> a
rotateAndDot v0 v1 letter = dot v0 (drop (ord letter - ord 'A') (cycle v1))

-- Find decoding offset that results in best match
-- between actual char frequencies and expected frequencies.
getKeyChar :: RealFrac a => [a] -> String -> Char
getKeyChar expected sample =
let charCounts = countEntries sample
countInSample c = findWithDefault 0 c charCounts
actual = fmap (fromIntegral . countInSample) ['A'..'Z']
in maximumBy (comparing $ rotateAndDot expected actual) ['A'..'Z']


main = do
main = do
let key = "VIGENERECIPHER"
let cr = filter (/=' ') crypt
text = "Beware the Jabberwock, my son! The jaws that bite, "
-- Assume that if there are less than 20 characters
++ "the claws that catch!"
-- per column, the key's too long to guess
distributions = fmap (distribute cr) [1..length cr `div` 20]
encr = encrypt key $ convert text
bestDistribution = maximumBy (comparing rate) distributions
decr = decrypt key encr
key = fmap (getKeyChar englishFrequencies) bestDistribution
printf " Input: %s\n Key: %s\nEncrypted: %s\nDecrypted: %s\n"
alphaSum a b = ['A'..'Z'] !! ((ord b - ord a) `mod` 26)
text key encr decr</lang>
mapM_ putStrLn ["Key: " ++ key, "Decrypted Text: " ++ zipWith alphaSum (cycle key) cr]

englishFrequencies =
[ 0.08167, 0.01492, 0.02782, 0.04253,
0.12702, 0.02228, 0.02015, 0.06094,
0.06966, 0.00153, 0.00772, 0.04025,
0.02406, 0.06749, 0.07507, 0.01929,
0.00095, 0.05987, 0.06327, 0.09056,
0.02758, 0.00978, 0.02360, 0.00150,
0.01974, 0.00074 ]

crypt = "\
\MOMUD EKAPV TQEFM OEVHP AJMII CDCTI FGYAG JSPXY ALUYM NSMYH\
\VUXJE LEPXJ FXGCM JHKDZ RYICU HYPUS PGIGM OIYHF WHTCQ KMLRD\
\ITLXZ LJFVQ GHOLW CUHLO MDSOE KTALU VYLNZ RFGBX PHVGA LWQIS\
\FGRPH JOOFW GUBYI LAPLA LCAFA AMKLG CETDW VOELJ IKGJB XPHVG\
\ALWQC SNWBU BYHCU HKOCE XJEYK BQKVY KIIEH GRLGH XEOLW AWFOJ\
\ILOVV RHPKD WIHKN ATUHN VRYAQ DIVHX FHRZV QWMWV LGSHN NLVZS\
\JLAKI FHXUF XJLXM TBLQV RXXHR FZXGV LRAJI EXPRV OSMNP KEPDT\
\LPRWM JAZPK LQUZA ALGZX GVLKL GJTUI ITDSU REZXJ ERXZS HMPST\
\MTEOE PAPJH SMFNB YVQUZ AALGA YDNMP AQOWT UHDBV TSMUE UIMVH\
\QGVRW AEFSP EMPVE PKXZY WLKJA GWALT VYYOB YIXOK IHPDS EVLEV\
\RVSGB JOGYW FHKBL GLXYA MVKIS KIEHY IMAPX UOISK PVAGN MZHPW\
\TTZPV XFCCD TUHJH WLAPF YULTB UXJLN SIJVV YOVDJ SOLXG TGRVO\
\SFRII CTMKO JFCQF KTINQ BWVHG TENLH HOGCS PSFPV GJOKM SIFPR\
\ZPAAS ATPTZ FTPPD PORRF TAXZP KALQA WMIUD BWNCT LEFKO ZQDLX\
\BUXJL ASIMR PNMBF ZCYLV WAPVF QRHZV ZGZEF KBYIO OFXYE VOWGB\
\BXVCB XBAWG LQKCM ICRRX MACUO IKHQU AJEGL OIJHH XPVZW JEWBA\
\FWAML ZZRXJ EKAHV FASMU LVVUT TGK\
\"</syntaxhighlight>
{{out}}
{{out}}
<pre style="font-size:80%">
<pre>
Key: THECHESHIRECAT
Input: Beware the Jabberwock, my son! The jaws that bite, the claws that catch!
Decrypted Text: THISWASTHEPOEMTHATALICEREADJABBERWOCKYTWASBRILLIGANDTHESLITHYTOVESDIDGYREANDGIMBLEINTHEWABEALLMIMSYWERETHEBOROGOVESANDTHEMOMERATHSOUTGRABEBEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCHBEWARETHEJUBJUBBIRDANDSHUNTHEFRUMIOUSBANDERSNATCHHETOOKHISVORPALSWORDINHANDLONGTIMETHEMANXOMEFOEHESOUGHTSORESTEDHEBYTHETUMTUMTREEANDSTOODAWHILEINTHOUGHTANDASINUFFISHTHOUGHTHESTOODTHEJABBERWOCKWITHEYESOFFLAMECAMEWHIFFLINGTHROUGHTHETULGEYWOODANDBURBLEDASITCAMEONETWOONETWOANDTHROUGHANDTHROUGHTHEVORPALBLADEWENTSNICKERSNACKHELEFTITDEADANDWITHITSHEADHEWENTGALUMPHINGBACKANDHASTTHOUSLAINTHEJABBERWOCKCOMETOMYARMSMYBEAMISHBOYOFRABJOUSDAYCALLOOHCALLAYHECHORTLEDINHISJOYTWASBRILLIGANDTHESLITHYTOVESDIDGYREANDGIMBLEINTHEWABEALLMIMSYWERETHEBOROGOVESANDTHEMOMERATHSOUTGRABEITSEEMSVERYPRETTYSHESAIDWHENSHEHADFINISHEDITBUTITSRATHERHARDTOUNDERSTAND
Key: VIGENERECIPHER
Encrypted: WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY
Decrypted: BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH
</pre>
</pre>


=={{header|Icon}} and {{header|Unicon}}==
=={{header|J}}==
<lang Icon>procedure main()
ptext := "Beware the Jabberwock, my son! The jaws that bite, the claws that catch!"
write("Key = ",ekey := "VIGENERECIPHER")
write("Plain Text = ",ptext)
write("Normalized = ",GFormat(ptext := NormalizeText(ptext)))
write("Enciphered = ",GFormat(ctext := Vignere("e",ekey,ptext)))
write("Deciphered = ",GFormat(ptext := Vignere("d",ekey,ctext)))
end


Implementation:
procedure Vignere(mode,ekey,ptext,alpha) #: Vignere cipher
<syntaxhighlight lang=J>NB. https://en.wikipedia.org/wiki/Kasiski_examination
/alpha := &ucase # default
kasiski=: {{
if *alpha ~= *cset(alpha) then runerr(205,alpha) # no dups
grams=. ({: #"1~1 < ;@{.)|:(#/.~;"0~.) g=. 3 <\ y
alpha ||:= alpha # unobstructed
deltas=. ;grams (2 -~/\ I.@E.)L:0 enc
{:,{.\:~(#/.~,.~.)1 -.~,+./~ deltas
}}


NB. https://en.wikipedia.org/wiki/Letter_frequency
every ctext:="" & p:=ptext[i := 1 to *ptext] & k:=ekey[(i-1)%*ekey+1] do
AZ=: 8 u: 65+i.26
case mode of {
lfreq=: 0.01*do{{)n
"e"|"encrypt":
8.2 1.5 2.8 4.3 13 2.2 2 6.1 7 0.15
ctext||:=map(p,alpha[1+:*alpha/2],alpha[find(k,alpha)+:(*alpha/2)])
0.77 4 2.4 6.7 7.5 1.9 0.095 6 6.3 9.1
"d"|"decrypt":
2.8 0.98 2.4 0.15 2 0.074
ctext||:=map(p,alpha[find(k,alpha)+:(*alpha/2)],alpha[1+:*alpha/2])
}}-.LF
default: runerr(205,mode)
}
return ctext
end</lang>


The following helper procedures will be of general use with classical cryptography tasks.
<lang Icon>
link strings


caesarkey=: {{
procedure NormalizeText(ptext,alpha) #: text/case classical crypto helper
freqs=. (<:#/.~AZ,y)%#y=. y ([-.-.) AZ
/alpha := &ucase # default
AZ{~(i. <./)lfreq +/&.:*:@:-"1 (i.26)|."0 1 freqs
if &lcase === (alpha := cset(alpha)) then ptext := map(ptext) # lower
}}
if &ucase === alpha then ptext := map(ptext,&lcase,&ucase) # upper
vigenerekey=: {{ caesarkey"1|:(-kasiski y) ]\y }}
return deletec(ptext,&cset--alpha) # only alphas
end


uncaesar=: {{ 26&|@-&(AZ i.x)&.(AZ&i.) y }}"0 1
procedure GFormat(text) #: 5 letter group formatting helper
unvigenere=: {{ ' '-.~,x uncaesar"0 1&.|:(-#x) ]\y }}</syntaxhighlight>
text ? (s := "", until pos(0) do s ||:= " " || move(5)|tab(0))
return s[2:0]
end</lang>


Here, kasiski finds all 3-grams (sequences of three adjacent letters) which appear more than once, finds all of the distances between nearest pairs of these sequences, and then further pairs each of these distances with all other distances, finding the greatest common divisor of those distance pairs. Finally, these LCDs are ordered by how many times they appear and the most frequent LCD is taken as the kasiski result.
{{libheader|Icon Programming Library}}
[http://www.cs.arizona.edu/icon/library/src/procs/strings.icn strings.icn provides deletec]


uncaesar works by finding the frequency of occurrence of each letter of the alphabet (in alphabetical order), and then each of the 26 rotations of that sequence are compared with a text frequency alphabet (obtained from a wikipedia table). The rotation with the least root-mean-square sum of differences is chosen as the correct location, and its index is reported as a letter of the alphabet (0=A, 1=B, etc.)
{{out}}
<pre>Key = VIGENERECIPHER
Plain Text = Beware the Jabberwock, my son! The jaws that bite, the claws that catch!
Normalized = BEWAR ETHEJ ABBER WOCKM YSONT HEJAW STHAT BITET HECLA WSTHA TCATCH
Enciphered = WMCEE IKLGR PIFVM EUGXQ PWQVI OIAVE YXUEK FKBTA LVXTG AFXYE VKPAGY
Deciphered = BEWAR ETHEJ ABBER WOCKM YSONT HEJAW STHAT BITET HECLA WSTHA TCATCH</pre>


(And, the length provided by kasiski is used to break out the sequences to be analyzed by uncaesar...)
=={{header|J}}==
'''Solution:'''<br>
Using <code>vig</code> from the [[j:Addons/convert/misc/vig|convert/misc/vig addon]]:
<lang j>NB.*vig c Vigenère cipher
NB. cipher=. key 0 vig charset plain
NB. plain=. key 1 vig charset cipher
vig=: conjunction define
:
r=. (#y) $ n i.x
n {~ (#n) | (r*_1^m) + n i.y
)


Task example:
ALPHA=: (65,:26) ];.0 a. NB. Character Set

preprocess=: (#~ e.&ALPHA)@toupper NB. force uppercase and discard non-alpha chars
<syntaxhighlight lang=J>enc=: {{)n
vigEncryptRC=: 0 vig ALPHA preprocess
MOMUD EKAPV TQEFM OEVHP AJMII CDCTI FGYAG JSPXY ALUYM NSMYH
vigDecryptRC=: 1 vig ALPHA preprocess</lang>
VUXJE LEPXJ FXGCM JHKDZ RYICU HYPUS PGIGM OIYHF WHTCQ KMLRD
ITLXZ LJFVQ GHOLW CUHLO MDSOE KTALU VYLNZ RFGBX PHVGA LWQIS
'''Example Use:'''
FGRPH JOOFW GUBYI LAPLA LCAFA AMKLG CETDW VOELJ IKGJB XPHVG
<lang j> 'VIGENERECIPHER' vigEncryptRC 'Beware the Jabberwock, my son! The jaws that bite, the claws that catch!'
ALWQC SNWBU BYHCU HKOCE XJEYK BQKVY KIIEH GRLGH XEOLW AWFOJ
WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY
ILOVV RHPKD WIHKN ATUHN VRYAQ DIVHX FHRZV QWMWV LGSHN NLVZS
'VIGENERECIPHER' vigDecryptRC 'WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY'
JLAKI FHXUF XJLXM TBLQV RXXHR FZXGV LRAJI EXPRV OSMNP KEPDT
BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH</lang>
LPRWM JAZPK LQUZA ALGZX GVLKL GJTUI ITDSU REZXJ ERXZS HMPST
MTEOE PAPJH SMFNB YVQUZ AALGA YDNMP AQOWT UHDBV TSMUE UIMVH
QGVRW AEFSP EMPVE PKXZY WLKJA GWALT VYYOB YIXOK IHPDS EVLEV
RVSGB JOGYW FHKBL GLXYA MVKIS KIEHY IMAPX UOISK PVAGN MZHPW
TTZPV XFCCD TUHJH WLAPF YULTB UXJLN SIJVV YOVDJ SOLXG TGRVO
SFRII CTMKO JFCQF KTINQ BWVHG TENLH HOGCS PSFPV GJOKM SIFPR
ZPAAS ATPTZ FTPPD PORRF TAXZP KALQA WMIUD BWNCT LEFKO ZQDLX
BUXJL ASIMR PNMBF ZCYLV WAPVF QRHZV ZGZEF KBYIO OFXYE VOWGB
BXVCB XBAWG LQKCM ICRRX MACUO IKHQU AJEGL OIJHH XPVZW JEWBA
FWAML ZZRXJ EKAHV FASMU LVVUT TGK
}}-.LF,' '

vigenerekey enc
THECHESHIRECAT
_80]\'THECHESHIRECAT' unvigenere enc
THISWASTHEPOEMTHATALICEREADJABBERWOCKYTWASBRILLIGANDTHESLITHYTOVESDIDGYREANDGIMB
LEINTHEWABEALLMIMSYWERETHEBOROGOVESANDTHEMOMERATHSOUTGRABEBEWARETHEJABBERWOCKMYS
ONTHEJAWSTHATBITETHECLAWSTHATCATCHBEWARETHEJUBJUBBIRDANDSHUNTHEFRUMIOUSBANDERSNA
TCHHETOOKHISVORPALSWORDINHANDLONGTIMETHEMANXOMEFOEHESOUGHTSORESTEDHEBYTHETUMTUMT
REEANDSTOODAWHILEINTHOUGHTANDASINUFFISHTHOUGHTHESTOODTHEJABBERWOCKWITHEYESOFFLAM
ECAMEWHIFFLINGTHROUGHTHETULGEYWOODANDBURBLEDASITCAMEONETWOONETWOANDTHROUGHANDTHR
OUGHTHEVORPALBLADEWENTSNICKERSNACKHELEFTITDEADANDWITHITSHEADHEWENTGALUMPHINGBACK
ANDHASTTHOUSLAINTHEJABBERWOCKCOMETOMYARMSMYBEAMISHBOYOFRABJOUSDAYCALLOOHCALLAYHE
CHORTLEDINHISJOYTWASBRILLIGANDTHESLITHYTOVESDIDGYREANDGIMBLEINTHEWABEALLMIMSYWER
ETHEBOROGOVESANDTHEMOMERATHSOUTGRABEITSEEMSVERYPRETTYSHESAIDWHENSHEHADFINISHEDIT
BUTITSRATHERHARDTOUNDERSTANDWYTWITSJWYAH
</syntaxhighlight>

As an aside, note that we could go directly from encrypted text to decrypted text, without showing the key. For example, using:
<syntaxhighlight lang=J>decaesar=: {{
freqs=. (<:#/.~AZ,y)%#y=. y ([-.-.) AZ
ndx=. (i. <./)lfreq +/&.:*:@:-"1 (i.26)|."0 1 freqs
26&|@-&ndx&.(AZ&i.) y
}}
devigenere=: {{ ' '-.~,decaesar"1&.|:(-kasiski y) ]\y }}</syntaxhighlight>

That said, it's also worth noting that noise issues mean that if this were to be used in practical contexts the approach should instead be to expose more intermediate results, rather than less, with a special focus on the representations of frequency distributions (here, we're always picking the first alternative, but it's vaguely plausible that a different alternative might actually be useful in some cases).


=={{header|Java}}==
=={{header|Java}}==
{{trans|D}}
{{trans|C}}
<lang java>public class VigenereCipher {
public static void main(String[] args) {
String key = "VIGENERECIPHER";
String ori = "Beware the Jabberwock, my son! The jaws that bite, the claws that catch!";
String enc = encrypt(ori, key);
System.out.println(enc);
System.out.println(decrypt(enc, key));
}


<syntaxhighlight lang="java">public class Vig{
static String encrypt(String text, final String key) {
String res = "";
static String encodedMessage =
"MOMUD EKAPV TQEFM OEVHP AJMII CDCTI FGYAG JSPXY ALUYM NSMYH VUXJE LEPXJ FXGCM JHKDZ RYICU HYPUS PGIGM OIYHF WHTCQ KMLRD ITLXZ LJFVQ GHOLW CUHLO MDSOE KTALU VYLNZ RFGBX PHVGA LWQIS FGRPH JOOFW GUBYI LAPLA LCAFA AMKLG CETDW VOELJ IKGJB XPHVG ALWQC SNWBU BYHCU HKOCE XJEYK BQKVY KIIEH GRLGH XEOLW AWFOJ ILOVV RHPKD WIHKN ATUHN VRYAQ DIVHX FHRZV QWMWV LGSHN NLVZS JLAKI FHXUF XJLXM TBLQV RXXHR FZXGV LRAJI EXPRV OSMNP KEPDT LPRWM JAZPK LQUZA ALGZX GVLKL GJTUI ITDSU REZXJ ERXZS HMPST MTEOE PAPJH SMFNB YVQUZ AALGA YDNMP AQOWT UHDBV TSMUE UIMVH QGVRW AEFSP EMPVE PKXZY WLKJA GWALT VYYOB YIXOK IHPDS EVLEV RVSGB JOGYW FHKBL GLXYA MVKIS KIEHY IMAPX UOISK PVAGN MZHPW TTZPV XFCCD TUHJH WLAPF YULTB UXJLN SIJVV YOVDJ SOLXG TGRVO SFRII CTMKO JFCQF KTINQ BWVHG TENLH HOGCS PSFPV GJOKM SIFPR ZPAAS ATPTZ FTPPD PORRF TAXZP KALQA WMIUD BWNCT LEFKO ZQDLX BUXJL ASIMR PNMBF ZCYLV WAPVF QRHZV ZGZEF KBYIO OFXYE VOWGB BXVCB XBAWG LQKCM ICRRX MACUO IKHQU AJEGL OIJHH XPVZW JEWBA FWAML ZZRXJ EKAHV FASMU LVVUT TGK";
text = text.toUpperCase();
for (int i = 0, j = 0; i < text.length(); i++) {
final static double freq[] = {
char c = text.charAt(i);
0.08167, 0.01492, 0.02782, 0.04253, 0.12702, 0.02228, 0.02015,
if (c < 'A' || c > 'Z') continue;
0.06094, 0.06966, 0.00153, 0.00772, 0.04025, 0.02406, 0.06749,
res += (char)((c + key.charAt(j) - 2 * 'A') % 26 + 'A');
0.07507, 0.01929, 0.00095, 0.05987, 0.06327, 0.09056, 0.02758,
j = ++j % key.length();
0.00978, 0.02360, 0.00150, 0.01974, 0.00074
};

public static void main(String[] args) {
int lenghtOfEncodedMessage = encodedMessage.length();
char[] encoded = new char [lenghtOfEncodedMessage] ;
char[] key = new char [lenghtOfEncodedMessage] ;

encodedMessage.getChars(0, lenghtOfEncodedMessage, encoded, 0);
int txt[] = new int[lenghtOfEncodedMessage];
int len = 0, j;

double fit, best_fit = 1e100;
for (j = 0; j < lenghtOfEncodedMessage; j++)
if (Character.isUpperCase(encoded[j]))
txt[len++] = encoded[j] - 'A';
for (j = 1; j < 30; j++) {
fit = freq_every_nth(txt, len, j, key);
System.out.printf("%f, key length: %2d ", fit, j);
System.out.print(key);
if (fit < best_fit) {
best_fit = fit;
System.out.print(" <--- best so far");
}
}
return res;
System.out.print("\n");

}
}
}



static String decrypt(String text, final String key) {
static String decrypt(String text, final String key) {
Line 1,309: Line 1,131:
return res;
return res;
}
}
}</lang>


static int best_match(final double []a, final double []b) {
<pre>WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY
double sum = 0, fit, d, best_fit = 1e100;
BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH</pre>
int i, rotate, best_rotate = 0;

for (i = 0; i < 26; i++)
=={{header|JavaScript}}==
sum += a[i];
<lang javascript>// helpers
for (rotate = 0; rotate < 26; rotate++) {
// helper
fit = 0;
function ordA(a) {
for (i = 0; i < 26; i++) {
return a.charCodeAt(0) - 65;
d = a[(i + rotate) % 26] / sum - b[i];
fit += d * d / b[i];
}
if (fit < best_fit) {
best_fit = fit;
best_rotate = rotate;
}
}
return best_rotate;
}
}

static double freq_every_nth(final int []msg, int len, int interval, char[] key) {
// vigenere
double sum, d, ret;
function vigenere(text, key, decode) {
double [] accu = new double [26];
var i = 0, b;
double [] out = new double [26];
key = key.toUpperCase().replace(/[^A-Z]/g, '');
int i, j, rot;
return text.toUpperCase().replace(/[^A-Z]/g, '').replace(/[A-Z]/g, function(a) {
b = key[i++ % key.length];
for (j = 0; j < interval; j++) {
return String.fromCharCode(((ordA(a) + (decode ? 26 - ordA(b) : ordA(b))) % 26 + 65));
for (i = 0; i < 26; i++)
});
out[i] = 0;
}
for (i = j; i < len; i += interval)

out[msg[i]]++;
// example
rot = best_match(out, freq);
var text = "The quick brown fox Jumped over the lazy Dog the lazy dog lazy dog dog";
try{
var key = 'alex';
key[j] = (char)(rot + 'A');
var enc = vigenere(text,key);
} catch (Exception e) {
var dec = vigenere(enc,key,true);
System.out.print(e.getMessage());

}
console.log(enc);
for (i = 0; i < 26; i++)
console.log(dec);</lang>
accu[i] += out[(i + rot) % 26];

}
=={{header|Jsish}}==
From Javascript entry.
for (i = 0, sum = 0; i < 26; i++)
<lang javascript>/* Vigenère cipher, in Jsish */
sum += accu[i];
"use strict";

for (i = 0, ret = 0; i < 26; i++) {
function ordA(a:string):number {
return a.charCodeAt(0) - 65;
d = accu[i] / sum - freq[i];
ret += d * d / freq[i];
}
key[interval] = '\0';
return ret;
}
}
// vigenere
function vigenereCipher(text:string, key:string, decode:boolean=false):string {
var i = 0, b;
key = key.toUpperCase().replace(/[^A-Z]/g, '');
return text.toUpperCase().replace(/[^A-Z]/g, '').replace(/[A-Z]/g,
function(a:string, idx:number, str:string) {
b = key[i++ % key.length];
return String.fromCharCode(((ordA(a) + (decode ? 26 - ordA(b) : ordA(b))) % 26 + 65));
});
}
}
</syntaxhighlight>

provide('vigenereCipher', 1);

if (Interp.conf('unitTest')) {
var text = "The quick brown fox Jumped over the lazy Dog the lazy dog lazy dog dog";
var key = 'jsish';
var enc = vigenereCipher(text, key);
; text;
; enc;
; vigenereCipher(enc, key, true);
}

/*
=!EXPECTSTART!=
text ==> The quick brown fox Jumped over the lazy Dog the lazy dog lazy dog dog
enc ==> CZMIBRUSTYXOVXVGBCEWNVWNLALPWSJRGVVPLPWSJRGVVPDIRFMGOVVP
vigenere(enc, key, true) ==> THEQUICKBROWNFOXJUMPEDOVERTHELAZYDOGTHELAZYDOGLAZYDOGDOG
=!EXPECTEND!=
*/</lang>

{{out}}
<pre>prompt$ jsish -u vigenereCipher.jsi
[PASS] vigenereCipher.jsi</pre>


=={{header|Julia}}==
=={{header|Julia}}==
{{works with|Julia|0.6}}
<lang Julia>function encrypt(msg::AbstractString, key::AbstractString)
msg = uppercase(join(filter(isalpha, collect(msg))))
key = uppercase(join(filter(isalpha, collect(key))))
msglen = length(msg)
keylen = length(key)


<syntaxhighlight lang="julia"># ciphertext block {{{1
if keylen < msglen
const ciphertext = filter(isalpha, """
key = repeat(key, div(msglen - keylen, keylen) + 2)[1:msglen]
MOMUD EKAPV TQEFM OEVHP AJMII CDCTI FGYAG JSPXY ALUYM NSMYH
end
VUXJE LEPXJ FXGCM JHKDZ RYICU HYPUS PGIGM OIYHF WHTCQ KMLRD
ITLXZ LJFVQ GHOLW CUHLO MDSOE KTALU VYLNZ RFGBX PHVGA LWQIS
FGRPH JOOFW GUBYI LAPLA LCAFA AMKLG CETDW VOELJ IKGJB XPHVG
ALWQC SNWBU BYHCU HKOCE XJEYK BQKVY KIIEH GRLGH XEOLW AWFOJ
ILOVV RHPKD WIHKN ATUHN VRYAQ DIVHX FHRZV QWMWV LGSHN NLVZS
JLAKI FHXUF XJLXM TBLQV RXXHR FZXGV LRAJI EXPRV OSMNP KEPDT
LPRWM JAZPK LQUZA ALGZX GVLKL GJTUI ITDSU REZXJ ERXZS HMPST
MTEOE PAPJH SMFNB YVQUZ AALGA YDNMP AQOWT UHDBV TSMUE UIMVH
QGVRW AEFSP EMPVE PKXZY WLKJA GWALT VYYOB YIXOK IHPDS EVLEV
RVSGB JOGYW FHKBL GLXYA MVKIS KIEHY IMAPX UOISK PVAGN MZHPW
TTZPV XFCCD TUHJH WLAPF YULTB UXJLN SIJVV YOVDJ SOLXG TGRVO
SFRII CTMKO JFCQF KTINQ BWVHG TENLH HOGCS PSFPV GJOKM SIFPR
ZPAAS ATPTZ FTPPD PORRF TAXZP KALQA WMIUD BWNCT LEFKO ZQDLX
BUXJL ASIMR PNMBF ZCYLV WAPVF QRHZV ZGZEF KBYIO OFXYE VOWGB
BXVCB XBAWG LQKCM ICRRX MACUO IKHQU AJEGL OIJHH XPVZW JEWBA
FWAML ZZRXJ EKAHV FASMU LVVUT TGK
""")
# }}}


# character frequencies {{{1
enc = Vector{Char}(msglen)
const letters = Dict{Char, Float32}(

'E' => 12.702,
@inbounds for i in 1:length(msg)
'T' => 9.056,
enc[i] = Char((Int(msg[i]) + Int(key[i]) - 130) % 26 + 65)
end
'A' => 8.167,
'O' => 7.507,

return join(enc)
'I' => 6.966,
'N' => 6.749,
end
'S' => 6.327,
'H' => 6.094,
'R' => 5.987,
'D' => 4.253,
'L' => 4.025,
'C' => 2.782,
'U' => 2.758,
'M' => 2.406,
'W' => 2.361,
'F' => 2.228,
'G' => 2.015,
'Y' => 1.974,
'P' => 1.929,
'B' => 1.492,
'V' => 0.978,
'K' => 0.772,
'J' => 0.153,
'X' => 0.150,
'Q' => 0.095,
'Z' => 0.074)
const digraphs = Dict{AbstractString, Float32}(
"TH" => 15.2,
"HE" => 12.8,
"IN" => 9.4,
"ER" => 9.4,
"AN" => 8.2,
"RE" => 6.8,
"ND" => 6.3,
"AT" => 5.9,
"ON" => 5.7,
"NT" => 5.6,
"HA" => 5.6,
"ES" => 5.6,
"ST" => 5.5,
"EN" => 5.5,
"ED" => 5.3,
"TO" => 5.2,
"IT" => 5.0,
"OU" => 5.0,
"EA" => 4.7,
"HI" => 4.6,
"IS" => 4.6,
"OR" => 4.3,
"TI" => 3.4,
"AS" => 3.3,
"TE" => 2.7,
"ET" => 1.9,
"NG" => 1.8,
"OF" => 1.6,
"AL" => 0.9,
"DE" => 0.9,
"SE" => 0.8,
"LE" => 0.8,
"SA" => 0.6,
"SI" => 0.5,
"AR" => 0.4,
"VE" => 0.4,
"RA" => 0.4,
"LD" => 0.2,
"UR" => 0.2)
const trigraphs = Dict{AbstractString, Float32}(
"THE" => 18.1,
"AND" => 7.3,
"ING" => 7.2,
"ION" => 4.2,
"ENT" => 4.2,
"HER" => 3.6,
"FOR" => 3.4,
"THA" => 3.3,
"NTH" => 3.3,
"INT" => 3.2,
"TIO" => 3.1,
"ERE" => 3.1,
"TER" => 3.0,
"EST" => 2.8,
"ERS" => 2.8,
"HAT" => 2.6,
"ATI" => 2.6,
"ATE" => 2.5,
"ALL" => 2.5,
"VER" => 2.4,
"HIS" => 2.4,
"HES" => 2.4,
"ETH" => 2.4,
"OFT" => 2.2,
"STH" => 2.1,
"RES" => 2.1,
"OTH" => 2.1,
"ITH" => 2.1,
"FTH" => 2.1,
"ONT" => 2.0)
# 1}}}


function decrypt(enc::AbstractString, key::AbstractString)
function decrypt(enc::ASCIIString, key::ASCIIString)
const enclen = length(enc)
enc = uppercase(join(filter(isalpha, collect(enc))))
const keylen = length(key)
key = uppercase(join(filter(isalpha, collect(key))))
msglen = length(enc)
keylen = length(key)


if keylen < msglen
if keylen < enclen
key = repeat(key, div(msglen - keylen, keylen) + 2)[1:msglen]
key = (key^(div(enclen - keylen, keylen) + 2))[1:enclen]
end
end


msg = Vector{Char}(msglen)
msg = Array(Char, enclen)


@inbounds for i in 1:length(enc)
for i=1:enclen
msg[i] = Char((Int(enc[i]) - Int(key[i]) + 26) % 26 + 65)
msg[i] = Char((Int(enc[i]) - Int(key[i]) + 26) % 26 + 65)
end
end


msg::Array{Char, 1}
return join(msg)
end
end


function cryptanalyze(enc::ASCIIString; maxkeylen::Integer = 20)
const messages = ("Attack at dawn.", "Don't attack.", "The war is over.")
const key = "LEMON"
const enclen = length(enc)
maxkey = ""
maxdec = ""
maxscore = 0.0


for keylen=1:maxkeylen
for msg in messages
enc = encrypt(msg, key)
key = Array(Char, keylen)
idx = filter(x -> x % keylen == 0, 1:enclen) - keylen + 1
dec = decrypt(enc, key)
println("Original: $msg\n -> encrypted: $enc\n -> decrypted: $dec")
end</lang>


for i=1:keylen
{{out}}
maxsubscore = 0.0


for j='A':'Z'
<pre>Original: Attack at dawn.
subscore = 0.0
-> encrypted: LXFOPVEFRNHR
-> decrypted: ATTACKATDAWN
Original: Don't attack.
-> encrypted: OSZHNEXMQX
-> decrypted: DONTATTACK
Original: The war is over.
-> encrypted: ELQKNCMECIPV
-> decrypted: THEWARISOVER</pre>


for k in decrypt(enc[idx], ascii(string(j)))
=={{header|Kotlin}}==
subscore += get(letters, k, 0.0)
<lang scala>// version 1.1.3
end


if subscore > maxsubscore
fun vigenere(text: String, key: String, encrypt: Boolean = true): String {
maxsubscore = subscore
val t = if (encrypt) text.toUpperCase() else text
key[i] = j
val sb = StringBuilder()
var ki = 0
end
for (c in t) {
end
if (c !in 'A'..'Z') continue
val ci = if (encrypt)
(c.toInt() + key[ki].toInt() - 130) % 26
else
(c.toInt() - key[ki].toInt() + 26) % 26
sb.append((ci + 65).toChar())
ki = (ki + 1) % key.length
}
return sb.toString()
}


idx += 1
fun main(args: Array<String>) {
val key = "VIGENERECIPHER"
end
val text = "Beware the Jabberwock, my son! The jaws that bite, the claws that catch!"
val encoded = vigenere(text, key)
println(encoded)
val decoded = vigenere(encoded, key, false)
println(decoded)
}</lang>


key = join(key)
{{out}}
const dec = decrypt(enc, key)
<pre>
score = 0.0
WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY
BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH
</pre>


for i in dec
=={{header|Liberty BASIC}}==
score += get(letters, i, 0.0)
<lang lb>
end
ori$ = "Beware the Jabberwock, my son! The jaws that bite, the claws that catch!"
key$ = filter$("vigenerecipher")
print ori$
print key$
enc$ = encrypt$(ori$, key$)
print enc$
dec$ = decrypt$(enc$, key$)
print dec$


for i=1:enclen - 2
end
const digraph = string(dec[i], dec[i + 1])
const trigraph = string(dec[i], dec[i + 1], dec[i + 2])


if haskey(digraphs, digraph)
function encrypt$(text$, key$)
score += 2 * get(digraphs, digraph, 0.0)
flt$ = filter$(text$)
encrypt$ = ""
end
j = 1
for i = 1 to len(flt$)
m$ = mid$(flt$, i, 1)
m = asc(m$)-asc("A")
k$ = mid$(key$, j, 1)
k = asc(k$)-asc("A")
j = (j mod len(key$)) + 1
c = (m + k) mod 26
c$=chr$(asc("A")+c)
encrypt$=encrypt$+c$
next
end function


if haskey(trigraphs, trigraph)
function decrypt$(flt$, key$)
score += 3 * get(trigraphs, trigraph, 0.0)
decrypt$ = ""
j = 1
end
for i = 1 to len(flt$)
end
m$ = mid$(flt$, i, 1)
m = asc(m$)-asc("A")
k$ = mid$(key$, j, 1)
k = asc(k$)-asc("A")
j = (j mod len(key$)) + 1
c = (m - k + 26) mod 26
c$=chr$(asc("A")+c)
decrypt$=decrypt$+c$
next
end function

function filter$(ori$)
'a..z A..Z go caps, other skipped
filter$=""
for i = 1 to len(ori$)
c$ = upper$(mid$(ori$,i,1))
if instr("ABCDEFGHIJKLMNOPQRSTUVWXYZ", c$) then filter$ = filter$ + c$
next
end function
</lang>
Beware the Jabberwock, my son! The jaws that bite, the claws that catch!
VIGENERECIPHER
WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY
BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH

=={{header|Lua}}==
<lang lua>function Encrypt( _msg, _key )
local msg = { _msg:upper():byte( 1, -1 ) }
local key = { _key:upper():byte( 1, -1 ) }
local enc = {}


local j, k = 1, 1
if score > maxscore
for i = 1, #msg do
maxscore = score
maxkey = key
if msg[i] >= string.byte('A') and msg[i] <= string.byte('Z') then
maxdec = dec
enc[k] = ( msg[i] + key[j] - 2*string.byte('A') ) % 26 + string.byte('A')
k = k + 1
if j == #key then j = 1 else j = j + 1 end
end
end
end
end
(maxkey, join(maxdec))::Tuple{ASCIIString, ASCIIString}
return string.char( unpack(enc) )
end
end


key, dec = cryptanalyze(ciphertext)
function Decrypt( _msg, _key )
println("key: ", key, "\n\n", dec)
local msg = { _msg:byte( 1, -1 ) }
local key = { _key:upper():byte( 1, -1 ) }
local dec = {}


# post-compilation profiling run
local j = 1
gc()
for i = 1, #msg do
t = @elapsed cryptanalyze(ciphertext)
dec[i] = ( msg[i] - key[j] + 26 ) % 26 + string.byte('A')
println("\nelapsed time: ", t, " seconds")</syntaxhighlight>
if j == #key then j = 1 else j = j + 1 end
end
return string.char( unpack(dec) )
end


{{out}}


<pre>key: THECHESHIRECAT
original = "Beware the Jabberwock, my son! The jaws that bite, the claws that catch!"
key = "VIGENERECIPHER";


THISWASTHEPOEMTHATALICEREADJABBERWOCKYTWASBRILLIGANDTHESLITHY...
encrypted = Encrypt( original, key )
decrypted = Decrypt( encrypted, key )


elapsed time: 0.042894211 seconds</pre>
print( encrypted )
print( decrypted )</lang>
<pre>WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY
BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH</pre>


=={{header|Mathematica}}==
=={{header|Kotlin}}==
{{trans|C}}
<lang Mathematica>encode[text_String, key_String] :=
This is a reasonably faithful translation of the C entry though I've restricted the key lengths examined to 26 to automatically produce the correct key and hence decrypted text. This is because the C entry examines key lengths up to 29 and a value of 28 gives a slightly better fit even though the key produced (THECHESCIRECATTHECHESHIRECAT) and resulting text don't make as much sense and so would be rejected if one were examining the candidate keys manually.
Module[{textCode, keyCode},
<syntaxhighlight lang="scala">// version 1.1.3
textCode =
Cases[ToCharacterCode[
ToUpperCase@
text], _?(IntervalMemberQ[Interval@{65, 90}, #] &)] - 65;
keyCode =
Cases[ToCharacterCode[
ToUpperCase@
key], _?(IntervalMemberQ[Interval@{65, 90}, #] &)] - 65;
keyCode =
If[Length[textCode] < Length[keyCode],
keyCode[[;; Length@textCode]],
PadRight[keyCode, Length@textCode, keyCode]];
FromCharacterCode[Mod[textCode + keyCode, 26] + 65]]


val encoded =
decode[text_String, key_String] :=
"MOMUD EKAPV TQEFM OEVHP AJMII CDCTI FGYAG JSPXY ALUYM NSMYH" +
Module[{textCode, keyCode},
"VUXJE LEPXJ FXGCM JHKDZ RYICU HYPUS PGIGM OIYHF WHTCQ KMLRD" +
textCode =
"ITLXZ LJFVQ GHOLW CUHLO MDSOE KTALU VYLNZ RFGBX PHVGA LWQIS" +
Cases[ToCharacterCode[
"FGRPH JOOFW GUBYI LAPLA LCAFA AMKLG CETDW VOELJ IKGJB XPHVG" +
ToUpperCase@
"ALWQC SNWBU BYHCU HKOCE XJEYK BQKVY KIIEH GRLGH XEOLW AWFOJ" +
text], _?(IntervalMemberQ[Interval@{65, 90}, #] &)] - 65;
"ILOVV RHPKD WIHKN ATUHN VRYAQ DIVHX FHRZV QWMWV LGSHN NLVZS" +
keyCode =
"JLAKI FHXUF XJLXM TBLQV RXXHR FZXGV LRAJI EXPRV OSMNP KEPDT" +
Cases[ToCharacterCode[
"LPRWM JAZPK LQUZA ALGZX GVLKL GJTUI ITDSU REZXJ ERXZS HMPST" +
ToUpperCase@
"MTEOE PAPJH SMFNB YVQUZ AALGA YDNMP AQOWT UHDBV TSMUE UIMVH" +
key], _?(IntervalMemberQ[Interval@{65, 90}, #] &)] - 65;
"QGVRW AEFSP EMPVE PKXZY WLKJA GWALT VYYOB YIXOK IHPDS EVLEV" +
keyCode =
"RVSGB JOGYW FHKBL GLXYA MVKIS KIEHY IMAPX UOISK PVAGN MZHPW" +
If[Length[textCode] < Length[keyCode],
"TTZPV XFCCD TUHJH WLAPF YULTB UXJLN SIJVV YOVDJ SOLXG TGRVO" +
keyCode[[;; Length@textCode]],
"SFRII CTMKO JFCQF KTINQ BWVHG TENLH HOGCS PSFPV GJOKM SIFPR" +
PadRight[keyCode, Length@textCode, keyCode]];
"ZPAAS ATPTZ FTPPD PORRF TAXZP KALQA WMIUD BWNCT LEFKO ZQDLX" +
FromCharacterCode[Mod[textCode - keyCode, 26] + 65]]</lang>
"BUXJL ASIMR PNMBF ZCYLV WAPVF QRHZV ZGZEF KBYIO OFXYE VOWGB" +
"BXVCB XBAWG LQKCM ICRRX MACUO IKHQU AJEGL OIJHH XPVZW JEWBA" +
"FWAML ZZRXJ EKAHV FASMU LVVUT TGK"


val freq = doubleArrayOf(
<pre>key = "Vigenere Cipher";
0.08167, 0.01492, 0.02782, 0.04253, 0.12702, 0.02228, 0.02015,
text = "Beware the Jabberwock, my son! The jaws that bite, the claws \
0.06094, 0.06966, 0.00153, 0.00772, 0.04025, 0.02406, 0.06749,
that catch!";
0.07507, 0.01929, 0.00095, 0.05987, 0.06327, 0.09056, 0.02758,
code = encode[text, key]
0.00978, 0.02360, 0.00150, 0.01974, 0.00074
)


fun bestMatch(a: DoubleArray): Int {
WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY
val sum = a.sum()
var bestFit = 1e100
var bestRotate = 0
for (rotate in 0..25) {
var fit = 0.0
for (i in 0..25) {
val d = a[(i + rotate) % 26] / sum - freq[i]
fit += d * d / freq[i]
}
if (fit < bestFit) {
bestFit = fit
bestRotate = rotate
}
}
return bestRotate
}


fun freqEveryNth(msg: IntArray, key: CharArray): Double {
decode[code, key]
val len = msg.size
val interval = key.size
val out = DoubleArray(26)
val accu = DoubleArray(26)
for (j in 0 until interval) {
out.fill(0.0)
for (i in j until len step interval) out[msg[i]]++
val rot = bestMatch(out)
key[j] = (rot + 65).toChar()
for (i in 0..25) accu[i] += out[(i + rot) % 26]
}
val sum = accu.sum()
var ret = 0.0
for (i in 0..25) {
val d = accu[i] / sum - freq[i]
ret += d * d / freq[i]
}
return ret
}


fun decrypt(text: String, key: String): String {
BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH
val sb = StringBuilder()
var ki = 0
for (c in text) {
if (c !in 'A'..'Z') continue
val ci = (c.toInt() - key[ki].toInt() + 26) % 26
sb.append((ci + 65).toChar())
ki = (ki + 1) % key.length
}
return sb.toString()
}


fun main(args: Array<String>) {
</pre>
val enc = encoded.replace(" ", "")
val txt = IntArray(enc.length) { enc[it] - 'A' }
var bestFit = 1e100
var bestKey = ""
val f = "%f %2d %s"
println(" Fit Length Key")
for (j in 1..26) {
val key = CharArray(j)
val fit = freqEveryNth(txt, key)
val sKey = key.joinToString("")
print(f.format(fit, j, sKey))
if (fit < bestFit) {
bestFit = fit
bestKey = sKey
print(" <--- best so far")
}
println()
}
println()
println("Best key : $bestKey")
println("\nDecrypted text:\n${decrypt(enc, bestKey)}")
}</syntaxhighlight>


{{out}}
=={{header|NetRexx}}==
<pre>
<lang NetRexx>/* NetRexx */
Fit Length Key
options replace format comments java crossref savelog symbols nobinary
2.984348 1 E <--- best so far
2.483684 2 EC <--- best so far
2.642487 3 TEE
1.976651 4 THEC <--- best so far
2.356881 5 EEEPU
2.203129 6 TCECEC
1.051163 7 THECSAS <--- best so far
1.645763 8 TJQGAHET
2.001380 9 VEIZSEGNT
1.824476 10 ECEGAWQTDS
1.623083 11 TNLUSRXPTAJ
1.253527 12 XLECTHQGTHEC
1.399037 13 LJJTDGFNOTENR
0.152370 14 THECHESHIRECAT <--- best so far
1.533951 15 JNTOOEEXFTGQTNH
1.068182 16 TJTSAEETEXHPXHNE
1.034093 17 AZRAXUHEJLREEXIEE
1.443345 18 VNIZQPALEPTSXSEXUC
1.090977 19 FUCAITCSLVTEZDUDEHS
0.979868 20 EQXGAHWTTQECEWUGXHPI
0.789410 21 HVRCSAFTHEBDLSTAERSES
0.881380 22 TVIJTCIGKAQPELECRXPTNC
0.952456 23 KKEQXGPWTCQEELIEHXUWASV
0.715968 24 ELAIXHQTTIEDXJETTNTGAEPC
0.891258 25 OTJUUEGERDNQTUQEAGWUTIEOA
0.852784 26 IGITEGECAGAVUNLJAHASAVTETW


Best key : THECHESHIRECAT
pt = 'Attack at dawn!'
key = 'LEMON'
test(key, pt)


Decrypted text:
key = 'N' -- rot-13
THISWASTHEPOEMTHATALICEREADJABBERWOCKYTWASBRILLIGANDTHESLITHYTOVESDIDGYREANDGIMBLEINTHEWABEALLMIMSYWERETHEBOROGOVESANDTHEMOMERATHSOUTGRABEBEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCHBEWARETHEJUBJUBBIRDANDSHUNTHEFRUMIOUSBANDERSNATCHHETOOKHISVORPALSWORDINHANDLONGTIMETHEMANXOMEFOEHESOUGHTSORESTEDHEBYTHETUMTUMTREEANDSTOODAWHILEINTHOUGHTANDASINUFFISHTHOUGHTHESTOODTHEJABBERWOCKWITHEYESOFFLAMECAMEWHIFFLINGTHROUGHTHETULGEYWOODANDBURBLEDASITCAMEONETWOONETWOANDTHROUGHANDTHROUGHTHEVORPALBLADEWENTSNICKERSNACKHELEFTITDEADANDWITHITSHEADHEWENTGALUMPHINGBACKANDHASTTHOUSLAINTHEJABBERWOCKCOMETOMYARMSMYBEAMISHBOYOFRABJOUSDAYCALLOOHCALLAYHECHORTLEDINHISJOYTWASBRILLIGANDTHESLITHYTOVESDIDGYREANDGIMBLEINTHEWABEALLMIMSYWERETHEBOROGOVESANDTHEMOMERATHSOUTGRABEITSEEMSVERYPRETTYSHESAIDWHENSHEHADFINISHEDITBUTITSRATHERHARDTOUNDERSTAND
test(key, pt)
</pre>


=={{header|Nim}}==
key = 'B' -- Caesar
{{trans|Julia}}
test(key, pt)
{{trans|Phix}}
This is a translation of Julia algorithm with some ideas from Phix translation.
<syntaxhighlight lang="nim">import sequtils, strutils, sugar, tables, times


const
pt = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
key = 'A'
test(key, pt)


CipherText = """MOMUD EKAPV TQEFM OEVHP AJMII CDCTI FGYAG JSPXY ALUYM NSMYH
pt = sampledata()
VUXJE LEPXJ FXGCM JHKDZ RYICU HYPUS PGIGM OIYHF WHTCQ KMLRD
key = 'Hamlet; Prince of Denmark'
ITLXZ LJFVQ GHOLW CUHLO MDSOE KTALU VYLNZ RFGBX PHVGA LWQIS
test(key, pt)
FGRPH JOOFW GUBYI LAPLA LCAFA AMKLG CETDW VOELJ IKGJB XPHVG
ALWQC SNWBU BYHCU HKOCE XJEYK BQKVY KIIEH GRLGH XEOLW AWFOJ
ILOVV RHPKD WIHKN ATUHN VRYAQ DIVHX FHRZV QWMWV LGSHN NLVZS
JLAKI FHXUF XJLXM TBLQV RXXHR FZXGV LRAJI EXPRV OSMNP KEPDT
LPRWM JAZPK LQUZA ALGZX GVLKL GJTUI ITDSU REZXJ ERXZS HMPST
MTEOE PAPJH SMFNB YVQUZ AALGA YDNMP AQOWT UHDBV TSMUE UIMVH
QGVRW AEFSP EMPVE PKXZY WLKJA GWALT VYYOB YIXOK IHPDS EVLEV
RVSGB JOGYW FHKBL GLXYA MVKIS KIEHY IMAPX UOISK PVAGN MZHPW
TTZPV XFCCD TUHJH WLAPF YULTB UXJLN SIJVV YOVDJ SOLXG TGRVO
SFRII CTMKO JFCQF KTINQ BWVHG TENLH HOGCS PSFPV GJOKM SIFPR
ZPAAS ATPTZ FTPPD PORRF TAXZP KALQA WMIUD BWNCT LEFKO ZQDLX
BUXJL ASIMR PNMBF ZCYLV WAPVF QRHZV ZGZEF KBYIO OFXYE VOWGB
BXVCB XBAWG LQKCM ICRRX MACUO IKHQU AJEGL OIJHH XPVZW JEWBA
FWAML ZZRXJ EKAHV FASMU LVVUT TGK""".splitWhitespace.join()


FreqLetters = {'E': 12.702, 'T': 9.056, 'A': 8.167, 'O': 7.507,
return
'I': 6.966, 'N': 6.749, 'S': 6.327, 'H': 6.094,
'R': 5.987, 'D': 4.253, 'L': 4.025, 'C': 2.782,
'U': 2.758, 'M': 2.406, 'W': 2.361, 'F': 2.228,
'G': 2.015, 'Y': 1.974, 'P': 1.929, 'B': 1.492,
'V': 0.978, 'K': 0.772, 'J': 0.153, 'X': 0.150,
'Q': 0.095, 'Z': 0.074}.toTable


FreqDigraphs = {"TH": 15.2, "HE": 12.8, "IN": 9.4, "ER": 9.4,
method vigenere(meth, key, text) public static
"AN": 8.2, "RE": 6.8, "ND": 6.3, "AT": 5.9,
"ON": 5.7, "NT": 5.6, "HA": 5.6, "ES": 5.6,
"ST": 5.5, "EN": 5.5, "ED": 5.3, "TO": 5.2,
"IT": 5.0, "OU": 5.0, "EA": 4.7, "HI": 4.6,
"IS": 4.6, "OR": 4.3, "TI": 3.4, "AS": 3.3,
"TE": 2.7, "ET": 1.9, "NG": 1.8, "OF": 1.6,
"AL": 0.9, "DE": 0.9, "SE": 0.8, "LE": 0.8,
"SA": 0.6, "SI": 0.5, "AR": 0.4, "VE": 0.4,
"RA": 0.4, "LD": 0.2, "UR": 0.2}.toTable


FreqTrigraphs = {"THE": 18.1, "AND": 7.3, "ING": 7.2, "ION": 4.2,
select
"ENT": 4.2, "HER": 3.6, "FOR": 3.4, "THA": 3.3,
when 'encipher'.abbrev(meth.lower, 1) then df = 1
"NTH": 3.3, "INT": 3.2, "TIO": 3.1, "ERE": 3.1,
when 'decipher'.abbrev(meth.lower, 1) then df = -1
"TER": 3.0, "EST": 2.8, "ERS": 2.8, "HAT": 2.6,
otherwise signal IllegalArgumentException(meth 'must be "encipher" or "decipher"')
"ATI": 2.6, "ATE": 2.5, "ALL": 2.5, "VER": 2.4,
end
"HIS": 2.4, "HES": 2.4, "ETH": 2.4, "OFT": 2.2,
"STH": 2.1, "RES": 2.1, "OTH": 2.1, "ITH": 2.1,
"FTH": 2.1, "ONT": 2.0}.toTable


func decrypt(enc, key: string): string =
alpha = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
let encLen = enc.len
let keyLen = key.len
result.setLen(encLen)
var k = 0
for i in 0..<encLen:
result[i] = chr((ord(enc[i]) - ord(key[k]) + 26) mod 26 + ord('A'))
k = (k + 1) mod keyLen


func cryptanalyze(enc: string; maxKeyLen = 20): tuple[maxKey, maxDec: string] =
text = stringscrubber(text)
let encLen = enc.len
key = stringscrubber(key)
code = ''
var maxScore = 0.0
loop l_ = 1 to text.length()
M = alpha.pos(text.substr(l_, 1)) - 1
k_ = (l_ - 1) // key.length()
K = alpha.pos(key.substr(k_ + 1, 1)) - 1
C = mod((M + K * df), alpha.length())
C = alpha.substr(C + 1, 1)
code = code || C
end l_


for keyLen in 1..maxKeyLen:
return code
var key = newString(keyLen)
var idx = collect(newSeq):
for i in 1..encLen:
if i mod keyLen == 0:
i - keyLen


for i in 0..<keyLen:
method vigenere_encipher(key, plaintext) public static
var maxSubscore = 0.0
for j in 'A'..'Z':
var subscore = 0.0
let encidx = idx.mapIt(enc[it]).join()
for k in decrypt(encidx, $j):
subscore += FreqLetters[k]
if subscore > maxSubscore:
maxSubscore = subscore
key[i] = j
for item in idx.mitems: inc item


let dec = decrypt(enc, key)
return vigenere('encipher', key, plaintext)
var score = 0.0
for i in dec:
score += FreqLetters[i]


for i in 0..(encLen - 3):
method vigenere_decipher(key, ciphertext) public static
let digraph = dec[i..(i+1)]
let trigraph = dec[i..(i+2)]
score += 2 * FreqDigraphs.getOrDefault(digraph)
score += 3 * FreqTrigraphs.getOrDefault(trigraph)


if score > maxScore:
return vigenere('decipher', key, ciphertext)
maxScore = score
result.maxKey = key
result.maxDec = dec


let t0 = cpuTime()
method mod(N = int, D = int) private static
let (key, dec) = CipherText.cryptanalyze()

echo "key: ", key, '\n'
return (D + (N // D)) // D
echo dec, '\n'

echo "Elapsed time: ", (cpuTime() - t0).formatFloat(ffDecimal, precision = 3), " s"</syntaxhighlight>
method stringscrubber(cleanup) private static

alpha = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'

cleanup = cleanup.upper.space(0)
loop label f_ forever
x_ = cleanup.verify(alpha)
if x_ = 0 then leave f_
cleanup = cleanup.changestr(cleanup.substr(x_, 1), '')
end f_

return cleanup

method test(key, pt) private static

ct = vigenere_encipher(key, pt)
display(ct)
dt = vigenere_decipher(key, ct)
display(dt)

return

method display(text) public static

line = ''
o_ = 0
loop c_ = 1 to text.length()
b_ = o_ // 5
o_ = o_ + 1
if b_ = 0 then line = line' '
line = line || text.substr(c_, 1)
end c_

say '....+....|'.copies(8)
loop label l_ forever
parse line w1 w2 w3 w4 w5 w6 W7 w8 w9 w10 w11 w12 line
pline = w1 w2 w3 w4 w5 w6 w7 w8 w9 w10 w11 w12
say pline.strip()
if line.strip().length() = 0 then leave l_
end l_
say

return

method sampledata() private static returns Rexx

NL = char('\n')
antic_disposition = Rexx[]

antic_disposition = [ -
Rexx("To be, or not to be--that is the question:" ), -
Rexx("Whether 'tis nobler in the mind to suffer" ), -
Rexx("The slings and arrows of outrageous fortune" ), -
Rexx("Or to take arms against a sea of troubles" ), -
Rexx("And by opposing end them. To die, to sleep--" ), -
Rexx("No more--and by a sleep to say we end" ), -
Rexx("The heartache, and the thousand natural shocks" ), -
Rexx("That flesh is heir to. 'Tis a consummation" ), -
Rexx("Devoutly to be wished. To die, to sleep--" ), -
Rexx("To sleep--perchance to dream: ay, there's the rub,"), -
Rexx("For in that sleep of death what dreams may come" ), -
Rexx("When we have shuffled off this mortal coil," ), -
Rexx("Must give us pause. There's the respect" ), -
Rexx("That makes calamity of so long life." ), -
Rexx("For who would bear the whips and scorns of time," ), -
Rexx("Th' oppressor's wrong, the proud man's contumely" ), -
Rexx("The pangs of despised love, the law's delay," ), -
Rexx("The insolence of office, and the spurns" ), -
Rexx("That patient merit of th' unworthy takes," ), -
Rexx("When he himself might his quietus make" ), -
Rexx("With a bare bodkin? Who would fardels bear," ), -
Rexx("To grunt and sweat under a weary life," ), -
Rexx("But that the dread of something after death," ), -
Rexx("The undiscovered country, from whose bourn" ), -
Rexx("No traveller returns, puzzles the will," ), -
Rexx("And makes us rather bear those ills we have" ), -
Rexx("Than fly to others that we know not of?" ), -
Rexx("Thus conscience does make cowards of us all," ), -
Rexx("And thus the native hue of resolution" ), -
Rexx("Is sicklied o'er with the pale cast of thought," ), -
Rexx("And enterprise of great pith and moment" ), -
Rexx("With this regard their currents turn awry" ), -
Rexx("And lose the name of action. -- Soft you now," ), -
Rexx("The fair Ophelia! -- Nymph, in thy orisons" ), -
Rexx("Be all my sins remembered." ) -
]

melancholy_dane = Rexx('')
loop l_ = 0 for antic_disposition.length
melancholy_dane = melancholy_dane || antic_disposition[l_] || NL
end l_
return melancholy_dane
</lang>


{{out}}
{{out}}
<pre>key: THECHESHIRECAT
<pre style="height: 60ex; overflow:scroll">
....+....|....+....|....+....|....+....|....+....|....+....|....+....|....+....|
LXFOP VEFRN HR
....+....|....+....|....+....|....+....|....+....|....+....|....+....|....+....|
ATTAC KATDA WN
....+....|....+....|....+....|....+....|....+....|....+....|....+....|....+....|
NGGNP XNGQN JA
....+....|....+....|....+....|....+....|....+....|....+....|....+....|....+....|
ATTAC KATDA WN
....+....|....+....|....+....|....+....|....+....|....+....|....+....|....+....|
BUUBD LBUEB XO
....+....|....+....|....+....|....+....|....+....|....+....|....+....|....+....|
ATTAC KATDA WN
....+....|....+....|....+....|....+....|....+....|....+....|....+....|....+....|
ABCDE FGHIJ KLMNO PQRST UVWXY Z
....+....|....+....|....+....|....+....|....+....|....+....|....+....|....+....|
ABCDE FGHIJ KLMNO PQRST UVWXY Z
....+....|....+....|....+....|....+....|....+....|....+....|....+....|....+....|
AONPS KCFBG QFSYK EGUSK RLQGP WMXFV JJIHM HVGUS EYILQ CMGIY MZKRR YRWHR
FVBAH QDPBC XANPH OWUSJ EOWYB TDLKX DLASQ VHZQI BDTFD HKQLV FHRON KRGYD
WRMOW DYOGM PXHRV QDCCU SSFUN XOUDF SIFIF LVGXC XOIRB NFWVR QLRWQ PIFNI
SUWSF MYNOL NPELX WVIEV EQMHE APTYO AHAFW TCUVN VYFFO WUACB CAHME JETJP
VULSN UXBFI JKJOZ DYFBR BVQRR JYSHF LPDVB QHMLW VLGQH WJWSF XEVZA OEWIX
EGMEE LOSFI GADIO HMMJX ATIMF VLSWX FSARZ XAHME WETVX BHHSF WLJTA KNYEM
XWFPP KBOIK MHRJQ HRFLS TFJYA VLBHJ HMLWZ ARKKS CATPF JJBTK ZSZVT NGSVD
OEDPW MWVZR UTSHW XUMTD KREEN EEPDQ GASTX RPBZG CSMER ZVPWF EBWPR GHEEF
HVGOI BDEGS JKBTR GTIXV YEKRV PBCIL HFZFY VCSJX UQPIY BDYLR LRFVG WQSQB
XUQPR XNSAQ HXHGQ FGHZT YIGTE CKDSP PPTNK PRKRG TOIAO EFPVF RTGXP ELGJI
GUXVA ETYKA PMEMX CKURT MHTIX UGNNY YTTJX TZVAJ JIBMH LVYSV VMMUR LMWZA
DWMSY XWZMK VGPTT LFTGV JBFOW SZLBI OLVKF MCHXA JJRCV HTJVH ZTRXK SIPEM
JELRT EKJDV LXIWO IUFEL TIKPR FVSFG SSEOD OAHUY KTUKM EFIOY KXUQU ENPSO
ZZXGV LPQYB YUCSD ODGOO EPFHJ IVAQX FFYIY XEIBL TGCRL ELHMN IGYKI JULCK
UDYLO XHLAE CXVJU FRMRK RVSQT PEHNM UCZSY KEARL PDVOF SIKHK PNVAS PQSJZ
OKYMT TFWVD EAPKI BHHHB QSDKR EOZAT GUABH YGFOP NZDKR BSFSI GPKQI GLIJR
JEQSF VBTUZ RBHJQ PMPWJ GSRDW ZDOTT PTTAV KNUXC KWLBG GYDHN PPRMT IXEKW
STIKE QAKZP TTLRW BFURP XKNWL GTIJB LGMCH MWVQE EYFWH RGETL BUAIC CTCUT
BUIHM HRNYE FPHCF TSGHF NGASI SRAGT EWKPR AALXA ZIAAQ DMLRG TYFBP SAYWU
TRTYO CGNQW EQMVW IEDPH


THISWASTHEPOEMTHATALICEREADJABBERWOCKYTWASBRILLIGANDTHESLITHYTOVESDIDGYREANDGIMBLEINTHEWABEALLMIMSYWERETHEBOROGOVESANDTHEMOMERATHSOUTGRABEBEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCHBEWARETHEJUBJUBBIRDANDSHUNTHEFRUMIOUSBANDERSNATCHHETOOKHISVORPALSWORDINHANDLONGTIMETHEMANXOMEFOEHESOUGHTSORESTEDHEBYTHETUMTUMTREEANDSTOODAWHILEINTHOUGHTANDASINUFFISHTHOUGHTHESTOODTHEJABBERWOCKWITHEYESOFFLAMECAMEWHIFFLINGTHROUGHTHETULGEYWOODANDBURBLEDASITCAMEONETWOONETWOANDTHROUGHANDTHROUGHTHEVORPALBLADEWENTSNICKERSNACKHELEFTITDEADANDWITHITSHEADHEWENTGALUMPHINGBACKANDHASTTHOUSLAINTHEJABBERWOCKCOMETOMYARMSMYBEAMISHBOYOFRABJOUSDAYCALLOOHCALLAYHECHORTLEDINHISJOYTWASBRILLIGANDTHESLITHYTOVESDIDGYREANDGIMBLEINTHEWABEALLMIMSYWERETHEBOROGOVESANDTHEMOMERATHSOUTGRABEITSEEMSVERYPRETTYSHESAIDWHENSHEHADFINISHEDITBUTITSRATHERHARDTOUNDERSTAND
....+....|....+....|....+....|....+....|....+....|....+....|....+....|....+....|
TOBEO RNOTT OBETH ATIST HEQUE STION WHETH ERTIS NOBLE RINTH EMIND TOSUF
FERTH ESLIN GSAND ARROW SOFOU TRAGE OUSFO RTUNE ORTOT AKEAR MSAGA INSTA
SEAOF TROUB LESAN DBYOP POSIN GENDT HEMTO DIETO SLEEP NOMOR EANDB YASLE
EPTOS AYWEE NDTHE HEART ACHEA NDTHE THOUS ANDNA TURAL SHOCK STHAT FLESH
ISHEI RTOTI SACON SUMMA TIOND EVOUT LYTOB EWISH EDTOD IETOS LEEPT OSLEE
PPERC HANCE TODRE AMAYT HERES THERU BFORI NTHAT SLEEP OFDEA THWHA TDREA
MSMAY COMEW HENWE HAVES HUFFL EDOFF THISM ORTAL COILM USTGI VEUSP AUSET
HERES THERE SPECT THATM AKESC ALAMI TYOFS OLONG LIFEF ORWHO WOULD BEART
HEWHI PSAND SCORN SOFTI METHO PPRES SORSW RONGT HEPRO UDMAN SCONT UMELY
THEPA NGSOF DESPI SEDLO VETHE LAWSD ELAYT HEINS OLENC EOFOF FICEA NDTHE
SPURN STHAT PATIE NTMER ITOFT HUNWO RTHYT AKESW HENHE HIMSE LFMIG HTHIS
QUIET USMAK EWITH ABARE BODKI NWHOW OULDF ARDEL SBEAR TOGRU NTAND SWEAT
UNDER AWEAR YLIFE BUTTH ATTHE DREAD OFSOM ETHIN GAFTE RDEAT HTHEU NDISC
OVERE DCOUN TRYFR OMWHO SEBOU RNNOT RAVEL LERRE TURNS PUZZL ESTHE WILLA
NDMAK ESUSR ATHER BEART HOSEI LLSWE HAVET HANFL YTOOT HERST HATWE KNOWN
OTOFT HUSCO NSCIE NCEDO ESMAK ECOWA RDSOF USALL ANDTH USTHE NATIV EHUEO
FRESO LUTIO NISSI CKLIE DOERW ITHTH EPALE CASTO FTHOU GHTAN DENTE RPRIS
EOFGR EATPI THAND MOMEN TWITH THISR EGARD THEIR CURRE NTSTU RNAWR YANDL
OSETH ENAME OFACT IONSO FTYOU NOWTH EFAIR OPHEL IANYM PHINT HYORI SONSB
EALLM YSINS REMEM BERED
</pre>


Elapsed time: 0.041 s</pre>
=={{header|Nim}}==
<lang nim>import strutils

proc isAlpha(c): bool = c in 'a'..'z' or c in 'A'..'Z'

proc encrypt(msg, key): string =
result = ""
var pos = 0
for c in msg:
if isAlpha c:
result.add chr(((ord(key[pos]) + ord(toUpper c)) mod 26) + ord('A'))
pos = (pos + 1) mod key.len

proc decrypt(msg, key): string =
result = ""
var pos = 0
for c in msg:
result.add chr(((26 + ord(c) - ord(key[pos])) mod 26) + ord('A'))
pos = (pos + 1) mod key.len

const text = "Beware the Jabberwock, my son! The jaws that bite, the claws that catch!"
const key = "VIGENERECIPHER"

let encr = encrypt(text, key)
let decr = decrypt(encr, key)

echo text
echo encr
echo decr</lang>
{{out}}
<pre>Beware the Jabberwock, my son! The jaws that bite, the claws that catch!
WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY
BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH</pre>

=={{header|Objeck}}==
{{trans|D}}
<lang objeck>
bundle Default {
class VigenereCipher {
function : Main(args : String[]) ~ Nil {
key := "VIGENERECIPHER";
ori := "Beware the Jabberwock, my son! The jaws that bite, the claws that catch!";
enc := encrypt(ori, key);
IO.Console->Print("encrypt: ")->PrintLine(enc);
IO.Console->Print("decrypt: ")->PrintLine(decrypt(enc, key));
}

function : native : encrypt(text : String, key : String) ~ String {
res := "";
text := text->ToUpper();
j := 0;

each(i : text) {
c := text->Get(i);
if(c >= 'A' & c <= 'Z') {
res->Append(((c + key->Get(j) - 2 * 'A') % 26 + 'A')->As(Char));
j += 1;
j := j % key->Size();
};
};

return res;
}

function : native : decrypt(text : String, key : String) ~ String {
res := "";
text := text->ToUpper();
j := 0;

each(i : text) {
c := text->Get(i);
if(c >= 'A' & c <= 'Z') {
res->Append(((c - key->Get(j) + 26) % 26 + 'A')->As(Char));
j += 1;
j := j % key->Size();
};
};

return res;
}
}
}
</lang>
<pre>
encrypt: WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY
decrypt: BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH
</pre>


=={{header|OCaml}}==
=={{header|OCaml}}==
Original version by [http://rosettacode.org/wiki/User:Vanyamil User:Vanyamil].
{{trans|C}}


Uses the Vigenere decrypt function from the Vigenere task solution (not included in the code below).
<lang ocaml>let cipher src key crypt =
{{works with|OCaml|above 4.05}}
let str = String.uppercase src in
<syntaxhighlight lang="ocaml">
let key = String.uppercase key in
(* Task : Vigenere cipher/Cryptanalysis *)


(*
(* strip out non-letters *)
Given some text you suspect has been encrypted
let len = String.length str in
with a Vigenère cipher, extract the key and plaintext.
let rec aux i j =
Uses correlation factors similar to other solutions.
if j >= len then String.sub str 0 i else
(originally tried Friedman test, didn't produce good result)
if str.[j] >= 'A' && str.[j] <= 'Z'
then (str.[i] <- str.[j]; aux (succ i) (succ j))
Coded in a way that allows non-english (by passing frequencies).
else aux i (succ j)
*)
in
let res = aux 0 0 in


(*** Helpers ***)
let slen = String.length res in
let klen = String.length key in


(* Implementation of Float.round to avoid v4.08 *)
let d = int_of_char in
let round (x : float) : float =
let f =
let rem = mod_float x 1. in
if crypt
if rem >= 0.5
then fun i -> d res.[i] - d 'A' + d key.[i mod klen] - d 'A'
then ceil x
else fun i -> d res.[i] - d key.[i mod klen] + 26
else floor x
in
for i = 0 to pred slen do
res.[i] <- char_of_int (d 'A' + (f i) mod 26)
done;
(res)


(* A function that updates array element at a position *)
let () =
let array_update (arr : 'a array) (idx : int) (update : 'a -> 'a) : unit =
let str = "Beware the Jabberwock, my son! The jaws that bite, \
the claws that catch!" in
let curr = Array.get arr idx in
Array.set arr idx (update curr)
let key = "VIGENERECIPHER" in


(*** Actual task at hand ***)
let cod = cipher str key true in
let dec = cipher cod key false in


(* the n'th element of array is how often the n'th letter was found *)
Printf.printf "Text: %s\n" str;
let observe_coincidences ?(step : int = 1) ?(offset : int = 0) (text : string) : int array =
Printf.printf "key: %s\n" key;
let arr = Array.make 26 0 in
Printf.printf "Code: %s\n" cod;
let a_code = Char.code 'A' in
Printf.printf "Back: %s\n" dec;
String.iteri (fun idx c -> if idx mod step = offset then array_update arr (Char.code c - a_code) succ) text;
;;</lang>
arr


(* Obtain correlation factor for the observed coincidences *)
Run:
let correlation_factor ?(sort : bool = true) (coincidences : int array) (freqs : float list) : float =
let clist = Array.to_list coincidences in
let clist = (if sort then List.sort compare clist else clist) in
List.fold_left2 (fun acc c f -> acc +. (float_of_int c *. f)) 0. clist freqs


(* Translation of the test used in other Rosetta Code solutions *)
<pre>$ ocaml vigenere_cipher.ml
let shifted_coincidences_test (freqs : float list) (text : string) : int =
Text: Beware the Jabberwock, my son! The jaws that bite, the claws that catch!
let sorted_freqs = List.sort compare freqs in
key: VIGENERECIPHER
let bestCorr = -100. in
Code: WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY
let max_keylen = String.length text / 20 in
Back: BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH</pre>
let rec helper idx (cur_len, cur_corr) (best_len, best_corr) =
if cur_len = max_keylen then (* Finished testing everything *)
best_len
else if idx = cur_len then (* Finished testing this key length *)
let (best_len, best_corr) = if cur_corr > best_corr then (cur_len, cur_corr) else (best_len, best_corr) in
helper 0 (cur_len + 1, ~-.0.5 *. float_of_int (cur_len + 1)) (best_len, best_corr)
else
let coincidences = observe_coincidences ~step:cur_len ~offset:idx text in
let factor = correlation_factor coincidences sorted_freqs in
helper (succ idx) (cur_len, cur_corr +. factor) (best_len, best_corr)
in
helper 0 (2, ~-.1.) (1, ~-.100.)


(* Returns the most likely shift value for this set *)
=={{header|ooRexx}}==
let break_caesar ?(step : int = 1) ?(offset : int = 0) (text : string) (freqs : float list) : int =
{{trans|NetRexx}}
let c_arr = observe_coincidences ~step ~offset text in
A reworking of the [[#NetRexx|NetRexx]] version using Open Object Rexx but shouldn't take much to translate to Classic Rexx.
let rec helper l curShift (maxShift, maxCorr) =
<lang REXX>/* Rexx */
if curShift = 26
Do
then maxShift
alpha = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
key = 'LEMON'
else
let corr = correlation_factor ~sort:false c_arr l in
let l' = List.tl l @ [List.hd l] in
if corr > maxCorr
then helper l' (curShift + 1) (curShift, corr)
else helper l' (curShift + 1) (maxShift, maxCorr)
in
helper freqs 0 (-1, -100.)


let break (keylen : int) (text : string) (freqs : float list) : key =
pt = 'Attack at dawn!'
let rec getCaesars idx acc =
Call test key, pt
if idx >= keylen then acc else
let shift = break_caesar ~step:keylen ~offset:idx text freqs in
let new_code = if shift = 0 then Char.code 'A' else Char.code 'Z' + 1 - shift in
getCaesars (succ idx) (acc ^ Char.(new_code |> chr |> escaped))
in
getCaesars 0 ""


let cryptanalyze (freqs : float list) (text : string) : key * string =
key = 'N'
let text = ascii_upper_letters_only text in
Call test key, pt
let keylen = shifted_coincidences_test freqs text in
let key = break keylen text freqs in
let pt = decrypt key text in
(key, pt)


(*** Output ***)
key = 'B'
Call test key, pt

pt = alpha
key = 'A'
Call test key, pt

pt = sampledata()
key = 'Hamlet; Prince of Denmark'
Call test key, pt

Return
End
Exit

vigenere:
Procedure Expose alpha
Do
Parse upper Arg meth, key, text

Select
When 'ENCIPHER'~abbrev(meth, 1) = 1 then df = 1
When 'DECIPHER'~abbrev(meth, 1) = 1 then df = -1
Otherwise Do
Say meth 'invalid. Must be "ENCIPHER" or "DECIPHER"'
Exit
End
End
text = stringscrubber(text)
key = stringscrubber(key)
code = ''

Do l_ = 1 to text~length()
M = alpha~pos(text~substr(l_, 1)) - 1
k_ = (l_ - 1) // key~length()
K = alpha~pos(key~substr(k_ + 1, 1)) - 1
C = mod((M + K * df), alpha~length())
C = alpha~substr(C + 1, 1)
code = code || C
End l_

Return code

Return
End
Exit

vigenere_encipher:
Procedure Expose alpha
Do
Parse upper Arg key, plaintext

Return vigenere('ENCIPHER', key, plaintext)
End
Exit

vigenere_decipher:
Procedure Expose alpha
Do
Parse upper Arg key, ciphertext

Return vigenere('DECIPHER', key, ciphertext)
End
Exit

mod:
Procedure
Do
Parse Arg N, D

Return (D + (N // D)) // D
End
Exit

stringscrubber:
Procedure Expose alpha
Do
Parse upper Arg cleanup

cleanup = cleanup~space(0)
Do label f_ forever
x_ = cleanup~verify(alpha)
If x_ = 0 then Leave f_
cleanup = cleanup~changestr(cleanup~substr(x_, 1), '')
end f_

Return cleanup
End
Exit

test:
Procedure Expose alpha
Do
Parse Arg key, pt

ct = vigenere_encipher(key, pt)
Call display ct
dt = vigenere_decipher(key, ct)
Call display dt

Return
End
Exit

display:
Procedure
Do
Parse Arg text

line = ''
o_ = 0
Do c_ = 1 to text~length()
b_ = o_ // 5
o_ = o_ + 1
If b_ = 0 then line = line' '
line = line || text~substr(c_, 1)
End c_

Say '....+....|'~copies(8)
Do label l_ forever
Parse Var line w1 w2 w3 w4 w5 w6 W7 w8 w9 w10 w11 w12 line
pline = w1 w2 w3 w4 w5 w6 w7 w8 w9 w10 w11 w12
Say pline~strip()
If line~strip()~length() = 0 then Leave l_
End l_
Say

Return
End
Exit

sampledata:
Procedure
Do

NL = '0a'x
X = 0
antic_disposition. = ''
X = X + 1; antic_disposition.0 = X; antic_disposition.X = "To be, or not to be--that is the question:"
X = X + 1; antic_disposition.0 = X; antic_disposition.X = "Whether 'tis nobler in the mind to suffer"
X = X + 1; antic_disposition.0 = X; antic_disposition.X = "The slings and arrows of outrageous fortune"
X = X + 1; antic_disposition.0 = X; antic_disposition.X = "Or to take arms against a sea of troubles"
X = X + 1; antic_disposition.0 = X; antic_disposition.X = "And by opposing end them. To die, to sleep--"
X = X + 1; antic_disposition.0 = X; antic_disposition.X = "No more--and by a sleep to say we end"
X = X + 1; antic_disposition.0 = X; antic_disposition.X = "The heartache, and the thousand natural shocks"
X = X + 1; antic_disposition.0 = X; antic_disposition.X = "That flesh is heir to. 'Tis a consummation"
X = X + 1; antic_disposition.0 = X; antic_disposition.X = "Devoutly to be wished. To die, to sleep--"
X = X + 1; antic_disposition.0 = X; antic_disposition.X = "To sleep--perchance to dream: ay, there's the rub,"
X = X + 1; antic_disposition.0 = X; antic_disposition.X = "For in that sleep of death what dreams may come"
X = X + 1; antic_disposition.0 = X; antic_disposition.X = "When we have shuffled off this mortal coil,"
X = X + 1; antic_disposition.0 = X; antic_disposition.X = "Must give us pause. There's the respect"
X = X + 1; antic_disposition.0 = X; antic_disposition.X = "That makes calamity of so long life."
X = X + 1; antic_disposition.0 = X; antic_disposition.X = "For who would bear the whips and scorns of time,"
X = X + 1; antic_disposition.0 = X; antic_disposition.X = "Th' oppressor's wrong, the proud man's contumely"
X = X + 1; antic_disposition.0 = X; antic_disposition.X = "The pangs of despised love, the law's delay,"
X = X + 1; antic_disposition.0 = X; antic_disposition.X = "The insolence of office, and the spurns"
X = X + 1; antic_disposition.0 = X; antic_disposition.X = "That patient merit of th' unworthy takes,"
X = X + 1; antic_disposition.0 = X; antic_disposition.X = "When he himself might his quietus make"
X = X + 1; antic_disposition.0 = X; antic_disposition.X = "With a bare bodkin? Who would fardels bear,"
X = X + 1; antic_disposition.0 = X; antic_disposition.X = "To grunt and sweat under a weary life,"
X = X + 1; antic_disposition.0 = X; antic_disposition.X = "But that the dread of something after death,"
X = X + 1; antic_disposition.0 = X; antic_disposition.X = "The undiscovered country, from whose bourn"
X = X + 1; antic_disposition.0 = X; antic_disposition.X = "No traveller returns, puzzles the will,"
X = X + 1; antic_disposition.0 = X; antic_disposition.X = "And makes us rather bear those ills we have"
X = X + 1; antic_disposition.0 = X; antic_disposition.X = "Than fly to others that we know not of?"
X = X + 1; antic_disposition.0 = X; antic_disposition.X = "Thus conscience does make cowards of us all,"
X = X + 1; antic_disposition.0 = X; antic_disposition.X = "And thus the native hue of resolution"
X = X + 1; antic_disposition.0 = X; antic_disposition.X = "Is sicklied o'er with the pale cast of thought,"
X = X + 1; antic_disposition.0 = X; antic_disposition.X = "And enterprise of great pith and moment"
X = X + 1; antic_disposition.0 = X; antic_disposition.X = "With this regard their currents turn awry"
X = X + 1; antic_disposition.0 = X; antic_disposition.X = "And lose the name of action. -- Soft you now,"
X = X + 1; antic_disposition.0 = X; antic_disposition.X = "The fair Ophelia! -- Nymph, in thy orisons"
X = X + 1; antic_disposition.0 = X; antic_disposition.X = "Be all my sins remembered."

melancholy_dane = ''
Do l_ = 1 for antic_disposition.0
melancholy_dane = melancholy_dane || antic_disposition.l_ || NL
End l_
Return melancholy_dane
End
Exit
</lang>


let _ =
let long_text = "\
MOMUD EKAPV TQEFM OEVHP AJMII CDCTI FGYAG JSPXY ALUYM NSMYH \
VUXJE LEPXJ FXGCM JHKDZ RYICU HYPUS PGIGM OIYHF WHTCQ KMLRD \
ITLXZ LJFVQ GHOLW CUHLO MDSOE KTALU VYLNZ RFGBX PHVGA LWQIS \
FGRPH JOOFW GUBYI LAPLA LCAFA AMKLG CETDW VOELJ IKGJB XPHVG \
ALWQC SNWBU BYHCU HKOCE XJEYK BQKVY KIIEH GRLGH XEOLW AWFOJ \
ILOVV RHPKD WIHKN ATUHN VRYAQ DIVHX FHRZV QWMWV LGSHN NLVZS \
JLAKI FHXUF XJLXM TBLQV RXXHR FZXGV LRAJI EXPRV OSMNP KEPDT \
LPRWM JAZPK LQUZA ALGZX GVLKL GJTUI ITDSU REZXJ ERXZS HMPST \
MTEOE PAPJH SMFNB YVQUZ AALGA YDNMP AQOWT UHDBV TSMUE UIMVH \
QGVRW AEFSP EMPVE PKXZY WLKJA GWALT VYYOB YIXOK IHPDS EVLEV \
RVSGB JOGYW FHKBL GLXYA MVKIS KIEHY IMAPX UOISK PVAGN MZHPW \
TTZPV XFCCD TUHJH WLAPF YULTB UXJLN SIJVV YOVDJ SOLXG TGRVO \
SFRII CTMKO JFCQF KTINQ BWVHG TENLH HOGCS PSFPV GJOKM SIFPR \
ZPAAS ATPTZ FTPPD PORRF TAXZP KALQA WMIUD BWNCT LEFKO ZQDLX \
BUXJL ASIMR PNMBF ZCYLV WAPVF QRHZV ZGZEF KBYIO OFXYE VOWGB \
BXVCB XBAWG LQKCM ICRRX MACUO IKHQU AJEGL OIJHH XPVZW JEWBA \
FWAML ZZRXJ EKAHV FASMU LVVUT TGK"
in
let english_freqs = [
0.08167; 0.01492; 0.02782; 0.04253; 0.12702; 0.02228; 0.02015;
0.06094; 0.06966; 0.00153; 0.00772; 0.04025; 0.02406; 0.06749;
0.07507; 0.01929; 0.00095; 0.05987; 0.06327; 0.09056; 0.02758;
0.00978; 0.02360; 0.00150; 0.01974; 0.00074
]
in
let (key, pt) = cryptanalyze english_freqs long_text in
Printf.printf "Key: %s\n\nText: %s" key pt
;;
</syntaxhighlight>
{{out}}
{{out}}
<pre>
<pre style="height: 60ex; overflow: scroll;">
Key: THECHESHIRECAT
....+....|....+....|....+....|....+....|....+....|....+....|....+....|....+....|
LXFOP VEFRN HR


Text: THISWASTHEPOEMTHATALICEREADJABBERWOC...
....+....|....+....|....+....|....+....|....+....|....+....|....+....|....+....|
ATTAC KATDA WN

....+....|....+....|....+....|....+....|....+....|....+....|....+....|....+....|
NGGNP XNGQN JA

....+....|....+....|....+....|....+....|....+....|....+....|....+....|....+....|
ATTAC KATDA WN

....+....|....+....|....+....|....+....|....+....|....+....|....+....|....+....|
BUUBD LBUEB XO

....+....|....+....|....+....|....+....|....+....|....+....|....+....|....+....|
ATTAC KATDA WN

....+....|....+....|....+....|....+....|....+....|....+....|....+....|....+....|
ABCDE FGHIJ KLMNO PQRST UVWXY Z

....+....|....+....|....+....|....+....|....+....|....+....|....+....|....+....|
ABCDE FGHIJ KLMNO PQRST UVWXY Z

....+....|....+....|....+....|....+....|....+....|....+....|....+....|....+....|
AONPS KCFBG QFSYK EGUSK RLQGP WMXFV JJIHM HVGUS EYILQ CMGIY MZKRR YRWHR
FVBAH QDPBC XANPH OWUSJ EOWYB TDLKX DLASQ VHZQI BDTFD HKQLV FHRON KRGYD
WRMOW DYOGM PXHRV QDCCU SSFUN XOUDF SIFIF LVGXC XOIRB NFWVR QLRWQ PIFNI
SUWSF MYNOL NPELX WVIEV EQMHE APTYO AHAFW TCUVN VYFFO WUACB CAHME JETJP
VULSN UXBFI JKJOZ DYFBR BVQRR JYSHF LPDVB QHMLW VLGQH WJWSF XEVZA OEWIX
EGMEE LOSFI GADIO HMMJX ATIMF VLSWX FSARZ XAHME WETVX BHHSF WLJTA KNYEM
XWFPP KBOIK MHRJQ HRFLS TFJYA VLBHJ HMLWZ ARKKS CATPF JJBTK ZSZVT NGSVD
OEDPW MWVZR UTSHW XUMTD KREEN EEPDQ GASTX RPBZG CSMER ZVPWF EBWPR GHEEF
HVGOI BDEGS JKBTR GTIXV YEKRV PBCIL HFZFY VCSJX UQPIY BDYLR LRFVG WQSQB
XUQPR XNSAQ HXHGQ FGHZT YIGTE CKDSP PPTNK PRKRG TOIAO EFPVF RTGXP ELGJI
GUXVA ETYKA PMEMX CKURT MHTIX UGNNY YTTJX TZVAJ JIBMH LVYSV VMMUR LMWZA
DWMSY XWZMK VGPTT LFTGV JBFOW SZLBI OLVKF MCHXA JJRCV HTJVH ZTRXK SIPEM
JELRT EKJDV LXIWO IUFEL TIKPR FVSFG SSEOD OAHUY KTUKM EFIOY KXUQU ENPSO
ZZXGV LPQYB YUCSD ODGOO EPFHJ IVAQX FFYIY XEIBL TGCRL ELHMN IGYKI JULCK
UDYLO XHLAE CXVJU FRMRK RVSQT PEHNM UCZSY KEARL PDVOF SIKHK PNVAS PQSJZ
OKYMT TFWVD EAPKI BHHHB QSDKR EOZAT GUABH YGFOP NZDKR BSFSI GPKQI GLIJR
JEQSF VBTUZ RBHJQ PMPWJ GSRDW ZDOTT PTTAV KNUXC KWLBG GYDHN PPRMT IXEKW
STIKE QAKZP TTLRW BFURP XKNWL GTIJB LGMCH MWVQE EYFWH RGETL BUAIC CTCUT
BUIHM HRNYE FPHCF TSGHF NGASI SRAGT EWKPR AALXA ZIAAQ DMLRG TYFBP SAYWU
TRTYO CGNQW EQMVW IEDPH

....+....|....+....|....+....|....+....|....+....|....+....|....+....|....+....|
TOBEO RNOTT OBETH ATIST HEQUE STION WHETH ERTIS NOBLE RINTH EMIND TOSUF
FERTH ESLIN GSAND ARROW SOFOU TRAGE OUSFO RTUNE ORTOT AKEAR MSAGA INSTA
SEAOF TROUB LESAN DBYOP POSIN GENDT HEMTO DIETO SLEEP NOMOR EANDB YASLE
EPTOS AYWEE NDTHE HEART ACHEA NDTHE THOUS ANDNA TURAL SHOCK STHAT FLESH
ISHEI RTOTI SACON SUMMA TIOND EVOUT LYTOB EWISH EDTOD IETOS LEEPT OSLEE
PPERC HANCE TODRE AMAYT HERES THERU BFORI NTHAT SLEEP OFDEA THWHA TDREA
MSMAY COMEW HENWE HAVES HUFFL EDOFF THISM ORTAL COILM USTGI VEUSP AUSET
HERES THERE SPECT THATM AKESC ALAMI TYOFS OLONG LIFEF ORWHO WOULD BEART
HEWHI PSAND SCORN SOFTI METHO PPRES SORSW RONGT HEPRO UDMAN SCONT UMELY
THEPA NGSOF DESPI SEDLO VETHE LAWSD ELAYT HEINS OLENC EOFOF FICEA NDTHE
SPURN STHAT PATIE NTMER ITOFT HUNWO RTHYT AKESW HENHE HIMSE LFMIG HTHIS
QUIET USMAK EWITH ABARE BODKI NWHOW OULDF ARDEL SBEAR TOGRU NTAND SWEAT
UNDER AWEAR YLIFE BUTTH ATTHE DREAD OFSOM ETHIN GAFTE RDEAT HTHEU NDISC
OVERE DCOUN TRYFR OMWHO SEBOU RNNOT RAVEL LERRE TURNS PUZZL ESTHE WILLA
NDMAK ESUSR ATHER BEART HOSEI LLSWE HAVET HANFL YTOOT HERST HATWE KNOWN
OTOFT HUSCO NSCIE NCEDO ESMAK ECOWA RDSOF USALL ANDTH USTHE NATIV EHUEO
FRESO LUTIO NISSI CKLIE DOERW ITHTH EPALE CASTO FTHOU GHTAN DENTE RPRIS
EOFGR EATPI THAND MOMEN TWITH THISR EGARD THEIR CURRE NTSTU RNAWR YANDL
OSETH ENAME OFACT IONSO FTYOU NOWTH EFAIR OPHEL IANYM PHINT HYORI SONSB
EALLM YSINS REMEM BERED
</pre>
</pre>


=={{header|Pascal}}==
=={{header|Perl}}==
<syntaxhighlight lang="perl">use strict;
<lang pascal>
use warnings;
// The Vigenere cipher in reasonably standard Pascal
use feature 'say';
// <no library functions: all conversions hand-coded>
PROGRAM Vigenere;


# from Wikipedia
// get a letter's alphabetic position (A=0)
my %English_letter_freq = (
FUNCTION letternum(letter: CHAR): BYTE;
E => 12.70, L => 4.03, Y => 1.97, P => 1.93, T => 9.06, A => 8.17, O => 7.51, I => 6.97, N => 6.75,
BEGIN
S => 6.33, H => 6.09, R => 5.99, D => 4.25, C => 2.78, U => 2.76, M => 2.41, W => 2.36, F => 2.23,
letternum := (ord(letter)-ord('A'));
G => 2.02, B => 1.29, V => 0.98, K => 0.77, J => 0.15, X => 0.15, Q => 0.10, Z => 0.07
END;
);
my @alphabet = sort keys %English_letter_freq;
my $max_key_lengths = 5; # number of keylengths to try


sub myguess {
// convert a character to uppercase
my ($text) = (@_);
FUNCTION uch(ch: CHAR): CHAR;
my ($seqtext, @spacing, @factors, @sortedfactors, $pos, %freq, %Keys);
BEGIN
uch := ch;
IF ch IN ['a'..'z'] THEN
uch := chr(ord(ch) AND $5F);
END;
// convert a string to uppercase
FUNCTION ucase(str: STRING): STRING;
VAR i: BYTE;
BEGIN
ucase := '';
FOR i := 1 TO Length(str) DO
ucase := ucase + uch(str[i]);
END;
// construct a Vigenere-compatible string:
// uppercase; no spaces or punctuation.
FUNCTION vstr(pt: STRING): STRING;
VAR c: Cardinal;
s: STRING;
BEGIN
vstr:= '';
s := ucase(pt);
FOR c := 1 TO Length(s) DO BEGIN
IF s[c] IN ['A'..'Z'] THEN
vstr += s[c];
END;
END;
// construct a repeating Vigenere key
FUNCTION vkey(pt, key: STRING): STRING;
VAR c,n: Cardinal;
k : STRING;
BEGIN
k := vstr(key);
vkey := '';
FOR c := 1 TO Length(pt) DO BEGIN
n := c mod Length(k);
IF n>0 THEN vkey += k[n] ELSE vkey += k[Length(k)];
END;
END;
// Vigenere encipher
FUNCTION enVig(pt,key:STRING): STRING;
VAR ct: STRING;
c,n : Cardinal;
BEGIN
ct := pt;
FOR c := 1 TO Length(pt) DO BEGIN
n := letternum(pt[c])+letternum(key[c]);
n := n mod 26;
ct[c]:=chr(ord('A')+n);
END;
enVig := ct;
END;
// Vigenere decipher
FUNCTION deVig(ct,key:STRING): STRING;
VAR pt : STRING;
c,n : INTEGER;
BEGIN
pt := ct;
FOR c := 1 TO Length(ct) DO BEGIN
n := letternum(ct[c])-letternum(key[c]);
IF n<0 THEN n:=26+n;
pt[c]:=chr(ord('A')+n);
END;
deVig := pt;
END;


# Kasiski examination
$seqtext = $text;
VAR key: STRING = 'Vigenere cipher';
while ($seqtext =~ /(...).*\1/) {
msg: STRING = 'Beware the Jabberwock! The jaws that bite, the claws that catch!';
$seqtext = substr($seqtext, 1+index($seqtext, $1));
vtx: STRING = '';
push @spacing, 1 + index($seqtext, $1);
ctx: STRING = '';
}
ptx: STRING = '';


for my $j (@spacing) {
BEGIN
push @factors, grep { $j % $_ == 0 } 2..$j;
// make Vigenere-compatible
}
vtx := vstr(msg);
$freq{$_}++ for @factors;
key := vkey(vtx,key);
@sortedfactors = grep { $_ >= 4 } sort { $freq{$b} <=> $freq{$a} } keys %freq; # discard very short keys
// Vigenere encipher / decipher
ctx := enVig(vtx,key);
ptx := deVig(ctx,key);
// display results
Writeln('Message : ',msg);
Writeln('Plaintext : ',vtx);
Writeln('Key : ',key);
Writeln('Ciphertext : ',ctx);
Writeln('Plaintext : ',ptx);
END.


for my $keylen ( @sortedfactors[0..$max_key_lengths-1] ) {
</lang>
my $keyguess = '';
for (my $i = 0; $i < $keylen; $i++) {
my($mykey, %chi_values, $bestguess);
for (my $j = 0; $j < length($text); $j += $keylen) {
$mykey .= substr($text, ($j+$i) % length($text), 1);
}


for my $subkey (@alphabet) {
{{out}}
my $decrypted = mycrypt($mykey, $subkey);
<pre>
my $length = length($decrypted);
Message : Beware the Jabberwock! The jaws that bite, the claws that catch!
for my $char (@alphabet) {
Plaintext : BEWARETHEJABBERWOCKTHEJAWSTHATBITETHECLAWSTHATCATCH
my $expected = $English_letter_freq{$char} * $length / 100;
Key : VIGENERECIPHERVIGENERECIPHERVIGENERECIPHERVIGENEREC
my $observed;
Ciphertext : WMCEEIKLGRPIFVMEUGXXYILILZXYVBHMGIKLGKAHAJOPGXPEKGJ
++$observed while $decrypted =~ /$char/g;
Plaintext : BEWARETHEJABBERWOCKTHEJAWSTHATBITETHECLAWSTHATCATCH
$chi_values{$subkey} += ($observed - $expected)**2 / $expected if $observed;
</pre>
}
}


$Keys{$keylen}{score} = $chi_values{'A'};
=={{header|Perl}}==
for my $sk (sort keys %chi_values) {
<lang perl>if( @ARGV != 3 ){
if ($chi_values{$sk} <= $Keys{$keylen}{score}) {
printHelp();
$bestguess = $sk;
$Keys{$keylen}{score} = $chi_values{$sk};
}
}
$keyguess .= $bestguess;
}
$Keys{$keylen}{key} = $keyguess;
}
map { $Keys{$_}{key} } sort { $Keys{$a}{score} <=> $Keys{$b}{score}} keys %Keys;
}
}


sub mycrypt {
# translate to upper-case, remove anything else
my ($text, $key) = @_;
map( (tr/a-z/A-Z/, s/[^A-Z]//g), @ARGV );
my ($new_text, %values_numbers);


my $cipher_decipher = $ARGV[ 0 ];
my $keylen = length($key);
@values_numbers{@alphabet} = 0..25;
my %values_letters = reverse %values_numbers;


for (my $i = 0; $i < length($text); $i++) {
if( $cipher_decipher !~ /ENC|DEC/ ){
my $val = -1 * $values_numbers{substr( $key, $i%$keylen, 1)} # negative shift for decode
printHelp(); # user should say what to do
+ $values_numbers{substr($text, $i, 1)};
$new_text .= $values_letters{ $val % 26 };
}
return $new_text;
}
}


my $cipher_text = <<~'EOD';
print "Key: " . (my $key = $ARGV[ 2 ]) . "\n";
MOMUD EKAPV TQEFM OEVHP AJMII CDCTI FGYAG JSPXY ALUYM NSMYH
VUXJE LEPXJ FXGCM JHKDZ RYICU HYPUS PGIGM OIYHF WHTCQ KMLRD
ITLXZ LJFVQ GHOLW CUHLO MDSOE KTALU VYLNZ RFGBX PHVGA LWQIS
FGRPH JOOFW GUBYI LAPLA LCAFA AMKLG CETDW VOELJ IKGJB XPHVG
ALWQC SNWBU BYHCU HKOCE XJEYK BQKVY KIIEH GRLGH XEOLW AWFOJ
ILOVV RHPKD WIHKN ATUHN VRYAQ DIVHX FHRZV QWMWV LGSHN NLVZS
JLAKI FHXUF XJLXM TBLQV RXXHR FZXGV LRAJI EXPRV OSMNP KEPDT
LPRWM JAZPK LQUZA ALGZX GVLKL GJTUI ITDSU REZXJ ERXZS HMPST
MTEOE PAPJH SMFNB YVQUZ AALGA YDNMP AQOWT UHDBV TSMUE UIMVH
QGVRW AEFSP EMPVE PKXZY WLKJA GWALT VYYOB YIXOK IHPDS EVLEV
RVSGB JOGYW FHKBL GLXYA MVKIS KIEHY IMAPX UOISK PVAGN MZHPW
TTZPV XFCCD TUHJH WLAPF YULTB UXJLN SIJVV YOVDJ SOLXG TGRVO
SFRII CTMKO JFCQF KTINQ BWVHG TENLH HOGCS PSFPV GJOKM SIFPR
ZPAAS ATPTZ FTPPD PORRF TAXZP KALQA WMIUD BWNCT LEFKO ZQDLX
BUXJL ASIMR PNMBF ZCYLV WAPVF QRHZV ZGZEF KBYIO OFXYE VOWGB
BXVCB XBAWG LQKCM ICRRX MACUO IKHQU AJEGL OIJHH XPVZW JEWBA
FWAML ZZRXJ EKAHV FASMU LVVUT TGK
EOD


my $text = uc($cipher_text) =~ s/[^@{[join '', @alphabet]}]//gr;
if( $cipher_decipher =~ /ENC/ ){
print "Plain-text: " . (my $plain = $ARGV[ 1 ]) . "\n";
print "Encrypted: " . Vigenere( 1, $key, $plain ) . "\n";
}elsif( $cipher_decipher =~ /DEC/ ){
print "Cipher-text: " . (my $cipher = $ARGV[ 1 ]) . "\n";
print "Decrypted: " . Vigenere( -1, $key, $cipher ) . "\n";
}


for my $key ( myguess($text) ) {
sub printHelp{
print "Usage:\n" .
say "Key $key\n" .
"Encrypting:\n perl cipher.pl ENC (plain text) (key)\n" .
"Key length " . length($key) . "\n" .
"Decrypting:\n perl cipher.pl DEC (cipher text) (key)\n";
"Plaintext " . substr(mycrypt($text, $key), 0, 80) . "...\n";
}</syntaxhighlight>
exit -1;
}


{{out}}
sub Vigenere{
<pre>Key THECHESHIRECAT
my ($direction, $key, $text) = @_;
Key length 14
for( my $count = 0; $count < length $text; $count ++ ){
Plaintext THISWASTHEPOEMTHATALICEREADJABBERWOCKYTWASBRILLIGANDTHESLITHYTOVESDIDGYREANDGIMB...
$key_offset = $direction * ord substr( $key, $count % length $key, 1);
$char_offset = ord substr( $text, $count, 1 );
$cipher .= chr 65 + ((($char_offset % 26) + ($key_offset % 26)) % 26);
# 65 is the ASCII character code for 'A'
}
return $cipher;
}</lang>


Key THECHESCIRECATTHECHESHIRECAT
Demonstration:
Key length 28
Plaintext THISWASYHEPOEMTHATALICEREADJABBERWOHKYTWASBRILLIGANDTHESLITHYTOAESDIDGYREANDGIMB...


Key TJGGAHET
<pre>$ perl cipher.pl ENC 'Beware the Jabberwock, my son! The jaws that bite, the claws that catch!' VIGENERECIPHER
Key: VIGENERECIPHER
Key length 8
Plaintext TFGODXGHWMNKEYIVLMBJACIPPTXWTBBNFRADSITFHCOSMGOTFYPOXCASLGRDFQCJTABEDSNFPTOBYIQZ...
Plain-text: BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH
Encrypted: WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY


Key THECSAS
$ perl cipher.pl DEC WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY VIGENERECIPHER
Key: VIGENERECIPHER
Key length 7
Plaintext THISLESHIRRYENTHATPPIQFEGKDKABBEGAOQLLVGATBRILAMGOOQVRETLITHNXOJFFFSDHYREACHGWNO...
Cipher-text: WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY
Decrypted: BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH


Key THEC
$ perl cipher.pl FOO WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY VIGENERECIPHER
Key length 4
Usage:
Plaintext THISKXGYWOPOLYIMLODNHCIGPVZAABBEFTCHZITWHEQWTGOKFARSECAJLITHMQCATCDIKSNWPVQFFIQQ...</pre>
Encrypting:
perl cipher.pl ENC (plain text) (key)
Decrypting:
perl cipher.pl DEC (cipher text) (key)</pre>


=={{header|Phix}}==
=={{header|Phix}}==
{{trans|Julia}}
<lang Phix>enum type mode ENCRYPT = +1, DECRYPT = -1 end type
<!--<syntaxhighlight lang="phix">(phixonline)-->

<span style="color: #000080;font-style:italic;">--
function Vigenere(string s, string key, mode m)
-- demo\rosetta\Cryptanalysis.exw
string res = ""
--</span>
integer k = 1, ch
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span>
s = upper(s)
<span style="color: #004080;">atom</span> <span style="color: #000000;">t0</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">time</span><span style="color: #0000FF;">()</span>
for i=1 to length(s) do
<span style="color: #008080;">constant</span> <span style="color: #000000;">ciphertext</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">substitute_all</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"""
ch = s[i]
MOMUD EKAPV TQEFM OEVHP AJMII CDCTI FGYAG JSPXY ALUYM NSMYH
if ch>='A' and ch<='Z' then
VUXJE LEPXJ FXGCM JHKDZ RYICU HYPUS PGIGM OIYHF WHTCQ KMLRD
res &= 'A'+mod(ch+m*(key[k]+26),26)
ITLXZ LJFVQ GHOLW CUHLO MDSOE KTALU VYLNZ RFGBX PHVGA LWQIS
k = mod(k,length(key))+1
FGRPH JOOFW GUBYI LAPLA LCAFA AMKLG CETDW VOELJ IKGJB XPHVG
end if
ALWQC SNWBU BYHCU HKOCE XJEYK BQKVY KIIEH GRLGH XEOLW AWFOJ
end for
ILOVV RHPKD WIHKN ATUHN VRYAQ DIVHX FHRZV QWMWV LGSHN NLVZS
return res
JLAKI FHXUF XJLXM TBLQV RXXHR FZXGV LRAJI EXPRV OSMNP KEPDT
end function
LPRWM JAZPK LQUZA ALGZX GVLKL GJTUI ITDSU REZXJ ERXZS HMPST
MTEOE PAPJH SMFNB YVQUZ AALGA YDNMP AQOWT UHDBV TSMUE UIMVH
QGVRW AEFSP EMPVE PKXZY WLKJA GWALT VYYOB YIXOK IHPDS EVLEV
RVSGB JOGYW FHKBL GLXYA MVKIS KIEHY IMAPX UOISK PVAGN MZHPW
TTZPV XFCCD TUHJH WLAPF YULTB UXJLN SIJVV YOVDJ SOLXG TGRVO
SFRII CTMKO JFCQF KTINQ BWVHG TENLH HOGCS PSFPV GJOKM SIFPR
ZPAAS ATPTZ FTPPD PORRF TAXZP KALQA WMIUD BWNCT LEFKO ZQDLX
BUXJL ASIMR PNMBF ZCYLV WAPVF QRHZV ZGZEF KBYIO OFXYE VOWGB
BXVCB XBAWG LQKCM ICRRX MACUO IKHQU AJEGL OIJHH XPVZW JEWBA
FWAML ZZRXJ EKAHV FASMU LVVUT TGK"""</span><span style="color: #0000FF;">,{</span><span style="color: #008000;">" "</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"\n"</span><span style="color: #0000FF;">},{</span><span style="color: #008000;">""</span><span style="color: #0000FF;">,</span><span style="color: #008000;">""</span><span style="color: #0000FF;">})</span>
<span style="color: #008080;">constant</span> <span style="color: #000000;">letters</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">new_dict</span><span style="color: #0000FF;">(</span>
constant key = "LEMON",
<span style="color: #0000FF;">{{</span><span style="color: #008000;">'E'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">12.702</span><span style="color: #0000FF;">},</span>
s = "ATTACK AT DAWN",
<span style="color: #0000FF;">{</span><span style="color: #008000;">'T'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">9.056</span><span style="color: #0000FF;">},</span>
e = Vigenere(s,key,ENCRYPT),
<span style="color: #0000FF;">{</span><span style="color: #008000;">'A'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">8.167</span><span style="color: #0000FF;">},</span>
d = Vigenere(e,key,DECRYPT)
<span style="color: #0000FF;">{</span><span style="color: #008000;">'O'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">7.507</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">'I'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">6.966</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">'N'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">6.749</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">'S'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">6.327</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">'H'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">6.094</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">'R'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">5.987</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">'D'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">4.253</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">'L'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">4.025</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">'C'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2.782</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">'U'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2.758</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">'M'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2.406</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">'W'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2.361</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">'F'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2.228</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">'G'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2.015</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">'Y'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1.974</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">'P'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1.929</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">'B'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1.492</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">'V'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0.978</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">'K'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0.772</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">'J'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0.153</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">'X'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0.150</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">'Q'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0.095</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">'Z'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0.074</span><span style="color: #0000FF;">}})</span>
<span style="color: #008080;">constant</span> <span style="color: #000000;">digraphs</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">new_dict</span><span style="color: #0000FF;">(</span>
<span style="color: #0000FF;">{{</span><span style="color: #008000;">"TH"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">15.2</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"HE"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">12.8</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"IN"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">9.4</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"ER"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">9.4</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"AN"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">8.2</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"RE"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">6.8</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"ND"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">6.3</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"AT"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">5.9</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"ON"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">5.7</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"NT"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">5.6</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"HA"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">5.6</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"ES"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">5.6</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"ST"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">5.5</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"EN"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">5.5</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"ED"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">5.3</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"TO"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">5.2</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"IT"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">5.0</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"OU"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">5.0</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"EA"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">4.7</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"HI"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">4.6</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"IS"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">4.6</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"OR"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">4.3</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"TI"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">3.4</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"AS"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">3.3</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"TE"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2.7</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"ET"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1.9</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"NG"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1.8</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"OF"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1.6</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"AL"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0.9</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"DE"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0.9</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"SE"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0.8</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"LE"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0.8</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"SA"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0.6</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"SI"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0.5</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"AR"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0.4</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"VE"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0.4</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"RA"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0.4</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"LD"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0.2</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"UR"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0.2</span><span style="color: #0000FF;">}})</span>
<span style="color: #008080;">constant</span> <span style="color: #000000;">trigraphs</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">new_dict</span><span style="color: #0000FF;">(</span>
<span style="color: #0000FF;">{{</span><span style="color: #008000;">"THE"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">18.1</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"AND"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">7.3</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"ING"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">7.2</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"ION"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">4.2</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"ENT"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">4.2</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"HER"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">3.6</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"FOR"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">3.4</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"THA"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">3.3</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"NTH"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">3.3</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"INT"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">3.2</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"TIO"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">3.1</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"ERE"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">3.1</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"TER"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">3.0</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"EST"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2.8</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"ERS"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2.8</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"HAT"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2.6</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"ATI"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2.6</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"ATE"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2.5</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"ALL"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2.5</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"VER"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2.4</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"HIS"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2.4</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"HES"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2.4</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"ETH"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2.4</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"OFT"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2.2</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"STH"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2.1</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"RES"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2.1</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"OTH"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2.1</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"ITH"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2.1</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"FTH"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2.1</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"ONT"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2.0</span><span style="color: #0000FF;">}})</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">decrypt</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">enc</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">string</span> <span style="color: #000000;">key</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">keylen</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">key</span><span style="color: #0000FF;">),</span> <span style="color: #000000;">k</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">msg</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #008000;">' '</span><span style="color: #0000FF;">,</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">enc</span><span style="color: #0000FF;">))</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">enc</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">msg</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">mod</span><span style="color: #0000FF;">(</span><span style="color: #000000;">enc</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]-</span><span style="color: #000000;">key</span><span style="color: #0000FF;">[</span><span style="color: #000000;">k</span><span style="color: #0000FF;">]+</span><span style="color: #000000;">26</span><span style="color: #0000FF;">,</span><span style="color: #000000;">26</span><span style="color: #0000FF;">)+</span><span style="color: #008000;">'A'</span>
<span style="color: #000000;">k</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">mod</span><span style="color: #0000FF;">(</span><span style="color: #000000;">k</span><span style="color: #0000FF;">,</span><span style="color: #000000;">keylen</span><span style="color: #0000FF;">)+</span><span style="color: #000000;">1</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">msg</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">cryptanalyze</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">enc</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">integer</span> <span style="color: #000000;">maxkeylen</span><span style="color: #0000FF;">=</span><span style="color: #000000;">20</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">enclen</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">enc</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">maxkey</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">""</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">maxdec</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">""</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">k1</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">" "</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">maxscore</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0.0</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">keylen</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">maxkeylen</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">key</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #008000;">' '</span><span style="color: #0000FF;">,</span><span style="color: #000000;">keylen</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">idx</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{}</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">enclen</span> <span style="color: #008080;">do</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">mod</span><span style="color: #0000FF;">(</span><span style="color: #000000;">i</span><span style="color: #0000FF;">,</span><span style="color: #000000;">keylen</span><span style="color: #0000FF;">)=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">idx</span> <span style="color: #0000FF;">&=</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">-</span><span style="color: #000000;">keylen</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">keylen</span> <span style="color: #008080;">do</span>
printf(1,"Original: %s\nEncrypted: %s\nDecrypted: %s\n",{s,e,d})</lang>
<span style="color: #004080;">atom</span> <span style="color: #000000;">maxsubscore</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0.0</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">j</span><span style="color: #0000FF;">=</span><span style="color: #008000;">'A'</span> <span style="color: #008080;">to</span> <span style="color: #008000;">'Z'</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">subscore</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0.0</span>
<span style="color: #000000;">k1</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">j</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">encidx</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">""</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">ii</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">idx</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">encidx</span> <span style="color: #0000FF;">&=</span> <span style="color: #000000;">enc</span><span style="color: #0000FF;">[</span><span style="color: #000000;">idx</span><span style="color: #0000FF;">[</span><span style="color: #000000;">ii</span><span style="color: #0000FF;">]]</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">dec</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">decrypt</span><span style="color: #0000FF;">(</span><span style="color: #000000;">encidx</span><span style="color: #0000FF;">,</span><span style="color: #000000;">k1</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">di</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">dec</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">subscore</span> <span style="color: #0000FF;">+=</span> <span style="color: #7060A8;">getd</span><span style="color: #0000FF;">(</span><span style="color: #000000;">dec</span><span style="color: #0000FF;">[</span><span style="color: #000000;">di</span><span style="color: #0000FF;">],</span><span style="color: #000000;">letters</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">subscore</span> <span style="color: #0000FF;">></span> <span style="color: #000000;">maxsubscore</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">maxsubscore</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">subscore</span>
<span style="color: #000000;">key</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">j</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #000000;">idx</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">sq_add</span><span style="color: #0000FF;">(</span><span style="color: #000000;">idx</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">dec</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">decrypt</span><span style="color: #0000FF;">(</span><span style="color: #000000;">enc</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">key</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">score</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0.0</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">dec</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">score</span> <span style="color: #0000FF;">+=</span> <span style="color: #7060A8;">getd</span><span style="color: #0000FF;">(</span><span style="color: #000000;">dec</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">],</span><span style="color: #000000;">letters</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">enclen</span> <span style="color: #0000FF;">-</span> <span style="color: #000000;">2</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">digraph</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">dec</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">..</span><span style="color: #000000;">i</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">trigraph</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">dec</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">..</span><span style="color: #000000;">i</span> <span style="color: #0000FF;">+</span> <span style="color: #000000;">2</span><span style="color: #0000FF;">]</span>
<span style="color: #000000;">score</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">2</span> <span style="color: #0000FF;">*</span> <span style="color: #7060A8;">getd</span><span style="color: #0000FF;">(</span><span style="color: #000000;">digraph</span><span style="color: #0000FF;">,</span><span style="color: #000000;">digraphs</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">score</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">3</span> <span style="color: #0000FF;">*</span> <span style="color: #7060A8;">getd</span><span style="color: #0000FF;">(</span><span style="color: #000000;">trigraph</span><span style="color: #0000FF;">,</span><span style="color: #000000;">trigraphs</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">score</span> <span style="color: #0000FF;">></span> <span style="color: #000000;">maxscore</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">maxscore</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">score</span>
<span style="color: #000000;">maxkey</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">key</span>
<span style="color: #000000;">maxdec</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">dec</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">return</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">maxkey</span><span style="color: #0000FF;">,</span><span style="color: #000000;">maxdec</span><span style="color: #0000FF;">}</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">fold</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">integer</span> <span style="color: #000000;">w</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">w</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">s</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">by</span> <span style="color: #000000;">w</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">..</span><span style="color: #000000;">i</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"\n"</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">s</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #004080;">string</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">key</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">dec</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">cryptanalyze</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ciphertext</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"key: %s\n\n%s\n\n"</span><span style="color: #0000FF;">,</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">key</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">fold</span><span style="color: #0000FF;">(</span><span style="color: #000000;">dec</span><span style="color: #0000FF;">,</span><span style="color: #000000;">80</span><span style="color: #0000FF;">)})</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"elapsed time: %3.2f seconds"</span><span style="color: #0000FF;">,{</span><span style="color: #7060A8;">time</span><span style="color: #0000FF;">()-</span><span style="color: #000000;">t0</span><span style="color: #0000FF;">})</span>
<span style="color: #0000FF;">{}</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">wait_key</span><span style="color: #0000FF;">()</span>
<!--</syntaxhighlight>-->
{{Out}}
{{Out}}
<pre>
<pre>
key: THECHESHIRECAT
Original: ATTACK AT DAWN
Encrypted: LXFOPVEFRNHR
Decrypted: ATTACKATDAWN
</pre>


THISWASTHEPOEMTHATALICEREADJABBERWOCKYTWASBRILLIGANDTHESLITHYTOVESDIDGYREANDGIM
=={{header|PHP}}==
BLEINTHEWABEALLMIMSYWERETHEBOROGOVESANDTHEMOMERATHSOUTGRABEBEWARETHEJABBERWOCKM
{{trans|C}}
YSONTHEJAWSTHATBITETHECLAWSTHATCATCHBEWARETHEJUBJUBBIRDANDSHUNTHEFRUMIOUSBANDER
<lang PHP><?php
SNATCHHETOOKHISVORPALSWORDINHANDLONGTIMETHEMANXOMEFOEHESOUGHTSORESTEDHEBYTHETUM
TUMTREEANDSTOODAWHILEINTHOUGHTANDASINUFFISHTHOUGHTHESTOODTHEJABBERWOCKWITHEYESO
FFLAMECAMEWHIFFLINGTHROUGHTHETULGEYWOODANDBURBLEDASITCAMEONETWOONETWOANDTHROUGH
ANDTHROUGHTHEVORPALBLADEWENTSNICKERSNACKHELEFTITDEADANDWITHITSHEADHEWENTGALUMPH
INGBACKANDHASTTHOUSLAINTHEJABBERWOCKCOMETOMYARMSMYBEAMISHBOYOFRABJOUSDAYCALLOOH
CALLAYHECHORTLEDINHISJOYTWASBRILLIGANDTHESLITHYTOVESDIDGYREANDGIMBLEINTHEWABEAL
LMIMSYWERETHEBOROGOVESANDTHEMOMERATHSOUTGRABEITSEEMSVERYPRETTYSHESAIDWHENSHEHAD
FINISHEDITBUTITSRATHERHARDTOUNDERSTAND


elapsed time: 0.42 seconds
$str = "Beware the Jabberwock, my son! The jaws that bite, the claws that catch!";
</pre>
$key = "VIGENERECIPHER";


=={{header|Python}}==
printf("Text: %s\n", $str);
{{trans|D}}
printf("key: %s\n", $key);
<syntaxhighlight lang="python">from string import uppercase
from operator import itemgetter


def vigenere_decrypt(target_freqs, input):
$cod = encipher($str, $key, true); printf("Code: %s\n", $cod);
nchars = len(uppercase)
$dec = encipher($cod, $key, false); printf("Back: %s\n", $dec);
ordA = ord('A')
sorted_targets = sorted(target_freqs)


def frequency(input):
function encipher($src, $key, $is_encode)
result = [[c, 0.0] for c in uppercase]
{
$key = strtoupper($key);
for c in input:
result[c - ordA][1] += 1
$src = strtoupper($src);
$dest = '';
return result


def correlation(input):
/* strip out non-letters */
for($i = 0; $i <= strlen($src); $i++) {
result = 0.0
$char = substr($src, $i, 1);
freq = frequency(input)
if(ctype_upper($char)) {
freq.sort(key=itemgetter(1))
$dest .= $char;
}
}


for($i = 0; $i <= strlen($dest); $i++) {
for i, f in enumerate(freq):
result += f[1] * sorted_targets[i]
$char = substr($dest, $i, 1);
if(!ctype_upper($char)) {
return result
continue;
}
$dest = substr_replace($dest,
chr (
ord('A') +
($is_encode
? ord($char) - ord('A') + ord($key[$i % strlen($key)]) - ord('A')
: ord($char) - ord($key[$i % strlen($key)]) + 26
) % 26
)
, $i, 1);
}


cleaned = [ord(c) for c in input.upper() if c.isupper()]
return $dest;
best_len = 0
}
best_corr = -100.0


# Assume that if there are less than 20 characters
?>
# per column, the key's too long to guess
</lang>
for i in xrange(2, len(cleaned) // 20):
{{out}}
pieces = [[] for _ in xrange(i)]
<pre>Text: Beware the Jabberwock, my son! The jaws that bite, the claws that catch!
for j, c in enumerate(cleaned):
key: VIGENERECIPHER
pieces[j % i].append(c)
Code: WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY
Back: BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH</pre>


# The correlation seems to increase for smaller
=={{header|PicoLisp}}==
# pieces/longer keys, so weigh against them a little
<lang PicoLisp>(de vigenereKey (Str)
corr = -0.5 * i + sum(correlation(p) for p in pieces)
(extract
'((C)
(when (>= "Z" (uppc C) "A")
(- (char (uppc C)) 65) ) )
(chop Str) ) )


if corr > best_corr:
(de vigenereEncrypt (Str Key)
best_len = i
(pack
(mapcar
best_corr = corr
'((C K)
(char (+ 65 (% (+ C K) 26))) )
(vigenereKey Str)
(apply circ (vigenereKey Key)) ) ) )


if best_len == 0:
(de vigenereDecrypt (Str Key)
return ("Text is too short to analyze", "")
(pack
(mapcar
'((C K)
(char (+ 65 (% (+ 26 (- C K)) 26))) )
(vigenereKey Str)
(apply circ (vigenereKey Key)) ) ) )</lang>
Test:
<pre>: (vigenereEncrypt
"Beware the Jabberwock, my son! The jaws that bite, the claws that catch!"
"VIGENERECIPHER" )
-> "WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY"


pieces = [[] for _ in xrange(best_len)]
: (vigenereDecrypt @ "VIGENERECIPHER")
for i, c in enumerate(cleaned):
-> "BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH"</pre>
pieces[i % best_len].append(c)


freqs = [frequency(p) for p in pieces]
=={{header|PL/I}}==
<lang PL/I>
cypher: procedure options (main); /* 21 September 2012 */
declare t(26) character (26);
declare (i, j, k, L) fixed binary;
declare (original, encoded, coder) character (1000) varying initial ('');
declare cypher character (30) varying;
declare (co, ct, cc) character (1);


/* Set up cypher table. */
key = ""
for fr in freqs:
t(1) = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
fr.sort(key=itemgetter(1), reverse=True)
do i = 2 to 26;
t(i) = substr(t(i-1), 2, 25) || substr(t(i-1), 1, 1);
end;


cypher = 'VIGILANCE';
m = 0
original = 'Meet me on Tuesday evening at seven.';
max_corr = 0.0
for j in xrange(nchars):
put edit ('Message=', original) (a);
corr = 0.0
original = uppercase(original);
c = ordA + j
for frc in fr:
d = (ord(frc[0]) - c + nchars) % nchars
corr += frc[1] * target_freqs[d]


if corr > max_corr:
/* Create the cypher text, same length as original, or longer. */
m = j
coder = repeat(cypher, length(original)/length(cypher));
max_corr = corr


key += chr(m + ordA)
/* Encode the original message, character by character. */
/* Non-alphabetic characters are ignored. */
L = 0;
do i = 1 to length(original);
co = substr(original, i, 1);
j = index(t(1), co);
if j = 0 then iterate; /* Ignore non-alphabetic character */
L = L + 1;
ct = substr(coder, L, 1);
k = index(t(1), ct);
encoded = encoded || substr(t(j), k, 1);
end;
put skip data (encoded);


r = (chr((c - ord(key[i % best_len]) + nchars) % nchars + ordA)
/* DECODING. */
for i, c in enumerate(cleaned))
put skip list ('Decoded=');
return (key, "".join(r))
do i = 1 to length(encoded);
cc = substr(coder, i, 1);
j = index(t(1), cc);
k = index(t(j), substr(encoded, i, 1));
put edit (substr(t(1), k, 1) ) (a(1));
end;
end cypher;
</lang>
{{out}}
<pre>
Message=Meet me on Tuesday evening at seven.
ENCODED='HMKBXEBPXPMYLLYRXIIQTOLTFGZZV';
Decoded= MEETMEONTUESDAYEVENINGATSEVEN
</pre>


=={{header|PowerShell}}==
<lang Powershell># Author: D. Cudnohufsky
function Get-VigenereCipher
{
Param
(
[Parameter(Mandatory=$true)]
[string] $Text,
[Parameter(Mandatory=$true)]
[string] $Key,
[switch] $Decode
)
begin
{
$map = [char]'A'..[char]'Z'
}
process
{
$Key = $Key -replace '[^a-zA-Z]',''
$Text = $Text -replace '[^a-zA-Z]',''


def main():
$keyChars = $Key.toUpper().ToCharArray()
encoded = """
$Chars = $Text.toUpper().ToCharArray()
MOMUD EKAPV TQEFM OEVHP AJMII CDCTI FGYAG JSPXY ALUYM NSMYH
VUXJE LEPXJ FXGCM JHKDZ RYICU HYPUS PGIGM OIYHF WHTCQ KMLRD
function encode
ITLXZ LJFVQ GHOLW CUHLO MDSOE KTALU VYLNZ RFGBX PHVGA LWQIS
{
FGRPH JOOFW GUBYI LAPLA LCAFA AMKLG CETDW VOELJ IKGJB XPHVG
ALWQC SNWBU BYHCU HKOCE XJEYK BQKVY KIIEH GRLGH XEOLW AWFOJ
ILOVV RHPKD WIHKN ATUHN VRYAQ DIVHX FHRZV QWMWV LGSHN NLVZS
JLAKI FHXUF XJLXM TBLQV RXXHR FZXGV LRAJI EXPRV OSMNP KEPDT
LPRWM JAZPK LQUZA ALGZX GVLKL GJTUI ITDSU REZXJ ERXZS HMPST
MTEOE PAPJH SMFNB YVQUZ AALGA YDNMP AQOWT UHDBV TSMUE UIMVH
QGVRW AEFSP EMPVE PKXZY WLKJA GWALT VYYOB YIXOK IHPDS EVLEV
RVSGB JOGYW FHKBL GLXYA MVKIS KIEHY IMAPX UOISK PVAGN MZHPW
TTZPV XFCCD TUHJH WLAPF YULTB UXJLN SIJVV YOVDJ SOLXG TGRVO
SFRII CTMKO JFCQF KTINQ BWVHG TENLH HOGCS PSFPV GJOKM SIFPR
ZPAAS ATPTZ FTPPD PORRF TAXZP KALQA WMIUD BWNCT LEFKO ZQDLX
BUXJL ASIMR PNMBF ZCYLV WAPVF QRHZV ZGZEF KBYIO OFXYE VOWGB
BXVCB XBAWG LQKCM ICRRX MACUO IKHQU AJEGL OIJHH XPVZW JEWBA
FWAML ZZRXJ EKAHV FASMU LVVUT TGK"""


english_frequences = [
param
0.08167, 0.01492, 0.02782, 0.04253, 0.12702, 0.02228, 0.02015,
(
$Char,
0.06094, 0.06966, 0.00153, 0.00772, 0.04025, 0.02406, 0.06749,
$keyChar,
0.07507, 0.01929, 0.00095, 0.05987, 0.06327, 0.09056, 0.02758,
0.00978, 0.02360, 0.00150, 0.01974, 0.00074]
$Alpha = [char]'A'..[char]'Z'
)


(key, decoded) = vigenere_decrypt(english_frequences, encoded)
$charIndex = $Alpha.IndexOf([int]$Char)
print "Key:", key
$keyIndex = $Alpha.IndexOf([int]$keyChar)
print "\nText:", decoded
$NewIndex = ($charIndex + $KeyIndex) - $Alpha.Length
$Alpha[$NewIndex]


main()</syntaxhighlight>
}
function decode
{


=={{header|Racket}}==
param
(
$Char,
$keyChar,
$Alpha = [char]'A'..[char]'Z'
)


=== Simple method ===
$charIndex = $Alpha.IndexOf([int]$Char)
This is a simple method that just tries to find a key of any length that minimizes the difference from the expected English character distributions.
$keyIndex = $Alpha.IndexOf([int]$keyChar)
$int = $charIndex - $keyIndex
if ($int -lt 0) { $NewIndex = $int + $Alpha.Length }
else { $NewIndex = $int }
$Alpha[$NewIndex]
}


<syntaxhighlight lang="racket">
while ( $keyChars.Length -lt $Chars.Length )
#lang at-exp racket
{
$keyChars = $keyChars + $keyChars
}


(define max-keylen 30)
for ( $i = 0; $i -lt $Chars.Length; $i++ )
{


(define text
if ( [int]$Chars[$i] -in $map -and [int]$keyChars[$i] -in $map )
@~a{MOMUD EKAPV TQEFM OEVHP AJMII CDCTI FGYAG JSPXY ALUYM NSMYH
{
VUXJE LEPXJ FXGCM JHKDZ RYICU HYPUS PGIGM OIYHF WHTCQ KMLRD
if ($Decode) {$Chars[$i] = decode $Chars[$i] $keyChars[$i] $map}
ITLXZ LJFVQ GHOLW CUHLO MDSOE KTALU VYLNZ RFGBX PHVGA LWQIS
else {$Chars[$i] = encode $Chars[$i] $keyChars[$i] $map}
FGRPH JOOFW GUBYI LAPLA LCAFA AMKLG CETDW VOELJ IKGJB XPHVG
ALWQC SNWBU BYHCU HKOCE XJEYK BQKVY KIIEH GRLGH XEOLW AWFOJ
ILOVV RHPKD WIHKN ATUHN VRYAQ DIVHX FHRZV QWMWV LGSHN NLVZS
JLAKI FHXUF XJLXM TBLQV RXXHR FZXGV LRAJI EXPRV OSMNP KEPDT
LPRWM JAZPK LQUZA ALGZX GVLKL GJTUI ITDSU REZXJ ERXZS HMPST
MTEOE PAPJH SMFNB YVQUZ AALGA YDNMP AQOWT UHDBV TSMUE UIMVH
QGVRW AEFSP EMPVE PKXZY WLKJA GWALT VYYOB YIXOK IHPDS EVLEV
RVSGB JOGYW FHKBL GLXYA MVKIS KIEHY IMAPX UOISK PVAGN MZHPW
TTZPV XFCCD TUHJH WLAPF YULTB UXJLN SIJVV YOVDJ SOLXG TGRVO
SFRII CTMKO JFCQF KTINQ BWVHG TENLH HOGCS PSFPV GJOKM SIFPR
ZPAAS ATPTZ FTPPD PORRF TAXZP KALQA WMIUD BWNCT LEFKO ZQDLX
BUXJL ASIMR PNMBF ZCYLV WAPVF QRHZV ZGZEF KBYIO OFXYE VOWGB
BXVCB XBAWG LQKCM ICRRX MACUO IKHQU AJEGL OIJHH XPVZW JEWBA
FWAML ZZRXJ EKAHV FASMU LVVUT TGK})


(define first-char (char->integer #\A))
$Chars[$i] = [char]$Chars[$i]
(define chars# (- (char->integer #\Z) first-char -1))
[string]$OutText += $Chars[$i]
}


(define freqs ; english letter frequencies from wikipedia
}
((compose1 list->vector (curry map (curryr / 100000.0)))
'(8167 1492 2782 4253 12702 2228 2015 6094 6966 153 772 4025 2406
$OutText
6749 7507 1929 95 5987 6327 9056 2758 978 2360 150 1974 74)))
$OutText = $null
}
}</lang>
Usage examples:
<pre>
Encode:
PS C:\> Get-VigenereCipher 'We attack at dawn.' 'lemon'
HIMHGLGWOGOEIB


(define text* (for/vector ([c (regexp-replace* #px"\\s+" text "")])
Decode:
(- (char->integer c) first-char)))
PS C:\> Get-VigenereCipher 'HIMHGLGWOGOEIB' 'lemon' -Decode
(define N (vector-length text*))
WEATTACKATDAWN
</pre>


(define (col-guesses len)
=={{header|PureBasic}}==
(for/list ([ofs len])
<lang PureBasic>Procedure prepString(text.s, Array letters(1))
(define text (for/list ([i (in-range ofs N len)]) (vector-ref text* i)))
;convert characters to an ordinal (0-25) and remove non-alphabetic characters,
(define cN (length text))
;returns dimension size of result array letters()
(define cfreqs (make-vector chars# 0))
Protected *letter.Character, index
Dim letters(Len(text))
(for ([c (in-list text)])
(vector-set! cfreqs c (add1 (vector-ref cfreqs c))))
text = UCase(text)
(for ([i chars#]) (vector-set! cfreqs i (/ (vector-ref cfreqs i) cN)))
*letter = @text
(argmin car
While *letter\c
(for/list ([d chars#])
Select *letter\c
Case 'A' To 'Z'
(cons (for/sum ([i chars#])
(expt (- (vector-ref freqs i)
letters(index) = *letter\c - 65
(vector-ref cfreqs (modulo (+ i d) chars#)))
index + 1
2))
EndSelect
*letter + SizeOf(Character)
d)))))
Wend
If index > 0
Redim letters(index - 1)
EndIf
ProcedureReturn index - 1
EndProcedure


(define best-key
Procedure.s VC_encrypt(text.s, keyText.s, reverse = 0)
(cdr (argmin car
;if reverse <> 0 then reverse the key (decrypt)
(for/list ([len (range 1 (add1 max-keylen))])
Protected *letter.Character
(define guesses (col-guesses len))
Dim text(0)
(cons (/ (apply + (map car guesses)) len) (map cdr guesses))))))
Dim keyText(0)
If prepString(text, text()) < 0 Or prepString(keyText, keyText()) < 0: ProcedureReturn: EndIf ;exit, nothing to work with
Protected i, keyLength = ArraySize(keyText())
If reverse
For i = 0 To keyLength
keyText(i) = 26 - keyText(i)
Next
EndIf
Protected textLength = ArraySize(text()) ;zero-based length
Protected result.s = Space(textLength + 1), *resultLetter.Character
keyLength + 1 ;convert from zero-based to one-based count
*resultLetter = @result
For i = 0 To textLength
*resultLetter\c = ((text(i) + keyText(i % keyLength)) % 26) + 65
*resultLetter + SizeOf(Character)
Next
ProcedureReturn result
EndProcedure


(printf "Best key found: ")
Procedure.s VC_decrypt(cypherText.s, keyText.s)
(for ([c best-key]) (display (integer->char (+ c first-char))))
ProcedureReturn VC_encrypt(cypherText, keyText.s, 1)
(newline)
EndProcedure


(printf "Decoded text:\n")
If OpenConsole()
(define decode-num
Define VignereCipher.s, plainText.s, encryptedText.s, decryptedText.s
(let ([cur '()])
(λ(n) (when (null? cur) (set! cur best-key))
VignereCipher.s = "VIGNERECIPHER"
(begin0 (modulo (- n (car cur)) chars#) (set! cur (cdr cur))))))
plainText = "The quick brown fox jumped over the lazy dogs.": PrintN(RSet("Plain text = ", 17) + #DQUOTE$ + plainText + #DQUOTE$)
(for ([c text])
encryptedText = VC_encrypt(plainText, VignereCipher): PrintN(RSet("Encrypted text = ", 17) + #DQUOTE$ + encryptedText + #DQUOTE$)
(define n (- (char->integer c) first-char))
decryptedText = VC_decrypt(encryptedText, VignereCipher): PrintN(RSet("Decrypted text = ", 17) + #DQUOTE$ + decryptedText + #DQUOTE$)
(if (not (< -1 n chars#)) (display c)
(display (integer->char (+ first-char (decode-num n))))))
Print(#CRLF$ + #CRLF$ + "Press ENTER to exit"): Input()
(newline)
CloseConsole()
</syntaxhighlight>
EndIf</lang>
{{out}}
<pre> Plain text = "The quick brown fox jumped over the lazy dogs."
Encrypted text = "OPKDYZGMJGVAEAWDWYDTGLDCIIOPKYEQCFWVZ"
Decrypted text = "THEQUICKBROWNFOXJUMPEDOVERTHELAZYDOGS"</pre>


Output:
=={{header|Python}}==
<pre>
{{Works with|Python|3}}
Best key found: THECHESHIRECAT
{{trans|Haskell}}
Decoded text:
<lang python>'''Vigenere encryption and decryption'''
THISW ASTHE POEMT HATAL ICERE ADJAB BERWO CKYTW ASBRI LLIGA
...
</pre>


=== An attempted more complete implementation ===
from itertools import starmap, cycle
This is an attempt at following the [http://en.wikipedia.org/wiki/Index_of_coincidence#Example Wikipedia] description. However, it performs just as well as the simple version. Most likely because I know almost nothing about cryptography...


<syntaxhighlight lang="racket">
#lang at-exp racket


(define max-keylen 30)
def encrypt(message, key):
'''Vigenere encryption of message using key.'''


(define text
# Converted to uppercase.
@~a{MOMUD EKAPV TQEFM OEVHP AJMII CDCTI FGYAG JSPXY ALUYM NSMYH
# Non-alpha characters stripped out.
VUXJE LEPXJ FXGCM JHKDZ RYICU HYPUS PGIGM OIYHF WHTCQ KMLRD
message = filter(str.isalpha, message.upper())
ITLXZ LJFVQ GHOLW CUHLO MDSOE KTALU VYLNZ RFGBX PHVGA LWQIS
FGRPH JOOFW GUBYI LAPLA LCAFA AMKLG CETDW VOELJ IKGJB XPHVG
ALWQC SNWBU BYHCU HKOCE XJEYK BQKVY KIIEH GRLGH XEOLW AWFOJ
ILOVV RHPKD WIHKN ATUHN VRYAQ DIVHX FHRZV QWMWV LGSHN NLVZS
JLAKI FHXUF XJLXM TBLQV RXXHR FZXGV LRAJI EXPRV OSMNP KEPDT
LPRWM JAZPK LQUZA ALGZX GVLKL GJTUI ITDSU REZXJ ERXZS HMPST
MTEOE PAPJH SMFNB YVQUZ AALGA YDNMP AQOWT UHDBV TSMUE UIMVH
QGVRW AEFSP EMPVE PKXZY WLKJA GWALT VYYOB YIXOK IHPDS EVLEV
RVSGB JOGYW FHKBL GLXYA MVKIS KIEHY IMAPX UOISK PVAGN MZHPW
TTZPV XFCCD TUHJH WLAPF YULTB UXJLN SIJVV YOVDJ SOLXG TGRVO
SFRII CTMKO JFCQF KTINQ BWVHG TENLH HOGCS PSFPV GJOKM SIFPR
ZPAAS ATPTZ FTPPD PORRF TAXZP KALQA WMIUD BWNCT LEFKO ZQDLX
BUXJL ASIMR PNMBF ZCYLV WAPVF QRHZV ZGZEF KBYIO OFXYE VOWGB
BXVCB XBAWG LQKCM ICRRX MACUO IKHQU AJEGL OIJHH XPVZW JEWBA
FWAML ZZRXJ EKAHV FASMU LVVUT TGK})


(define first-char (char->integer #\A))
def enc(c, k):
(define chars# (- (char->integer #\Z) first-char -1))
'''Single letter encryption.'''


(define freqs ; english letter frequencies from wikipedia
return chr(((ord(k) + ord(c) - 2 * ord('A')) % 26) + ord('A'))
((compose1 list->vector (curry map (curryr / 100000.0)))
'(8167 1492 2782 4253 12702 2228 2015 6094 6966 153 772 4025 2406
6749 7507 1929 95 5987 6327 9056 2758 978 2360 150 1974 74)))


(define (n*n-1 n) (* n (sub1 n)))
return ''.join(starmap(enc, zip(message, cycle(key))))


(define text* (for/vector ([c (regexp-replace* #px"\\s+" text "")])
(- (char->integer c) first-char)))
(define N (vector-length text*))
(define (get-col-length+freqs width offset)
(define text (for/list ([i (in-range offset N width)]) (vector-ref text* i)))
(define cN (length text))
(define freqs (make-vector chars# 0))
(for ([c (in-list text)]) (vector-set! freqs c (add1 (vector-ref freqs c))))
(values cN freqs))


(define expected-IC (* chars# (for*/sum ([x freqs]) (* x x))))
def decrypt(message, key):
'''Vigenere decryption of message using key.'''


;; maps key lengths to average index of coincidence
def dec(c, k):
(define keylen->ICs
'''Single letter decryption.'''
(for/vector ([len (in-range 1 (add1 (* max-keylen 2)))])
(for/sum ([ofs len])
(define-values [cN cfreqs] (get-col-length+freqs len ofs))
(/ (for/sum ([i chars#]) (n*n-1 (vector-ref cfreqs i)))
(/ (n*n-1 cN) chars#) len 1.0))))


;; given a key length find the key that minimizes errors from alphabet freqs,
return chr(((ord(c) - ord(k) - 2 * ord('A')) % 26) + ord('A'))
;; return (cons average-error key)
(define (guess-key len)
(define guesses
(for/list ([ofs len])
(define-values [cN cfreqs] (get-col-length+freqs len ofs))
(for ([i chars#]) (vector-set! cfreqs i (/ (vector-ref cfreqs i) cN)))
(argmin car
(for/list ([d chars#])
(cons (for/sum ([i chars#])
(expt (- (vector-ref freqs i)
(vector-ref cfreqs (modulo (+ i d) chars#)))
2))
d)))))
(cons (/ (apply + (map car guesses)) len) (map cdr guesses)))


;; look for a key length that minimizes error from expected-IC, with some
return ''.join(starmap(dec, zip(message, cycle(key))))
;; stupid consideration of multiples of the length (which should also have low
;; errors), for each one guess a key, then find the one that minimizes both (in
;; a way that looks like it works, but undoubtedly is wrong in all kinds of
;; ways) and return the winner key
(define best-key
((compose1 cdr (curry argmin car))
(for/list ([i (* max-keylen 2)])
;; get the error from the expected-IC for the length and its multiples,
;; with decreasing weights for the multiples
(define with-multiples
(for/list ([j (in-range i (* max-keylen 2) (add1 i))] [div N])
(cons (/ (abs (- (vector-ref keylen->ICs j) expected-IC)) expected-IC)
(/ (add1 div)))))
(define total (/ (for/sum ([x with-multiples]) (* (car x) (cdr x)))
(for/sum ([x with-multiples]) (cdr x))))
(define guess (guess-key (add1 i)))
(define guess*total (* total (car guess) (car guess)))
;; (printf "~a~a: ~a ~s\n" (if (< i 9) " " "") (add1 i)
;; (list total (car guess) guess*total) (cdr guess))
(cons guess*total (cdr guess)))))


(printf "Best key found: ")
(for ([c best-key]) (display (integer->char (+ c first-char))))
(newline)


(printf "Decoded text:\n")
def main():
(define decode-num
'''Demonstration'''
(let ([cur '()])

(λ(n) (when (null? cur) (set! cur best-key))
text = 'Beware the Jabberwock, my son! The jaws that bite, ' + (
(begin0 (modulo (- n (car cur)) chars#) (set! cur (cdr cur))))))
'the claws that catch!'
(for ([c text])
)
(define n (- (char->integer c) first-char))
key = 'VIGENERECIPHER'
(if (not (< -1 n chars#)) (display c)

(display (integer->char (+ first-char (decode-num n))))))
encr = encrypt(text, key)
(newline)
decr = decrypt(encr, key)
</syntaxhighlight>

print(text)
print(encr)
print(decr)


if __name__ == '__main__':
main()
</lang>
{{out}}
<pre>Beware the Jabberwock, my son! The jaws that bite, the claws that catch!
WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY
BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH</pre>

=={{header|R}}==
<lang r>mod1 = function(v, n)
# mod1(1:20, 6) => 1 2 3 4 5 6 1 2 3 4 5 6 1 2 3 4 5 6 1 2
((v - 1) %% n) + 1

str2ints = function(s)
as.integer(Filter(Negate(is.na),
factor(levels = LETTERS, strsplit(toupper(s), "")[[1]])))

vigen = function(input, key, decrypt = F)
{input = str2ints(input)
key = rep(str2ints(key), len = length(input)) - 1
paste(collapse = "", LETTERS[
mod1(input + (if (decrypt) -1 else 1)*key, length(LETTERS))])}

message(vigen("Beware the Jabberwock, my son! The jaws that bite, the claws that catch!", "vigenerecipher"))
# WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY
message(vigen("WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY", "vigenerecipher", decrypt = T))
# BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH</lang>

=={{header|Racket}}==
<lang racket>
#lang racket
(define chr integer->char)
(define ord char->integer)

(define (encrypt msg key)
(define cleaned
(list->string
(for/list ([c (string-upcase msg)]
#:when (char-alphabetic? c)) c)))
(list->string
(for/list ([c cleaned] [k (in-cycle key)])
(chr (+ (modulo (+ (ord c) (ord k)) 26) (ord #\A))))))

(define (decrypt msg key)
(list->string
(for/list ([c msg] [k (in-cycle key)])
(chr (+ (modulo (- (ord c) (ord k)) 26) (ord #\A))))))

(decrypt (encrypt "Beware the Jabberwock, my son! The jaws that bite, the claws that catch!"
"VIGENERECIPHER")
"VIGENERECIPHER")
</lang>
{{out}}
<lang racket>
"BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH"
</lang>


=={{header|Raku}}==
=={{header|Raku}}==
(formerly Perl 6)
(formerly Perl 6)
{{trans|Perl}}
{{Works with|rakudo|2015-11-14}}
<syntaxhighlight lang="raku" line># from Wikipedia
<lang perl6>sub s2v ($s) { $s.uc.comb(/ <[ A..Z ]> /)».ord »-» 65 }
constant %English-letter-freq = (
sub v2s (@v) { (@v »%» 26 »+» 65)».chr.join }
E => 12.70, L => 4.03, Y => 1.97, P => 1.93, T => 9.06, A => 8.17, O => 7.51, I => 6.97, N => 6.75,
S => 6.33, H => 6.09, R => 5.99, D => 4.25, C => 2.78, U => 2.76, M => 2.41, W => 2.36, F => 2.23,
G => 2.02, B => 1.29, V => 0.98, K => 0.77, J => 0.15, X => 0.15, Q => 0.10, Z => 0.07
);
constant @alphabet = %English-letter-freq.keys.sort;
constant max_key_lengths = 5; # number of keylengths to try


sub myguess ($text) {
sub blacken ($red, $key) { v2s(s2v($red) »+» s2v($key)) }
my ($seqtext, @spacing, @factors, $pos, %freq, %Keys);
sub redden ($blk, $key) { v2s(s2v($blk) »-» s2v($key)) }


# Kasiski examination
my $red = "Beware the Jabberwock, my son! The jaws that bite, the claws that catch!";
$seqtext = $text;
my $key = "Vigenere Cipher!!!";
while ($seqtext ~~ /$<sequence>=[...].*$<sequence>/) {
$seqtext = substr($seqtext, 1+index($seqtext, $<sequence>));
push @spacing, 1 + index($seqtext, $<sequence>);
}
for @spacing -> $j {
%freq{$_}++ for grep { $j %% $_ }, 2..$j;
}


# discard very short keys, and test only the most likely remaining key lengths
say $red;
(%freq.keys.grep(* > 3).sort({%freq{$_}}).tail(max_key_lengths)).race(:1batch).map: -> $keylen {
say my $black = blacken($red, $key);
my $key-guess = '';
say redden($black, $key);</lang>
loop (my $i = 0; $i < $keylen; $i++) {
{{out}}
my ($mykey, %chi-square, $best-guess);
<pre>Beware the Jabberwock, my son! The jaws that bite, the claws that catch!
loop (my $j = 0; $j < $text.chars; $j += $keylen) {
WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY
$mykey ~= substr($text, ($j+$i) % $text.chars, 1);
BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH</pre>
}
This is a natural job for hyperoperators, which can vectorize any operator.
For infix operators the pointy end indicates which side to "dwim", repeating
elements on that side until the other side runs out. In particular, repeating
the key naturally falls out of this cyclic dwimmery, as does repeating the various constants to be applied with any of several operations to every element of the list. Factoring out the canonicalization and decanonicalization lets us see quite clearly that the only difference between encryption and decryptions is the sign of the vector addition/subtraction. Since hyperops are inherently parallelizable, this algorithm might run well in your GPU.


for @alphabet -> $subkey {
=={{header|Red}}==
my $decrypted = mycrypt($mykey, $subkey);
note: this program is much longer than it needed to be - because i couldn't resist
my $length = $decrypted.chars;
to add some more features to make it actually "useful" :-) So not only can u encrypt any character (because the crypted message will be base 64 encoded), but it also includes a Gui.
for @alphabet -> $char {
the Gui window has buttons to access the clipboard too - so u can get the original text from clipboard and put the crypted message back again. To execute it,simply download the latest red.exe (about 1,1 MB size! ) from red-lang.org. This program can also be compiled to an .exe (+ red runtime.dll ) by simply execute <pre>red.exe -c vign1.red</pre> or <pre>red.exe -r vign1.red</pre> which creates a single .exe file whithout the need for any .dll . should be working on windows , linux ( under wine ) and mac OS.
my $expected = %English-letter-freq{$char} * $length / 100;
<lang Red>Red [needs: 'view]
my $observed = $decrypted.comb.grep(* eq $char).elems;
%chi-square{$subkey} += ($observed - $expected)² / $expected if $observed;
}
}
%Keys{$keylen}{'score'} = %chi-square{@alphabet[0]};
for %chi-square.keys.sort -> $sk {
if (%chi-square{$sk} <= %Keys{$keylen}{'score'}) {
$best-guess = $sk;
%Keys{$keylen}{'score'} = %chi-square{$sk};
}
}
$key-guess ~= $best-guess;
}
%Keys{$keylen}{'key'} = $key-guess;
}
%Keys.keys.sort({ %Keys{$_}{'score'} }).map:{ %Keys{$_}{'key'} };
}


sub mycrypt ($text, $key) {
CRLF: copy "^M^/" ;; constant for 0D 0A line feed
constant %values-numbers = @alphabet Z=> ^@alphabet;
;;------------------------------------
constant %values-letters = %values-numbers.invert;
crypt: func ["function to en- or decrypt message from textarea tx1"
/decrypt "decrypting switch/refinement" ][
;;------------------------------------


my ($new-text);
;; when decrypting we have to remove the superflous newlines
my $keylen = $key.chars;
;; and undo the base64 encoding first ...
loop (my $i = 0; $i < $text.chars; $i++) {
txt: either decrypt [ ;; message to en- or decrypt
my $val = -1 * %values-numbers{substr( $key, $i%$keylen, 1)} # negative shift for decode
s: copy tx1/text
+ %values-numbers{substr($text, $i, 1)};
;; newline could be single 0a byte or crlf sequence when copied from clipboard...
$new-text ~= %values-letters{ $val % @alphabet };
debase replace/all s either find s CRLF [CRLF ] [ newline ] ""
}
] [
tx1/text ;; plaintext message
return $new-text;
}
]


my $cipher-text = .uc.trans(@alphabet => '', :c) given q:to/EOD/;
txt: to-binary txt ;; handle message as binary
MOMUD EKAPV TQEFM OEVHP AJMII CDCTI FGYAG JSPXY ALUYM NSMYH
key: to-binary key1/text ;; handle key also as binary
VUXJE LEPXJ FXGCM JHKDZ RYICU HYPUS PGIGM OIYHF WHTCQ KMLRD
ITLXZ LJFVQ GHOLW CUHLO MDSOE KTALU VYLNZ RFGBX PHVGA LWQIS
FGRPH JOOFW GUBYI LAPLA LCAFA AMKLG CETDW VOELJ IKGJB XPHVG
ALWQC SNWBU BYHCU HKOCE XJEYK BQKVY KIIEH GRLGH XEOLW AWFOJ
ILOVV RHPKD WIHKN ATUHN VRYAQ DIVHX FHRZV QWMWV LGSHN NLVZS
JLAKI FHXUF XJLXM TBLQV RXXHR FZXGV LRAJI EXPRV OSMNP KEPDT
LPRWM JAZPK LQUZA ALGZX GVLKL GJTUI ITDSU REZXJ ERXZS HMPST
MTEOE PAPJH SMFNB YVQUZ AALGA YDNMP AQOWT UHDBV TSMUE UIMVH
QGVRW AEFSP EMPVE PKXZY WLKJA GWALT VYYOB YIXOK IHPDS EVLEV
RVSGB JOGYW FHKBL GLXYA MVKIS KIEHY IMAPX UOISK PVAGN MZHPW
TTZPV XFCCD TUHJH WLAPF YULTB UXJLN SIJVV YOVDJ SOLXG TGRVO
SFRII CTMKO JFCQF KTINQ BWVHG TENLH HOGCS PSFPV GJOKM SIFPR
ZPAAS ATPTZ FTPPD PORRF TAXZP KALQA WMIUD BWNCT LEFKO ZQDLX
BUXJL ASIMR PNMBF ZCYLV WAPVF QRHZV ZGZEF KBYIO OFXYE VOWGB
BXVCB XBAWG LQKCM ICRRX MACUO IKHQU AJEGL OIJHH XPVZW JEWBA
FWAML ZZRXJ EKAHV FASMU LVVUT TGK
EOD


for myguess($cipher-text) -> $key {
bin: copy either decrypt [ "" ][ #{} ] ;; buffer for output
say "Key $key\n" ~
"Key length {$key.chars}\n" ~
"Plaintext {substr(mycrypt($cipher-text, $key), 0, 80)}...\n";
}</syntaxhighlight>
{{out}}
<pre>Key THECHESHIRECAT
Key length 14
Plaintext THISWASTHEPOEMTHATALICEREADJABBERWOCKYTWASBRILLIGANDTHESLITHYTOVESDIDGYREANDGIMB...


Key THECHESCIRECATTHECHESHIRECAT
code: copy #{} ;; temp field to collect utf8 bytes when decrypting
Key length 28
Plaintext THISWASYHEPOEMTHATALICEREADJABBERWOHKYTWASBRILLIGANDTHESLITHYTOAESDIDGYREANDGIMB...


Key TJGGAHET
;; loop over length of binary! message ...
repeat pos length? txt [
Key length 8
Plaintext TFGODXGHWMNKEYIVLMBJACIPPTXWTBBNFRADSITFHCOSMGOTFYPOXCASLGRDFQCJTABEDSNFPTOBYIQZ...
k: to-integer key/(1 + modulo pos length? key) ;; get corresponding key byte
c: to-integer txt/:pos ;; get integer value from message byte at position pos
either decrypt [ ;; decrypting ?
c: modulo ( 256 + c - k ) 256 ;; compute original byte value
case [
;; byte starting with 11.... ( >= 192 dec ) is utf8 startbyte
;; byte starting with 10... ( >= 128 dec) is utf8 follow up byte , below is single ascii byte
( c >= 192 ) or ( c < 128 ) [ ;; starting utf8 sequence byte or below 128 normal ascii ?
;; append last code to buffer, maybe normal ascii or utf8 sequence...
if not empty? code [ append bin to-char code ] ;; save previous code first
code: append copy #{} c ;; start new code
]
true [ append code c ] ;; otherwise utf8 follow up byte, append to startbyte
]
][
append bin modulo ( c + k ) 256 ;; encrypting , simply collect binary bytes
]
] ;; close repeat loop


Key THECSAS
either decrypt [ ;; collect utf-8 characters
Key length 7
append bin to-char code ;; append last code
Plaintext THISLESHIRRYENTHATPPIQFEGKDKABBEGAOQLLVGATBRILAMGOOQVRETLITHNXOJFFFSDHYREACHGWNO...
tx2/text: to-string bin ;; create valid utf8 string when decrypting
][ ;; base64 encoding of crypted binary to get readable text string...
s: enbase copy bin ;; base 64 is default
while [40 < length? s ] [ ;; insert newlines for better "readability"
s: skip s either head? s [40][41] ;; ... every 40 characters
insert s newline
]
tx2/text: head s ;; reset s pointing to head again
]
]
;----------------------------------------------------------
; start of program
;----------------------------------------------------------
view layout [title "vigenere cyphre" ;Define nice GUI :- )
;----------------------------------------------------------
backdrop silver ;; define window background colour
text "message:" pad 99x1 button "get-clip" [tx1/text: read-clipboard]
;; code in brackets will be executed, when button is clicked:
button "clear" [tx1/text: copy "" ] return
tx1: area 330x80 "" return
text 25x20 "Key:" key1: field 290x20 "secretkey" return
button "crypt" [crypt ] button "decrypt" [crypt/decrypt ]
button "swap" [tx1/text: copy tx2/text tx2/text: copy "" ] return
text "de-/encrypted message:" pad 50x1 button "copy clip" [ write-clipboard tx2/text]
button "clear" [tx2/text: copy "" ] return
tx2: area 330x100 return
pad 270x1 button "Quit " [quit]
]
</lang>
{{output}}
the message <pre>Beware the Jabberwock, my son! The jaws that bite, the claws that catch!</pre> with key "VIGENERECIPHER" translates to <pre>i6y8r7e3ZbextWiPs7irrLfFtLWwb2m9wWXFxbdo
ZaKtt2Wtqse7Zca+qrtlsK7Gqm9pxLCqcrm1qLzBZcatpL1wq6bGubFo</pre>
decrypting returns the original message <pre>Beware the Jabberwock, my son! The jaws that bite, the claws that catch!</pre>


Key THEC
=={{header|REXX}}==
Key length 4
===uppercase text only===
Plaintext THISKXGYWOPOLYIMLODNHCIGPVZAABBEFTCHZITWHEQWTGOKFARSECAJLITHMQCATCDIKSNWPVQFFIQQ...</pre>
<lang rexx>/*REXX program encrypts (and displays) uppercased text using the Vigenère cypher.*/
@.1 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
L=length(@.1)
do j=2 to L; jm=j-1; q=@.jm
@.j=substr(q, 2, L - 1)left(q, 1)
end /*j*/

cypher = space('WHOOP DE DOO NO BIG DEAL HERE OR THERE', 0)
oMsg = 'People solve problems by trial and error; judgement helps pick the trial.'
oMsgU = oMsg; upper oMsgU
cypher_= copies(cypher, length(oMsg) % length(cypher) )
say ' original text =' oMsg
xMsg= Ncypher(oMsgU); say ' cyphered text =' xMsg
bMsg= Dcypher(xMsg) ; say 're-cyphered text =' bMsg
exit
/*──────────────────────────────────────────────────────────────────────────────────────*/
Ncypher: parse arg x; nMsg=; #=1 /*unsupported char? ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓*/
do i=1 for length(x); j=pos(substr(x,i,1), @.1); if j==0 then iterate
nMsg=nMsg || substr(@.j, pos( substr( cypher_, #, 1), @.1), 1); #=#+1
end /*j*/
return nMsg
/*──────────────────────────────────────────────────────────────────────────────────────*/
Dcypher: parse arg x; dMsg=
do i=1 for length(x); j=pos(substr(cypher_, i, 1), @.1)
dMsg=dMsg || substr(@.1, pos( substr(x, i, 1), @.j), 1 )
end /*j*/
return dMsg</lang>
{{out|output|text=&nbsp; when using the default internal fields:}}
<pre>
original text = People solve problems by trial and error; judgement helps pick the trial.
cyphered text = LLCDAHWRZJRDSWHOIMDICKVWREHRUINYCFYXHJSARBUPKOTSAPGBXVVMYMRP
re-cyphered text = PEOPLESOLVEPROBLEMSBYTRIALANDERRORJUDGEMENTHELPSPICKTHETRIAL
</pre>

===supports most characters===
This version supports all characters on the &nbsp; IBM Model M &nbsp; keyboard, including blanks, &nbsp; but any other
<br>characters can be added as long as they're viewable.
Additional characters can be added by simply appending them to the &nbsp; <big>'''@.1'''</big> &nbsp; variable.
<lang rexx>/*REXX program encrypts (and displays) most text using the Vigenère cypher. */
@abc= 'abcdefghijklmnopqrstuvwxyz'; @abcU=@abc; upper @abcU
@.1 = @abcU || @abc'0123456789~`!@#$%^&*()_-+={}|[]\:;<>?,./" '''
L=length(@.1)
do j=2 to length(@.1); jm=j - 1; q=@.jm
@.j=substr(q, 2, L - 1)left(q, 1)
end /*j*/

cypher = space('WHOOP DE DOO NO BIG DEAL HERE OR THERE', 0)
oMsg = 'Making things easy is just knowing the shortcuts. --- Gerard J. Schildberger'
cypher_= copies(cypher, length(oMsg) % length(cypher) )
say ' original text =' oMsg
xMsg= Ncypher(oMsg); say ' cyphered text =' xMsg
bMsg= Dcypher(xMsg); say 're-cyphered text =' bMsg
exit
/*──────────────────────────────────────────────────────────────────────────────────────*/
Ncypher: parse arg x; nMsg=; #=1 /*unsupported char? ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓*/
do i=1 for length(x); j=pos(substr(x,i,1), @.1); if j==0 then iterate
nMsg=nMsg || substr(@.j, pos( substr( cypher_, #, 1), @.1), 1); #=# + 1
end /*j*/
return nMsg
/*──────────────────────────────────────────────────────────────────────────────────────*/
Dcypher: parse arg x; dMsg=
do i=1 for length(x); j=pos(substr(cypher_, i, 1), @.1)
dMsg=dMsg || substr(@.1, pos( substr(x, i, 1), @.j), 1 )
end /*j*/
return dMsg</lang>
{{out|output|text=&nbsp; when using the default internal fields:}}
<pre>
original text = Making things easy is just knowing the shortcuts. --- Gerard J. Schildberger
cyphered text = ihyw2jCwvw0utGkdwyJpwPn89!Fo4s&p1uNwlhM6u2s1ixxsGF}"}MXxye8h/H?/QafgjbZcpecp
re-cyphered text = Making things easy is just knowing the shortcuts. --- Gerard J. Schildberger
</pre>

=={{header|Ring}}==
<lang ring>
# Project : Vigenère cipher

key = "LEMON"
plaintext = "ATTACK AT DAWN"
ciphertext = encrypt(plaintext, key)
see "key = "+ key + nl
see "plaintext = " + plaintext + nl
see "ciphertext = " + ciphertext + nl
see "decrypted = " + decrypt(ciphertext, key) + nl

func encrypt(plain, key)
o = ""
k = 0
plain = fnupper(plain)
key = fnupper(key)
for i = 1 to len(plain)
n = ascii(plain[i])
if n >= 65 and n <= 90
o = o + char(65 + (n + ascii(key[k+1])) % 26)
k = (k + 1) % len(key)
ok
next
return o
func decrypt(cipher, key)
o = ""
k = 0
cipher = fnupper(cipher)
key = fnupper(key)
for i = 1 to len(cipher)
n = ascii(cipher[i])
o = o + char(65 + (n + 26 - ascii(key[k+1])) % 26)
k = (k + 1) % len(key)
next
return o
func fnupper(a)
for aa = 1 to len(a)
c = ascii(a[aa])
if c >= 97 and c <= 122
a[aa] = char(c-32)
ok
next
return a
</lang>
Output:
<pre>
key = LEMON
plaintext = ATTACK AT DAWN
ciphertext = LXFOPVEFRNHR
decrypted = ATTACKATDAWN
</pre>

=={{header|Ruby}}==
<lang Ruby>module VigenereCipher
BASE = 'A'.ord
SIZE = 'Z'.ord - BASE + 1
def encrypt(text, key)
crypt(text, key, :+)
end
def decrypt(text, key)
crypt(text, key, :-)
end
def crypt(text, key, dir)
text = text.upcase.gsub(/[^A-Z]/, '')
key_iterator = key.upcase.gsub(/[^A-Z]/, '').chars.map{|c| c.ord - BASE}.cycle
text.each_char.inject('') do |ciphertext, char|
offset = key_iterator.next
ciphertext << ((char.ord - BASE).send(dir, offset) % SIZE + BASE).chr
end
end
end</lang>

Demonstration:

<lang Ruby>include VigenereCipher

plaintext = 'Beware the Jabberwock, my son! The jaws that bite, the claws that catch!'
key = 'Vigenere cipher'
ciphertext = VigenereCipher.encrypt(plaintext, key)
recovered = VigenereCipher.decrypt(ciphertext, key)

puts "Original: #{plaintext}"
puts "Encrypted: #{ciphertext}"
puts "Decrypted: #{recovered}"</lang>

{{out}}
<pre>
Original: Beware the Jabberwock, my son! The jaws that bite, the claws that catch!
Encrypted: WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY
Decrypted: BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH
</pre>


=={{header|Rust}}==
=={{header|Rust}}==
{{trans|Kotlin}}
<lang rust>use std::ascii::AsciiExt;
Note that the character to/from byte ('''u8''') conversions work here only because the key and cryptogram are composed of ASCII characters only. Indeed, Rust's '''char''' type is a ''Unicode scalar value'', how they are represented is well summarized in the Rust book's [https://doc.rust-lang.org/std/primitive.char.html subchapter on strings].
<syntaxhighlight lang="rust">
use std::iter::FromIterator;


const CRYPTOGRAM: &str = "MOMUD EKAPV TQEFM OEVHP AJMII CDCTI FGYAG JSPXY ALUYM NSMYH
static A: u8 = 'A' as u8;
VUXJE LEPXJ FXGCM JHKDZ RYICU HYPUS PGIGM OIYHF WHTCQ KMLRD
ITLXZ LJFVQ GHOLW CUHLO MDSOE KTALU VYLNZ RFGBX PHVGA LWQIS
FGRPH JOOFW GUBYI LAPLA LCAFA AMKLG CETDW VOELJ IKGJB XPHVG
ALWQC SNWBU BYHCU HKOCE XJEYK BQKVY KIIEH GRLGH XEOLW AWFOJ
ILOVV RHPKD WIHKN ATUHN VRYAQ DIVHX FHRZV QWMWV LGSHN NLVZS
JLAKI FHXUF XJLXM TBLQV RXXHR FZXGV LRAJI EXPRV OSMNP KEPDT
LPRWM JAZPK LQUZA ALGZX GVLKL GJTUI ITDSU REZXJ ERXZS HMPST
MTEOE PAPJH SMFNB YVQUZ AALGA YDNMP AQOWT UHDBV TSMUE UIMVH
QGVRW AEFSP EMPVE PKXZY WLKJA GWALT VYYOB YIXOK IHPDS EVLEV
RVSGB JOGYW FHKBL GLXYA MVKIS KIEHY IMAPX UOISK PVAGN MZHPW
TTZPV XFCCD TUHJH WLAPF YULTB UXJLN SIJVV YOVDJ SOLXG TGRVO
SFRII CTMKO JFCQF KTINQ BWVHG TENLH HOGCS PSFPV GJOKM SIFPR
ZPAAS ATPTZ FTPPD PORRF TAXZP KALQA WMIUD BWNCT LEFKO ZQDLX
BUXJL ASIMR PNMBF ZCYLV WAPVF QRHZV ZGZEF KBYIO OFXYE VOWGB
BXVCB XBAWG LQKCM ICRRX MACUO IKHQU AJEGL OIJHH XPVZW JEWBA
FWAML ZZRXJ EKAHV FASMU LVVUT TGK";


const FREQUENCIES: [f32; 26] = [
fn uppercase_and_filter(input: &str) -> Vec<u8> {
0.08167, 0.01492, 0.02202, 0.04253, 0.12702, 0.02228, 0.02015, 0.06094, 0.06966, 0.00153,
let alphabet = b"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
0.01292, 0.04025, 0.02406, 0.06749, 0.07507, 0.01929, 0.00095, 0.05987, 0.06327, 0.09356,
let mut result = Vec::new();
0.02758, 0.00978, 0.02560, 0.00150, 0.01994, 0.00077,
];


fn best_match(a: &[f32]) -> u8 {
for c in input.chars() {
let sum: f32 = a.iter().sum();
// Ignore anything that is not in our short list of chars. We can then safely cast to u8.
let mut best_fit = std::f32::MAX;
if alphabet.iter().any(|&x| x as char == c) {
let mut best_rotate = 0;
result.push(c.to_ascii_uppercase() as u8);
for rotate in 0..=25 {
let mut fit = 0.;
for i in 0..=25 {
let char_freq = FREQUENCIES[i];
let idx = (i + rotate as usize) % 26 as usize;
let d = a[idx] / sum - char_freq;
fit += d * d / char_freq;
}
if fit < best_fit {
best_fit = fit;
best_rotate = rotate;
}
}
}
}


return result;
best_rotate
}
}


fn vigenere(key: &str, text: &str, is_encoding: bool) -> String {
fn freq_every_nth(msg: &[u8], key: &mut [char]) -> f32 {
let len = msg.len();

let key_bytes = uppercase_and_filter(key);
let interval = key.len();
let text_bytes = uppercase_and_filter(text);
let mut accu = [0.; 26];
for j in 0..interval {

let mut result_bytes = Vec::new();
let mut out = [0.; 26];
for i in (j..len).step_by(interval) {

let idx = msg[i] as usize;
for (i, c) in text_bytes.iter().enumerate() {
let c2 = if is_encoding {
out[idx] += 1.;
}
(c + key_bytes[i % key_bytes.len()] - 2 * A) % 26 + A
} else {
let rot = best_match(&out);
(c + 26 - key_bytes[i % key_bytes.len()]) % 26 + A
key[j] = char::from(rot + b'A');
};
for i in 0..=25 {
result_bytes.push(c2);
let idx: usize = (i + rot as usize) % 26;
accu[i] += out[idx];
}
}
}
let sum: f32 = accu.iter().sum();
let mut ret = 0.;
for i in 0..=25 {
let char_freq = FREQUENCIES[i];
let d = accu[i] / sum - char_freq;
ret += d * d / char_freq;
}
ret
}


fn decrypt(text: &str, key: &str) -> String {
String::from_utf8(result_bytes).unwrap()
let key_chars_cycle = key.as_bytes().iter().map(|b| *b as i32).cycle();
let is_ascii_uppercase = |c: &u8| (b'A'..=b'Z').contains(c);
text.as_bytes()
.iter()
.filter(|c| is_ascii_uppercase(c))
.map(|b| *b as i32)
.zip(key_chars_cycle)
.fold(String::new(), |mut acc, (c, key_char)| {
let ci: u8 = ((c - key_char + 26) % 26) as u8;
acc.push(char::from(b'A' + ci));
acc
})
}
}

fn main() {
fn main() {
let enc = CRYPTOGRAM
let text = "Beware the Jabberwock, my son! The jaws that bite, the claws that catch!";
.split_ascii_whitespace()
let key = "VIGENERECIPHER";
.collect::<Vec<_>>()

println!("Text: {}", text);
.join("");
let cryptogram: Vec<u8> = enc.as_bytes().iter().map(|b| u8::from(b - b'A')).collect();
println!("Key: {}", key);
let mut best_fit = std::f32::MAX;

let encoded = vigenere(key, text, true);
let mut best_key = String::new();
for j in 1..=26 {
println!("Code: {}", encoded);
let decoded = vigenere(key, &encoded, false);
let mut key = vec!['\0'; j];
let fit = freq_every_nth(&cryptogram, &mut key);
println!("Back: {}", decoded);
let s_key = String::from_iter(key); // 'from_iter' is imported from std::iter::FromIterator;
}</lang>
if fit < best_fit {

best_fit = fit;
=={{header|Scala}}==
best_key = s_key;
Valid characters for messages: A through Z, zero, 1 to 9, and full-stop (.)
}
<lang scala>
object Vigenere {
def encrypt(msg: String, key: String) : String = {
var result: String = ""
var j = 0

for (i <- 0 to msg.length - 1) {
val c = msg.charAt(i)
if (c >= 'A' && c <= 'Z') {
result += ((c + key.charAt(j) - 2 * 'A') % 26 + 'A').toChar
j = (j + 1) % key.length
}
}
}


println!("best key: {}", &best_key);
return result
println!("\nDecrypted text:\n{}", decrypt(&enc, &best_key));
}

def decrypt(msg: String, key: String) : String = {
var result: String = ""
var j = 0

for (i <- 0 to msg.length - 1) {
val c = msg.charAt(i)
if (c >= 'A' && c <= 'Z') {
result += ((c - key.charAt(j) + 26) % 26 + 'A').toChar
j = (j + 1) % key.length
}
}

return result
}
}
}
</syntaxhighlight>

println("Encrypt text ABC => " + Vigenere.encrypt("ABC", "KEY"))
println("Decrypt text KFA => " + Vigenere.decrypt("KFA", "KEY"))
</lang>

{{out}}
<pre>scala> Encrypt text ABC => KFA
scala> Decrypt text KFA => ABC</pre>

=={{header|Seed7}}==
<lang seed7>$ include "seed7_05.s7i";

const func string: vigenereCipher (in string: source, in var string: keyword) is func
result
var string: dest is "";
local
var char: ch is ' ';
var integer: index is 1;
var integer: shift is 0;
begin
keyword := upper(keyword);
for ch range source do
if ch in {'A' .. 'Z'} | {'a' .. 'z'} then
shift := ord(keyword[succ(pred(index) rem length(keyword))]) - ord('A');
dest &:= chr(ord('A') + (ord(upper(ch)) - ord('A') + shift) rem 26);
incr(index);
end if;
end for;
end func;

const func string: vigenereDecipher (in string: source, in var string: keyword) is func
result
var string: dest is "";
local
var char: ch is ' ';
var integer: index is 0;
var integer: shift is 0;
begin
keyword := upper(keyword);
for ch key index range source do
if ch in {'A' .. 'Z'} | {'a' .. 'z'} then
shift := ord(keyword[succ(pred(index) rem length(keyword))]) - ord('A');
dest &:= chr(ord('A') + (ord(upper(ch)) - ord('A') - shift) mod 26);
end if;
end for;
end func;

const proc: main is func
local
const string: input is "Beware the Jabberwock, my son! The jaws that bite, the claws that catch!";
const string: keyword is "VIGENERECIPHER";
var string: encrypted is "";
var string: decrypted is "";
begin
writeln("Input: " <& input);
writeln("key: " <& keyword);
encrypted := vigenereCipher(input, keyword);
writeln("Encrypted: " <& encrypted);
decrypted := vigenereDecipher(encrypted, keyword);
writeln("Decrypted: " <& decrypted);
end func;</lang>

{{out}}
{{out}}
<pre>
<pre>
best key: THECHESHIRECAT
Input: Beware the Jabberwock, my son! The jaws that bite, the claws that catch!
key: VIGENERECIPHER
Encrypted: WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY
Decrypted: BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH
</pre>


Decrypted text:
=={{header|Sidef}}==
THISWASTHEPOEMTHATALICEREADJABBERWOCKYTWASBRILLIGANDTHESLITHYTOVESDIDGYREANDGIMBLEINTHEWABEALLMIMSYWERETHEBOROGOVESANDTHEMOMERATHSOUTGRABEBEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCHBEWARETHEJUBJUBBIRDANDSHUNTHEFRUMIOUSBANDERSNATCHHETOOKHISVORPALSWORDINHANDLONGTIMETHEMANXOMEFOEHESOUGHTSORESTEDHEBYTHETUMTUMTREEANDSTOODAWHILEINTHOUGHTANDASINUFFISHTHOUGHTHESTOODTHEJABBERWOCKWITHEYESOFFLAMECAMEWHIFFLINGTHROUGHTHETULGEYWOODANDBURBLEDASITCAMEONETWOONETWOANDTHROUGHANDTHROUGHTHEVORPALBLADEWENTSNICKERSNACKHELEFTITDEADANDWITHITSHEADHEWENTGALUMPHINGBACKANDHASTTHOUSLAINTHEJABBERWOCKCOMETOMYARMSMYBEAMISHBOYOFRABJOUSDAYCALLOOHCALLAYHECHORTLEDINHISJOYTWASBRILLIGANDTHESLITHYTOVESDIDGYREANDGIMBLEINTHEWABEALLMIMSYWERETHEBOROGOVESANDTHEMOMERATHSOUTGRABEITSEEMSVERYPRETTYSHESAIDWHENSHEHADFINISHEDITBUTITSRATHERHARDTOUNDERSTAND
{{trans|Perl 6}}
<lang ruby>func s2v(s) { s.uc.scan(/[A-Z]/).map{.ord} »-» 65 }
func v2s(v) { v »%» 26 »+» 65 -> map{.chr}.join }
 
func blacken (red, key) { v2s(s2v(red) »+« s2v(key)) }
func redden (blk, key) { v2s(s2v(blk) »-« s2v(key)) }
 
var red = "Beware the Jabberwock, my son! The jaws that bite, the claws that catch!"
var key = "Vigenere Cipher!!!"
 
say red
say (var black = blacken(red, key))
say redden(black, key)</lang>
{{out}}
<pre>
Beware the Jabberwock, my son! The jaws that bite, the claws that catch!
WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY
BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH
</pre>
</pre>


=={{header|Smalltalk}}==
=={{header|Tcl}}==
{{trans|Python}}
in the following code, the cypher should consist of upper-case characters only. If that is not guaranteed, apply prep to it before passing it to encrypt/decrypt..
<syntaxhighlight lang="tcl">package require Tcl 8.6
{{works with|Smalltalk/X}}
<lang smalltalk>
prep := [:s | s select:[:ch | ch isLetter] thenCollect:[:ch | ch asUppercase]].
encrypt := [:s :cypher | (prep value:s) keysAndValuesCollect:[:i :ch | ch rot:((cypher at:((i-1)\\key size+1))-$A) ]].
decrypt := [:s :cypher | (prep value:s) keysAndValuesCollect:[:i :ch | ch rot:26-((cypher at:((i-1)\\key size+1))-$A) ]].
</lang>
Test:
<lang smalltalk>
plain := 'Beware the Jabberwock, my son! The jaws that bite, the claws that catch!'.
cypher := 'VIGENERECIPHER'.
crypted := encrypt value:plain value:cypher.
plain2 := decrypt value:crypted value:cypher.


oo::class create VigenereAnalyzer {
crypted -> 'WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY'
variable letterFrequencies sortedTargets
plain2 -> 'BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH'
constructor {{frequencies {
</lang>
0.08167 0.01492 0.02782 0.04253 0.12702 0.02228 0.02015

0.06094 0.06966 0.00153 0.00772 0.04025 0.02406 0.06749
=={{header|Swift}}==
0.07507 0.01929 0.00095 0.05987 0.06327 0.09056 0.02758

0.00978 0.02360 0.00150 0.01974 0.00074
Can support a larger range of characters, if desired
}}} {

set letterFrequencies $frequencies
<lang swift>public func convertToUnicodeScalars(
set sortedTargets [lsort -real $frequencies]
str: String,
if {[llength $frequencies] != 26} {
minChar: UInt32,
error "wrong length of frequency table"
maxChar: UInt32
}
) -> [UInt32] {
var scalars = [UInt32]()

for scalar in str.unicodeScalars {
let val = scalar.value

guard val >= minChar && val <= maxChar else {
continue
}
}


### Utility methods
scalars.append(val)
# Find the value of $idxvar in the range [$from..$to) that maximizes the value
}
# in $scorevar (which is computed by evaluating $body)

method Best {idxvar from to scorevar body} {
return scalars
upvar 1 $idxvar i $scorevar s
}
set bestI $from

for {set i $from} {$i < $to} {incr i} {
public struct Vigenere {
uplevel 1 $body
private let keyScalars: [UInt32]
if {![info exist bestS] || $bestS < $s} {
private let smallestScalar: UInt32
set bestI $i
private let largestScalar: UInt32
set bestS $s
private let sizeAlphabet: UInt32
}

}
public init?(key: String, smallestCharacter: Character = "A", largestCharacter: Character = "Z") {
return $bestI
let smallScalars = smallestCharacter.unicodeScalars
let largeScalars = largestCharacter.unicodeScalars

guard smallScalars.count == 1, largeScalars.count == 1 else {
return nil
}
}
# Simple list map

method Map {var list body} {
self.smallestScalar = smallScalars.first!.value
upvar 1 $var v
self.largestScalar = largeScalars.first!.value
set result {}
self.sizeAlphabet = (largestScalar - smallestScalar) + 1
foreach v $list {lappend result [uplevel 1 $body]}

return $result
let scalars = convertToUnicodeScalars(str: key, minChar: smallestScalar, maxChar: largestScalar)

guard !scalars.isEmpty else {
return nil
}
}
# Simple partition of $list into $groups groups; thus, the partition of

# {a b c d e f} into 3 produces {a d} {b e} {c f}
self.keyScalars = scalars
method Partition {list groups} {

}
set i 0
foreach val $list {

dict lappend result $i $val
public func decrypt(_ str: String) -> String? {
if {[incr i] >= $groups} {
let txtBytes = convertToUnicodeScalars(str: str, minChar: smallestScalar, maxChar: largestScalar)
set i 0

}
guard !txtBytes.isEmpty else {
}
return nil
return [dict values $result]
}
}


var res = ""
### Helper methods
# Get the actual counts of different types of characters in the given list

method Frequency cleaned {
for (i, c) in txtBytes.enumerated() where c >= smallestScalar && c <= largestScalar {
guard let char =
for {set i 0} {$i < 26} {incr i} {
dict set tbl $i 0
UnicodeScalar((c &+ sizeAlphabet &- keyScalars[i % keyScalars.count]) % sizeAlphabet &+ smallestScalar)
}
else {
foreach ch $cleaned {
return nil
dict incr tbl [expr {[scan $ch %c] - 65}]
}
}

return $tbl
res += String(char)
}
}


# Get the correlation factor of the characters in a given list with the
return res
# class-specified language frequency corpus
}
method Correlation cleaned {

set result 0.0
public func encrypt(_ str: String) -> String? {
set freq [lsort -integer [dict values [my Frequency $cleaned]]]
let txtBytes = convertToUnicodeScalars(str: str, minChar: smallestScalar, maxChar: largestScalar)
foreach f $freq s $sortedTargets {

set result [expr {$result + $f * $s}]
guard !txtBytes.isEmpty else {
}
return nil
return $result
}
}


# Compute an estimate for the key length
var res = ""
method GetKeyLength {cleaned {required 20}} {

# Assume that we need at least 20 characters per column to guess
for (i, c) in txtBytes.enumerated() where c >= smallestScalar && c <= largestScalar {
set bestLength [my Best i 2 [expr {[llength $cleaned] / $required}] corr {
guard let char =
set corr [expr {-0.5 * $i}]
UnicodeScalar((c &+ keyScalars[i % keyScalars.count] &- 2 &* smallestScalar) % sizeAlphabet &+ smallestScalar)
foreach chars [my Partition $cleaned $i] {
else {
set corr [expr {$corr + [my Correlation $chars]}]
return nil
}

res += String(char)
}

return res
}
}

let text = "Beware the Jabberwock, my son! The jaws that bite, the claws that catch!";
let key = "VIGENERECIPHER";
let cipher = Vigenere(key: key)!

print("Key: \(key)")
print("Plain Text: \(text)")

let encoded = cipher.encrypt(text.uppercased())!

print("Cipher Text: \(encoded)")

let decoded = cipher.decrypt(encoded)!

print("Decoded: \(decoded)")

print("\nLarger set:")

let key2 = "Vigenère cipher"
let text2 = "This is a ünicode string 😃"

let cipher2 = Vigenere(key: key2, smallestCharacter: " ", largestCharacter: "🛹")!

print("Key: \(key2)")
print("Plain Text: \(text2)")

let encoded2 = cipher2.encrypt(text2)!

print("Cipher Text: \(encoded2)")

let decoded2 = cipher2.decrypt(encoded2)!

print("Decoded: \(decoded2)")</lang>

{{out}}

<pre>Key: VIGENERECIPHER
Plain Text: Beware the Jabberwock, my son! The jaws that bite, the claws that catch!
Cipher Text: WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY
Decoded: BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH

Larger set:
Key: Vigenère cipher
Plain Text: This is a ünicode string 😃
Cipher Text: �±°¸nıÅeacŅ¾±¨Á�®g¸Âĺ»³gc🙌
Decoded: This is a ünicode string 😃</pre>

=={{header|Tcl}}==
{{trans|C++}}
<lang tcl>package require Tcl 8.6

oo::class create Vigenere {
variable key
constructor {protoKey} {
foreach c [split $protoKey ""] {
if {[regexp {[A-Za-z]} $c]} {
lappend key [scan [string toupper $c] %c]
}
}
}]
if {$bestLength == 0} {
error "text is too short to analyze"
}
}
return $bestLength
}
}


# Compute the key from the given frequency tables and the class-specified
method encrypt {text} {
# language frequency corpus
set out ""
method GetKeyFromFreqs freqs {
set j 0
foreach c [split $text ""] {
foreach f $freqs {
if {[regexp {[^a-zA-Z]} $c]} continue
set m [my Best i 0 26 corr {
set corr 0.0
scan [string toupper $c] %c c
foreach {ch count} $f {
append out [format %c [expr {($c+[lindex $key $j]-130)%26+65}]]
set j [expr {($j+1) % [llength $key]}]
set d [expr {($ch - $i) % 26}]
set corr [expr {$corr + $count*[lindex $letterFrequencies $d]}]
}
}]
append key [format %c [expr {65 + $m}]]
}
}
return $out
return $key
}
}


##### The main analyzer method #####
method decrypt {text} {
method analyze input {
set out ""
# Turn the input into a clean letter sequence
set j 0
set cleaned [regexp -all -inline {[A-Z]} [string toupper $input]]
foreach c [split $text ""] {
# Get the (estimated) key length
if {[regexp {[^A-Z]} $c]} continue
set bestLength [my GetKeyLength $cleaned]
scan $c %c c
# Get the frequency mapping for the partitioned input text
append out [format %c [expr {($c-[lindex $key $j]+26)%26+65}]]
set freqs [my Map p [my Partition $cleaned $bestLength] {my Frequency $p}]
set j [expr {($j+1) % [llength $key]}]
# Get the key itself
}
return $out
return [my GetKeyFromFreqs $freqs]
}
}
}</lang>
}</syntaxhighlight>
Demonstration (that assumes that the Tcl solution to [[Vigenère cipher#Tcl|Vigenère cipher]] task is present):
Demonstrating:
<lang tcl>set cypher [Vigenere new "Vigenere Cipher"]
<syntaxhighlight lang="tcl">set encoded "
MOMUD EKAPV TQEFM OEVHP AJMII CDCTI FGYAG JSPXY ALUYM NSMYH
set original "Beware the Jabberwock, my son! The jaws that bite, the claws that catch!"
VUXJE LEPXJ FXGCM JHKDZ RYICU HYPUS PGIGM OIYHF WHTCQ KMLRD
set encrypted [$cypher encrypt $original]
ITLXZ LJFVQ GHOLW CUHLO MDSOE KTALU VYLNZ RFGBX PHVGA LWQIS
set decrypted [$cypher decrypt $encrypted]
FGRPH JOOFW GUBYI LAPLA LCAFA AMKLG CETDW VOELJ IKGJB XPHVG
puts $original
ALWQC SNWBU BYHCU HKOCE XJEYK BQKVY KIIEH GRLGH XEOLW AWFOJ
puts "Encrypted: $encrypted"
ILOVV RHPKD WIHKN ATUHN VRYAQ DIVHX FHRZV QWMWV LGSHN NLVZS
puts "Decrypted: $decrypted"</lang>
JLAKI FHXUF XJLXM TBLQV RXXHR FZXGV LRAJI EXPRV OSMNP KEPDT
{{out}}
LPRWM JAZPK LQUZA ALGZX GVLKL GJTUI ITDSU REZXJ ERXZS HMPST
<pre>
MTEOE PAPJH SMFNB YVQUZ AALGA YDNMP AQOWT UHDBV TSMUE UIMVH
Beware the Jabberwock, my son! The jaws that bite, the claws that catch!
QGVRW AEFSP EMPVE PKXZY WLKJA GWALT VYYOB YIXOK IHPDS EVLEV
Encrypted: WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY
RVSGB JOGYW FHKBL GLXYA MVKIS KIEHY IMAPX UOISK PVAGN MZHPW
Decrypted: BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH
TTZPV XFCCD TUHJH WLAPF YULTB UXJLN SIJVV YOVDJ SOLXG TGRVO
</pre>
SFRII CTMKO JFCQF KTINQ BWVHG TENLH HOGCS PSFPV GJOKM SIFPR
ZPAAS ATPTZ FTPPD PORRF TAXZP KALQA WMIUD BWNCT LEFKO ZQDLX
BUXJL ASIMR PNMBF ZCYLV WAPVF QRHZV ZGZEF KBYIO OFXYE VOWGB
BXVCB XBAWG LQKCM ICRRX MACUO IKHQU AJEGL OIJHH XPVZW JEWBA
FWAML ZZRXJ EKAHV FASMU LVVUT TGK
"
VigenereAnalyzer create englishVigenereAnalyzer
set key [englishVigenereAnalyzer analyze $encoded]
Vigenere create decoder $key
set decoded [decoder decrypt $encoded]
puts "Key: $key"
puts "Text: $decoded"</syntaxhighlight>


=={{header|TXR}}==
=={{header|Vedit macro language}}==
This implementation is fully autonomous as long as the text is long enough and there are not too many non-English words in the original text.


The text to be analysed must be in current edit buffer. A new buffer is opened to display the results.
<lang txr>@(next :args)
@(do
(defun vig-op (plus-or-minus)
(op + #\A [mod [plus-or-minus (- @1 #\A) (- @2 #\A)] 26]))


To automatically find the best key, a dictionary is used to find English words within the decrypted text.
(defun vig (msg key encrypt)
I have used unixdict.txt, but if you do not have it available, you can use the Scribe English dictionary that comes with Vedit.
(mapcar (vig-op [if encrypt + -]) msg (repeat key))))
However, that is unnecessarily big. A smaller dictionary is faster and may actually give better results.
@(coll)@{key /[A-Za-z]/}@(end)
It might be good idea to use dictionary that only contains the most common English words.
@(coll)@{msg /[A-Za-z]/}@(end)
@(cat key "")
@(filter :upcase key)
@(cat msg "")
@(filter :upcase msg)
@(bind encoded @(vig msg key t))
@(bind decoded @(vig msg key nil))
@(bind check @(vig encoded key nil))
@(output)
text: @msg
key: @key
enc: @encoded
dec: @decoded
check: @check
@(end)</lang>


This implementation finds the best and 2nd best Caesar key for each key position.
Here, the TXR pattern language is used to scan letters out of two arguments,
It then checks key combinations where max one char is taken from 2nd best Caesar key.
and convert them to upper case.
If this does not solve some encrypted text, you could increase the number of key combinations to be checked.
The embedded TXR Lisp dialect handles the Vigenère logic,
in just a few lines of code.


<syntaxhighlight lang="vedit">// (1) Copy text into tmp buffer and remove non-alpha chars.
Lisp programmers may do a "double take" at what is going on here: yes <code>mapcar</code> can operate on strings and return strings in TXR Lisp. <code>(repeat key)</code> produces an infinite lazy list; but that's okay because <code>mapcar</code> stops after the shortest input runs out of items.


Chdir(PATH_ONLY)
Run:
BOF
Reg_Copy(10, ALL) // copy text to new buffer
Buf_Switch(Buf_Free)
Reg_Ins(10)
BOF
Replace ("|!|A", "", BEGIN+ALL+NOERR) // remove non-alpha chars
Reg_Copy_Block(10,0,EOB_pos) // @10 = text to be analysed


#20 = Buf_Num // buffer for text being analyzed
<pre>$ txr vigenere.txr 'vigenere cipher' 'Beware the Jabberwock... The jaws that... the claws that catch!'
#21 = Buf_Free // buffer for English frequency list (A-Z)
text: BEWARETHEJABBERWOCKTHEJAWSTHATTHECLAWSTHATCATCH
Buf_Switch(#21)
key: VIGENERECIPHER
Ins_Text("8167 1492 2782 4253 12702 2228 2015 6094 6966 153 772 4025 2406 6749 7507 1929 95 5987 6327 9056 2758 978 2360 150 1974 74")
enc: WMCEEIKLGRPIFVMEUGXXYILILZXYVBZLRGCEYAIOEKXIZGU
File_Open("unixdict.txt") // or use "|(MACRO_DIR)\scribe\english.vdf"
dec: GWQWEACDCBLUXNWOIYXPQAHSHLPQFLNDRYUWUKEAWCHSNYU
#23 = Buf_Num // buffer for dictionary
check: BEWARETHEJABBERWOCKTHEJAWSTHATTHECLAWSTHATCATCH</pre>
#24 = Buf_Free // buffer for key canditates


Buf_Switch(#24)
=={{header|TypeScript}}==
for (#1=0; #1<5; #1++) { // Fill table for 5 keys of 50 chars
<lang JavaScript>class Vigenere {
Ins_Char('.', COUNT, 50)
Ins_Newline
}
#22 = Buf_Free // buffer for results


#25 = Reg_Size(10) // number of letters in the text
key: string
#26 = 26 // number of characters in the alphabet
#61 = min(#25/10, 50) // max key length to try


/** Create new cipher based on key */
// (2) Check Index of coincidence (or Kp) for each key length
constructor(key: string) {
this.key = Vigenere.formatText(key)
}


Buf_Switch(#22) // buffer for results
/** Enrypt a given text using key */
Ins_Text("KeyLen Kp dist ") Ins_Newline
encrypt(plainText: string): string {
Ins_Text("-----------------") Ins_Newline
return Array.prototype.map.call(Vigenere.formatText(plainText), (letter: string, index: number): string => {
#13 = Cur_Pos
return String.fromCharCode((letter.charCodeAt(0) + this.key.charCodeAt(index % this.key.length) - 130) % 26 + 65)
#7 = 0 // no Caesar encryption
}).join('')
for (#5=1; #5<=#61; #5++) {
Buf_Switch(#20) // text being analyzed
BOF
#54 = 0; // sum of Kp's
for (#6=0; #6<#5; #6++) { // for each slide
Goto_Pos(#6)
Call("CHARACTER_FREQUENCIES")
Call("INDEX_OF_COINCIDENCE") // #51 = Kp * 10000
#54 += #51
}
}
#54 /= #5 // average of Kp's
Buf_Switch(#22)
Num_Ins(#5, COUNT, 3) // write key length
IT(": ")
Num_Ins(#54, NOCR) // average Kp
Num_Ins(670-#54) // distance to English Kp
}
Buf_Switch(#22)
Sort_Merge("5,12", #13, Cur_Pos, REVERSE) // sort the results by Kp value
Ins_Newline


// (3) Check the best 4 key lengths to find which one gives the best decrypt result
/** Decrypt ciphertext based on key */
decrypt(cipherText: string): string {
return Array.prototype.map.call(Vigenere.formatText(cipherText), (letter: string, index: number): string => {
return String.fromCharCode((letter.charCodeAt(0) - this.key.charCodeAt(index % this.key.length) + 26) % 26 + 65)
}).join('')
}


#38 = 0 // max number of correct characters found
/** Converts to uppercase and removes non characters */
#19 = 1 // best key length
private static formatText(text: string): string {
for (#14 = 0; #14<4; #14++) { // try 4 best key lengths
return text.toUpperCase().replace(/[^A-Z]/g, "")
Buf_Switch(#22) // results buffer
Goto_Pos(#13) Line(#14)
#5 = Num_Eval(SUPPRESS) // #5 = key length
Call("FIND_KEYS") // find Caesar key for each key character
#4 = -1 // try best match key chars only
Call("BUILD_KEY")
EOF
Ins_Text("Key length ")
Num_Ins(#5, LEFT)
Reg_Ins(10) // encrypted text
BOL
Call("DECRYPT_LINE")
BOL
Call("FIND_ENGLISH_WORDS") // #37 = number of English chars
EOL Ins_Newline
Ins_Text("Correct chars: ")
Num_Ins(#37)
if (#37 > #38) {
#38 = #37
#19 = #5
}
}
Update()

}
}


Ins_Text("Using key length: ") Num_Ins(#19) Ins_Newline
/** Example usage */
(() => {
#5 = #19
Call("FIND_KEYS") // find Caesar key for each key character
let original: string = "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book."


// (4) Decrypt with different key combinations and try to find English words.
console.log(`Original: ${original}`)
// Try key combinations where max one char is taken from 2nd best Caesar key.


#38 = 0 // max number of chars in English words found
let vig: Vigenere = new Vigenere("vigenere")
#39 = -1 // best key number found
for (#4 = -1; #4 < #19; #4++)
{
Call("BUILD_KEY")
Buf_Switch(#22) // results
Reg_Ins(10) // encrypted text
BOL
Call("DECRYPT_LINE")
BOL
Update()
Call("FIND_ENGLISH_WORDS") // #37 := number of correct letters in text
if (#37 > #38) {
#38 = #37 // new highest number of correct chars
#39 = #4 // new best key
}


EOL IT(" -- ") // display results
let encoded: string = vig.encrypt(original)
Num_Ins(#4, COUNT, 3) // key number
Ins_Text(": ")
for (#6=0; #6<#19; #6++) { // display key
#9 = 130 + #6
Ins_Char(#@9)
}
Ins_Text(" correct chars =")
Num_Ins(#37)
}
Ins_Text("Best key = ")
Num_Ins(#39, LEFT)
#4 = #39
Ins_Newline


// Display results
console.log(`After encryption: ${encoded}`)
//
Buf_Switch(#24) // table for key canditates
BOF
Reg_Copy_Block(14, Cur_Pos, Cur_Pos+#19) // best Caesar key chars
Line(1)
Reg_Copy_Block(15, Cur_Pos, Cur_Pos+#19) // 2nd best Caesar key chars
Call("BUILD_KEY")
Buf_Switch(#22)
Ins_Text("Key 1: ") Reg_Ins(14) Ins_Newline
Ins_Text("Key 2: ") Reg_Ins(15) Ins_Newline
Ins_Text("Key: ")
for (#6=0; #6 < #19; #6++) {
#9 = #6+130
Ins_Char(#@9)
}
Ins_Newline
Ins_Newline


// decrypt the text with selected key
let back: string = vig.decrypt(encoded)
Ins_Text("Decrypted text:") Ins_Newline
Reg_Ins(10)
BOL
Call("DECRYPT_LINE")
BOL Reg_Copy(13,1)
EOL Ins_Newline


// Find English words from the text
console.log(`After decryption: ${back}`)
Reg_Ins(13)
Call("FIND_ENGLISH_WORDS")
EOL
Ins_Newline
Num_Ins(#37, NOCR) IT(" of ")
Num_Ins(#25, NOCR) IT(" characters are English words. ")
Ins_Newline


Buf_Switch(#20) Buf_Quit(OK)
})()
Buf_Switch(#21) Buf_Quit(OK)
</lang>
Buf_Switch(#23) Buf_Quit(OK)
Buf_Switch(#24) Buf_Quit(OK)


Statline_Message("Done!")
=={{header|VBA}}==
Return
<lang vb>Option Explicit


/////////////////////////////////////////////////////////////////////////////
Sub test()
//
Dim Encryp As String
// Caesar decrypt current line and count character frequencies.
Encryp = Vigenere("Beware the Jabberwock, my son! The jaws that bite, the claws that catch!", "vigenerecipher", True)
// in: #5 = step size, #7 = encryption key, #26 = num of chars in alphabet
Debug.Print "Encrypt:= """ & Encryp & """"
// out: #65...#90 = frequencies, #60 = number of chars
Debug.Print "Decrypt:= """ & Vigenere(Encryp, "vigenerecipher", False) & """"
End Sub


:CHARACTER_FREQUENCIES:
Private Function Vigenere(sWord As String, sKey As String, Enc As Boolean) As String
Save_Pos
Dim bw() As Byte, bk() As Byte, i As Long, c As Long
for (#8 = 'A'; #8<='Z'; #8++) {
Const sW As String = "ÁÂÃÄÅÇÈÉÊËÌÍÎÏÑÒÓÔÕÖÙÚÛÜÝ"
#@8 = 0 // reset frequency counters
Const sWo As String = "AAAAACEEEEIIIINOOOOOUUUUY"
}
Const A As Long = 65
#60 = 0 // total number of chars
Const N As Long = 26
while (!At_EOL) {
if (Cur_Char >= 'A' && Cur_Char <= 'Z') {
#8 = (Cur_Char-'A'+#26-#7) % #26 + 'A' // decrypted char
#@8++
#60++
}
Char(#5)
}
Restore_Pos
Return


// Calculate Index of Coincidence (Kp).
c = Len(sKey)
// in: character frequencies in #65...#90, #60 = num of chars
i = Len(sWord)
// out: #51 = IC * 10000
sKey = Left(IIf(c < i, StrRept(sKey, (i / c) + 1), sKey), i)
//
sKey = StrConv(sKey, vbUpperCase) 'Upper case
:INDEX_OF_COINCIDENCE:
sWord = StrConv(sWord, vbUpperCase)
Num_Push(10,15)
sKey = StrReplace(sKey, sW, sWo) 'Replace accented characters
#10 = 0
sWord = StrReplace(sWord, sW, sWo)
for (#11 = 'A'; #11<='Z'; #11++) {
sKey = RemoveChars(sKey) 'Remove characters (numerics, spaces, comas, ...)
#10 += (#@11 * (#@11-1)) // Calculate sigma{ni * (ni-1)}
sWord = RemoveChars(sWord)
}
bk = CharToAscii(sKey) 'To work with Bytes instead of String
#12 = #60 * (#60-1) // #12 = N * (N-1)
bw = CharToAscii(sWord)
#51 = #10 * 10000 / #12 // #51 = Kp * 10000
For i = LBound(bw) To UBound(bw)
Num_Pop(10,15)
Vigenere = Vigenere & Chr((IIf(Enc, ((bw(i) - A) + (bk(i) - A)), ((bw(i) - A) - (bk(i) - A)) + N) Mod N) + A)
Return
Next i
End Function


// Find best and 2nd best Caesar key for each character position of Vigenère key.
Private Function StrRept(s As String, N As Long) As String
// in: #5=step size (key length)
Dim j As Long, c As String
// out: keys in buffer #24
For j = 1 To N
//
c = c & s
:FIND_KEYS:
Next
for (#6 = 0; #6 < #5; #6++) { // for each char position in the key
StrRept = c
#30 = -1 // best key char found so far
End Function
#31 = -1 // 2nd best key char
#32 = MAXNUM // smallest error found so far
#33 = MAXNUM // 2nd smallest error found so far
for (#7 = 0; #7 < #26; #7++) { // for each possible key value
#35 = 0 // total frequency error compared to English
Buf_Switch(#20) // text being analyzed
Goto_Pos(#6)
Call("CHARACTER_FREQUENCIES")
Buf_Switch(#21) // English frequency table
BOF
for (#8 = 'A'; #8<='Z'; #8++) { // calculate total frequency error
#34 = Num_Eval(SUPPRESS+ADVANCE)
#35 += abs((#@8*100000+50000)/#60-#34)
}


if (#35 < #32) { // found better match?
Private Function StrReplace(s As String, What As String, By As String) As String
#33 = #32
Dim t() As String, u() As String, i As Long
#32 = #35
t = SplitString(What)
#31 = #30
u = SplitString(By)
StrReplace = s
#30 = #7
For i = LBound(t) To UBound(t)
} else {
if (#35 < #33) { // 2nd best match?
StrReplace = Replace(StrReplace, t(i), u(i))
#33 = #35
Next i
#31 = #7
End Function
}
}
}
Buf_Switch(#24) // table for key canditates
BOF
Goto_Col(#6+1)
Ins_Char(#30+'A', OVERWRITE) // save the best match
Line(1)
Goto_Col(#6+1)
Ins_Char(#31+'A', OVERWRITE) // save 2nd best match
}
Buf_Switch(#22) // results buffer
Return


// Combine actual key from 1st and 2nd best Caesar key characters
Private Function SplitString(s As String) As String()
// Use 1st key chars and (possibly) one character from 2nd key.
SplitString = Split(StrConv(s, vbUnicode), Chr(0))
// #4 = index of the char to be picked from 2nd key, -1 = none.
End Function
// #5 = key length
//
:BUILD_KEY:
Buf_Switch(#24) // table for key canditates
BOF
for (#6=0; #6<#5; #6++) { // copy 1st key
#8 = 130 + #6
#@8 = Cur_Char
Char(1)
}
if (#4 >= 0) {
#8 = 130 + #4 // pick one char from 2st key
Line(1)
Goto_Col(#4+1)
#@8 = Cur_Char
}
Buf_Switch(#22) // results buffer
Return


// Decrypt text on current line
Private Function RemoveChars(str As String) As String
// in: #5 = key length, #130...#189 = key
Dim b() As Byte, i As Long
//
b = CharToAscii(str)
:DECRYPT_LINE:
For i = LBound(b) To UBound(b)
Num_Push(6,9)
If b(i) >= 65 And b(i) <= 90 Then RemoveChars = RemoveChars & Chr(b(i))
Next i
#6 = 0
While (!At_EOL) {
End Function
#9 = #6+130
#7 = #@9
#8 = (Cur_Char - #7 + #26) % #26 + 'A' // decrypted char
Ins_Char(#8, OVERWRITE)
#6++
if (#6 >= #5) {
#6 = 0
}
}
Num_Pop(6,9)
Return


// Find English words from text on current line
Private Function CharToAscii(s As String) As Byte()
// out: #37 = number of chars matched
CharToAscii = StrConv(s, vbFromUnicode)
//
End Function</lang>
:FIND_ENGLISH_WORDS:
Buf_Switch(#23) // dictionary
BOF
While (!At_EOF) {
Reg_Copy_Block(12, Cur_Pos, EOL_Pos)
if (Reg_Size(12) > 2) {
Buf_Switch(#22) // buffer for results
BOL
while (Search_Block(@12, Cur_Pos, EOL_Pos, NOERR)) {
Reg_Ins(12, OVERWRITE)
}
Buf_Switch(#23)
}
Line(1, ERRBREAK)
}


Buf_Switch(#22)
{{Out}}
BOL
<pre>Encrypt:= "WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY"
#37 = Search_Block("|V", Cur_Pos, EOL_Pos, ALL+NOERR)
Decrypt:= "BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH"</pre>
Return </syntaxhighlight>


=={{header|VBScript}}==
=={{header|V (Vlang)}}==
{{trans|Liberty BASIC}}
{{trans|Go}}
<syntaxhighlight lang="v (vlang)">import strings
<lang vb>
const encoded =
Function Encrypt(text,key)
"MOMUD EKAPV TQEFM OEVHP AJMII CDCTI FGYAG JSPXY ALUYM NSMYH" +
text = OnlyCaps(text)
"VUXJE LEPXJ FXGCM JHKDZ RYICU HYPUS PGIGM OIYHF WHTCQ KMLRD" +
key = OnlyCaps(key)
"ITLXZ LJFVQ GHOLW CUHLO MDSOE KTALU VYLNZ RFGBX PHVGA LWQIS" +
j = 1
"FGRPH JOOFW GUBYI LAPLA LCAFA AMKLG CETDW VOELJ IKGJB XPHVG" +
For i = 1 To Len(text)
"ALWQC SNWBU BYHCU HKOCE XJEYK BQKVY KIIEH GRLGH XEOLW AWFOJ" +
ms = Mid(text,i,1)
"ILOVV RHPKD WIHKN ATUHN VRYAQ DIVHX FHRZV QWMWV LGSHN NLVZS" +
m = Asc(ms) - Asc("A")
"JLAKI FHXUF XJLXM TBLQV RXXHR FZXGV LRAJI EXPRV OSMNP KEPDT" +
ks = Mid(key,j,1)
"LPRWM JAZPK LQUZA ALGZX GVLKL GJTUI ITDSU REZXJ ERXZS HMPST" +
k = Asc(ks) - Asc("A")
"MTEOE PAPJH SMFNB YVQUZ AALGA YDNMP AQOWT UHDBV TSMUE UIMVH" +
j = (j Mod Len(key)) + 1
"QGVRW AEFSP EMPVE PKXZY WLKJA GWALT VYYOB YIXOK IHPDS EVLEV" +
c = (m + k) Mod 26
"RVSGB JOGYW FHKBL GLXYA MVKIS KIEHY IMAPX UOISK PVAGN MZHPW" +
c = Chr(Asc("A")+c)
"TTZPV XFCCD TUHJH WLAPF YULTB UXJLN SIJVV YOVDJ SOLXG TGRVO" +
Encrypt = Encrypt & c
"SFRII CTMKO JFCQF KTINQ BWVHG TENLH HOGCS PSFPV GJOKM SIFPR" +
Next
"ZPAAS ATPTZ FTPPD PORRF TAXZP KALQA WMIUD BWNCT LEFKO ZQDLX" +
End Function
"BUXJL ASIMR PNMBF ZCYLV WAPVF QRHZV ZGZEF KBYIO OFXYE VOWGB" +
"BXVCB XBAWG LQKCM ICRRX MACUO IKHQU AJEGL OIJHH XPVZW JEWBA" +
"FWAML ZZRXJ EKAHV FASMU LVVUT TGK"
const freq = [
0.08167, 0.01492, 0.02782, 0.04253, 0.12702, 0.02228, 0.02015,
0.06094, 0.06966, 0.00153, 0.00772, 0.04025, 0.02406, 0.06749,
0.07507, 0.01929, 0.00095, 0.05987, 0.06327, 0.09056, 0.02758,
0.00978, 0.02360, 0.00150, 0.01974, 0.00074,
]
fn sum(a []f64) f64 {
mut s := 0.0
for f in a {
s += f
}
return s
}
fn best_match(a []f64) int {
s := sum(a)
mut best_fit, mut best_rotate := 1e100, 0
for rotate in 0..26 {
mut fit := 0.0
for i in 0..26 {
d := a[(i+rotate)%26]/s - freq[i]
fit += d * d / freq[i]
}
if fit < best_fit {
best_fit, best_rotate = fit, rotate
}
}
return best_rotate
}
fn freq_every_nth(msg []int, mut key []u8) f64 {
l := msg.len
interval := key.len
mut out := []f64{len: 26}
mut accu := []f64{len: 26}
for j in 0..interval {
for z in 0..26 {
out[z] = 0.0
}
for i := j; i < l; i += interval {
out[msg[i]]++
}
rot := best_match(out)
key[j] = u8(rot + 65)
for i := 0; i < 26; i++ {
accu[i] += out[(i+rot)%26]
}
}
s := sum(accu)
mut ret := 0.0
for i := 0; i < 26; i++ {
d := accu[i]/s - freq[i]
ret += d * d / freq[i]
}
return ret
}
fn decrypt(text string, key string) string {
mut sb := strings.new_builder(128)
mut ki := 0
for c in text {
if c < 'A'[0] || c > 'Z'[0] {
continue
}
ci := (c - key[ki] + 26) % 26
sb.write_rune(ci + 65)
ki = (ki + 1) % key.len
}
return sb.str()
}
fn main() {
enc := encoded.replace(" ", "")
mut txt := []int{len: enc.len}
for i in 0..txt.len {
txt[i] = int(enc[i] - 'A'[0])
}
mut best_fit, mut best_key := 1e100, ""
println(" Fit Length Key")
for j := 1; j <= 26; j++ {
mut key := []u8{len: j}
fit := freq_every_nth(txt, mut key)
s_key := key.bytestr()
print("${fit:.6} ${j:2} $s_key")
if fit < best_fit {
best_fit, best_key = fit, s_key
print(" <--- best so far")
}
println('')
}
println("\nBest key : $best_key")
println("\nDecrypted text:\n${decrypt(enc, best_key)}")
}</syntaxhighlight>


{{out}}
Function Decrypt(text,key)
Note: carriage returns inserted into decrypted text after every 80 characters to make it more readable.
key = OnlyCaps(key)
<pre>
j = 1
Fit Length Key
For i = 1 To Len(text)
2.984348 1 E <--- best so far
ms = Mid(text,i,1)
2.483684 2 EC <--- best so far
m = Asc(ms) - Asc("A")
2.642487 3 TEE
ks = Mid(key,j,1)
1.976651 4 THEC <--- best so far
k = Asc(ks) - Asc("A")
2.356881 5 EEEPU
j = (j Mod Len(key)) + 1
c = (m - k + 26) Mod 26
2.203129 6 TCECEC
1.051163 7 THECSAS <--- best so far
c = Chr(Asc("A")+c)
1.645763 8 TJQGAHET
Decrypt = Decrypt & c
2.001380 9 VEIZSEGNT
Next
1.824476 10 ECEGAWQTDS
End Function
1.623083 11 TNLUSRXPTAJ
1.253527 12 XLECTHQGTHEC
1.399037 13 LJJTDGFNOTENR
0.152370 14 THECHESHIRECAT <--- best so far
1.533951 15 JNTOOEEXFTGQTNH
1.068182 16 TJTSAEETEXHPXHNE
1.034093 17 AZRAXUHEJLREEXIEE
1.443345 18 VNIZQPALEPTSXSEXUC
1.090977 19 FUCAITCSLVTEZDUDEHS
0.979868 20 EQXGAHWTTQECEWUGXHPI
0.789410 21 HVRCSAFTHEBDLSTAERSES
0.881380 22 TVIJTCIGKAQPELECRXPTNC
0.952456 23 KKEQXGPWTCQEELIEHXUWASV
0.715968 24 ELAIXHQTTIEDXJETTNTGAEPC
0.891258 25 OTJUUEGERDNQTUQEAGWUTIEOA
0.852784 26 IGITEGECAGAVUNLJAHASAVTETW


Best key : THECHESHIRECAT
Function OnlyCaps(s)
For i = 1 To Len(s)
char = UCase(Mid(s,i,1))
If Asc(char) >= 65 And Asc(char) <= 90 Then
OnlyCaps = OnlyCaps & char
End If
Next
End Function


Decrypted text:
'testing the functions
THISWASTHEPOEMTHATALICEREADJABBERWOCKYTWASBRILLIGANDTHESLITHYTOVESDIDGYREANDGIMB
orig_text = "Beware the Jabberwock, my son! The jaws that bite, the claws that catch!"
LEINTHEWABEALLMIMSYWERETHEBOROGOVESANDTHEMOMERATHSOUTGRABEBEWARETHEJABBERWOCKMYS
orig_key = "vigenerecipher"
ONTHEJAWSTHATBITETHECLAWSTHATCATCHBEWARETHEJUBJUBBIRDANDSHUNTHEFRUMIOUSBANDERSNA
WScript.StdOut.WriteLine "Original: " & orig_text
TCHHETOOKHISVORPALSWORDINHANDLONGTIMETHEMANXOMEFOEHESOUGHTSORESTEDHEBYTHETUMTUMT
WScript.StdOut.WriteLine "Key: " & orig_key
REEANDSTOODAWHILEINTHOUGHTANDASINUFFISHTHOUGHTHESTOODTHEJABBERWOCKWITHEYESOFFLAM
WScript.StdOut.WriteLine "Encrypted: " & Encrypt(orig_text,orig_key)
ECAMEWHIFFLINGTHROUGHTHETULGEYWOODANDBURBLEDASITCAMEONETWOONETWOANDTHROUGHANDTHR
WScript.StdOut.WriteLine "Decrypted: " & Decrypt(Encrypt(orig_text,orig_key),orig_key)
OUGHTHEVORPALBLADEWENTSNICKERSNACKHELEFTITDEADANDWITHITSHEADHEWENTGALUMPHINGBACK
</lang>
ANDHASTTHOUSLAINTHEJABBERWOCKCOMETOMYARMSMYBEAMISHBOYOFRABJOUSDAYCALLOOHCALLAYHE

CHORTLEDINHISJOYTWASBRILLIGANDTHESLITHYTOVESDIDGYREANDGIMBLEINTHEWABEALLMIMSYWER
{{Out}}
ETHEBOROGOVESANDTHEMOMERATHSOUTGRABEITSEEMSVERYPRETTYSHESAIDWHENSHEHADFINISHEDIT
<pre>
BUTITSRATHERHARDTOUNDERSTAND
Original: Beware the Jabberwock, my son! The jaws that bite, the claws that catch!
Key: vigenerecipher
Encrypted: WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY
Decrypted: BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH
</pre>
</pre>


=={{header|Wren}}==
An alternate implementation using RegExp to filter the input
{{trans|Kotlin}}
<lang vb>
{{libheader|Wren-math}}
'vigenere cypher
{{libheader|Wren-iterate}}
option explicit
{{libheader|Wren-str}}
const asca =65 'ascii(a)
{{libheader|Wren-fmt}}
<syntaxhighlight lang="wren">import "./math" for Nums
import "./iterate" for Stepped
import "./str" for Char, Str
import "./fmt" for Fmt


var encoded =
function filter(s)
"MOMUD EKAPV TQEFM OEVHP AJMII CDCTI FGYAG JSPXY ALUYM NSMYH" +
with new regexp
"VUXJE LEPXJ FXGCM JHKDZ RYICU HYPUS PGIGM OIYHF WHTCQ KMLRD" +
.pattern="[^A-Z]"
"ITLXZ LJFVQ GHOLW CUHLO MDSOE KTALU VYLNZ RFGBX PHVGA LWQIS" +
.global=1
"FGRPH JOOFW GUBYI LAPLA LCAFA AMKLG CETDW VOELJ IKGJB XPHVG" +
filter=.replace(ucase(s),"")
"ALWQC SNWBU BYHCU HKOCE XJEYK BQKVY KIIEH GRLGH XEOLW AWFOJ" +
end with
"ILOVV RHPKD WIHKN ATUHN VRYAQ DIVHX FHRZV QWMWV LGSHN NLVZS" +
end function
"JLAKI FHXUF XJLXM TBLQV RXXHR FZXGV LRAJI EXPRV OSMNP KEPDT" +
"LPRWM JAZPK LQUZA ALGZX GVLKL GJTUI ITDSU REZXJ ERXZS HMPST" +
"MTEOE PAPJH SMFNB YVQUZ AALGA YDNMP AQOWT UHDBV TSMUE UIMVH" +
"QGVRW AEFSP EMPVE PKXZY WLKJA GWALT VYYOB YIXOK IHPDS EVLEV" +
"RVSGB JOGYW FHKBL GLXYA MVKIS KIEHY IMAPX UOISK PVAGN MZHPW" +
"TTZPV XFCCD TUHJH WLAPF YULTB UXJLN SIJVV YOVDJ SOLXG TGRVO" +
"SFRII CTMKO JFCQF KTINQ BWVHG TENLH HOGCS PSFPV GJOKM SIFPR" +
"ZPAAS ATPTZ FTPPD PORRF TAXZP KALQA WMIUD BWNCT LEFKO ZQDLX" +
"BUXJL ASIMR PNMBF ZCYLV WAPVF QRHZV ZGZEF KBYIO OFXYE VOWGB" +
"BXVCB XBAWG LQKCM ICRRX MACUO IKHQU AJEGL OIJHH XPVZW JEWBA" +
"FWAML ZZRXJ EKAHV FASMU LVVUT TGK"


var freq = [
function vigenere (s,k,sign)
0.08167, 0.01492, 0.02782, 0.04253, 0.12702, 0.02228, 0.02015,
dim s1,i,a,b
0.06094, 0.06966, 0.00153, 0.00772, 0.04025, 0.02406, 0.06749,
for i=0 to len(s)-1
0.07507, 0.01929, 0.00095, 0.05987, 0.06327, 0.09056, 0.02758,
a=asc(mid(s,i+1,1))-asca
0.00978, 0.02360, 0.00150, 0.01974, 0.00074
b=sign * (asc(mid(k,(i mod len(k))+1,1))-asca)
]
s1=s1 & chr(((a+b+26) mod 26) +asca)
next
vigenere=s1
end function


var bestMatch = Fn.new { |a|
function encrypt(s,k): encrypt=vigenere(s,k,1) :end function
var sum = Nums.sum(a)
function decrypt(s,k): decrypt=vigenere(s,k,-1) :end function
var bestFit = 1e100
var bestRotate = 0
for (rotate in 0..25) {
var fit = 0
for (i in 0..25) {
var d = a[(i + rotate) % 26] / sum - freq[i]
fit = fit + d * d / freq[i]
}
if (fit < bestFit) {
bestFit = fit
bestRotate = rotate
}
}
return bestRotate
}


var freqEveryNth = Fn.new { |msg, key|
'test--------------------------
var len = msg.count
dim plaintext,filtered,key,encoded
var interval = key.count
key="VIGENERECYPHER"
var out = List.filled(26, 0)
plaintext = "Beware the Jabberwock, my son! The jaws that bite, the claws that catch!"
var accu = List.filled(26, 0)
filtered= filter(plaintext)
for (j in 0...interval) {
wscript.echo filtered
for (i in 0..25) out[i] = 0
encoded=encrypt(filtered,key)
for (i in Stepped.new(j...len, interval)) out[msg[i]] = out[msg[i]] + 1
wscript.echo encoded
var rot = bestMatch.call(out)
wscript.echo decrypt(encoded,key)
key[j] = Char.fromCode(rot + 65)

for (i in 0..25) accu[i] = accu[i] + out[(i + rot) % 26]
</lang>
}
var sum = Nums.sum(accu)
var ret = 0
for (i in 0..25) {
var d = accu[i] / sum - freq[i]
ret = ret + d * d / freq[i]
}
return ret
}


var decrypt = Fn.new { |text, key|
=={{header|Vedit macro language}}==
var sb = ""
Encrypts and then decrypts one line of text on current edit buffer,
var ki = 0
starting from cursor location.
for (c in text) {
The user enters the keyword (upper or lower case).
if (Char.isAsciiUpper(c)) {
<lang vedit>Get_Input(10, "Key: ", STATLINE+NOCR) // @10 = key
var ci = (c.bytes[0] - key[ki].bytes[0] + 26) % 26
Reg_Copy_Block(11, Cur_Pos, EOL_Pos) // @11 = copy of original text
sb = sb + Char.fromCode(ci + 65)
EOL Ins_Newline
ki = (ki + 1) % key.count
Ins_Text("Key = ") Reg_Ins(10) Ins_Newline
}

}
// Prepare the key into numeric registers #130..:
return sb
Buf_Switch(Buf_Free)
Reg_Ins(10)
Case_Upper_Block(0, Cur_Pos)
BOF
#2 = Reg_Size(10) // #2 = key length
for (#3=130; #3 < 130+#2; #3++) {
#@3 = Cur_Char
Char(1)
}
}
Buf_Quit(OK)


var enc = encoded.replace(" ", "")
Ins_Text("Encrypted: ")
var txt = List.filled(enc.count, 0)
#4 = Cur_Pos
for (i in 0...txt.count) txt[i] = Char.code(enc[i]) - 65
Reg_Ins(11) // copy of original text
var bestFit = 1e100
Replace_Block("|!|A", "", #4, EOL_Pos, BEGIN+ALL+NOERR) // remove non-alpha chars
var bestKey = ""
Case_Upper_Block(#4, EOL_Pos) // convert to upper case
var f = "$f $2d $s"
Goto_Pos(#4)
System.print(" Fit Length Key")
#1 = 1; Call("ENCRYPT_DECRYPT") // Encrypt the line
for (j in 1..26) {
Reg_Copy_Block(11, #4, Cur_Pos) // Copy encrypted text text to next line
var key = List.filled(j, "")
Ins_Newline
var fit = freqEveryNth.call(txt, key)
Ins_Text("Decrypted: ")
var sKey = key.join("")
Reg_Ins(11, BEGIN)
Fmt.write(f, fit, j, sKey)
#1 = -1; Call("ENCRYPT_DECRYPT") // Decrypt the line
if (fit < bestFit) {

bestFit = fit
Return
bestKey = sKey

System.write(" <--- best so far")
// Encrypt or decrypt text on current line in-place, starting from cursor position.
// in: #1 = direction (1=encrypt, -1=decrypt)
// #2 = key length, #130...#189 = the key
//
:ENCRYPT_DECRYPT:
Num_Push(6,9)
#6 = 0
While (!At_EOL) {
#7 = #6+130 // pointer to key array
#8 = #@7 // get key character
#9 = (Cur_Char + #8*#1 + 26) % 26 + 'A' // decrypt/encrypt
Ins_Char(#9, OVERWRITE) // write the converted char
#6 = (#6+1) % #2
}
}
Num_Pop(6,9)
System.print()
}
Return </lang>
System.print()
System.print("Best key : %(bestKey)")
System.print("\nDecrypted text:\n%(decrypt.call(enc, bestKey))")</syntaxhighlight>


{{out}}
{{out}}
<pre>
<pre>
Fit Length Key
Beware the Jabberwock, my son! The jaws that bite, the claws that catch!
2.984348 1 E <--- best so far
Key = vigenerecipher
2.483684 2 EC <--- best so far
Encrypted: WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY
2.642487 3 TEE
Decrypted: BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH
1.976651 4 THEC <--- best so far
</pre>
2.356881 5 EEEPU
2.203129 6 TCECEC
1.051163 7 THECSAS <--- best so far
1.645763 8 TJQGAHET
2.001380 9 VEIZSEGNT
1.824476 10 ECEGAWQTDS
1.623083 11 TNLUSRXPTAJ
1.253527 12 XLECTHQGTHEC
1.399037 13 LJJTDGFNOTENR
0.152370 14 THECHESHIRECAT <--- best so far
1.533951 15 JNTOOEEXFTGQTNH
1.068182 16 TJTSAEETEXHPXHNE
1.034093 17 AZRAXUHEJLREEXIEE
1.443345 18 VNIZQPALEPTSXSEXUC
1.090977 19 FUCAITCSLVTEZDUDEHS
0.979868 20 EQXGAHWTTQECEWUGXHPI
0.789410 21 HVRCSAFTHEBDLSTAERSES
0.881380 22 TVIJTCIGKAQPELECRXPTNC
0.952456 23 KKEQXGPWTCQEELIEHXUWASV
0.715968 24 ELAIXHQTTIEDXJETTNTGAEPC
0.891258 25 OTJUUEGERDNQTUQEAGWUTIEOA
0.852784 26 IGITEGECAGAVUNLJAHASAVTETW


Best key : THECHESHIRECAT
=={{header|XPL0}}==
The KEYWORD must be UPPERCASE. Precede it with a minus sign to decrypt a file.
Usage: vigenere KEYWORD <infile.txt >outfile.xxx


Decrypted text:
<lang XPL0>code ChIn=7, ChOut=8;
THISWASTHEPOEMTHATALICEREADJABBERWOCKYTWASBRILLIGANDTHESLITHYTOVESDIDGYREANDGIMBLEINTHEWABEALLMIMSYWERETHEBOROGOVESANDTHEMOMERATHSOUTGRABEBEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCHBEWARETHEJUBJUBBIRDANDSHUNTHEFRUMIOUSBANDERSNATCHHETOOKHISVORPALSWORDINHANDLONGTIMETHEMANXOMEFOEHESOUGHTSORESTEDHEBYTHETUMTUMTREEANDSTOODAWHILEINTHOUGHTANDASINUFFISHTHOUGHTHESTOODTHEJABBERWOCKWITHEYESOFFLAMECAMEWHIFFLINGTHROUGHTHETULGEYWOODANDBURBLEDASITCAMEONETWOONETWOANDTHROUGHANDTHROUGHTHEVORPALBLADEWENTSNICKERSNACKHELEFTITDEADANDWITHITSHEADHEWENTGALUMPHINGBACKANDHASTTHOUSLAINTHEJABBERWOCKCOMETOMYARMSMYBEAMISHBOYOFRABJOUSDAYCALLOOHCALLAYHECHORTLEDINHISJOYTWASBRILLIGANDTHESLITHYTOVESDIDGYREANDGIMBLEINTHEWABEALLMIMSYWERETHEBOROGOVESANDTHEMOMERATHSOUTGRABEITSEEMSVERYPRETTYSHESAIDWHENSHEHADFINISHEDITBUTITSRATHERHARDTOUNDERSTAND
int Neg, C, Len, I, Key;
char KeyWord(80);
[Neg:= false; \skip to KEYWORD
repeat C:= ChIn(8); if C=^- then Neg:= true; until C>=^A & C<=^Z;
Len:= 0; \read in KEYWORD
repeat KeyWord(Len):= C-^A; Len:= Len+1; C:= ChIn(8); until C<^A ! C>^Z;
I:= 0; \initialize cycling index
repeat C:= ChIn(1);
if C>=^a & C<=^z then C:= C-$20; \capitalize
if C>=^A & C<=^Z then \discard non-alphas
[Key:= KeyWord(I); I:= I+1; if I>=Len then I:= 0;
if Neg then Key:= -Key; \decrypting?
C:= C+Key;
if C>^Z then C:= C-26
else if C<^A then C:= C+26;
ChOut(0, C);
];
until C=$1A; \EOF
ChOut(0, $1A); \encrypted file must end with EOF otherwise the decode will hang
]</lang>

{{out}}
<pre>
KEYWORD = ACE
infile = Pack my box with five dozen liquor jugs.
outfile = PCGKOCBQBWKXHHMVGHOBINNMQWSRLYGU
KEYWORD = -ACE
outfile = PACKMYBOXWITHFIVEDOZENLIQUORJUGS
</pre>
</pre>


=={{header|zkl}}==
=={{header|zkl}}==
{{trans|C}}
{{trans|Python}}
<syntaxhighlight lang="zkl">var[const] uppercase=["A".."Z"].pump(String),
<lang zkl>fcn encipher(src,key,is_encode){
english_frequences=T( // A..Z
upperCase:=["A".."Z"].pump(String);
0.08167, 0.01492, 0.02782, 0.04253, 0.12702, 0.02228, 0.02015,
src=src.toUpper().inCommon(upperCase); // only uppercase
0.06094, 0.06966, 0.00153, 0.00772, 0.04025, 0.02406, 0.06749,
key=key.toUpper().inCommon(upperCase).pump(List,"toAsc");
0.07507, 0.01929, 0.00095, 0.05987, 0.06327, 0.09056, 0.02758,

0.00978, 0.02360, 0.00150, 0.01974, 0.00074);
const A="A".toAsc();
klen:=Walker.cycle(key.len()); // 0,1,2,3,..,keyLen-1,0,1,2,3, ...
fcn vigenere_decrypt(target_freqs, input){ // ( (float,...), string)
src.pump(String,'wrap(c){ i:=klen.next(); c=c.toAsc();
nchars,ordA :=uppercase.len(),"A".toAsc();
(A + ( if(is_encode) c - A + key[i] - A;
sorted_targets:=target_freqs.sort();
else c - key[i] + 26 ) % 26).toChar()
});
frequency:='wrap(input){ // (n,n,n,n,...), n is ASCII index ("A"==65)
}</lang>
result:=uppercase.pump(List(),List.fp1(0)); // ( ("A",0),("B",0) ...)
<lang zkl>str := "Beware the Jabberwock, my son! The jaws that bite, "
foreach c in (input){ result[c - ordA][1] += 1 }
"the claws that catch!";
result // --> mutable list of mutable lists ( ("A",Int)...("Z",Int) )
key := "Vigenere Cipher";
};

correlation:='wrap(input){ // (n,n,n,n,...), n is ASCII index ("A"==65)
println("Text: ", str);
result,freq:=0.0, frequency(input);
println("key: ", key);
freq.sort(fcn([(_,a)],[(_,b)]){ a<b }); // sort letters by frequency
foreach i,f in (freq.enumerate()){ result+=sorted_targets[i]*f[1] }
result // -->Float
};
cleaned:=input.toUpper().pump(List,uppercase.holds,Void.Filter,"toAsc");
best_len,best_corr := 0,-100.0;
# Assume that if there are less than 20 characters
# per column, the key's too long to guess
foreach i in ([2..cleaned.len()/20]){
pieces:=(i).pump(List,List.copy); // ( (),() ... )
foreach c in (cleaned){ pieces[__cWalker.idx%i].append(c) }
# The correlation seems to increase for smaller
# pieces/longer keys, so weigh against them a little
corr:=-0.5*i + pieces.apply(correlation).sum(0.0);
if(corr>best_corr) best_len,best_corr=i,corr;
}
if(best_len==0) return("Text is too short to analyze", "");
pieces:=best_len.pump(List,List.copy);
foreach c in (cleaned){ pieces[__cWalker.idx%best_len].append(c) }
key,freqs := "",pieces.apply(frequency);
foreach fr in (freqs){
fr.sort(fcn([(_,a)],[(_,b)]){ a>b }); // reverse sort by freq
m,max_corr := 0,0.0;
foreach j in (nchars){
corr,c := 0.0,ordA + j;
foreach frc in (fr){
d:=(frc[0].toAsc() - c + nchars) % nchars;
corr+=target_freqs[d]*frc[1];
if(corr>max_corr) m,max_corr=j,corr;
}
}
key+=(m + ordA).toChar();
}
cleaned.enumerate().apply('wrap([(i,c])){
cod := encipher(str, key, True); println("Code: ", cod);
( (c - (key[i%best_len]).toAsc() + nchars)%nchars + ordA ).toChar()
dec := encipher(cod, key, False); println("Back: ", dec);</lang>
}).concat() :
T(key,_);
}</syntaxhighlight>
<syntaxhighlight lang="zkl">encryptedText:=
#<<<
"MOMUD EKAPV TQEFM OEVHP AJMII CDCTI FGYAG JSPXY ALUYM NSMYH
VUXJE LEPXJ FXGCM JHKDZ RYICU HYPUS PGIGM OIYHF WHTCQ KMLRD
ITLXZ LJFVQ GHOLW CUHLO MDSOE KTALU VYLNZ RFGBX PHVGA LWQIS
FGRPH JOOFW GUBYI LAPLA LCAFA AMKLG CETDW VOELJ IKGJB XPHVG
ALWQC SNWBU BYHCU HKOCE XJEYK BQKVY KIIEH GRLGH XEOLW AWFOJ
ILOVV RHPKD WIHKN ATUHN VRYAQ DIVHX FHRZV QWMWV LGSHN NLVZS
JLAKI FHXUF XJLXM TBLQV RXXHR FZXGV LRAJI EXPRV OSMNP KEPDT
LPRWM JAZPK LQUZA ALGZX GVLKL GJTUI ITDSU REZXJ ERXZS HMPST
MTEOE PAPJH SMFNB YVQUZ AALGA YDNMP AQOWT UHDBV TSMUE UIMVH
QGVRW AEFSP EMPVE PKXZY WLKJA GWALT VYYOB YIXOK IHPDS EVLEV
RVSGB JOGYW FHKBL GLXYA MVKIS KIEHY IMAPX UOISK PVAGN MZHPW
TTZPV XFCCD TUHJH WLAPF YULTB UXJLN SIJVV YOVDJ SOLXG TGRVO
SFRII CTMKO JFCQF KTINQ BWVHG TENLH HOGCS PSFPV GJOKM SIFPR
ZPAAS ATPTZ FTPPD PORRF TAXZP KALQA WMIUD BWNCT LEFKO ZQDLX
BUXJL ASIMR PNMBF ZCYLV WAPVF QRHZV ZGZEF KBYIO OFXYE VOWGB
BXVCB XBAWG LQKCM ICRRX MACUO IKHQU AJEGL OIJHH XPVZW JEWBA
FWAML ZZRXJ EKAHV FASMU LVVUT TGK";
#<<<
key,decoded:=vigenere_decrypt(english_frequences,encryptedText);
println("Key:", key);
println("Decoded text:", decoded);</syntaxhighlight>
{{out}}
{{out}}
<pre>
<pre>
Key:THECHESHIRECAT
Text: Beware the Jabberwock, my son! The jaws that bite, the claws that catch!
Decoded text:THISWASTHEPOEMTHATALICEREADJABBERWOCKYTWASBRILLIGANDTHESLITHYTOVESDIDGYREANDGIMBLEINTHEWABEALLMIMSYWERETHEBOROGOVESANDTHEMOMERATHSOUTGRABEBEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCHBEWARETHEJUBJUBBIRDANDSHUNTHEFRUMIOUSBANDERSNATCHHETOOKHISVORPALSWORDINHANDLONGTIMETHEMANXOMEFOEHESOUGHTSORESTEDHEBYTHETUMTUMTREEANDSTOODAWHILEINTHOUGHTANDASINUFFISHTHOUGHTHESTOODTHEJABBERWOCKWITHEYESOFFLAMECAMEWHIFFLINGTHROUGHTHETULGEYWOODANDBURBLEDASITCAMEONETWOONETWOANDTHROUGHANDTHROUGHTHEVORPALBLADEWENTSNICKERSNACKHELEFTITDEADANDWITHITSHEADHEWENTGALUMPHINGBACKANDHASTTHOUSLAINTHEJABBERWOCKCOMETOMYARMSMYBEAMISHBOYOFRABJOUSDAYCALLOOHCALLAYHECHORTLEDINHISJOYTWASBRILLIGANDTHESLITHYTOVESDIDGYREANDGIMBLEINTHEWABEALLMIMSYWERETHEBOROGOVESANDTHEMOMERATHSOUTGRABEITSEEMSVERYPRETTYSHESAIDWHENSHEHADFINISHEDITBUTITSRATHERHARDTOUNDERSTAND
key: Vigenere Cipher
Code: WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY
Back: BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH
</pre>
</pre>

Latest revision as of 11:08, 16 February 2024

Task
Vigenère cipher/Cryptanalysis
You are encouraged to solve this task according to the task description, using any language you may know.

Given some text you suspect has been encrypted with a Vigenère cipher, extract the key and plaintext. There are several methods for doing this. See the Wikipedia entry for more information. Use the following encrypted text:

MOMUD EKAPV TQEFM OEVHP AJMII CDCTI FGYAG JSPXY ALUYM NSMYH
VUXJE LEPXJ FXGCM JHKDZ RYICU HYPUS PGIGM OIYHF WHTCQ KMLRD
ITLXZ LJFVQ GHOLW CUHLO MDSOE KTALU VYLNZ RFGBX PHVGA LWQIS
FGRPH JOOFW GUBYI LAPLA LCAFA AMKLG CETDW VOELJ IKGJB XPHVG
ALWQC SNWBU BYHCU HKOCE XJEYK BQKVY KIIEH GRLGH XEOLW AWFOJ
ILOVV RHPKD WIHKN ATUHN VRYAQ DIVHX FHRZV QWMWV LGSHN NLVZS
JLAKI FHXUF XJLXM TBLQV RXXHR FZXGV LRAJI EXPRV OSMNP KEPDT
LPRWM JAZPK LQUZA ALGZX GVLKL GJTUI ITDSU REZXJ ERXZS HMPST
MTEOE PAPJH SMFNB YVQUZ AALGA YDNMP AQOWT UHDBV TSMUE UIMVH
QGVRW AEFSP EMPVE PKXZY WLKJA GWALT VYYOB YIXOK IHPDS EVLEV
RVSGB JOGYW FHKBL GLXYA MVKIS KIEHY IMAPX UOISK PVAGN MZHPW
TTZPV XFCCD TUHJH WLAPF YULTB UXJLN SIJVV YOVDJ SOLXG TGRVO
SFRII CTMKO JFCQF KTINQ BWVHG TENLH HOGCS PSFPV GJOKM SIFPR
ZPAAS ATPTZ FTPPD PORRF TAXZP KALQA WMIUD BWNCT LEFKO ZQDLX
BUXJL ASIMR PNMBF ZCYLV WAPVF QRHZV ZGZEF KBYIO OFXYE VOWGB
BXVCB XBAWG LQKCM ICRRX MACUO IKHQU AJEGL OIJHH XPVZW JEWBA
FWAML ZZRXJ EKAHV FASMU LVVUT TGK

Letter frequencies for English can be found here.

Specifics for this task:

  • Take only the ciphertext as input. You can assume it's all capitalized and has no punctuation, but it might have whitespace.
  • Assume the plaintext is written in English.
  • Find and output the key.
  • Use that key to decrypt and output the original plaintext. Maintaining the whitespace from the ciphertext is optional.
  • The algorithm doesn't have to be perfect (which may not be possible) but it should work when given enough ciphertext. The example above is fairly long, and should be plenty for any algorithm.

11l

Translation of: Python
-V ascii_uppercase = Array(‘A’..‘Z’)

F vigenere_decrypt(target_freqs, input)
   V nchars = :ascii_uppercase.len
   V ordA = ‘A’.code
   V sorted_targets = sorted(target_freqs)

   F frequency(input)
      V result = :ascii_uppercase.map(c -> (c, 0.0))
      L(c) input
         result[c - @ordA][1]++
      R result

   F correlation(input)
      V result = 0.0
      V freq = sorted(@frequency(input), key' a -> a[1])

      L(f) freq
         result += f[1] * @sorted_targets[L.index]
      R result

   V cleaned = input.uppercase().filter(c -> c.is_uppercase()).map(c -> c.code)
   V best_len = 0
   V best_corr = -100.0

   L(i) 2 .< cleaned.len I/ 20
      V pieces = [[Int]()] * i
      L(c) cleaned
         pieces[L.index % i].append(c)
      V corr = -0.5 * i + sum(pieces.map(p -> @correlation(p)))

      I corr > best_corr
         best_len = i
         best_corr = corr

   I best_len == 0
      R (‘Text is too short to analyze’, ‘’)

   V pieces = [[Int]()] * best_len
   L(c) cleaned
      pieces[L.index % best_len].append(c)

   V freqs = pieces.map(p -> @frequency(p))

   V key = ‘’
   L(fr_) freqs
      V fr = sorted(fr_, key' a -> a[1], reverse' 1B)
      V m = 0
      V max_corr = 0.0
      L(j) 0 .< nchars
         V corr = 0.0
         V c = ordA + j
         L(frc) fr
            V d = (frc[0].code - c + nchars) % nchars
            corr += frc[1] * target_freqs[d]

         I corr > max_corr
            m = j
            max_corr = corr

      key ‘’= Char(code' m + ordA)

   V r = (enumerate(cleaned).map((i, c) -> Char(code' (c - @key[i % @best_len].code + @nchars) % @nchars + @ordA)))
   R (key, r.join(‘’))

V encoded = ‘
    MOMUD EKAPV TQEFM OEVHP AJMII CDCTI FGYAG JSPXY ALUYM NSMYH
    VUXJE LEPXJ FXGCM JHKDZ RYICU HYPUS PGIGM OIYHF WHTCQ KMLRD
    ITLXZ LJFVQ GHOLW CUHLO MDSOE KTALU VYLNZ RFGBX PHVGA LWQIS
    FGRPH JOOFW GUBYI LAPLA LCAFA AMKLG CETDW VOELJ IKGJB XPHVG
    ALWQC SNWBU BYHCU HKOCE XJEYK BQKVY KIIEH GRLGH XEOLW AWFOJ
    ILOVV RHPKD WIHKN ATUHN VRYAQ DIVHX FHRZV QWMWV LGSHN NLVZS
    JLAKI FHXUF XJLXM TBLQV RXXHR FZXGV LRAJI EXPRV OSMNP KEPDT
    LPRWM JAZPK LQUZA ALGZX GVLKL GJTUI ITDSU REZXJ ERXZS HMPST
    MTEOE PAPJH SMFNB YVQUZ AALGA YDNMP AQOWT UHDBV TSMUE UIMVH
    QGVRW AEFSP EMPVE PKXZY WLKJA GWALT VYYOB YIXOK IHPDS EVLEV
    RVSGB JOGYW FHKBL GLXYA MVKIS KIEHY IMAPX UOISK PVAGN MZHPW
    TTZPV XFCCD TUHJH WLAPF YULTB UXJLN SIJVV YOVDJ SOLXG TGRVO
    SFRII CTMKO JFCQF KTINQ BWVHG TENLH HOGCS PSFPV GJOKM SIFPR
    ZPAAS ATPTZ FTPPD PORRF TAXZP KALQA WMIUD BWNCT LEFKO ZQDLX
    BUXJL ASIMR PNMBF ZCYLV WAPVF QRHZV ZGZEF KBYIO OFXYE VOWGB
    BXVCB XBAWG LQKCM ICRRX MACUO IKHQU AJEGL OIJHH XPVZW JEWBA
    FWAML ZZRXJ EKAHV FASMU LVVUT TGK’

V english_frequences = [
   0.08167, 0.01492, 0.02782, 0.04253, 0.12702, 0.02228, 0.02015,
   0.06094, 0.06966, 0.00153, 0.00772, 0.04025, 0.02406, 0.06749,
   0.07507, 0.01929, 0.00095, 0.05987, 0.06327, 0.09056, 0.02758,
   0.00978, 0.02360, 0.00150, 0.01974, 0.00074]

V (key, decoded) = vigenere_decrypt(english_frequences, encoded)
print(‘Key: ’key)
print("\nText: "decoded)
Output:
Key: THECHESHIRECAT

Text: THISWASTHEPOEMTHATALICEREADJABBERWOCKYTWASBRILLIGANDTHESLITHYTOVESDIDGYREANDGIMBLEINTHEWABEALLMIMSYWERETHEBOROGOVE...

Ada

The program is not fully auto, but makes a small number of suggestions for the right key and plaintext.

with Ada.Text_IO;

procedure Vignere_Cryptanalysis is

   subtype Letter is Character range 'A' .. 'Z';

   function "+"(X, Y: Letter) return Letter is
   begin
      return Character'Val( ( (Character'Pos(X)-Character'Pos('A'))
                                + (Character'Pos(Y)-Character'Pos('A')) ) mod 26
                          + Character'Pos('A'));
   end;

   function "-"(X, Y: Letter) return Letter is
   begin
      return Character'Val( ( (Character'Pos(X)-Character'Pos('A'))
                                - (Character'Pos(Y)-Character'Pos('A')) ) mod 26
                          + Character'Pos('A'));
   end;

   type Frequency_Array is array (Letter) of Float;

   English: Frequency_Array :=
     ( 0.08167, 0.01492, 0.02782, 0.04253, 0.12702, 0.02228, 0.02015,
       0.06094, 0.06966, 0.00153, 0.00772, 0.04025, 0.02406, 0.06749,
       0.07507, 0.01929, 0.00095, 0.05987, 0.06327, 0.09056, 0.02758,
       0.00978, 0.02360, 0.00150, 0.01974, 0.00074 );

   function Get_Frequency(S: String) return Frequency_Array is
      Result: Frequency_Array := (others => 0.0);
      Offset: Float := 1.0/Float(S'Length);
   begin
      for I in S'Range loop
         if S(I) in Letter then
            Result(S(I)) := Result(S(I)) + Offset;
         end if;
      end loop;
      return Result;
   end Get_Frequency;

   function Remove_Whitespace(S: String) return String is
   begin
      if S="" then
         return "";
      elsif S(S'First) in Letter then
         return S(S'First) & Remove_Whitespace(S(S'First+1 .. S'Last));
      else
         return Remove_Whitespace(S(S'First+1 .. S'Last));
      end if;
   end Remove_Whitespace;

   function Distance(A, B: Frequency_Array;
                     Offset: Character := 'A') return Float is
      Result: Float := 0.0;
      Diff: Float;
   begin
      for C in A'Range loop
         Diff := A(C+Offset) - B(C);
         Result := Result + (Diff * Diff);
      end loop;
      return Result;
   end Distance;

   function Find_Key(Cryptogram: String; Key_Length: Positive) return String is

      function Find_Caesar_Key(S: String) return Letter is
         Frequency: Frequency_Array := Get_Frequency(S);
         Candidate: Letter := 'A'; -- a fake candidate
         Candidate_Dist : Float := Distance(Frequency, English, 'A');
         New_Dist: Float;

      begin

         for L in Letter range 'B' .. 'Z' loop
            New_Dist := Distance(Frequency, English, L);
            if New_Dist <= Candidate_Dist then
               Candidate_Dist := New_Dist;
               Candidate      := L;
            end if;
         end loop;
         return Candidate;
      end Find_Caesar_Key;

      function Get_Slide(S: String; Step: Positive) return String is
      begin
         if S'Length= 0 then
            return "";
         else
            return S(S'First) & Get_Slide(S(S'First+Step .. S'Last), Step);
         end if;
      end Get_Slide;

      Key: String(1 .. Key_Length);

      S: String renames Cryptogram;

   begin
      for I in Key'Range loop
         Key(I) := Find_Caesar_Key(Get_Slide(S(S'First+I-1 .. S'Last),
                                             Key_Length));
      end loop;
      return Key;
   end Find_Key;

   function Key_Char(Key: String; Index: Positive) return Letter is
   begin
      if Index > Key'Last then
         return Key_Char(Key, Index-Key'Last);
      else
         return Key(Index);
      end if;
   end Key_Char;

   Ciphertext: String := Remove_Whitespace(
     "MOMUD EKAPV TQEFM OEVHP AJMII CDCTI FGYAG JSPXY ALUYM NSMYH" &
     "VUXJE LEPXJ FXGCM JHKDZ RYICU HYPUS PGIGM OIYHF WHTCQ KMLRD" &
     "ITLXZ LJFVQ GHOLW CUHLO MDSOE KTALU VYLNZ RFGBX PHVGA LWQIS" &
     "FGRPH JOOFW GUBYI LAPLA LCAFA AMKLG CETDW VOELJ IKGJB XPHVG" &
     "ALWQC SNWBU BYHCU HKOCE XJEYK BQKVY KIIEH GRLGH XEOLW AWFOJ" &
     "ILOVV RHPKD WIHKN ATUHN VRYAQ DIVHX FHRZV QWMWV LGSHN NLVZS" &
     "JLAKI FHXUF XJLXM TBLQV RXXHR FZXGV LRAJI EXPRV OSMNP KEPDT" &
     "LPRWM JAZPK LQUZA ALGZX GVLKL GJTUI ITDSU REZXJ ERXZS HMPST" &
     "MTEOE PAPJH SMFNB YVQUZ AALGA YDNMP AQOWT UHDBV TSMUE UIMVH" &
     "QGVRW AEFSP EMPVE PKXZY WLKJA GWALT VYYOB YIXOK IHPDS EVLEV" &
     "RVSGB JOGYW FHKBL GLXYA MVKIS KIEHY IMAPX UOISK PVAGN MZHPW" &
     "TTZPV XFCCD TUHJH WLAPF YULTB UXJLN SIJVV YOVDJ SOLXG TGRVO" &
     "SFRII CTMKO JFCQF KTINQ BWVHG TENLH HOGCS PSFPV GJOKM SIFPR" &
     "ZPAAS ATPTZ FTPPD PORRF TAXZP KALQA WMIUD BWNCT LEFKO ZQDLX" &
     "BUXJL ASIMR PNMBF ZCYLV WAPVF QRHZV ZGZEF KBYIO OFXYE VOWGB" &
     "BXVCB XBAWG LQKCM ICRRX MACUO IKHQU AJEGL OIJHH XPVZW JEWBA" &
     "FWAML ZZRXJ EKAHV FASMU LVVUT TGK");

   Best_Plain: String := Ciphertext;
   Best_Dist:  Float := Distance(English, Get_Frequency(Best_Plain));
   Best_Key:   String := Ciphertext;
   Best_Key_L: Natural := 0;

begin -- Vignere_Cryptanalysis
   for I in 1 .. Ciphertext'Length/10 loop
      declare
         Key: String(1 .. I) := Find_Key(Ciphertext, I);
         Plaintext: String(Ciphertext'Range);
      begin
         for I in Ciphertext'Range loop
            Plaintext(I) := Ciphertext(I) - Key_Char(Key, I);
         end loop;
         if Distance(English, Get_Frequency(Plaintext)) < Best_Dist then
            Best_Plain := Plaintext;
            Best_Dist  := Distance(English, Get_Frequency(Plaintext));
            Best_Key(1 .. I) := Key;
            Best_Key_L := I;
            if Best_dist < 0.01 then
               declare
                  use Ada.Text_IO;
               begin
                  Put_Line("Key       =" & Best_Key(1 .. Best_Key_L));
                  Put_Line("Distance = " & Float'Image(Best_Dist));
                  New_Line;
                  Put_Line("Plaintext =");
                  Put_Line(Best_Plain);
                  New_Line; New_Line;
               end;
            end if;
         end if;
      end;
   end loop;
end Vignere_Cryptanalysis;

C

This finds the right key (I think, I didn't try to decode it after getting the key). The program is not fully auto, but by its output, the result is pretty obvious.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <math.h>

const char *encoded =
    "MOMUD EKAPV TQEFM OEVHP AJMII CDCTI FGYAG JSPXY ALUYM NSMYH"
    "VUXJE LEPXJ FXGCM JHKDZ RYICU HYPUS PGIGM OIYHF WHTCQ KMLRD"
    "ITLXZ LJFVQ GHOLW CUHLO MDSOE KTALU VYLNZ RFGBX PHVGA LWQIS"
    "FGRPH JOOFW GUBYI LAPLA LCAFA AMKLG CETDW VOELJ IKGJB XPHVG"
    "ALWQC SNWBU BYHCU HKOCE XJEYK BQKVY KIIEH GRLGH XEOLW AWFOJ"
    "ILOVV RHPKD WIHKN ATUHN VRYAQ DIVHX FHRZV QWMWV LGSHN NLVZS"
    "JLAKI FHXUF XJLXM TBLQV RXXHR FZXGV LRAJI EXPRV OSMNP KEPDT"
    "LPRWM JAZPK LQUZA ALGZX GVLKL GJTUI ITDSU REZXJ ERXZS HMPST"
    "MTEOE PAPJH SMFNB YVQUZ AALGA YDNMP AQOWT UHDBV TSMUE UIMVH"
    "QGVRW AEFSP EMPVE PKXZY WLKJA GWALT VYYOB YIXOK IHPDS EVLEV"
    "RVSGB JOGYW FHKBL GLXYA MVKIS KIEHY IMAPX UOISK PVAGN MZHPW"
    "TTZPV XFCCD TUHJH WLAPF YULTB UXJLN SIJVV YOVDJ SOLXG TGRVO"
    "SFRII CTMKO JFCQF KTINQ BWVHG TENLH HOGCS PSFPV GJOKM SIFPR"
    "ZPAAS ATPTZ FTPPD PORRF TAXZP KALQA WMIUD BWNCT LEFKO ZQDLX"
    "BUXJL ASIMR PNMBF ZCYLV WAPVF QRHZV ZGZEF KBYIO OFXYE VOWGB"
    "BXVCB XBAWG LQKCM ICRRX MACUO IKHQU AJEGL OIJHH XPVZW JEWBA"
    "FWAML ZZRXJ EKAHV FASMU LVVUT TGK";

const double freq[] = {
    0.08167, 0.01492, 0.02782, 0.04253, 0.12702, 0.02228, 0.02015,
    0.06094, 0.06966, 0.00153, 0.00772, 0.04025, 0.02406, 0.06749,
    0.07507, 0.01929, 0.00095, 0.05987, 0.06327, 0.09056, 0.02758,
    0.00978, 0.02360, 0.00150, 0.01974, 0.00074
};

int best_match(const double *a, const double *b) {
    double sum = 0, fit, d, best_fit = 1e100;
    int i, rotate, best_rotate = 0;
    for (i = 0; i < 26; i++)
        sum += a[i];
    for (rotate = 0; rotate < 26; rotate++) {
        fit = 0;
        for (i = 0; i < 26; i++) {
            d = a[(i + rotate) % 26] / sum - b[i];
            fit += d * d / b[i];
        }

        if (fit < best_fit) {
            best_fit = fit;
            best_rotate = rotate;
        }
    }

    return best_rotate;
}

double freq_every_nth(const int *msg, int len, int interval, char *key) {
    double sum, d, ret;
    double out[26], accu[26] = {0};
    int i, j, rot;

    for (j = 0; j < interval; j++) {
        for (i = 0; i < 26; i++)
            out[i] = 0;
        for (i = j; i < len; i += interval)
            out[msg[i]]++;
        key[j] = rot = best_match(out, freq);
        key[j] += 'A';
        for (i = 0; i < 26; i++)
            accu[i] += out[(i + rot) % 26];
    }

    for (i = 0, sum = 0; i < 26; i++)
        sum += accu[i];

    for (i = 0, ret = 0; i < 26; i++) {
        d = accu[i] / sum - freq[i];
        ret += d * d / freq[i];
    }

    key[interval] = '\0';
    return ret;
}

int main() {
    int txt[strlen(encoded)];
    int len = 0, j;
    char key[100];
    double fit, best_fit = 1e100;

    for (j = 0; encoded[j] != '\0'; j++)
        if (isupper(encoded[j]))
            txt[len++] = encoded[j] - 'A';

    for (j = 1; j < 30; j++) {
        fit = freq_every_nth(txt, len, j, key);
        printf("%f, key length: %2d, %s", fit, j, key);
        if (fit < best_fit) {
            best_fit = fit;
            printf(" <--- best so far");
        }
        printf("\n");
    }

    return 0;
}

C++

Not guaranteed to give a 100% correct answer, but it works here. Requires C++0x.

#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <algorithm>
#include <array>
using namespace std;

typedef array<pair<char, double>, 26> FreqArray;

class VigenereAnalyser 
{
private:
  array<double, 26> targets;
  array<double, 26> sortedTargets;
  FreqArray freq;

  // Update the freqs array
  FreqArray& frequency(const string& input) 
  {
    for (char c = 'A'; c <= 'Z'; ++c)
      freq[c - 'A'] = make_pair(c, 0);

    for (size_t i = 0; i < input.size(); ++i)
      freq[input[i] - 'A'].second++;

    return freq;
  }

  double correlation(const string& input) 
  {
    double result = 0.0;
    frequency(input);

    sort(freq.begin(), freq.end(), [](pair<char, double> u, pair<char, double> v)->bool
      { return u.second < v.second; });

    for (size_t i = 0; i < 26; ++i)
      result += freq[i].second * sortedTargets[i];

    return result;
  }

public:
  VigenereAnalyser(const array<double, 26>& targetFreqs) 
  {
    targets = targetFreqs;
    sortedTargets = targets;
    sort(sortedTargets.begin(), sortedTargets.end());
  }

  pair<string, string> analyze(string input) 
  {
    string cleaned;
    for (size_t i = 0; i < input.size(); ++i) 
    {
      if (input[i] >= 'A' && input[i] <= 'Z')
        cleaned += input[i];
      else if (input[i] >= 'a' && input[i] <= 'z')
        cleaned += input[i] + 'A' - 'a';
    }

    size_t bestLength = 0;
    double bestCorr = -100.0;

    // Assume that if there are less than 20 characters
    // per column, the key's too long to guess
    for (size_t i = 2; i < cleaned.size() / 20; ++i) 
    {
      vector<string> pieces(i);
      for (size_t j = 0; j < cleaned.size(); ++j)
        pieces[j % i] += cleaned[j];

      // The correlation increases artificially for smaller
      // pieces/longer keys, so weigh against them a little
      double corr = -0.5*i;
      for (size_t j = 0; j < i; ++j)
        corr += correlation(pieces[j]);

      if (corr > bestCorr) 
      {
        bestLength = i;
        bestCorr = corr;
      }
    }

    if (bestLength == 0)
      return make_pair("Text is too short to analyze", "");

    vector<string> pieces(bestLength);
    for (size_t i = 0; i < cleaned.size(); ++i)
      pieces[i % bestLength] += cleaned[i];

    vector<FreqArray> freqs;
    for (size_t i = 0; i < bestLength; ++i)
      freqs.push_back(frequency(pieces[i]));

    string key = "";
    for (size_t i = 0; i < bestLength; ++i) 
    {
      sort(freqs[i].begin(), freqs[i].end(), [](pair<char, double> u, pair<char, double> v)->bool
        { return u.second > v.second; });

      size_t m = 0;
      double mCorr = 0.0;
      for (size_t j = 0; j < 26; ++j) 
      {
        double corr = 0.0;
        char c = 'A' + j;
        for (size_t k = 0; k < 26; ++k) 
        {
          int d = (freqs[i][k].first - c + 26) % 26;
          corr += freqs[i][k].second * targets[d];
        }

        if (corr > mCorr) 
        {
          m = j;
          mCorr = corr;
        }
      }

      key += m + 'A';
    }

    string result = "";
    for (size_t i = 0; i < cleaned.size(); ++i)
      result += (cleaned[i] - key[i % key.length()] + 26) % 26 + 'A';

    return make_pair(result, key);
  }
};

int main() 
{
  string input =
    "MOMUD EKAPV TQEFM OEVHP AJMII CDCTI FGYAG JSPXY ALUYM NSMYH"
    "VUXJE LEPXJ FXGCM JHKDZ RYICU HYPUS PGIGM OIYHF WHTCQ KMLRD"
    "ITLXZ LJFVQ GHOLW CUHLO MDSOE KTALU VYLNZ RFGBX PHVGA LWQIS"
    "FGRPH JOOFW GUBYI LAPLA LCAFA AMKLG CETDW VOELJ IKGJB XPHVG"
    "ALWQC SNWBU BYHCU HKOCE XJEYK BQKVY KIIEH GRLGH XEOLW AWFOJ"
    "ILOVV RHPKD WIHKN ATUHN VRYAQ DIVHX FHRZV QWMWV LGSHN NLVZS"
    "JLAKI FHXUF XJLXM TBLQV RXXHR FZXGV LRAJI EXPRV OSMNP KEPDT"
    "LPRWM JAZPK LQUZA ALGZX GVLKL GJTUI ITDSU REZXJ ERXZS HMPST"
    "MTEOE PAPJH SMFNB YVQUZ AALGA YDNMP AQOWT UHDBV TSMUE UIMVH"
    "QGVRW AEFSP EMPVE PKXZY WLKJA GWALT VYYOB YIXOK IHPDS EVLEV"
    "RVSGB JOGYW FHKBL GLXYA MVKIS KIEHY IMAPX UOISK PVAGN MZHPW"
    "TTZPV XFCCD TUHJH WLAPF YULTB UXJLN SIJVV YOVDJ SOLXG TGRVO"
    "SFRII CTMKO JFCQF KTINQ BWVHG TENLH HOGCS PSFPV GJOKM SIFPR"
    "ZPAAS ATPTZ FTPPD PORRF TAXZP KALQA WMIUD BWNCT LEFKO ZQDLX"
    "BUXJL ASIMR PNMBF ZCYLV WAPVF QRHZV ZGZEF KBYIO OFXYE VOWGB"
    "BXVCB XBAWG LQKCM ICRRX MACUO IKHQU AJEGL OIJHH XPVZW JEWBA"
    "FWAML ZZRXJ EKAHV FASMU LVVUT TGK";

  array<double, 26> english = {
    0.08167, 0.01492, 0.02782, 0.04253, 0.12702, 0.02228,
    0.02015, 0.06094, 0.06966, 0.00153, 0.00772, 0.04025,
    0.02406, 0.06749, 0.07507, 0.01929, 0.00095, 0.05987,
    0.06327, 0.09056, 0.02758, 0.00978, 0.02360, 0.00150,
    0.01974, 0.00074};

  VigenereAnalyser va(english);
  pair<string, string> output = va.analyze(input);

  cout << "Key: " << output.second << endl << endl;
  cout << "Text: " << output.first << endl;
}

D

Translation of: C++
import std.stdio, std.algorithm, std.typecons, std.string,
       std.array, std.numeric, std.ascii;

string[2] vigenereDecrypt(in double[] targetFreqs, in string input) {
    enum nAlpha = std.ascii.uppercase.length;

    static double correlation(in string txt, in double[] sTargets)
    pure nothrow /*@safe*/ @nogc {
        uint[nAlpha] charCounts = 0;
        foreach (immutable c; txt)
            charCounts[c - 'A']++;
        return charCounts[].sort().release.dotProduct(sTargets);
    }

    static frequency(in string txt) pure nothrow @safe {
        auto freqs = new Tuple!(char,"c", uint,"d")[nAlpha];
        foreach (immutable i, immutable c; std.ascii.uppercase)
            freqs[i] = tuple(c, 0);
        foreach (immutable c; txt)
            freqs[c - 'A'].d++;
        return freqs;
    }

    static string[2] decode(in string cleaned, in string key)
    pure nothrow @safe {
        assert(!key.empty);
        string decoded;
        foreach (immutable i, immutable c; cleaned)
            decoded ~= (c - key[i % $] + nAlpha) % nAlpha + 'A';
        return [key, decoded];
    }

    static size_t findBestLength(in string cleaned,
                                 in double[] sTargets)
    pure nothrow /*@safe*/ {
        size_t bestLength;
        double bestCorr = -100.0;

        // Assume that if there are less than 20 characters
        // per column, the key's too long to guess
        foreach (immutable i; 2 .. cleaned.length / 20) {
            auto pieces = new Appender!string[i];
            foreach (immutable j, immutable c; cleaned)
                pieces[j % i] ~= c;

            // The correlation seems to increase for smaller
            // pieces/longer keys, so weigh against them a little
            double corr = -0.5 * i;
            foreach (const p; pieces)
                corr += correlation(p.data, sTargets);

            if (corr > bestCorr) {
                bestLength = i;
                bestCorr = corr;
            }
        }

        return bestLength;
    }

    static string findKey(in string cleaned, in size_t bestLength,
                          in double[] targetFreqs) pure nothrow @safe {
        auto pieces = new string[bestLength];
        foreach (immutable i, immutable c; cleaned)
            pieces[i % bestLength] ~= c;

        string key;
        foreach (fr; pieces.map!frequency) {
            fr.sort!q{ a.d > b.d };

            size_t m;
            double maxCorr = 0.0;
            foreach (immutable j, immutable c; uppercase) {
                double corr = 0.0;
                foreach (immutable frc; fr) {
                    immutable di = (frc.c - c + nAlpha) % nAlpha;
                    corr += frc.d * targetFreqs[di];
                }

                if (corr > maxCorr) {
                    m = j;
                    maxCorr = corr;
                }
            }

            key ~= m + 'A';
        }

        return key;
    }

    immutable cleaned = input.toUpper.removechars("^A-Z");

    //immutable sortedTargets = targetFreqs.sorted;
    immutable sortedTargets = targetFreqs.dup.sort().release.idup;

    immutable bestLength = findBestLength(cleaned, sortedTargets);
    if (bestLength == 0)
        throw new Exception("Text is too short to analyze.");

    immutable string key = findKey(cleaned, bestLength, targetFreqs);
    return decode(cleaned, key);
}


void main() {
    immutable encoded = "MOMUD EKAPV TQEFM OEVHP AJMII CDCTI FGYAG
JSPXY ALUYM NSMYH VUXJE LEPXJ FXGCM JHKDZ RYICU HYPUS PGIGM OIYHF
WHTCQ KMLRD ITLXZ LJFVQ GHOLW CUHLO MDSOE KTALU VYLNZ RFGBX PHVGA
LWQIS FGRPH JOOFW GUBYI LAPLA LCAFA AMKLG CETDW VOELJ IKGJB XPHVG
ALWQC SNWBU BYHCU HKOCE XJEYK BQKVY KIIEH GRLGH XEOLW AWFOJ ILOVV
RHPKD WIHKN ATUHN VRYAQ DIVHX FHRZV QWMWV LGSHN NLVZS JLAKI FHXUF
XJLXM TBLQV RXXHR FZXGV LRAJI EXPRV OSMNP KEPDT LPRWM JAZPK LQUZA
ALGZX GVLKL GJTUI ITDSU REZXJ ERXZS HMPST MTEOE PAPJH SMFNB YVQUZ
AALGA YDNMP AQOWT UHDBV TSMUE UIMVH QGVRW AEFSP EMPVE PKXZY WLKJA
GWALT VYYOB YIXOK IHPDS EVLEV RVSGB JOGYW FHKBL GLXYA MVKIS KIEHY
IMAPX UOISK PVAGN MZHPW TTZPV XFCCD TUHJH WLAPF YULTB UXJLN SIJVV
YOVDJ SOLXG TGRVO SFRII CTMKO JFCQF KTINQ BWVHG TENLH HOGCS PSFPV
GJOKM SIFPR ZPAAS ATPTZ FTPPD PORRF TAXZP KALQA WMIUD BWNCT LEFKO
ZQDLX BUXJL ASIMR PNMBF ZCYLV WAPVF QRHZV ZGZEF KBYIO OFXYE VOWGB
BXVCB XBAWG LQKCM ICRRX MACUO IKHQU AJEGL OIJHH XPVZW JEWBA FWAML
ZZRXJ EKAHV FASMU LVVUT TGK";

    immutable englishFrequences = [0.08167, 0.01492, 0.02782, 0.04253,
        0.12702, 0.02228, 0.02015, 0.06094, 0.06966, 0.00153, 0.00772,
        0.04025, 0.02406, 0.06749, 0.07507, 0.01929, 0.00095, 0.05987,
        0.06327, 0.09056, 0.02758, 0.00978, 0.02360, 0.00150, 0.01974,
        0.00074];

    immutable key_dec = vigenereDecrypt(englishFrequences, encoded);
    writefln("Key: %s\n\nText: %s", key_dec[0], key_dec[1]);
}
Output (cut):
Key: THECHESHIRECAT

Text: THISWASTHEPOEMTHATALICEREADJABBERWOCKYTWASBRILLIGANDTHESLITHY...

Go

Translation of: Kotlin
package main

import (
    "fmt"
    "strings"
)

var encoded = 
    "MOMUD EKAPV TQEFM OEVHP AJMII CDCTI FGYAG JSPXY ALUYM NSMYH" +
    "VUXJE LEPXJ FXGCM JHKDZ RYICU HYPUS PGIGM OIYHF WHTCQ KMLRD" +
    "ITLXZ LJFVQ GHOLW CUHLO MDSOE KTALU VYLNZ RFGBX PHVGA LWQIS" +
    "FGRPH JOOFW GUBYI LAPLA LCAFA AMKLG CETDW VOELJ IKGJB XPHVG" +
    "ALWQC SNWBU BYHCU HKOCE XJEYK BQKVY KIIEH GRLGH XEOLW AWFOJ" +
    "ILOVV RHPKD WIHKN ATUHN VRYAQ DIVHX FHRZV QWMWV LGSHN NLVZS" +
    "JLAKI FHXUF XJLXM TBLQV RXXHR FZXGV LRAJI EXPRV OSMNP KEPDT" +
    "LPRWM JAZPK LQUZA ALGZX GVLKL GJTUI ITDSU REZXJ ERXZS HMPST" +
    "MTEOE PAPJH SMFNB YVQUZ AALGA YDNMP AQOWT UHDBV TSMUE UIMVH" +
    "QGVRW AEFSP EMPVE PKXZY WLKJA GWALT VYYOB YIXOK IHPDS EVLEV" +
    "RVSGB JOGYW FHKBL GLXYA MVKIS KIEHY IMAPX UOISK PVAGN MZHPW" +
    "TTZPV XFCCD TUHJH WLAPF YULTB UXJLN SIJVV YOVDJ SOLXG TGRVO" +
    "SFRII CTMKO JFCQF KTINQ BWVHG TENLH HOGCS PSFPV GJOKM SIFPR" +
    "ZPAAS ATPTZ FTPPD PORRF TAXZP KALQA WMIUD BWNCT LEFKO ZQDLX" +
    "BUXJL ASIMR PNMBF ZCYLV WAPVF QRHZV ZGZEF KBYIO OFXYE VOWGB" +
    "BXVCB XBAWG LQKCM ICRRX MACUO IKHQU AJEGL OIJHH XPVZW JEWBA" +
    "FWAML ZZRXJ EKAHV FASMU LVVUT TGK"

var freq = [26]float64{
    0.08167, 0.01492, 0.02782, 0.04253, 0.12702, 0.02228, 0.02015,
    0.06094, 0.06966, 0.00153, 0.00772, 0.04025, 0.02406, 0.06749,
    0.07507, 0.01929, 0.00095, 0.05987, 0.06327, 0.09056, 0.02758,
    0.00978, 0.02360, 0.00150, 0.01974, 0.00074,
}

func sum(a []float64) (sum float64) {
    for _, f := range a {
        sum += f
    }
    return
}

func bestMatch(a []float64) int {
    sum := sum(a)
    bestFit, bestRotate := 1e100, 0
    for rotate := 0; rotate < 26; rotate++ {
        fit := 0.0
        for i := 0; i < 26; i++ {
            d := a[(i+rotate)%26]/sum - freq[i]
            fit += d * d / freq[i]
        }
        if fit < bestFit {
            bestFit, bestRotate = fit, rotate
        }
    }
    return bestRotate
}

func freqEveryNth(msg []int, key []byte) float64 {
    l := len(msg)
    interval := len(key)
    out := make([]float64, 26)
    accu := make([]float64, 26)
    for j := 0; j < interval; j++ {
        for k := 0; k < 26; k++ {
            out[k] = 0.0
        }
        for i := j; i < l; i += interval {
            out[msg[i]]++
        }
        rot := bestMatch(out)
        key[j] = byte(rot + 65)
        for i := 0; i < 26; i++ {
            accu[i] += out[(i+rot)%26]
        }
    }
    sum := sum(accu)
    ret := 0.0
    for i := 0; i < 26; i++ {
        d := accu[i]/sum - freq[i]
        ret += d * d / freq[i]
    }
    return ret
}

func decrypt(text, key string) string {
    var sb strings.Builder
    ki := 0
    for _, c := range text {
        if c < 'A' || c > 'Z' {
            continue
        }
        ci := (c - rune(key[ki]) + 26) % 26
        sb.WriteRune(ci + 65)
        ki = (ki + 1) % len(key)
    }
    return sb.String()
}

func main() {
    enc := strings.Replace(encoded, " ", "", -1)
    txt := make([]int, len(enc))
    for i := 0; i < len(txt); i++ {
        txt[i] = int(enc[i] - 'A')
    }
    bestFit, bestKey := 1e100, ""
    fmt.Println("  Fit     Length   Key")
    for j := 1; j <= 26; j++ {
        key := make([]byte, j)
        fit := freqEveryNth(txt, key)
        sKey := string(key)
        fmt.Printf("%f    %2d     %s", fit, j, sKey)
        if fit < bestFit {
            bestFit, bestKey = fit, sKey
            fmt.Print(" <--- best so far")
        }
        fmt.Println()
    }
    fmt.Println("\nBest key :", bestKey)
    fmt.Printf("\nDecrypted text:\n%s\n", decrypt(enc, bestKey))
}
Output:

Note: carriage returns inserted into decrypted text after every 80 characters to make it more readable.

  Fit     Length   Key
2.984348     1     E <--- best so far
2.483684     2     EC <--- best so far
2.642487     3     TEE
1.976651     4     THEC <--- best so far
2.356881     5     EEEPU
2.203129     6     TCECEC
1.051163     7     THECSAS <--- best so far
1.645763     8     TJQGAHET
2.001380     9     VEIZSEGNT
1.824476    10     ECEGAWQTDS
1.623083    11     TNLUSRXPTAJ
1.253527    12     XLECTHQGTHEC
1.399037    13     LJJTDGFNOTENR
0.152370    14     THECHESHIRECAT <--- best so far
1.533951    15     JNTOOEEXFTGQTNH
1.068182    16     TJTSAEETEXHPXHNE
1.034093    17     AZRAXUHEJLREEXIEE
1.443345    18     VNIZQPALEPTSXSEXUC
1.090977    19     FUCAITCSLVTEZDUDEHS
0.979868    20     EQXGAHWTTQECEWUGXHPI
0.789410    21     HVRCSAFTHEBDLSTAERSES
0.881380    22     TVIJTCIGKAQPELECRXPTNC
0.952456    23     KKEQXGPWTCQEELIEHXUWASV
0.715968    24     ELAIXHQTTIEDXJETTNTGAEPC
0.891258    25     OTJUUEGERDNQTUQEAGWUTIEOA
0.852784    26     IGITEGECAGAVUNLJAHASAVTETW

Best key : THECHESHIRECAT

Decrypted text:
THISWASTHEPOEMTHATALICEREADJABBERWOCKYTWASBRILLIGANDTHESLITHYTOVESDIDGYREANDGIMB
LEINTHEWABEALLMIMSYWERETHEBOROGOVESANDTHEMOMERATHSOUTGRABEBEWARETHEJABBERWOCKMYS
ONTHEJAWSTHATBITETHECLAWSTHATCATCHBEWARETHEJUBJUBBIRDANDSHUNTHEFRUMIOUSBANDERSNA
TCHHETOOKHISVORPALSWORDINHANDLONGTIMETHEMANXOMEFOEHESOUGHTSORESTEDHEBYTHETUMTUMT
REEANDSTOODAWHILEINTHOUGHTANDASINUFFISHTHOUGHTHESTOODTHEJABBERWOCKWITHEYESOFFLAM
ECAMEWHIFFLINGTHROUGHTHETULGEYWOODANDBURBLEDASITCAMEONETWOONETWOANDTHROUGHANDTHR
OUGHTHEVORPALBLADEWENTSNICKERSNACKHELEFTITDEADANDWITHITSHEADHEWENTGALUMPHINGBACK
ANDHASTTHOUSLAINTHEJABBERWOCKCOMETOMYARMSMYBEAMISHBOYOFRABJOUSDAYCALLOOHCALLAYHE
CHORTLEDINHISJOYTWASBRILLIGANDTHESLITHYTOVESDIDGYREANDGIMBLEINTHEWABEALLMIMSYWER
ETHEBOROGOVESANDTHEMOMERATHSOUTGRABEITSEEMSVERYPRETTYSHESAIDWHENSHEHADFINISHEDIT
BUTITSRATHERHARDTOUNDERSTAND

Haskell

{-# LANGUAGE TupleSections #-}
import Data.List(transpose, nub, sort, maximumBy)
import Data.Ord (comparing)
import Data.Char (ord)
import Data.Map (Map, fromListWith, toList, findWithDefault)

average :: Fractional a => [a] -> a
average as = sum as / fromIntegral (length as)

-- Create a map from each entry in list to the number of occurrences of
-- that entry in the list.
countEntries :: Ord a => [a] -> Map a Int
countEntries = fromListWith (+) . fmap (,1)

-- Break a string up into substrings of n chars.
breakup :: Int -> [a] -> [[a]]
breakup _ [] = []
breakup n as = 
    let (h, r) = splitAt n as
    in h:breakup n r

-- Dole out elements of a string over a n element distribution.
distribute :: [a] -> Int -> [[a]]
distribute as n = transpose $ breakup n as

-- The probability that members of a pair of characters taken randomly
-- from a given string are equal.
coincidence :: (Ord a, Fractional b) => [a] -> b
coincidence str = 
    let charCounts = snd <$> toList (countEntries str)
        strln = length str
        d = fromIntegral $ strln * (strln - 1)
        n = fromIntegral $ sum $ fmap (\cc -> cc * (cc-1)) charCounts
    in n / d

-- Use the average probablity of coincidence for all the members of
-- a distribution to rate the distribution - the higher the better.
-- The correlation increases artificially for smaller
-- pieces/longer keys, so weigh against them a little
rate :: (Ord a, Fractional b) => [[a]] -> b
rate d =  average (fmap coincidence d) - fromIntegral (length d) / 3000.0 

-- Multiply elements of lists together and add up the results.
dot :: Num a => [a] -> [a] -> a
dot v0 v1 = sum $ zipWith (*) v0 v1

-- Given two lists of floats, rotate one of them by the number of
-- characters indicated by letter and then 'dot' them together.
rotateAndDot :: Num a => [a] -> [a] -> Char -> a
rotateAndDot v0 v1 letter = dot v0 (drop (ord letter - ord 'A') (cycle v1))  

-- Find decoding offset that results in best match 
-- between actual char frequencies and expected frequencies.
getKeyChar :: RealFrac a => [a] -> String -> Char
getKeyChar expected sample =
    let charCounts = countEntries sample
        countInSample c = findWithDefault 0 c charCounts
        actual = fmap (fromIntegral . countInSample) ['A'..'Z']
    in maximumBy (comparing $ rotateAndDot expected actual) ['A'..'Z']

main = do
    let cr = filter (/=' ') crypt
        -- Assume that if there are less than 20 characters
        -- per column, the key's too long to guess
        distributions = fmap (distribute cr) [1..length cr `div` 20]
        bestDistribution = maximumBy (comparing rate) distributions
        key = fmap (getKeyChar englishFrequencies) bestDistribution
        alphaSum a b = ['A'..'Z'] !! ((ord b - ord a) `mod` 26)
    mapM_ putStrLn ["Key: " ++ key, "Decrypted Text: " ++ zipWith alphaSum (cycle key) cr]

englishFrequencies = 
    [ 0.08167, 0.01492, 0.02782, 0.04253, 
      0.12702, 0.02228, 0.02015, 0.06094, 
      0.06966, 0.00153, 0.00772, 0.04025, 
      0.02406, 0.06749, 0.07507, 0.01929, 
      0.00095, 0.05987, 0.06327, 0.09056, 
      0.02758, 0.00978, 0.02360, 0.00150, 
      0.01974, 0.00074 ] 

crypt = "\
    \MOMUD EKAPV TQEFM OEVHP AJMII CDCTI FGYAG JSPXY ALUYM NSMYH\
    \VUXJE LEPXJ FXGCM JHKDZ RYICU HYPUS PGIGM OIYHF WHTCQ KMLRD\
    \ITLXZ LJFVQ GHOLW CUHLO MDSOE KTALU VYLNZ RFGBX PHVGA LWQIS\
    \FGRPH JOOFW GUBYI LAPLA LCAFA AMKLG CETDW VOELJ IKGJB XPHVG\
    \ALWQC SNWBU BYHCU HKOCE XJEYK BQKVY KIIEH GRLGH XEOLW AWFOJ\
    \ILOVV RHPKD WIHKN ATUHN VRYAQ DIVHX FHRZV QWMWV LGSHN NLVZS\
    \JLAKI FHXUF XJLXM TBLQV RXXHR FZXGV LRAJI EXPRV OSMNP KEPDT\
    \LPRWM JAZPK LQUZA ALGZX GVLKL GJTUI ITDSU REZXJ ERXZS HMPST\
    \MTEOE PAPJH SMFNB YVQUZ AALGA YDNMP AQOWT UHDBV TSMUE UIMVH\
    \QGVRW AEFSP EMPVE PKXZY WLKJA GWALT VYYOB YIXOK IHPDS EVLEV\
    \RVSGB JOGYW FHKBL GLXYA MVKIS KIEHY IMAPX UOISK PVAGN MZHPW\
    \TTZPV XFCCD TUHJH WLAPF YULTB UXJLN SIJVV YOVDJ SOLXG TGRVO\
    \SFRII CTMKO JFCQF KTINQ BWVHG TENLH HOGCS PSFPV GJOKM SIFPR\
    \ZPAAS ATPTZ FTPPD PORRF TAXZP KALQA WMIUD BWNCT LEFKO ZQDLX\
    \BUXJL ASIMR PNMBF ZCYLV WAPVF QRHZV ZGZEF KBYIO OFXYE VOWGB\
    \BXVCB XBAWG LQKCM ICRRX MACUO IKHQU AJEGL OIJHH XPVZW JEWBA\
    \FWAML ZZRXJ EKAHV FASMU LVVUT TGK\
    \"
Output:
Key: THECHESHIRECAT
Decrypted Text: THISWASTHEPOEMTHATALICEREADJABBERWOCKYTWASBRILLIGANDTHESLITHYTOVESDIDGYREANDGIMBLEINTHEWABEALLMIMSYWERETHEBOROGOVESANDTHEMOMERATHSOUTGRABEBEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCHBEWARETHEJUBJUBBIRDANDSHUNTHEFRUMIOUSBANDERSNATCHHETOOKHISVORPALSWORDINHANDLONGTIMETHEMANXOMEFOEHESOUGHTSORESTEDHEBYTHETUMTUMTREEANDSTOODAWHILEINTHOUGHTANDASINUFFISHTHOUGHTHESTOODTHEJABBERWOCKWITHEYESOFFLAMECAMEWHIFFLINGTHROUGHTHETULGEYWOODANDBURBLEDASITCAMEONETWOONETWOANDTHROUGHANDTHROUGHTHEVORPALBLADEWENTSNICKERSNACKHELEFTITDEADANDWITHITSHEADHEWENTGALUMPHINGBACKANDHASTTHOUSLAINTHEJABBERWOCKCOMETOMYARMSMYBEAMISHBOYOFRABJOUSDAYCALLOOHCALLAYHECHORTLEDINHISJOYTWASBRILLIGANDTHESLITHYTOVESDIDGYREANDGIMBLEINTHEWABEALLMIMSYWERETHEBOROGOVESANDTHEMOMERATHSOUTGRABEITSEEMSVERYPRETTYSHESAIDWHENSHEHADFINISHEDITBUTITSRATHERHARDTOUNDERSTAND

J

Implementation:

NB. https://en.wikipedia.org/wiki/Kasiski_examination
kasiski=: {{ 
  grams=. ({: #"1~1 < ;@{.)|:(#/.~;"0~.) g=. 3 <\ y
  deltas=. ;grams (2 -~/\ I.@E.)L:0 enc
  {:,{.\:~(#/.~,.~.)1 -.~,+./~ deltas
}}

NB. https://en.wikipedia.org/wiki/Letter_frequency
AZ=: 8 u: 65+i.26
lfreq=: 0.01*do{{)n
 8.2 1.5 2.8 4.3 13 2.2 2 6.1 7 0.15
 0.77 4 2.4 6.7 7.5 1.9 0.095 6 6.3 9.1
 2.8 0.98 2.4 0.15 2 0.074
}}-.LF


caesarkey=: {{
  freqs=. (<:#/.~AZ,y)%#y=. y ([-.-.) AZ
  AZ{~(i. <./)lfreq +/&.:*:@:-"1 (i.26)|."0 1 freqs
}}
vigenerekey=: {{ caesarkey"1|:(-kasiski y) ]\y }}

uncaesar=: {{ 26&|@-&(AZ i.x)&.(AZ&i.) y }}"0 1
unvigenere=: {{ ' '-.~,x uncaesar"0 1&.|:(-#x) ]\y }}

Here, kasiski finds all 3-grams (sequences of three adjacent letters) which appear more than once, finds all of the distances between nearest pairs of these sequences, and then further pairs each of these distances with all other distances, finding the greatest common divisor of those distance pairs. Finally, these LCDs are ordered by how many times they appear and the most frequent LCD is taken as the kasiski result.

uncaesar works by finding the frequency of occurrence of each letter of the alphabet (in alphabetical order), and then each of the 26 rotations of that sequence are compared with a text frequency alphabet (obtained from a wikipedia table). The rotation with the least root-mean-square sum of differences is chosen as the correct location, and its index is reported as a letter of the alphabet (0=A, 1=B, etc.)

(And, the length provided by kasiski is used to break out the sequences to be analyzed by uncaesar...)

Task example:

enc=: {{)n
MOMUD EKAPV TQEFM OEVHP AJMII CDCTI FGYAG JSPXY ALUYM NSMYH
VUXJE LEPXJ FXGCM JHKDZ RYICU HYPUS PGIGM OIYHF WHTCQ KMLRD
ITLXZ LJFVQ GHOLW CUHLO MDSOE KTALU VYLNZ RFGBX PHVGA LWQIS
FGRPH JOOFW GUBYI LAPLA LCAFA AMKLG CETDW VOELJ IKGJB XPHVG
ALWQC SNWBU BYHCU HKOCE XJEYK BQKVY KIIEH GRLGH XEOLW AWFOJ
ILOVV RHPKD WIHKN ATUHN VRYAQ DIVHX FHRZV QWMWV LGSHN NLVZS
JLAKI FHXUF XJLXM TBLQV RXXHR FZXGV LRAJI EXPRV OSMNP KEPDT
LPRWM JAZPK LQUZA ALGZX GVLKL GJTUI ITDSU REZXJ ERXZS HMPST
MTEOE PAPJH SMFNB YVQUZ AALGA YDNMP AQOWT UHDBV TSMUE UIMVH
QGVRW AEFSP EMPVE PKXZY WLKJA GWALT VYYOB YIXOK IHPDS EVLEV
RVSGB JOGYW FHKBL GLXYA MVKIS KIEHY IMAPX UOISK PVAGN MZHPW
TTZPV XFCCD TUHJH WLAPF YULTB UXJLN SIJVV YOVDJ SOLXG TGRVO
SFRII CTMKO JFCQF KTINQ BWVHG TENLH HOGCS PSFPV GJOKM SIFPR
ZPAAS ATPTZ FTPPD PORRF TAXZP KALQA WMIUD BWNCT LEFKO ZQDLX
BUXJL ASIMR PNMBF ZCYLV WAPVF QRHZV ZGZEF KBYIO OFXYE VOWGB
BXVCB XBAWG LQKCM ICRRX MACUO IKHQU AJEGL OIJHH XPVZW JEWBA
FWAML ZZRXJ EKAHV FASMU LVVUT TGK
}}-.LF,' '

   vigenerekey enc
THECHESHIRECAT
   _80]\'THECHESHIRECAT' unvigenere enc
THISWASTHEPOEMTHATALICEREADJABBERWOCKYTWASBRILLIGANDTHESLITHYTOVESDIDGYREANDGIMB
LEINTHEWABEALLMIMSYWERETHEBOROGOVESANDTHEMOMERATHSOUTGRABEBEWARETHEJABBERWOCKMYS
ONTHEJAWSTHATBITETHECLAWSTHATCATCHBEWARETHEJUBJUBBIRDANDSHUNTHEFRUMIOUSBANDERSNA
TCHHETOOKHISVORPALSWORDINHANDLONGTIMETHEMANXOMEFOEHESOUGHTSORESTEDHEBYTHETUMTUMT
REEANDSTOODAWHILEINTHOUGHTANDASINUFFISHTHOUGHTHESTOODTHEJABBERWOCKWITHEYESOFFLAM
ECAMEWHIFFLINGTHROUGHTHETULGEYWOODANDBURBLEDASITCAMEONETWOONETWOANDTHROUGHANDTHR
OUGHTHEVORPALBLADEWENTSNICKERSNACKHELEFTITDEADANDWITHITSHEADHEWENTGALUMPHINGBACK
ANDHASTTHOUSLAINTHEJABBERWOCKCOMETOMYARMSMYBEAMISHBOYOFRABJOUSDAYCALLOOHCALLAYHE
CHORTLEDINHISJOYTWASBRILLIGANDTHESLITHYTOVESDIDGYREANDGIMBLEINTHEWABEALLMIMSYWER
ETHEBOROGOVESANDTHEMOMERATHSOUTGRABEITSEEMSVERYPRETTYSHESAIDWHENSHEHADFINISHEDIT
BUTITSRATHERHARDTOUNDERSTANDWYTWITSJWYAH

As an aside, note that we could go directly from encrypted text to decrypted text, without showing the key. For example, using:

decaesar=: {{
  freqs=. (<:#/.~AZ,y)%#y=. y ([-.-.) AZ
  ndx=. (i. <./)lfreq +/&.:*:@:-"1 (i.26)|."0 1 freqs
  26&|@-&ndx&.(AZ&i.) y
}}
devigenere=: {{ ' '-.~,decaesar"1&.|:(-kasiski y) ]\y }}

That said, it's also worth noting that noise issues mean that if this were to be used in practical contexts the approach should instead be to expose more intermediate results, rather than less, with a special focus on the representations of frequency distributions (here, we're always picking the first alternative, but it's vaguely plausible that a different alternative might actually be useful in some cases).

Java

Translation of: C
public class Vig{
static String encodedMessage =
    "MOMUD EKAPV TQEFM OEVHP AJMII CDCTI FGYAG JSPXY ALUYM NSMYH VUXJE LEPXJ FXGCM JHKDZ RYICU HYPUS PGIGM OIYHF WHTCQ KMLRD ITLXZ LJFVQ GHOLW CUHLO MDSOE KTALU VYLNZ RFGBX PHVGA LWQIS FGRPH JOOFW GUBYI LAPLA LCAFA AMKLG CETDW VOELJ IKGJB XPHVG ALWQC SNWBU BYHCU HKOCE XJEYK BQKVY KIIEH GRLGH XEOLW AWFOJ ILOVV RHPKD WIHKN ATUHN VRYAQ DIVHX FHRZV QWMWV LGSHN NLVZS JLAKI FHXUF XJLXM TBLQV RXXHR FZXGV LRAJI EXPRV OSMNP KEPDT LPRWM JAZPK LQUZA ALGZX GVLKL GJTUI ITDSU REZXJ ERXZS HMPST MTEOE PAPJH SMFNB YVQUZ AALGA YDNMP AQOWT UHDBV TSMUE UIMVH QGVRW AEFSP EMPVE PKXZY WLKJA GWALT VYYOB YIXOK IHPDS EVLEV RVSGB JOGYW FHKBL GLXYA MVKIS KIEHY IMAPX UOISK PVAGN MZHPW TTZPV XFCCD TUHJH WLAPF YULTB UXJLN SIJVV YOVDJ SOLXG TGRVO SFRII CTMKO JFCQF KTINQ BWVHG TENLH HOGCS PSFPV GJOKM SIFPR ZPAAS ATPTZ FTPPD PORRF TAXZP KALQA WMIUD BWNCT LEFKO ZQDLX BUXJL ASIMR PNMBF ZCYLV WAPVF QRHZV ZGZEF KBYIO OFXYE VOWGB BXVCB XBAWG LQKCM ICRRX MACUO IKHQU AJEGL OIJHH XPVZW JEWBA FWAML ZZRXJ EKAHV FASMU LVVUT TGK";
 
final static double freq[] = {
    0.08167, 0.01492, 0.02782, 0.04253, 0.12702, 0.02228, 0.02015,
    0.06094, 0.06966, 0.00153, 0.00772, 0.04025, 0.02406, 0.06749,
    0.07507, 0.01929, 0.00095, 0.05987, 0.06327, 0.09056, 0.02758,
    0.00978, 0.02360, 0.00150, 0.01974, 0.00074
};
 

public static void main(String[] args) {
    int lenghtOfEncodedMessage = encodedMessage.length();
    char[] encoded = new char [lenghtOfEncodedMessage] ;
    char[] key =  new char [lenghtOfEncodedMessage] ;

    encodedMessage.getChars(0, lenghtOfEncodedMessage, encoded, 0);
    int txt[] = new int[lenghtOfEncodedMessage];
    int len = 0, j;

    double fit, best_fit = 1e100;
 
    for (j = 0; j < lenghtOfEncodedMessage; j++)
        if (Character.isUpperCase(encoded[j]))
            txt[len++] = encoded[j] - 'A';
 
    for (j = 1; j < 30; j++) {
        fit = freq_every_nth(txt, len, j, key);
        System.out.printf("%f, key length: %2d ", fit, j);
            System.out.print(key);
        if (fit < best_fit) {
            best_fit = fit;
            System.out.print(" <--- best so far");
        }
        System.out.print("\n");

    }
}


    static String decrypt(String text, final String key) {
        String res = "";
        text = text.toUpperCase();
        for (int i = 0, j = 0; i < text.length(); i++) {
            char c = text.charAt(i);
            if (c < 'A' || c > 'Z') continue;
            res += (char)((c - key.charAt(j) + 26) % 26 + 'A');
            j = ++j % key.length();
        }
        return res;
    }

static int best_match(final double []a, final double []b) {
    double sum = 0, fit, d, best_fit = 1e100;
    int i, rotate, best_rotate = 0;
    for (i = 0; i < 26; i++)
        sum += a[i];
    for (rotate = 0; rotate < 26; rotate++) {
        fit = 0;
        for (i = 0; i < 26; i++) {
            d = a[(i + rotate) % 26] / sum - b[i];
            fit += d * d / b[i];
        }
 
        if (fit < best_fit) {
            best_fit = fit;
            best_rotate = rotate;
        }
    }
 
    return best_rotate;
}
 
static double freq_every_nth(final int []msg, int len, int interval, char[] key) {
    double sum, d, ret;
    double  [] accu = new double [26];
    double  [] out = new double [26];
    int i, j, rot;
 
    for (j = 0; j < interval; j++) {
        for (i = 0; i < 26; i++)
            out[i] = 0;
        for (i = j; i < len; i += interval)
            out[msg[i]]++;
	rot = best_match(out, freq);
	try{
            key[j] = (char)(rot + 'A');
	} catch (Exception e) {
		System.out.print(e.getMessage());
	}
        for (i = 0; i < 26; i++)
            accu[i] += out[(i + rot) % 26];
    }
 
    for (i = 0, sum = 0; i < 26; i++)
        sum += accu[i];
 
    for (i = 0, ret = 0; i < 26; i++) {
        d = accu[i] / sum - freq[i];
        ret += d * d / freq[i];
    }
 
    key[interval] = '\0';
    return ret;
}
 
}

Julia

# ciphertext block {{{1
const ciphertext = filter(isalpha, """
MOMUD EKAPV TQEFM OEVHP AJMII CDCTI FGYAG JSPXY ALUYM NSMYH
VUXJE LEPXJ FXGCM JHKDZ RYICU HYPUS PGIGM OIYHF WHTCQ KMLRD
ITLXZ LJFVQ GHOLW CUHLO MDSOE KTALU VYLNZ RFGBX PHVGA LWQIS
FGRPH JOOFW GUBYI LAPLA LCAFA AMKLG CETDW VOELJ IKGJB XPHVG
ALWQC SNWBU BYHCU HKOCE XJEYK BQKVY KIIEH GRLGH XEOLW AWFOJ
ILOVV RHPKD WIHKN ATUHN VRYAQ DIVHX FHRZV QWMWV LGSHN NLVZS
JLAKI FHXUF XJLXM TBLQV RXXHR FZXGV LRAJI EXPRV OSMNP KEPDT
LPRWM JAZPK LQUZA ALGZX GVLKL GJTUI ITDSU REZXJ ERXZS HMPST
MTEOE PAPJH SMFNB YVQUZ AALGA YDNMP AQOWT UHDBV TSMUE UIMVH
QGVRW AEFSP EMPVE PKXZY WLKJA GWALT VYYOB YIXOK IHPDS EVLEV
RVSGB JOGYW FHKBL GLXYA MVKIS KIEHY IMAPX UOISK PVAGN MZHPW
TTZPV XFCCD TUHJH WLAPF YULTB UXJLN SIJVV YOVDJ SOLXG TGRVO
SFRII CTMKO JFCQF KTINQ BWVHG TENLH HOGCS PSFPV GJOKM SIFPR
ZPAAS ATPTZ FTPPD PORRF TAXZP KALQA WMIUD BWNCT LEFKO ZQDLX
BUXJL ASIMR PNMBF ZCYLV WAPVF QRHZV ZGZEF KBYIO OFXYE VOWGB
BXVCB XBAWG LQKCM ICRRX MACUO IKHQU AJEGL OIJHH XPVZW JEWBA
FWAML ZZRXJ EKAHV FASMU LVVUT TGK
""")
# }}}

# character frequencies {{{1
const letters = Dict{Char, Float32}(
    'E' => 12.702,
    'T' => 9.056,
    'A' => 8.167,
    'O' => 7.507,
    'I' => 6.966,
    'N' => 6.749,
    'S' => 6.327,
    'H' => 6.094,
    'R' => 5.987,
    'D' => 4.253,
    'L' => 4.025,
    'C' => 2.782,
    'U' => 2.758,
    'M' => 2.406,
    'W' => 2.361,
    'F' => 2.228,
    'G' => 2.015,
    'Y' => 1.974,
    'P' => 1.929,
    'B' => 1.492,
    'V' => 0.978,
    'K' => 0.772,
    'J' => 0.153,
    'X' => 0.150,
    'Q' => 0.095,
    'Z' => 0.074)
const digraphs = Dict{AbstractString, Float32}(
    "TH" => 15.2,
    "HE" => 12.8,
    "IN" => 9.4,
    "ER" => 9.4,
    "AN" => 8.2,
    "RE" => 6.8,
    "ND" => 6.3,
    "AT" => 5.9,
    "ON" => 5.7,
    "NT" => 5.6,
    "HA" => 5.6,
    "ES" => 5.6,
    "ST" => 5.5,
    "EN" => 5.5,
    "ED" => 5.3,
    "TO" => 5.2,
    "IT" => 5.0,
    "OU" => 5.0,
    "EA" => 4.7,
    "HI" => 4.6,
    "IS" => 4.6,
    "OR" => 4.3,
    "TI" => 3.4,
    "AS" => 3.3,
    "TE" => 2.7,
    "ET" => 1.9,
    "NG" => 1.8,
    "OF" => 1.6,
    "AL" => 0.9,
    "DE" => 0.9,
    "SE" => 0.8,
    "LE" => 0.8,
    "SA" => 0.6,
    "SI" => 0.5,
    "AR" => 0.4,
    "VE" => 0.4,
    "RA" => 0.4,
    "LD" => 0.2,
    "UR" => 0.2)
const trigraphs = Dict{AbstractString, Float32}(
    "THE" => 18.1,
    "AND" => 7.3,
    "ING" => 7.2,
    "ION" => 4.2,
    "ENT" => 4.2,
    "HER" => 3.6,
    "FOR" => 3.4,
    "THA" => 3.3,
    "NTH" => 3.3,
    "INT" => 3.2,
    "TIO" => 3.1,
    "ERE" => 3.1,
    "TER" => 3.0,
    "EST" => 2.8,
    "ERS" => 2.8,
    "HAT" => 2.6,
    "ATI" => 2.6,
    "ATE" => 2.5,
    "ALL" => 2.5,
    "VER" => 2.4,
    "HIS" => 2.4,
    "HES" => 2.4,
    "ETH" => 2.4,
    "OFT" => 2.2,
    "STH" => 2.1,
    "RES" => 2.1,
    "OTH" => 2.1,
    "ITH" => 2.1,
    "FTH" => 2.1,
    "ONT" => 2.0)
# 1}}}

function decrypt(enc::ASCIIString, key::ASCIIString)
    const enclen = length(enc)
    const keylen = length(key)

    if keylen < enclen
        key = (key^(div(enclen - keylen, keylen) + 2))[1:enclen]
    end

    msg = Array(Char, enclen)

    for i=1:enclen
        msg[i] = Char((Int(enc[i]) - Int(key[i]) + 26) % 26 + 65)
    end

    msg::Array{Char, 1}
end

function cryptanalyze(enc::ASCIIString; maxkeylen::Integer = 20)
    const enclen = length(enc)
    maxkey = ""
    maxdec = ""
    maxscore = 0.0

    for keylen=1:maxkeylen
        key = Array(Char, keylen)
        idx = filter(x -> x % keylen == 0, 1:enclen) - keylen + 1

        for i=1:keylen
            maxsubscore = 0.0

            for j='A':'Z'
                subscore = 0.0

                for k in decrypt(enc[idx], ascii(string(j)))
                    subscore += get(letters, k, 0.0)
                end

                if subscore > maxsubscore
                    maxsubscore = subscore
                    key[i] = j
                end
            end

            idx += 1
        end

        key = join(key)
        const dec = decrypt(enc, key)
        score = 0.0

        for i in dec
            score += get(letters, i, 0.0)
        end

        for i=1:enclen - 2
            const digraph = string(dec[i], dec[i + 1])
            const trigraph = string(dec[i], dec[i + 1], dec[i + 2])

            if haskey(digraphs, digraph)
                score += 2 * get(digraphs, digraph, 0.0)
            end

            if haskey(trigraphs, trigraph)
                score += 3 * get(trigraphs, trigraph, 0.0)
            end
        end

        if score > maxscore
            maxscore = score
            maxkey = key
            maxdec = dec
        end
    end
    
    (maxkey, join(maxdec))::Tuple{ASCIIString, ASCIIString}
end

key, dec = cryptanalyze(ciphertext)
println("key: ", key, "\n\n", dec)

# post-compilation profiling run
gc()
t = @elapsed cryptanalyze(ciphertext)
println("\nelapsed time: ", t, " seconds")
Output:
key: THECHESHIRECAT

THISWASTHEPOEMTHATALICEREADJABBERWOCKYTWASBRILLIGANDTHESLITHY...

elapsed time: 0.042894211 seconds

Kotlin

Translation of: C

This is a reasonably faithful translation of the C entry though I've restricted the key lengths examined to 26 to automatically produce the correct key and hence decrypted text. This is because the C entry examines key lengths up to 29 and a value of 28 gives a slightly better fit even though the key produced (THECHESCIRECATTHECHESHIRECAT) and resulting text don't make as much sense and so would be rejected if one were examining the candidate keys manually.

// version 1.1.3

val encoded = 
    "MOMUD EKAPV TQEFM OEVHP AJMII CDCTI FGYAG JSPXY ALUYM NSMYH" +
    "VUXJE LEPXJ FXGCM JHKDZ RYICU HYPUS PGIGM OIYHF WHTCQ KMLRD" +
    "ITLXZ LJFVQ GHOLW CUHLO MDSOE KTALU VYLNZ RFGBX PHVGA LWQIS" +
    "FGRPH JOOFW GUBYI LAPLA LCAFA AMKLG CETDW VOELJ IKGJB XPHVG" +
    "ALWQC SNWBU BYHCU HKOCE XJEYK BQKVY KIIEH GRLGH XEOLW AWFOJ" +
    "ILOVV RHPKD WIHKN ATUHN VRYAQ DIVHX FHRZV QWMWV LGSHN NLVZS" +
    "JLAKI FHXUF XJLXM TBLQV RXXHR FZXGV LRAJI EXPRV OSMNP KEPDT" +
    "LPRWM JAZPK LQUZA ALGZX GVLKL GJTUI ITDSU REZXJ ERXZS HMPST" +
    "MTEOE PAPJH SMFNB YVQUZ AALGA YDNMP AQOWT UHDBV TSMUE UIMVH" +
    "QGVRW AEFSP EMPVE PKXZY WLKJA GWALT VYYOB YIXOK IHPDS EVLEV" +
    "RVSGB JOGYW FHKBL GLXYA MVKIS KIEHY IMAPX UOISK PVAGN MZHPW" +
    "TTZPV XFCCD TUHJH WLAPF YULTB UXJLN SIJVV YOVDJ SOLXG TGRVO" +
    "SFRII CTMKO JFCQF KTINQ BWVHG TENLH HOGCS PSFPV GJOKM SIFPR" +
    "ZPAAS ATPTZ FTPPD PORRF TAXZP KALQA WMIUD BWNCT LEFKO ZQDLX" +
    "BUXJL ASIMR PNMBF ZCYLV WAPVF QRHZV ZGZEF KBYIO OFXYE VOWGB" +
    "BXVCB XBAWG LQKCM ICRRX MACUO IKHQU AJEGL OIJHH XPVZW JEWBA" +
    "FWAML ZZRXJ EKAHV FASMU LVVUT TGK"

val freq = doubleArrayOf(
    0.08167, 0.01492, 0.02782, 0.04253, 0.12702, 0.02228, 0.02015,
    0.06094, 0.06966, 0.00153, 0.00772, 0.04025, 0.02406, 0.06749,
    0.07507, 0.01929, 0.00095, 0.05987, 0.06327, 0.09056, 0.02758,
    0.00978, 0.02360, 0.00150, 0.01974, 0.00074
)

fun bestMatch(a: DoubleArray): Int {
    val sum = a.sum()
    var bestFit = 1e100
    var bestRotate = 0
    for (rotate in 0..25) {
        var fit = 0.0
        for (i in 0..25) {
            val d = a[(i + rotate) % 26] / sum - freq[i]
            fit += d * d / freq[i]
        } 
        if (fit < bestFit) {
            bestFit = fit
            bestRotate = rotate
        }
    }
    return bestRotate
}

fun freqEveryNth(msg: IntArray, key: CharArray): Double {
    val len = msg.size
    val interval = key.size
    val out = DoubleArray(26)
    val accu = DoubleArray(26)
    for (j in 0 until interval) {
        out.fill(0.0)
        for (i in j until len step interval) out[msg[i]]++
        val rot = bestMatch(out)
        key[j] = (rot + 65).toChar()
        for (i in 0..25) accu[i] += out[(i + rot) % 26]
    }
    val sum = accu.sum()
    var ret = 0.0
    for (i in 0..25) {
        val d = accu[i] / sum - freq[i]
        ret += d * d / freq[i]
    }
    return ret
}

fun decrypt(text: String, key: String): String {
    val sb = StringBuilder()
    var ki = 0
    for (c in text) {
        if (c !in 'A'..'Z') continue
        val ci = (c.toInt() - key[ki].toInt() +  26) % 26
        sb.append((ci + 65).toChar())
        ki = (ki + 1) % key.length
    }
    return sb.toString()
}

fun main(args: Array<String>) {
    val enc = encoded.replace(" ", "")
    val txt = IntArray(enc.length) { enc[it] - 'A' }
    var bestFit = 1e100
    var bestKey = ""
    val f = "%f    %2d     %s"
    println("  Fit     Length   Key")
    for (j in 1..26) {
        val key = CharArray(j)
        val fit = freqEveryNth(txt, key)
        val sKey = key.joinToString("")
        print(f.format(fit, j, sKey))
        if (fit < bestFit) {
           bestFit = fit
           bestKey = sKey
           print(" <--- best so far")
        }
        println()
    }
    println()
    println("Best key : $bestKey") 
    println("\nDecrypted text:\n${decrypt(enc, bestKey)}")
}
Output:
  Fit     Length   Key
2.984348     1     E <--- best so far
2.483684     2     EC <--- best so far
2.642487     3     TEE
1.976651     4     THEC <--- best so far
2.356881     5     EEEPU
2.203129     6     TCECEC
1.051163     7     THECSAS <--- best so far
1.645763     8     TJQGAHET
2.001380     9     VEIZSEGNT
1.824476    10     ECEGAWQTDS
1.623083    11     TNLUSRXPTAJ
1.253527    12     XLECTHQGTHEC
1.399037    13     LJJTDGFNOTENR
0.152370    14     THECHESHIRECAT <--- best so far
1.533951    15     JNTOOEEXFTGQTNH
1.068182    16     TJTSAEETEXHPXHNE
1.034093    17     AZRAXUHEJLREEXIEE
1.443345    18     VNIZQPALEPTSXSEXUC
1.090977    19     FUCAITCSLVTEZDUDEHS
0.979868    20     EQXGAHWTTQECEWUGXHPI
0.789410    21     HVRCSAFTHEBDLSTAERSES
0.881380    22     TVIJTCIGKAQPELECRXPTNC
0.952456    23     KKEQXGPWTCQEELIEHXUWASV
0.715968    24     ELAIXHQTTIEDXJETTNTGAEPC
0.891258    25     OTJUUEGERDNQTUQEAGWUTIEOA
0.852784    26     IGITEGECAGAVUNLJAHASAVTETW

Best key : THECHESHIRECAT

Decrypted text:
THISWASTHEPOEMTHATALICEREADJABBERWOCKYTWASBRILLIGANDTHESLITHYTOVESDIDGYREANDGIMBLEINTHEWABEALLMIMSYWERETHEBOROGOVESANDTHEMOMERATHSOUTGRABEBEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCHBEWARETHEJUBJUBBIRDANDSHUNTHEFRUMIOUSBANDERSNATCHHETOOKHISVORPALSWORDINHANDLONGTIMETHEMANXOMEFOEHESOUGHTSORESTEDHEBYTHETUMTUMTREEANDSTOODAWHILEINTHOUGHTANDASINUFFISHTHOUGHTHESTOODTHEJABBERWOCKWITHEYESOFFLAMECAMEWHIFFLINGTHROUGHTHETULGEYWOODANDBURBLEDASITCAMEONETWOONETWOANDTHROUGHANDTHROUGHTHEVORPALBLADEWENTSNICKERSNACKHELEFTITDEADANDWITHITSHEADHEWENTGALUMPHINGBACKANDHASTTHOUSLAINTHEJABBERWOCKCOMETOMYARMSMYBEAMISHBOYOFRABJOUSDAYCALLOOHCALLAYHECHORTLEDINHISJOYTWASBRILLIGANDTHESLITHYTOVESDIDGYREANDGIMBLEINTHEWABEALLMIMSYWERETHEBOROGOVESANDTHEMOMERATHSOUTGRABEITSEEMSVERYPRETTYSHESAIDWHENSHEHADFINISHEDITBUTITSRATHERHARDTOUNDERSTAND

Nim

Translation of: Julia
Translation of: Phix

This is a translation of Julia algorithm with some ideas from Phix translation.

import sequtils, strutils, sugar, tables, times

const

  CipherText = """MOMUD EKAPV TQEFM OEVHP AJMII CDCTI FGYAG JSPXY ALUYM NSMYH
                  VUXJE LEPXJ FXGCM JHKDZ RYICU HYPUS PGIGM OIYHF WHTCQ KMLRD
                  ITLXZ LJFVQ GHOLW CUHLO MDSOE KTALU VYLNZ RFGBX PHVGA LWQIS
                  FGRPH JOOFW GUBYI LAPLA LCAFA AMKLG CETDW VOELJ IKGJB XPHVG
                  ALWQC SNWBU BYHCU HKOCE XJEYK BQKVY KIIEH GRLGH XEOLW AWFOJ
                  ILOVV RHPKD WIHKN ATUHN VRYAQ DIVHX FHRZV QWMWV LGSHN NLVZS
                  JLAKI FHXUF XJLXM TBLQV RXXHR FZXGV LRAJI EXPRV OSMNP KEPDT
                  LPRWM JAZPK LQUZA ALGZX GVLKL GJTUI ITDSU REZXJ ERXZS HMPST
                  MTEOE PAPJH SMFNB YVQUZ AALGA YDNMP AQOWT UHDBV TSMUE UIMVH
                  QGVRW AEFSP EMPVE PKXZY WLKJA GWALT VYYOB YIXOK IHPDS EVLEV
                  RVSGB JOGYW FHKBL GLXYA MVKIS KIEHY IMAPX UOISK PVAGN MZHPW
                  TTZPV XFCCD TUHJH WLAPF YULTB UXJLN SIJVV YOVDJ SOLXG TGRVO
                  SFRII CTMKO JFCQF KTINQ BWVHG TENLH HOGCS PSFPV GJOKM SIFPR
                  ZPAAS ATPTZ FTPPD PORRF TAXZP KALQA WMIUD BWNCT LEFKO ZQDLX
                  BUXJL ASIMR PNMBF ZCYLV WAPVF QRHZV ZGZEF KBYIO OFXYE VOWGB
                  BXVCB XBAWG LQKCM ICRRX MACUO IKHQU AJEGL OIJHH XPVZW JEWBA
                  FWAML ZZRXJ EKAHV FASMU LVVUT TGK""".splitWhitespace.join()

  FreqLetters = {'E': 12.702, 'T': 9.056, 'A': 8.167, 'O': 7.507,
                 'I':  6.966, 'N': 6.749, 'S': 6.327, 'H': 6.094,
                 'R':  5.987, 'D': 4.253, 'L': 4.025, 'C': 2.782,
                 'U':  2.758, 'M': 2.406, 'W': 2.361, 'F': 2.228,
                 'G':  2.015, 'Y': 1.974, 'P': 1.929, 'B': 1.492,
                 'V':  0.978, 'K': 0.772, 'J': 0.153, 'X': 0.150,
                 'Q':  0.095, 'Z': 0.074}.toTable

  FreqDigraphs = {"TH": 15.2, "HE": 12.8, "IN": 9.4, "ER": 9.4,
                  "AN":  8.2, "RE":  6.8, "ND": 6.3, "AT": 5.9,
                  "ON":  5.7, "NT":  5.6, "HA": 5.6, "ES": 5.6,
                  "ST":  5.5, "EN":  5.5, "ED": 5.3, "TO": 5.2,
                  "IT":  5.0, "OU":  5.0, "EA": 4.7, "HI": 4.6,
                  "IS":  4.6, "OR":  4.3, "TI": 3.4, "AS": 3.3,
                  "TE":  2.7, "ET":  1.9, "NG": 1.8, "OF": 1.6,
                  "AL":  0.9, "DE":  0.9, "SE": 0.8, "LE": 0.8,
                  "SA":  0.6, "SI":  0.5, "AR": 0.4, "VE": 0.4,
                  "RA":  0.4, "LD":  0.2, "UR": 0.2}.toTable

  FreqTrigraphs = {"THE": 18.1, "AND": 7.3, "ING": 7.2, "ION": 4.2,
                   "ENT":  4.2, "HER": 3.6, "FOR": 3.4, "THA": 3.3,
                   "NTH":  3.3, "INT": 3.2, "TIO": 3.1, "ERE": 3.1,
                   "TER":  3.0, "EST": 2.8, "ERS": 2.8, "HAT": 2.6,
                   "ATI":  2.6, "ATE": 2.5, "ALL": 2.5, "VER": 2.4,
                   "HIS":  2.4, "HES": 2.4, "ETH": 2.4, "OFT": 2.2,
                   "STH":  2.1, "RES": 2.1, "OTH": 2.1, "ITH": 2.1,
                   "FTH":  2.1, "ONT": 2.0}.toTable

func decrypt(enc, key: string): string =
  let encLen = enc.len
  let keyLen = key.len
  result.setLen(encLen)
  var k = 0
  for i in 0..<encLen:
    result[i] = chr((ord(enc[i]) - ord(key[k]) + 26) mod 26 + ord('A'))
    k = (k + 1) mod keyLen

func cryptanalyze(enc: string; maxKeyLen = 20): tuple[maxKey, maxDec: string] =
  let encLen = enc.len
  var maxScore = 0.0

  for keyLen in 1..maxKeyLen:
    var key = newString(keyLen)
    var idx = collect(newSeq):
                for i in 1..encLen:
                  if i mod keyLen == 0:
                    i - keyLen

    for  i in 0..<keyLen:
      var maxSubscore = 0.0
      for j in 'A'..'Z':
        var subscore = 0.0
        let encidx = idx.mapIt(enc[it]).join()
        for k in decrypt(encidx, $j):
          subscore += FreqLetters[k]
        if subscore > maxSubscore:
          maxSubscore = subscore
          key[i] = j
      for item in idx.mitems: inc item

    let dec = decrypt(enc, key)
    var score = 0.0
    for i in dec:
      score += FreqLetters[i]

    for i in 0..(encLen - 3):
      let digraph = dec[i..(i+1)]
      let trigraph = dec[i..(i+2)]
      score += 2 * FreqDigraphs.getOrDefault(digraph)
      score += 3 * FreqTrigraphs.getOrDefault(trigraph)

    if score > maxScore:
      maxScore = score
      result.maxKey = key
      result.maxDec = dec

let t0 = cpuTime()
let (key, dec) = CipherText.cryptanalyze()
echo "key: ", key, '\n'
echo dec, '\n'
echo "Elapsed time: ", (cpuTime() - t0).formatFloat(ffDecimal, precision = 3), " s"
Output:
key: THECHESHIRECAT

THISWASTHEPOEMTHATALICEREADJABBERWOCKYTWASBRILLIGANDTHESLITHYTOVESDIDGYREANDGIMBLEINTHEWABEALLMIMSYWERETHEBOROGOVESANDTHEMOMERATHSOUTGRABEBEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCHBEWARETHEJUBJUBBIRDANDSHUNTHEFRUMIOUSBANDERSNATCHHETOOKHISVORPALSWORDINHANDLONGTIMETHEMANXOMEFOEHESOUGHTSORESTEDHEBYTHETUMTUMTREEANDSTOODAWHILEINTHOUGHTANDASINUFFISHTHOUGHTHESTOODTHEJABBERWOCKWITHEYESOFFLAMECAMEWHIFFLINGTHROUGHTHETULGEYWOODANDBURBLEDASITCAMEONETWOONETWOANDTHROUGHANDTHROUGHTHEVORPALBLADEWENTSNICKERSNACKHELEFTITDEADANDWITHITSHEADHEWENTGALUMPHINGBACKANDHASTTHOUSLAINTHEJABBERWOCKCOMETOMYARMSMYBEAMISHBOYOFRABJOUSDAYCALLOOHCALLAYHECHORTLEDINHISJOYTWASBRILLIGANDTHESLITHYTOVESDIDGYREANDGIMBLEINTHEWABEALLMIMSYWERETHEBOROGOVESANDTHEMOMERATHSOUTGRABEITSEEMSVERYPRETTYSHESAIDWHENSHEHADFINISHEDITBUTITSRATHERHARDTOUNDERSTAND

Elapsed time: 0.041 s

OCaml

Original version by User:Vanyamil.

Uses the Vigenere decrypt function from the Vigenere task solution (not included in the code below).

Works with: OCaml version above 4.05
(* Task : Vigenere cipher/Cryptanalysis *)

(*  
	Given some text you suspect has been encrypted 
	with a Vigenère cipher, extract the key and plaintext.
	Uses correlation factors similar to other solutions.
	(originally tried Friedman test, didn't produce good result)
	
	Coded in a way that allows non-english (by passing frequencies).
*)

(*** Helpers ***)

(* Implementation of Float.round to avoid v4.08 *)
let round (x : float) : float = 
    let rem = mod_float x 1. in
    if rem >= 0.5 
    then ceil x
    else floor x

(* A function that updates array element at a position *)
let array_update (arr : 'a array) (idx : int) (update : 'a -> 'a) : unit =
    let curr = Array.get arr idx in
    Array.set arr idx (update curr)

(*** Actual task at hand ***)

(* the n'th element of array is how often the n'th letter was found *)
let observe_coincidences ?(step : int = 1) ?(offset : int = 0) (text : string) : int array =
    let arr = Array.make 26 0 in
    let a_code = Char.code 'A' in
    String.iteri (fun idx c -> if idx mod step = offset then array_update arr (Char.code c - a_code) succ) text;
    arr

(* Obtain correlation factor for the observed coincidences *)
let correlation_factor ?(sort : bool = true) (coincidences : int array) (freqs : float list) : float =
    let clist = Array.to_list coincidences in
    let clist = (if sort then List.sort compare clist else clist) in
    List.fold_left2 (fun acc c f -> acc +. (float_of_int c *. f)) 0. clist freqs

(* Translation of the test used in other Rosetta Code solutions *)
let shifted_coincidences_test (freqs : float list) (text : string) : int = 
    let sorted_freqs = List.sort compare freqs in
    let bestCorr = -100. in 
    let max_keylen = String.length text / 20 in
    let rec helper idx (cur_len, cur_corr) (best_len, best_corr) = 
        if cur_len = max_keylen then (* Finished testing everything *)
            best_len
        else if idx = cur_len then (* Finished testing this key length *)
            let (best_len, best_corr) = if cur_corr > best_corr then (cur_len, cur_corr) else (best_len, best_corr) in
            helper 0 (cur_len + 1,  ~-.0.5 *. float_of_int (cur_len + 1)) (best_len, best_corr)
        else
            let coincidences = observe_coincidences ~step:cur_len ~offset:idx text in
            let factor = correlation_factor coincidences sorted_freqs in
            helper (succ idx) (cur_len, cur_corr +. factor) (best_len, best_corr)
    in
    helper 0 (2, ~-.1.) (1, ~-.100.)

(* Returns the most likely shift value for this set *)
let break_caesar ?(step : int = 1) ?(offset : int = 0) (text : string) (freqs : float list) : int =
    let c_arr = observe_coincidences ~step ~offset text in
    let rec helper l curShift (maxShift, maxCorr) = 
        if curShift = 26 
        then maxShift
        else
            let corr = correlation_factor ~sort:false c_arr l in
            let l' = List.tl l @ [List.hd l] in
            if corr > maxCorr 
            then helper l' (curShift + 1) (curShift, corr)
            else helper l' (curShift + 1) (maxShift, maxCorr)
    in
    helper freqs 0 (-1, -100.)

let break (keylen : int) (text : string) (freqs : float list) : key = 
    let rec getCaesars idx acc = 
        if idx >= keylen then acc else
        let shift = break_caesar ~step:keylen ~offset:idx text freqs in
        let new_code = if shift = 0 then Char.code 'A' else Char.code 'Z' + 1 - shift in
        getCaesars (succ idx) (acc ^ Char.(new_code |> chr |> escaped))
    in
    getCaesars 0 ""

let cryptanalyze (freqs : float list) (text : string) : key * string = 
    let text = ascii_upper_letters_only text in
    let keylen = shifted_coincidences_test freqs text in
    let key = break keylen text freqs in
    let pt = decrypt key text in
    (key, pt)

(*** Output ***)

let _ =
    let long_text = "\
MOMUD EKAPV TQEFM OEVHP AJMII CDCTI FGYAG JSPXY ALUYM NSMYH \
VUXJE LEPXJ FXGCM JHKDZ RYICU HYPUS PGIGM OIYHF WHTCQ KMLRD \
ITLXZ LJFVQ GHOLW CUHLO MDSOE KTALU VYLNZ RFGBX PHVGA LWQIS \
FGRPH JOOFW GUBYI LAPLA LCAFA AMKLG CETDW VOELJ IKGJB XPHVG \
ALWQC SNWBU BYHCU HKOCE XJEYK BQKVY KIIEH GRLGH XEOLW AWFOJ \
ILOVV RHPKD WIHKN ATUHN VRYAQ DIVHX FHRZV QWMWV LGSHN NLVZS \
JLAKI FHXUF XJLXM TBLQV RXXHR FZXGV LRAJI EXPRV OSMNP KEPDT \
LPRWM JAZPK LQUZA ALGZX GVLKL GJTUI ITDSU REZXJ ERXZS HMPST \
MTEOE PAPJH SMFNB YVQUZ AALGA YDNMP AQOWT UHDBV TSMUE UIMVH \
QGVRW AEFSP EMPVE PKXZY WLKJA GWALT VYYOB YIXOK IHPDS EVLEV \
RVSGB JOGYW FHKBL GLXYA MVKIS KIEHY IMAPX UOISK PVAGN MZHPW \
TTZPV XFCCD TUHJH WLAPF YULTB UXJLN SIJVV YOVDJ SOLXG TGRVO \
SFRII CTMKO JFCQF KTINQ BWVHG TENLH HOGCS PSFPV GJOKM SIFPR \
ZPAAS ATPTZ FTPPD PORRF TAXZP KALQA WMIUD BWNCT LEFKO ZQDLX \
BUXJL ASIMR PNMBF ZCYLV WAPVF QRHZV ZGZEF KBYIO OFXYE VOWGB \
BXVCB XBAWG LQKCM ICRRX MACUO IKHQU AJEGL OIJHH XPVZW JEWBA \
FWAML ZZRXJ EKAHV FASMU LVVUT TGK"
    in
    let english_freqs = [
        0.08167; 0.01492; 0.02782; 0.04253; 0.12702; 0.02228; 0.02015;
        0.06094; 0.06966; 0.00153; 0.00772; 0.04025; 0.02406; 0.06749;
        0.07507; 0.01929; 0.00095; 0.05987; 0.06327; 0.09056; 0.02758;
        0.00978; 0.02360; 0.00150; 0.01974; 0.00074
    ] 
    in
    let (key, pt) = cryptanalyze english_freqs long_text in
    Printf.printf "Key:  %s\n\nText: %s" key pt
;;
Output:
Key:  THECHESHIRECAT

Text: THISWASTHEPOEMTHATALICEREADJABBERWOC...

Perl

use strict;
use warnings;
use feature 'say';

# from Wikipedia
my %English_letter_freq = (
     E => 12.70,  L => 4.03,  Y => 1.97,  P => 1.93,  T => 9.06,  A => 8.17,  O => 7.51,  I => 6.97,  N => 6.75,
     S =>  6.33,  H => 6.09,  R => 5.99,  D => 4.25,  C => 2.78,  U => 2.76,  M => 2.41,  W => 2.36,  F => 2.23,
     G =>  2.02,  B => 1.29,  V => 0.98,  K => 0.77,  J => 0.15,  X => 0.15,  Q => 0.10,  Z => 0.07
);
my @alphabet = sort keys %English_letter_freq;
my $max_key_lengths = 5; # number of keylengths to try

sub myguess {
    my ($text) = (@_);
    my ($seqtext, @spacing, @factors, @sortedfactors, $pos, %freq, %Keys);

    # Kasiski examination
    $seqtext = $text;
    while ($seqtext =~ /(...).*\1/) {
        $seqtext = substr($seqtext, 1+index($seqtext, $1));
        push @spacing,  1 + index($seqtext, $1);
    }

    for my $j (@spacing) {
        push @factors, grep { $j % $_ == 0 } 2..$j;
    }
    $freq{$_}++ for @factors;
    @sortedfactors = grep { $_ >= 4 } sort { $freq{$b} <=> $freq{$a} } keys %freq; # discard very short keys

    for my $keylen ( @sortedfactors[0..$max_key_lengths-1] ) {
        my $keyguess = '';
        for (my $i = 0; $i < $keylen; $i++) {
            my($mykey, %chi_values, $bestguess);
            for (my $j = 0; $j < length($text); $j += $keylen) {
                $mykey .= substr($text, ($j+$i) % length($text), 1);
            }

            for my $subkey (@alphabet) {
                my $decrypted = mycrypt($mykey, $subkey);
                my $length    = length($decrypted);
                for my $char (@alphabet) {
                    my $expected = $English_letter_freq{$char} * $length / 100;
                    my $observed;
                    ++$observed while $decrypted =~ /$char/g;
                    $chi_values{$subkey} += ($observed - $expected)**2 / $expected if $observed;
                }
            }

            $Keys{$keylen}{score} = $chi_values{'A'};
            for my $sk (sort keys %chi_values) {
                if ($chi_values{$sk} <= $Keys{$keylen}{score}) {
                    $bestguess = $sk;
                    $Keys{$keylen}{score} = $chi_values{$sk};
                }
            }
            $keyguess .= $bestguess;
        }
        $Keys{$keylen}{key} = $keyguess;
    }
    map { $Keys{$_}{key} } sort { $Keys{$a}{score} <=> $Keys{$b}{score}} keys %Keys;
}

sub mycrypt {
    my ($text, $key) = @_;
    my ($new_text, %values_numbers);

    my $keylen = length($key);
    @values_numbers{@alphabet} = 0..25;
    my %values_letters = reverse %values_numbers;

    for (my $i = 0; $i < length($text); $i++) {
        my $val =  -1 * $values_numbers{substr( $key, $i%$keylen, 1)} # negative shift for decode
                 +      $values_numbers{substr($text, $i,         1)};
        $new_text .= $values_letters{ $val % 26 };
    }
    return $new_text;
}

my $cipher_text = <<~'EOD';
    MOMUD EKAPV TQEFM OEVHP AJMII CDCTI FGYAG JSPXY ALUYM NSMYH
    VUXJE LEPXJ FXGCM JHKDZ RYICU HYPUS PGIGM OIYHF WHTCQ KMLRD
    ITLXZ LJFVQ GHOLW CUHLO MDSOE KTALU VYLNZ RFGBX PHVGA LWQIS
    FGRPH JOOFW GUBYI LAPLA LCAFA AMKLG CETDW VOELJ IKGJB XPHVG
    ALWQC SNWBU BYHCU HKOCE XJEYK BQKVY KIIEH GRLGH XEOLW AWFOJ
    ILOVV RHPKD WIHKN ATUHN VRYAQ DIVHX FHRZV QWMWV LGSHN NLVZS
    JLAKI FHXUF XJLXM TBLQV RXXHR FZXGV LRAJI EXPRV OSMNP KEPDT
    LPRWM JAZPK LQUZA ALGZX GVLKL GJTUI ITDSU REZXJ ERXZS HMPST
    MTEOE PAPJH SMFNB YVQUZ AALGA YDNMP AQOWT UHDBV TSMUE UIMVH
    QGVRW AEFSP EMPVE PKXZY WLKJA GWALT VYYOB YIXOK IHPDS EVLEV
    RVSGB JOGYW FHKBL GLXYA MVKIS KIEHY IMAPX UOISK PVAGN MZHPW
    TTZPV XFCCD TUHJH WLAPF YULTB UXJLN SIJVV YOVDJ SOLXG TGRVO
    SFRII CTMKO JFCQF KTINQ BWVHG TENLH HOGCS PSFPV GJOKM SIFPR
    ZPAAS ATPTZ FTPPD PORRF TAXZP KALQA WMIUD BWNCT LEFKO ZQDLX
    BUXJL ASIMR PNMBF ZCYLV WAPVF QRHZV ZGZEF KBYIO OFXYE VOWGB
    BXVCB XBAWG LQKCM ICRRX MACUO IKHQU AJEGL OIJHH XPVZW JEWBA
    FWAML ZZRXJ EKAHV FASMU LVVUT TGK
EOD

my $text = uc($cipher_text) =~ s/[^@{[join '', @alphabet]}]//gr;

for my $key ( myguess($text) ) {
    say "Key        $key\n" .
        "Key length " . length($key) . "\n" .
        "Plaintext  " . substr(mycrypt($text, $key), 0, 80) . "...\n";
}
Output:
Key        THECHESHIRECAT
Key length 14
Plaintext  THISWASTHEPOEMTHATALICEREADJABBERWOCKYTWASBRILLIGANDTHESLITHYTOVESDIDGYREANDGIMB...

Key        THECHESCIRECATTHECHESHIRECAT
Key length 28
Plaintext  THISWASYHEPOEMTHATALICEREADJABBERWOHKYTWASBRILLIGANDTHESLITHYTOAESDIDGYREANDGIMB...

Key        TJGGAHET
Key length 8
Plaintext  TFGODXGHWMNKEYIVLMBJACIPPTXWTBBNFRADSITFHCOSMGOTFYPOXCASLGRDFQCJTABEDSNFPTOBYIQZ...

Key        THECSAS
Key length 7
Plaintext  THISLESHIRRYENTHATPPIQFEGKDKABBEGAOQLLVGATBRILAMGOOQVRETLITHNXOJFFFSDHYREACHGWNO...

Key        THEC
Key length 4
Plaintext  THISKXGYWOPOLYIMLODNHCIGPVZAABBEFTCHZITWHEQWTGOKFARSECAJLITHMQCATCDIKSNWPVQFFIQQ...

Phix

Translation of: Julia
--
-- demo\rosetta\Cryptanalysis.exw
--
with javascript_semantics
atom t0 = time()
constant ciphertext = substitute_all("""
MOMUD EKAPV TQEFM OEVHP AJMII CDCTI FGYAG JSPXY ALUYM NSMYH
VUXJE LEPXJ FXGCM JHKDZ RYICU HYPUS PGIGM OIYHF WHTCQ KMLRD
ITLXZ LJFVQ GHOLW CUHLO MDSOE KTALU VYLNZ RFGBX PHVGA LWQIS
FGRPH JOOFW GUBYI LAPLA LCAFA AMKLG CETDW VOELJ IKGJB XPHVG
ALWQC SNWBU BYHCU HKOCE XJEYK BQKVY KIIEH GRLGH XEOLW AWFOJ
ILOVV RHPKD WIHKN ATUHN VRYAQ DIVHX FHRZV QWMWV LGSHN NLVZS
JLAKI FHXUF XJLXM TBLQV RXXHR FZXGV LRAJI EXPRV OSMNP KEPDT
LPRWM JAZPK LQUZA ALGZX GVLKL GJTUI ITDSU REZXJ ERXZS HMPST
MTEOE PAPJH SMFNB YVQUZ AALGA YDNMP AQOWT UHDBV TSMUE UIMVH
QGVRW AEFSP EMPVE PKXZY WLKJA GWALT VYYOB YIXOK IHPDS EVLEV
RVSGB JOGYW FHKBL GLXYA MVKIS KIEHY IMAPX UOISK PVAGN MZHPW
TTZPV XFCCD TUHJH WLAPF YULTB UXJLN SIJVV YOVDJ SOLXG TGRVO
SFRII CTMKO JFCQF KTINQ BWVHG TENLH HOGCS PSFPV GJOKM SIFPR
ZPAAS ATPTZ FTPPD PORRF TAXZP KALQA WMIUD BWNCT LEFKO ZQDLX
BUXJL ASIMR PNMBF ZCYLV WAPVF QRHZV ZGZEF KBYIO OFXYE VOWGB
BXVCB XBAWG LQKCM ICRRX MACUO IKHQU AJEGL OIJHH XPVZW JEWBA
FWAML ZZRXJ EKAHV FASMU LVVUT TGK""",{" ","\n"},{"",""})

constant letters = new_dict(
   {{'E',12.702},
    {'T',9.056},
    {'A',8.167},
    {'O',7.507},
    {'I',6.966},
    {'N',6.749},
    {'S',6.327},
    {'H',6.094},
    {'R',5.987},
    {'D',4.253},
    {'L',4.025},
    {'C',2.782},
    {'U',2.758},
    {'M',2.406},
    {'W',2.361},
    {'F',2.228},
    {'G',2.015},
    {'Y',1.974},
    {'P',1.929},
    {'B',1.492},
    {'V',0.978},
    {'K',0.772},
    {'J',0.153},
    {'X',0.150},
    {'Q',0.095},
    {'Z',0.074}})
constant digraphs = new_dict(
   {{"TH",15.2},
    {"HE",12.8},
    {"IN",9.4},
    {"ER",9.4},
    {"AN",8.2},
    {"RE",6.8},
    {"ND",6.3},
    {"AT",5.9},
    {"ON",5.7},
    {"NT",5.6},
    {"HA",5.6},
    {"ES",5.6},
    {"ST",5.5},
    {"EN",5.5},
    {"ED",5.3},
    {"TO",5.2},
    {"IT",5.0},
    {"OU",5.0},
    {"EA",4.7},
    {"HI",4.6},
    {"IS",4.6},
    {"OR",4.3},
    {"TI",3.4},
    {"AS",3.3},
    {"TE",2.7},
    {"ET",1.9},
    {"NG",1.8},
    {"OF",1.6},
    {"AL",0.9},
    {"DE",0.9},
    {"SE",0.8},
    {"LE",0.8},
    {"SA",0.6},
    {"SI",0.5},
    {"AR",0.4},
    {"VE",0.4},
    {"RA",0.4},
    {"LD",0.2},
    {"UR",0.2}})
constant trigraphs = new_dict(
   {{"THE",18.1},
    {"AND",7.3},
    {"ING",7.2},
    {"ION",4.2},
    {"ENT",4.2},
    {"HER",3.6},
    {"FOR",3.4},
    {"THA",3.3},
    {"NTH",3.3},
    {"INT",3.2},
    {"TIO",3.1},
    {"ERE",3.1},
    {"TER",3.0},
    {"EST",2.8},
    {"ERS",2.8},
    {"HAT",2.6},
    {"ATI",2.6},
    {"ATE",2.5},
    {"ALL",2.5},
    {"VER",2.4},
    {"HIS",2.4},
    {"HES",2.4},
    {"ETH",2.4},
    {"OFT",2.2},
    {"STH",2.1},
    {"RES",2.1},
    {"OTH",2.1},
    {"ITH",2.1},
    {"FTH",2.1},
    {"ONT",2.0}})
 
function decrypt(string enc, string key)
    integer keylen = length(key), k = 1
    string msg = repeat(' ', length(enc))
    for i=1 to length(enc) do
        msg[i] = mod(enc[i]-key[k]+26,26)+'A'
        k = mod(k,keylen)+1
    end for
    return msg
end function
 
function cryptanalyze(string enc, integer maxkeylen=20)
    integer enclen = length(enc)
    string maxkey = "",
           maxdec = "",
           k1 = " "
    atom maxscore = 0.0
 
    for keylen=1 to maxkeylen do
        string key = repeat(' ',keylen)
        sequence idx = {}
        for i=1 to enclen do
            if mod(i,keylen)=0 then
                idx &= i-keylen+1
            end if
        end for

        for i=1 to keylen do
            atom maxsubscore = 0.0
 
            for j='A' to 'Z' do
                atom subscore = 0.0
 
                k1[1] = j
                string encidx = ""
                for ii=1 to length(idx) do
                    encidx &= enc[idx[ii]]
                end for
                string dec = decrypt(encidx,k1)
                for di=1 to length(dec) do
                    subscore += getd(dec[di],letters)
                end for
 
                if subscore > maxsubscore then
                    maxsubscore = subscore
                    key[i] = j
                end if
            end for
 
            idx = sq_add(idx,1)
        end for
 
        string dec = decrypt(enc, key)
        atom score = 0.0
 
        for i=1 to length(dec) do
            score += getd(dec[i],letters)
        end for
 
        for i=1 to enclen - 2 do
            string digraph = dec[i..i+1]
            string trigraph = dec[i..i + 2]
            score += 2 * getd(digraph,digraphs)
            score += 3 * getd(trigraph,trigraphs)
        end for
 
        if score > maxscore then
            maxscore = score
            maxkey = key
            maxdec = dec
        end if
    end for
 
    return {maxkey,maxdec}
end function
 
function fold(string s, integer w)
    for i=w to length(s) by w do
        s[i..i-1] = "\n"
    end for
    return s
end function

string {key, dec} = cryptanalyze(ciphertext)
printf(1,"key: %s\n\n%s\n\n", {key, fold(dec,80)})
 
printf(1,"elapsed time: %3.2f seconds",{time()-t0})

{} = wait_key()
Output:
key: THECHESHIRECAT

THISWASTHEPOEMTHATALICEREADJABBERWOCKYTWASBRILLIGANDTHESLITHYTOVESDIDGYREANDGIM
BLEINTHEWABEALLMIMSYWERETHEBOROGOVESANDTHEMOMERATHSOUTGRABEBEWARETHEJABBERWOCKM
YSONTHEJAWSTHATBITETHECLAWSTHATCATCHBEWARETHEJUBJUBBIRDANDSHUNTHEFRUMIOUSBANDER
SNATCHHETOOKHISVORPALSWORDINHANDLONGTIMETHEMANXOMEFOEHESOUGHTSORESTEDHEBYTHETUM
TUMTREEANDSTOODAWHILEINTHOUGHTANDASINUFFISHTHOUGHTHESTOODTHEJABBERWOCKWITHEYESO
FFLAMECAMEWHIFFLINGTHROUGHTHETULGEYWOODANDBURBLEDASITCAMEONETWOONETWOANDTHROUGH
ANDTHROUGHTHEVORPALBLADEWENTSNICKERSNACKHELEFTITDEADANDWITHITSHEADHEWENTGALUMPH
INGBACKANDHASTTHOUSLAINTHEJABBERWOCKCOMETOMYARMSMYBEAMISHBOYOFRABJOUSDAYCALLOOH
CALLAYHECHORTLEDINHISJOYTWASBRILLIGANDTHESLITHYTOVESDIDGYREANDGIMBLEINTHEWABEAL
LMIMSYWERETHEBOROGOVESANDTHEMOMERATHSOUTGRABEITSEEMSVERYPRETTYSHESAIDWHENSHEHAD
FINISHEDITBUTITSRATHERHARDTOUNDERSTAND

elapsed time: 0.42 seconds

Python

Translation of: D
from string import uppercase
from operator import itemgetter

def vigenere_decrypt(target_freqs, input):
    nchars = len(uppercase)
    ordA = ord('A')
    sorted_targets = sorted(target_freqs)

    def frequency(input):
        result = [[c, 0.0] for c in uppercase]
        for c in input:
            result[c - ordA][1] += 1
        return result

    def correlation(input):
        result = 0.0
        freq = frequency(input)
        freq.sort(key=itemgetter(1))

        for i, f in enumerate(freq):
            result += f[1] * sorted_targets[i]
        return result

    cleaned = [ord(c) for c in input.upper() if c.isupper()]
    best_len = 0
    best_corr = -100.0

    # Assume that if there are less than 20 characters
    # per column, the key's too long to guess
    for i in xrange(2, len(cleaned) // 20):
        pieces = [[] for _ in xrange(i)]
        for j, c in enumerate(cleaned):
            pieces[j % i].append(c)

        # The correlation seems to increase for smaller
        # pieces/longer keys, so weigh against them a little
        corr = -0.5 * i + sum(correlation(p) for p in pieces)

        if corr > best_corr:
            best_len = i
            best_corr = corr

    if best_len == 0:
        return ("Text is too short to analyze", "")

    pieces = [[] for _ in xrange(best_len)]
    for i, c in enumerate(cleaned):
        pieces[i % best_len].append(c)

    freqs = [frequency(p) for p in pieces]

    key = ""
    for fr in freqs:
        fr.sort(key=itemgetter(1), reverse=True)

        m = 0
        max_corr = 0.0
        for j in xrange(nchars):
            corr = 0.0
            c = ordA + j
            for frc in fr:
                d = (ord(frc[0]) - c + nchars) % nchars
                corr += frc[1] * target_freqs[d]

            if corr > max_corr:
                m = j
                max_corr = corr

        key += chr(m + ordA)

    r = (chr((c - ord(key[i % best_len]) + nchars) % nchars + ordA)
         for i, c in enumerate(cleaned))
    return (key, "".join(r))


def main():
    encoded = """
        MOMUD EKAPV TQEFM OEVHP AJMII CDCTI FGYAG JSPXY ALUYM NSMYH
        VUXJE LEPXJ FXGCM JHKDZ RYICU HYPUS PGIGM OIYHF WHTCQ KMLRD
        ITLXZ LJFVQ GHOLW CUHLO MDSOE KTALU VYLNZ RFGBX PHVGA LWQIS
        FGRPH JOOFW GUBYI LAPLA LCAFA AMKLG CETDW VOELJ IKGJB XPHVG
        ALWQC SNWBU BYHCU HKOCE XJEYK BQKVY KIIEH GRLGH XEOLW AWFOJ
        ILOVV RHPKD WIHKN ATUHN VRYAQ DIVHX FHRZV QWMWV LGSHN NLVZS
        JLAKI FHXUF XJLXM TBLQV RXXHR FZXGV LRAJI EXPRV OSMNP KEPDT
        LPRWM JAZPK LQUZA ALGZX GVLKL GJTUI ITDSU REZXJ ERXZS HMPST
        MTEOE PAPJH SMFNB YVQUZ AALGA YDNMP AQOWT UHDBV TSMUE UIMVH
        QGVRW AEFSP EMPVE PKXZY WLKJA GWALT VYYOB YIXOK IHPDS EVLEV
        RVSGB JOGYW FHKBL GLXYA MVKIS KIEHY IMAPX UOISK PVAGN MZHPW
        TTZPV XFCCD TUHJH WLAPF YULTB UXJLN SIJVV YOVDJ SOLXG TGRVO
        SFRII CTMKO JFCQF KTINQ BWVHG TENLH HOGCS PSFPV GJOKM SIFPR
        ZPAAS ATPTZ FTPPD PORRF TAXZP KALQA WMIUD BWNCT LEFKO ZQDLX
        BUXJL ASIMR PNMBF ZCYLV WAPVF QRHZV ZGZEF KBYIO OFXYE VOWGB
        BXVCB XBAWG LQKCM ICRRX MACUO IKHQU AJEGL OIJHH XPVZW JEWBA
        FWAML ZZRXJ EKAHV FASMU LVVUT TGK"""

    english_frequences = [
        0.08167, 0.01492, 0.02782, 0.04253, 0.12702, 0.02228, 0.02015,
        0.06094, 0.06966, 0.00153, 0.00772, 0.04025, 0.02406, 0.06749,
        0.07507, 0.01929, 0.00095, 0.05987, 0.06327, 0.09056, 0.02758,
        0.00978, 0.02360, 0.00150, 0.01974, 0.00074]

    (key, decoded) = vigenere_decrypt(english_frequences, encoded)
    print "Key:", key
    print "\nText:", decoded

main()

Racket

Simple method

This is a simple method that just tries to find a key of any length that minimizes the difference from the expected English character distributions.

#lang at-exp racket

(define max-keylen 30)

(define text
  @~a{MOMUD EKAPV TQEFM OEVHP AJMII CDCTI FGYAG JSPXY ALUYM NSMYH
      VUXJE LEPXJ FXGCM JHKDZ RYICU HYPUS PGIGM OIYHF WHTCQ KMLRD
      ITLXZ LJFVQ GHOLW CUHLO MDSOE KTALU VYLNZ RFGBX PHVGA LWQIS
      FGRPH JOOFW GUBYI LAPLA LCAFA AMKLG CETDW VOELJ IKGJB XPHVG
      ALWQC SNWBU BYHCU HKOCE XJEYK BQKVY KIIEH GRLGH XEOLW AWFOJ
      ILOVV RHPKD WIHKN ATUHN VRYAQ DIVHX FHRZV QWMWV LGSHN NLVZS
      JLAKI FHXUF XJLXM TBLQV RXXHR FZXGV LRAJI EXPRV OSMNP KEPDT
      LPRWM JAZPK LQUZA ALGZX GVLKL GJTUI ITDSU REZXJ ERXZS HMPST
      MTEOE PAPJH SMFNB YVQUZ AALGA YDNMP AQOWT UHDBV TSMUE UIMVH
      QGVRW AEFSP EMPVE PKXZY WLKJA GWALT VYYOB YIXOK IHPDS EVLEV
      RVSGB JOGYW FHKBL GLXYA MVKIS KIEHY IMAPX UOISK PVAGN MZHPW
      TTZPV XFCCD TUHJH WLAPF YULTB UXJLN SIJVV YOVDJ SOLXG TGRVO
      SFRII CTMKO JFCQF KTINQ BWVHG TENLH HOGCS PSFPV GJOKM SIFPR
      ZPAAS ATPTZ FTPPD PORRF TAXZP KALQA WMIUD BWNCT LEFKO ZQDLX
      BUXJL ASIMR PNMBF ZCYLV WAPVF QRHZV ZGZEF KBYIO OFXYE VOWGB
      BXVCB XBAWG LQKCM ICRRX MACUO IKHQU AJEGL OIJHH XPVZW JEWBA
      FWAML ZZRXJ EKAHV FASMU LVVUT TGK})

(define first-char (char->integer #\A))
(define chars# (- (char->integer #\Z) first-char -1))

(define freqs ; english letter frequencies from wikipedia
  ((compose1 list->vector (curry map (curryr / 100000.0)))
   '(8167 1492 2782 4253 12702 2228 2015 6094 6966 153 772 4025 2406
     6749 7507 1929 95 5987 6327 9056 2758 978 2360 150 1974 74)))

(define text* (for/vector ([c (regexp-replace* #px"\\s+" text "")])
                (- (char->integer c) first-char)))
(define N (vector-length text*))

(define (col-guesses len)
  (for/list ([ofs len])
    (define text (for/list ([i (in-range ofs N len)]) (vector-ref text* i)))
    (define cN (length text))
    (define cfreqs (make-vector chars# 0))
    (for ([c (in-list text)])
      (vector-set! cfreqs c (add1 (vector-ref cfreqs c))))
    (for ([i chars#]) (vector-set! cfreqs i (/ (vector-ref cfreqs i) cN)))
    (argmin car
      (for/list ([d chars#])
        (cons (for/sum ([i chars#])
                (expt (- (vector-ref freqs i)
                         (vector-ref cfreqs (modulo (+ i d) chars#)))
                      2))
              d)))))

(define best-key
  (cdr (argmin car
         (for/list ([len (range 1 (add1 max-keylen))])
           (define guesses (col-guesses len))
           (cons (/ (apply + (map car guesses)) len) (map cdr guesses))))))

(printf "Best key found: ")
(for ([c best-key]) (display (integer->char (+ c first-char))))
(newline)

(printf "Decoded text:\n")
(define decode-num
  (let ([cur '()])
    (λ(n) (when (null? cur) (set! cur best-key))
          (begin0 (modulo (- n (car cur)) chars#) (set! cur (cdr cur))))))
(for ([c text])
  (define n (- (char->integer c) first-char))
  (if (not (< -1 n chars#)) (display c)
      (display (integer->char (+ first-char (decode-num n))))))
(newline)

Output:

Best key found: THECHESHIRECAT
Decoded text:
THISW ASTHE POEMT HATAL ICERE ADJAB BERWO CKYTW ASBRI LLIGA
...

An attempted more complete implementation

This is an attempt at following the Wikipedia description. However, it performs just as well as the simple version. Most likely because I know almost nothing about cryptography...

#lang at-exp racket

(define max-keylen 30)

(define text
  @~a{MOMUD EKAPV TQEFM OEVHP AJMII CDCTI FGYAG JSPXY ALUYM NSMYH
      VUXJE LEPXJ FXGCM JHKDZ RYICU HYPUS PGIGM OIYHF WHTCQ KMLRD
      ITLXZ LJFVQ GHOLW CUHLO MDSOE KTALU VYLNZ RFGBX PHVGA LWQIS
      FGRPH JOOFW GUBYI LAPLA LCAFA AMKLG CETDW VOELJ IKGJB XPHVG
      ALWQC SNWBU BYHCU HKOCE XJEYK BQKVY KIIEH GRLGH XEOLW AWFOJ
      ILOVV RHPKD WIHKN ATUHN VRYAQ DIVHX FHRZV QWMWV LGSHN NLVZS
      JLAKI FHXUF XJLXM TBLQV RXXHR FZXGV LRAJI EXPRV OSMNP KEPDT
      LPRWM JAZPK LQUZA ALGZX GVLKL GJTUI ITDSU REZXJ ERXZS HMPST
      MTEOE PAPJH SMFNB YVQUZ AALGA YDNMP AQOWT UHDBV TSMUE UIMVH
      QGVRW AEFSP EMPVE PKXZY WLKJA GWALT VYYOB YIXOK IHPDS EVLEV
      RVSGB JOGYW FHKBL GLXYA MVKIS KIEHY IMAPX UOISK PVAGN MZHPW
      TTZPV XFCCD TUHJH WLAPF YULTB UXJLN SIJVV YOVDJ SOLXG TGRVO
      SFRII CTMKO JFCQF KTINQ BWVHG TENLH HOGCS PSFPV GJOKM SIFPR
      ZPAAS ATPTZ FTPPD PORRF TAXZP KALQA WMIUD BWNCT LEFKO ZQDLX
      BUXJL ASIMR PNMBF ZCYLV WAPVF QRHZV ZGZEF KBYIO OFXYE VOWGB
      BXVCB XBAWG LQKCM ICRRX MACUO IKHQU AJEGL OIJHH XPVZW JEWBA
      FWAML ZZRXJ EKAHV FASMU LVVUT TGK})

(define first-char (char->integer #\A))
(define chars# (- (char->integer #\Z) first-char -1))

(define freqs ; english letter frequencies from wikipedia
  ((compose1 list->vector (curry map (curryr / 100000.0)))
   '(8167 1492 2782 4253 12702 2228 2015 6094 6966 153 772 4025 2406
     6749 7507 1929 95 5987 6327 9056 2758 978 2360 150 1974 74)))

(define (n*n-1 n) (* n (sub1 n)))

(define text* (for/vector ([c (regexp-replace* #px"\\s+" text "")])
                (- (char->integer c) first-char)))
(define N (vector-length text*))
(define (get-col-length+freqs width offset)
  (define text (for/list ([i (in-range offset N width)]) (vector-ref text* i)))
  (define cN (length text))
  (define freqs (make-vector chars# 0))
  (for ([c (in-list text)]) (vector-set! freqs c (add1 (vector-ref freqs c))))
  (values cN freqs))

(define expected-IC (* chars# (for*/sum ([x freqs]) (* x x))))

;; maps key lengths to average index of coincidence
(define keylen->ICs
  (for/vector ([len (in-range 1 (add1 (* max-keylen 2)))])
    (for/sum ([ofs len])
      (define-values [cN cfreqs] (get-col-length+freqs len ofs))
      (/ (for/sum ([i chars#]) (n*n-1 (vector-ref cfreqs i)))
         (/ (n*n-1 cN) chars#) len 1.0))))

;; given a key length find the key that minimizes errors from alphabet freqs,
;; return (cons average-error key)
(define (guess-key len)
  (define guesses
    (for/list ([ofs len])
      (define-values [cN cfreqs] (get-col-length+freqs len ofs))
      (for ([i chars#]) (vector-set! cfreqs i (/ (vector-ref cfreqs i) cN)))
      (argmin car
        (for/list ([d chars#])
          (cons (for/sum ([i chars#])
                  (expt (- (vector-ref freqs i)
                           (vector-ref cfreqs (modulo (+ i d) chars#)))
                        2))
                d)))))
  (cons (/ (apply + (map car guesses)) len) (map cdr guesses)))

;; look for a key length that minimizes error from expected-IC, with some
;; stupid consideration of multiples of the length (which should also have low
;; errors), for each one guess a key, then find the one that minimizes both (in
;; a way that looks like it works, but undoubtedly is wrong in all kinds of
;; ways) and return the winner key
(define best-key
  ((compose1 cdr (curry argmin car))
   (for/list ([i (* max-keylen 2)])
     ;; get the error from the expected-IC for the length and its multiples,
     ;; with decreasing weights for the multiples
     (define with-multiples
       (for/list ([j (in-range i (* max-keylen 2) (add1 i))] [div N])
         (cons (/ (abs (- (vector-ref keylen->ICs j) expected-IC)) expected-IC)
               (/ (add1 div)))))
     (define total (/ (for/sum ([x with-multiples]) (* (car x) (cdr x)))
                      (for/sum ([x with-multiples]) (cdr x))))
     (define guess (guess-key (add1 i)))
     (define guess*total (* total (car guess) (car guess)))
     ;; (printf "~a~a: ~a ~s\n" (if (< i 9) " " "") (add1 i)
     ;;       (list total (car guess) guess*total) (cdr guess))
     (cons guess*total (cdr guess)))))

(printf "Best key found: ")
(for ([c best-key]) (display (integer->char (+ c first-char))))
(newline)

(printf "Decoded text:\n")
(define decode-num
  (let ([cur '()])
    (λ(n) (when (null? cur) (set! cur best-key))
          (begin0 (modulo (- n (car cur)) chars#) (set! cur (cdr cur))))))
(for ([c text])
  (define n (- (char->integer c) first-char))
  (if (not (< -1 n chars#)) (display c)
      (display (integer->char (+ first-char (decode-num n))))))
(newline)

Raku

(formerly Perl 6)

Translation of: Perl
# from Wikipedia
constant %English-letter-freq = (
     E => 12.70,  L => 4.03,  Y => 1.97,  P => 1.93,  T => 9.06,  A => 8.17,  O => 7.51,  I => 6.97,  N => 6.75,
     S =>  6.33,  H => 6.09,  R => 5.99,  D => 4.25,  C => 2.78,  U => 2.76,  M => 2.41,  W => 2.36,  F => 2.23,
     G =>  2.02,  B => 1.29,  V => 0.98,  K => 0.77,  J => 0.15,  X => 0.15,  Q => 0.10,  Z => 0.07
);
constant @alphabet = %English-letter-freq.keys.sort;
constant max_key_lengths = 5; # number of keylengths to try

sub myguess ($text) {
    my ($seqtext, @spacing, @factors, $pos, %freq, %Keys);

    # Kasiski examination
    $seqtext = $text;
    while ($seqtext ~~ /$<sequence>=[...].*$<sequence>/) {
        $seqtext = substr($seqtext, 1+index($seqtext, $<sequence>));
        push @spacing, 1 + index($seqtext, $<sequence>);
    }
    for @spacing -> $j {
        %freq{$_}++ for grep { $j %% $_ }, 2..$j;
    }

    # discard very short keys, and test only the most likely remaining key lengths
    (%freq.keys.grep(* > 3).sort({%freq{$_}}).tail(max_key_lengths)).race(:1batch).map: -> $keylen {
        my $key-guess = '';
        loop (my $i = 0; $i < $keylen; $i++) {
            my ($mykey, %chi-square, $best-guess);
            loop (my $j = 0; $j < $text.chars; $j += $keylen) {
                $mykey ~= substr($text, ($j+$i) % $text.chars, 1);
            }

            for @alphabet -> $subkey {
                my $decrypted = mycrypt($mykey, $subkey);
                my $length    = $decrypted.chars;
                for @alphabet -> $char {
                    my $expected = %English-letter-freq{$char} * $length / 100;
                    my $observed = $decrypted.comb.grep(* eq $char).elems;
                    %chi-square{$subkey} += ($observed - $expected)² / $expected if $observed;
                }
            }
            %Keys{$keylen}{'score'} = %chi-square{@alphabet[0]};
            for %chi-square.keys.sort -> $sk {
                if (%chi-square{$sk} <= %Keys{$keylen}{'score'}) {
                    $best-guess = $sk;
                    %Keys{$keylen}{'score'} = %chi-square{$sk};
                }
            }
            $key-guess ~= $best-guess;
        }
        %Keys{$keylen}{'key'} = $key-guess;
    }
    %Keys.keys.sort({ %Keys{$_}{'score'} }).map:{ %Keys{$_}{'key'} };
}

sub mycrypt ($text, $key) {
    constant %values-numbers = @alphabet Z=> ^@alphabet;
    constant %values-letters = %values-numbers.invert;

    my ($new-text);
    my $keylen = $key.chars;
    loop (my $i = 0; $i < $text.chars; $i++) {
        my $val =  -1 * %values-numbers{substr( $key, $i%$keylen, 1)} # negative shift for decode
                 +      %values-numbers{substr($text, $i,         1)};
        $new-text ~= %values-letters{ $val % @alphabet };
    }
    return $new-text;
}

my $cipher-text = .uc.trans(@alphabet => '', :c) given q:to/EOD/;
    MOMUD EKAPV TQEFM OEVHP AJMII CDCTI FGYAG JSPXY ALUYM NSMYH
    VUXJE LEPXJ FXGCM JHKDZ RYICU HYPUS PGIGM OIYHF WHTCQ KMLRD
    ITLXZ LJFVQ GHOLW CUHLO MDSOE KTALU VYLNZ RFGBX PHVGA LWQIS
    FGRPH JOOFW GUBYI LAPLA LCAFA AMKLG CETDW VOELJ IKGJB XPHVG
    ALWQC SNWBU BYHCU HKOCE XJEYK BQKVY KIIEH GRLGH XEOLW AWFOJ
    ILOVV RHPKD WIHKN ATUHN VRYAQ DIVHX FHRZV QWMWV LGSHN NLVZS
    JLAKI FHXUF XJLXM TBLQV RXXHR FZXGV LRAJI EXPRV OSMNP KEPDT
    LPRWM JAZPK LQUZA ALGZX GVLKL GJTUI ITDSU REZXJ ERXZS HMPST
    MTEOE PAPJH SMFNB YVQUZ AALGA YDNMP AQOWT UHDBV TSMUE UIMVH
    QGVRW AEFSP EMPVE PKXZY WLKJA GWALT VYYOB YIXOK IHPDS EVLEV
    RVSGB JOGYW FHKBL GLXYA MVKIS KIEHY IMAPX UOISK PVAGN MZHPW
    TTZPV XFCCD TUHJH WLAPF YULTB UXJLN SIJVV YOVDJ SOLXG TGRVO
    SFRII CTMKO JFCQF KTINQ BWVHG TENLH HOGCS PSFPV GJOKM SIFPR
    ZPAAS ATPTZ FTPPD PORRF TAXZP KALQA WMIUD BWNCT LEFKO ZQDLX
    BUXJL ASIMR PNMBF ZCYLV WAPVF QRHZV ZGZEF KBYIO OFXYE VOWGB
    BXVCB XBAWG LQKCM ICRRX MACUO IKHQU AJEGL OIJHH XPVZW JEWBA
    FWAML ZZRXJ EKAHV FASMU LVVUT TGK
EOD

for myguess($cipher-text) -> $key {
    say "Key        $key\n" ~
        "Key length {$key.chars}\n" ~
        "Plaintext  {substr(mycrypt($cipher-text, $key), 0, 80)}...\n";
}
Output:
Key        THECHESHIRECAT
Key length 14
Plaintext  THISWASTHEPOEMTHATALICEREADJABBERWOCKYTWASBRILLIGANDTHESLITHYTOVESDIDGYREANDGIMB...

Key        THECHESCIRECATTHECHESHIRECAT
Key length 28
Plaintext  THISWASYHEPOEMTHATALICEREADJABBERWOHKYTWASBRILLIGANDTHESLITHYTOAESDIDGYREANDGIMB...

Key        TJGGAHET
Key length 8
Plaintext  TFGODXGHWMNKEYIVLMBJACIPPTXWTBBNFRADSITFHCOSMGOTFYPOXCASLGRDFQCJTABEDSNFPTOBYIQZ...

Key        THECSAS
Key length 7
Plaintext  THISLESHIRRYENTHATPPIQFEGKDKABBEGAOQLLVGATBRILAMGOOQVRETLITHNXOJFFFSDHYREACHGWNO...

Key        THEC
Key length 4
Plaintext  THISKXGYWOPOLYIMLODNHCIGPVZAABBEFTCHZITWHEQWTGOKFARSECAJLITHMQCATCDIKSNWPVQFFIQQ...

Rust

Translation of: Kotlin

Note that the character to/from byte (u8) conversions work here only because the key and cryptogram are composed of ASCII characters only. Indeed, Rust's char type is a Unicode scalar value, how they are represented is well summarized in the Rust book's subchapter on strings.

use std::iter::FromIterator;

const CRYPTOGRAM: &str = "MOMUD EKAPV TQEFM OEVHP AJMII CDCTI FGYAG JSPXY ALUYM NSMYH
VUXJE LEPXJ FXGCM JHKDZ RYICU HYPUS PGIGM OIYHF WHTCQ KMLRD
ITLXZ LJFVQ GHOLW CUHLO MDSOE KTALU VYLNZ RFGBX PHVGA LWQIS
FGRPH JOOFW GUBYI LAPLA LCAFA AMKLG CETDW VOELJ IKGJB XPHVG
ALWQC SNWBU BYHCU HKOCE XJEYK BQKVY KIIEH GRLGH XEOLW AWFOJ
ILOVV RHPKD WIHKN ATUHN VRYAQ DIVHX FHRZV QWMWV LGSHN NLVZS
JLAKI FHXUF XJLXM TBLQV RXXHR FZXGV LRAJI EXPRV OSMNP KEPDT
LPRWM JAZPK LQUZA ALGZX GVLKL GJTUI ITDSU REZXJ ERXZS HMPST
MTEOE PAPJH SMFNB YVQUZ AALGA YDNMP AQOWT UHDBV TSMUE UIMVH
QGVRW AEFSP EMPVE PKXZY WLKJA GWALT VYYOB YIXOK IHPDS EVLEV
RVSGB JOGYW FHKBL GLXYA MVKIS KIEHY IMAPX UOISK PVAGN MZHPW
TTZPV XFCCD TUHJH WLAPF YULTB UXJLN SIJVV YOVDJ SOLXG TGRVO
SFRII CTMKO JFCQF KTINQ BWVHG TENLH HOGCS PSFPV GJOKM SIFPR
ZPAAS ATPTZ FTPPD PORRF TAXZP KALQA WMIUD BWNCT LEFKO ZQDLX
BUXJL ASIMR PNMBF ZCYLV WAPVF QRHZV ZGZEF KBYIO OFXYE VOWGB
BXVCB XBAWG LQKCM ICRRX MACUO IKHQU AJEGL OIJHH XPVZW JEWBA
FWAML ZZRXJ EKAHV FASMU LVVUT TGK";

const FREQUENCIES: [f32; 26] = [
    0.08167, 0.01492, 0.02202, 0.04253, 0.12702, 0.02228, 0.02015, 0.06094, 0.06966, 0.00153,
    0.01292, 0.04025, 0.02406, 0.06749, 0.07507, 0.01929, 0.00095, 0.05987, 0.06327, 0.09356,
    0.02758, 0.00978, 0.02560, 0.00150, 0.01994, 0.00077,
];

fn best_match(a: &[f32]) -> u8 {
    let sum: f32 = a.iter().sum();
    let mut best_fit = std::f32::MAX;
    let mut best_rotate = 0;
    for rotate in 0..=25 {
        let mut fit = 0.;
        for i in 0..=25 {
            let char_freq = FREQUENCIES[i];
            let idx = (i + rotate as usize) % 26 as usize;
            let d = a[idx] / sum - char_freq;
            fit += d * d / char_freq;
        }
        if fit < best_fit {
            best_fit = fit;
            best_rotate = rotate;
        }
    }

    best_rotate
}

fn freq_every_nth(msg: &[u8], key: &mut [char]) -> f32 {
    let len = msg.len();
    let interval = key.len();
    let mut accu = [0.; 26];
    for j in 0..interval {
        let mut out = [0.; 26];
        for i in (j..len).step_by(interval) {
            let idx = msg[i] as usize;
            out[idx] += 1.;
        }
        let rot = best_match(&out);
        key[j] = char::from(rot + b'A');
        for i in 0..=25 {
            let idx: usize = (i + rot as usize) % 26;
            accu[i] += out[idx];
        }
    }
    let sum: f32 = accu.iter().sum();
    let mut ret = 0.;
    for i in 0..=25 {
        let char_freq = FREQUENCIES[i];
        let d = accu[i] / sum - char_freq;
        ret += d * d / char_freq;
    }
    ret
}

fn decrypt(text: &str, key: &str) -> String {
    let key_chars_cycle = key.as_bytes().iter().map(|b| *b as i32).cycle();
    let is_ascii_uppercase = |c: &u8| (b'A'..=b'Z').contains(c);
    text.as_bytes()
        .iter()
        .filter(|c| is_ascii_uppercase(c))
        .map(|b| *b as i32)
        .zip(key_chars_cycle)
        .fold(String::new(), |mut acc, (c, key_char)| {
            let ci: u8 = ((c - key_char + 26) % 26) as u8;
            acc.push(char::from(b'A' + ci));
            acc
        })
}
fn main() {
    let enc = CRYPTOGRAM
        .split_ascii_whitespace()
        .collect::<Vec<_>>()
        .join("");
    let cryptogram: Vec<u8> = enc.as_bytes().iter().map(|b| u8::from(b - b'A')).collect();
    let mut best_fit = std::f32::MAX;
    let mut best_key = String::new();
    for j in 1..=26 {
        let mut key = vec!['\0'; j];
        let fit = freq_every_nth(&cryptogram, &mut key);
        let s_key = String::from_iter(key); // 'from_iter' is imported from std::iter::FromIterator;
        if fit < best_fit {
            best_fit = fit;
            best_key = s_key;
        }
    }

    println!("best key: {}", &best_key);
    println!("\nDecrypted text:\n{}", decrypt(&enc, &best_key));
}
Output:
best key: THECHESHIRECAT

Decrypted text:
THISWASTHEPOEMTHATALICEREADJABBERWOCKYTWASBRILLIGANDTHESLITHYTOVESDIDGYREANDGIMBLEINTHEWABEALLMIMSYWERETHEBOROGOVESANDTHEMOMERATHSOUTGRABEBEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCHBEWARETHEJUBJUBBIRDANDSHUNTHEFRUMIOUSBANDERSNATCHHETOOKHISVORPALSWORDINHANDLONGTIMETHEMANXOMEFOEHESOUGHTSORESTEDHEBYTHETUMTUMTREEANDSTOODAWHILEINTHOUGHTANDASINUFFISHTHOUGHTHESTOODTHEJABBERWOCKWITHEYESOFFLAMECAMEWHIFFLINGTHROUGHTHETULGEYWOODANDBURBLEDASITCAMEONETWOONETWOANDTHROUGHANDTHROUGHTHEVORPALBLADEWENTSNICKERSNACKHELEFTITDEADANDWITHITSHEADHEWENTGALUMPHINGBACKANDHASTTHOUSLAINTHEJABBERWOCKCOMETOMYARMSMYBEAMISHBOYOFRABJOUSDAYCALLOOHCALLAYHECHORTLEDINHISJOYTWASBRILLIGANDTHESLITHYTOVESDIDGYREANDGIMBLEINTHEWABEALLMIMSYWERETHEBOROGOVESANDTHEMOMERATHSOUTGRABEITSEEMSVERYPRETTYSHESAIDWHENSHEHADFINISHEDITBUTITSRATHERHARDTOUNDERSTAND

Tcl

Translation of: Python
package require Tcl 8.6

oo::class create VigenereAnalyzer {
    variable letterFrequencies sortedTargets
    constructor {{frequencies {
 	0.08167 0.01492 0.02782 0.04253 0.12702 0.02228 0.02015
	0.06094 0.06966 0.00153 0.00772 0.04025 0.02406 0.06749
	0.07507 0.01929 0.00095 0.05987 0.06327 0.09056 0.02758
	0.00978 0.02360 0.00150 0.01974 0.00074
    }}} {
	set letterFrequencies $frequencies
	set sortedTargets [lsort -real $frequencies]
	if {[llength $frequencies] != 26} {
	    error "wrong length of frequency table"
	}
    }

    ### Utility methods
    # Find the value of $idxvar in the range [$from..$to) that maximizes the value
    # in $scorevar (which is computed by evaluating $body) 
    method Best {idxvar from to scorevar body} {
	upvar 1 $idxvar i $scorevar s
	set bestI $from
	for {set i $from} {$i < $to} {incr i} {
	    uplevel 1 $body
	    if {![info exist bestS] || $bestS < $s} {
		set bestI $i
		set bestS $s
	    }
	}
	return $bestI
    }
    # Simple list map
    method Map {var list body} {
	upvar 1 $var v
	set result {}
	foreach v $list {lappend result [uplevel 1 $body]}
	return $result
    }
    # Simple partition of $list into $groups groups; thus, the partition of
    # {a b c d e f} into 3 produces {a d} {b e} {c f}
    method Partition {list groups} {
	set i 0
	foreach val $list {
	    dict lappend result $i $val
	    if {[incr i] >= $groups} {
		set i 0
	    }
	}
	return [dict values $result]
    }

    ### Helper methods
    # Get the actual counts of different types of characters in the given list
    method Frequency cleaned {
	for {set i 0} {$i < 26} {incr i} {
	    dict set tbl $i 0
	}
	foreach ch $cleaned {
	    dict incr tbl [expr {[scan $ch %c] - 65}]
	}
	return $tbl
    }

    # Get the correlation factor of the characters in a given list with the
    # class-specified language frequency corpus
    method Correlation cleaned {
	set result 0.0
	set freq [lsort -integer [dict values [my Frequency $cleaned]]]
	foreach f $freq s $sortedTargets {
	    set result [expr {$result + $f * $s}]
	}
	return $result
    }

    # Compute an estimate for the key length
    method GetKeyLength {cleaned {required 20}} {
	# Assume that we need at least 20 characters per column to guess
	set bestLength [my Best i 2 [expr {[llength $cleaned] / $required}] corr {
	    set corr [expr {-0.5 * $i}]
	    foreach chars [my Partition $cleaned $i] {
		set corr [expr {$corr + [my Correlation $chars]}]
	    }
	}]
	if {$bestLength == 0} {
	    error "text is too short to analyze"
	}
	return $bestLength
    }

    # Compute the key from the given frequency tables and the class-specified
    # language frequency corpus
    method GetKeyFromFreqs freqs {
	foreach f $freqs {
	    set m [my Best i 0 26 corr {
		set corr 0.0
		foreach {ch count} $f {
		    set d [expr {($ch - $i) % 26}]
		    set corr [expr {$corr + $count*[lindex $letterFrequencies $d]}]
		}
	    }]
	    append key [format %c [expr {65 + $m}]]
	}
	return $key
    }

    ##### The main analyzer method #####
    method analyze input {
	# Turn the input into a clean letter sequence
	set cleaned [regexp -all -inline {[A-Z]} [string toupper $input]]
	# Get the (estimated) key length
	set bestLength [my GetKeyLength $cleaned]
	# Get the frequency mapping for the partitioned input text
	set freqs [my Map p [my Partition $cleaned $bestLength] {my Frequency $p}]
	# Get the key itself
	return [my GetKeyFromFreqs $freqs]
    }
}

Demonstration (that assumes that the Tcl solution to Vigenère cipher task is present):

set encoded "
    MOMUD EKAPV TQEFM OEVHP AJMII CDCTI FGYAG JSPXY ALUYM NSMYH
    VUXJE LEPXJ FXGCM JHKDZ RYICU HYPUS PGIGM OIYHF WHTCQ KMLRD
    ITLXZ LJFVQ GHOLW CUHLO MDSOE KTALU VYLNZ RFGBX PHVGA LWQIS
    FGRPH JOOFW GUBYI LAPLA LCAFA AMKLG CETDW VOELJ IKGJB XPHVG
    ALWQC SNWBU BYHCU HKOCE XJEYK BQKVY KIIEH GRLGH XEOLW AWFOJ
    ILOVV RHPKD WIHKN ATUHN VRYAQ DIVHX FHRZV QWMWV LGSHN NLVZS
    JLAKI FHXUF XJLXM TBLQV RXXHR FZXGV LRAJI EXPRV OSMNP KEPDT
    LPRWM JAZPK LQUZA ALGZX GVLKL GJTUI ITDSU REZXJ ERXZS HMPST
    MTEOE PAPJH SMFNB YVQUZ AALGA YDNMP AQOWT UHDBV TSMUE UIMVH
    QGVRW AEFSP EMPVE PKXZY WLKJA GWALT VYYOB YIXOK IHPDS EVLEV
    RVSGB JOGYW FHKBL GLXYA MVKIS KIEHY IMAPX UOISK PVAGN MZHPW
    TTZPV XFCCD TUHJH WLAPF YULTB UXJLN SIJVV YOVDJ SOLXG TGRVO
    SFRII CTMKO JFCQF KTINQ BWVHG TENLH HOGCS PSFPV GJOKM SIFPR
    ZPAAS ATPTZ FTPPD PORRF TAXZP KALQA WMIUD BWNCT LEFKO ZQDLX
    BUXJL ASIMR PNMBF ZCYLV WAPVF QRHZV ZGZEF KBYIO OFXYE VOWGB
    BXVCB XBAWG LQKCM ICRRX MACUO IKHQU AJEGL OIJHH XPVZW JEWBA
    FWAML ZZRXJ EKAHV FASMU LVVUT TGK
"
VigenereAnalyzer create englishVigenereAnalyzer
set key [englishVigenereAnalyzer analyze $encoded]
Vigenere create decoder $key
set decoded [decoder decrypt $encoded]
puts "Key: $key"
puts "Text: $decoded"

Vedit macro language

This implementation is fully autonomous as long as the text is long enough and there are not too many non-English words in the original text.

The text to be analysed must be in current edit buffer. A new buffer is opened to display the results.

To automatically find the best key, a dictionary is used to find English words within the decrypted text. I have used unixdict.txt, but if you do not have it available, you can use the Scribe English dictionary that comes with Vedit. However, that is unnecessarily big. A smaller dictionary is faster and may actually give better results. It might be good idea to use dictionary that only contains the most common English words.

This implementation finds the best and 2nd best Caesar key for each key position. It then checks key combinations where max one char is taken from 2nd best Caesar key. If this does not solve some encrypted text, you could increase the number of key combinations to be checked.

// (1) Copy text into tmp buffer and remove non-alpha chars.

Chdir(PATH_ONLY)
BOF
Reg_Copy(10, ALL)                       // copy text to new buffer
Buf_Switch(Buf_Free)
Reg_Ins(10)
BOF
Replace ("|!|A", "", BEGIN+ALL+NOERR)   // remove non-alpha chars
Reg_Copy_Block(10,0,EOB_pos)            // @10 = text to be analysed

#20 = Buf_Num                           // buffer for text being analyzed
#21 = Buf_Free                          // buffer for English frequency list (A-Z)
Buf_Switch(#21)
Ins_Text("8167 1492 2782 4253 12702 2228 2015 6094 6966 153 772 4025 2406 6749 7507 1929 95 5987 6327 9056 2758 978 2360 150 1974 74")
File_Open("unixdict.txt")               // or use "|(MACRO_DIR)\scribe\english.vdf"
#23 = Buf_Num                           // buffer for dictionary
#24 = Buf_Free                          // buffer for key canditates

Buf_Switch(#24)
for (#1=0; #1<5; #1++) {                // Fill table for 5 keys of 50 chars
    Ins_Char('.', COUNT, 50)
    Ins_Newline
}
#22 = Buf_Free                          // buffer for results

#25 = Reg_Size(10)                      // number of letters in the text
#26 = 26                                // number of characters in the alphabet
#61 = min(#25/10, 50)                   // max key length to try

// (2) Check Index of coincidence (or Kp) for each key length

Buf_Switch(#22)                         // buffer for results
Ins_Text("KeyLen Kp   dist ") Ins_Newline
Ins_Text("-----------------") Ins_Newline
#13 = Cur_Pos
#7 = 0                                  // no Caesar encryption
for (#5=1; #5<=#61; #5++) {
    Buf_Switch(#20)                     // text being analyzed
    BOF
    #54 = 0;                            // sum of Kp's
    for (#6=0; #6<#5; #6++) {           // for each slide
        Goto_Pos(#6)
        Call("CHARACTER_FREQUENCIES")
        Call("INDEX_OF_COINCIDENCE")    // #51 = Kp * 10000
        #54 += #51
    }
    #54 /= #5                           // average of Kp's
    Buf_Switch(#22)
    Num_Ins(#5, COUNT, 3)               // write key length
    IT(": ")
    Num_Ins(#54, NOCR)                  // average Kp
    Num_Ins(670-#54)                    // distance to English Kp
}
Buf_Switch(#22)
Sort_Merge("5,12", #13, Cur_Pos, REVERSE)  // sort the results by Kp value
Ins_Newline

// (3) Check the best 4 key lengths to find which one gives the best decrypt result

#38 = 0                                 // max number of correct characters found
#19 = 1                                 // best key length
for (#14 = 0; #14<4; #14++) {           // try 4 best key lengths
    Buf_Switch(#22)                     // results buffer
    Goto_Pos(#13) Line(#14)
    #5 = Num_Eval(SUPPRESS)             // #5 = key length
    Call("FIND_KEYS")                   // find Caesar key for each key character
    #4 = -1                             // try best match key chars only
    Call("BUILD_KEY")
    EOF
    Ins_Text("Key length ")
    Num_Ins(#5, LEFT)
    Reg_Ins(10)                         // encrypted text
    BOL
    Call("DECRYPT_LINE")
    BOL
    Call("FIND_ENGLISH_WORDS")          // #37 = number of English chars
    EOL Ins_Newline
    Ins_Text("Correct chars: ")
    Num_Ins(#37)
    if (#37 > #38) {
        #38 = #37
        #19 = #5
    }
    Update()
}

Ins_Text("Using key length: ") Num_Ins(#19) Ins_Newline
#5 = #19
Call("FIND_KEYS")                       // find Caesar key for each key character

// (4) Decrypt with different key combinations and try to find English words.
//     Try key combinations where max one char is taken from 2nd best Caesar key.

#38 = 0                                 // max number of chars in English words found
#39 = -1                                // best key number found
for (#4 = -1; #4 < #19; #4++)
{
    Call("BUILD_KEY")
    Buf_Switch(#22)                     // results
    Reg_Ins(10)                         // encrypted text
    BOL
    Call("DECRYPT_LINE")
    BOL
    Update()
    Call("FIND_ENGLISH_WORDS")          // #37 := number of correct letters in text
    if (#37 > #38) {
        #38 = #37                       // new highest number of correct chars
        #39 = #4                        // new best key
    }

    EOL IT(" -- ")                      // display results
    Num_Ins(#4, COUNT, 3)               // key number
    Ins_Text(": ")
    for (#6=0; #6<#19; #6++) {          // display key
        #9 = 130 + #6
        Ins_Char(#@9)
    }
    Ins_Text("  correct chars =")
    Num_Ins(#37)
}
Ins_Text("Best key = ")
Num_Ins(#39, LEFT)
#4 = #39
Ins_Newline

// Display results
//
Buf_Switch(#24)                         // table for key canditates
BOF
Reg_Copy_Block(14, Cur_Pos, Cur_Pos+#19)  // best Caesar key chars
Line(1)
Reg_Copy_Block(15, Cur_Pos, Cur_Pos+#19)  // 2nd best Caesar key chars
Call("BUILD_KEY")
Buf_Switch(#22)
Ins_Text("Key 1: ") Reg_Ins(14) Ins_Newline
Ins_Text("Key 2: ") Reg_Ins(15) Ins_Newline
Ins_Text("Key:   ")
for (#6=0; #6 < #19; #6++) {
    #9 = #6+130
    Ins_Char(#@9)
}
Ins_Newline
Ins_Newline

// decrypt the text with selected key
Ins_Text("Decrypted text:") Ins_Newline
Reg_Ins(10)
BOL
Call("DECRYPT_LINE")
BOL Reg_Copy(13,1)
EOL Ins_Newline

// Find English words from the text
Reg_Ins(13)
Call("FIND_ENGLISH_WORDS")
EOL
Ins_Newline
Num_Ins(#37, NOCR) IT(" of ")
Num_Ins(#25, NOCR) IT(" characters are English words. ")
Ins_Newline

Buf_Switch(#20) Buf_Quit(OK)
Buf_Switch(#21) Buf_Quit(OK)
Buf_Switch(#23) Buf_Quit(OK)
Buf_Switch(#24) Buf_Quit(OK)

Statline_Message("Done!")
Return

/////////////////////////////////////////////////////////////////////////////
//
// Caesar decrypt current line and count character frequencies.
//   in: #5 = step size, #7 = encryption key, #26 = num of chars in alphabet
//  out: #65...#90 = frequencies, #60 = number of chars

:CHARACTER_FREQUENCIES:
    Save_Pos
    for (#8 = 'A'; #8<='Z'; #8++) {
        #@8 = 0                         // reset frequency counters
    }
    #60 = 0                             // total number of chars
    while (!At_EOL) {
        if (Cur_Char >= 'A' && Cur_Char <= 'Z') {
            #8 = (Cur_Char-'A'+#26-#7) % #26 + 'A'  // decrypted char
            #@8++
            #60++
        }
        Char(#5)
    }
    Restore_Pos
Return

// Calculate Index of Coincidence (Kp).
//   in: character frequencies in #65...#90, #60 = num of chars
//  out: #51 = IC * 10000
//
:INDEX_OF_COINCIDENCE:
    Num_Push(10,15)
    #10 = 0
    for (#11 = 'A'; #11<='Z'; #11++) {
        #10 += (#@11 * (#@11-1))        // Calculate sigma{ni * (ni-1)}
    }
    #12 = #60 * (#60-1)                 // #12 = N * (N-1)
    #51 = #10 * 10000 / #12             // #51 = Kp * 10000
    Num_Pop(10,15)
Return

// Find best and 2nd best Caesar key for each character position of Vigenère key.
//   in: #5=step size (key length)
//  out: keys in buffer #24
//
:FIND_KEYS:
    for (#6 = 0; #6 < #5; #6++) {               // for each char position in the key
        #30 = -1                                // best key char found so far
        #31 = -1                                // 2nd best key char
        #32 = MAXNUM                            // smallest error found so far
        #33 = MAXNUM                            // 2nd smallest error found so far
        for (#7 = 0; #7 < #26; #7++) {          // for each possible key value
            #35 = 0                             // total frequency error compared to English
            Buf_Switch(#20)                     // text being analyzed
            Goto_Pos(#6)
            Call("CHARACTER_FREQUENCIES")
            Buf_Switch(#21)                     // English frequency table
            BOF
            for (#8 = 'A'; #8<='Z'; #8++) {     // calculate total frequency error
                #34 = Num_Eval(SUPPRESS+ADVANCE)
                #35 += abs((#@8*100000+50000)/#60-#34)
            }

            if (#35 < #32) {                    // found better match?
                #33 = #32
                #32 = #35
                #31 = #30
                #30 = #7
            } else {
                if (#35 < #33) {                // 2nd best match?
                    #33 = #35
                    #31 = #7
                }
            }
        }
        Buf_Switch(#24)                         // table for key canditates
        BOF
        Goto_Col(#6+1)
        Ins_Char(#30+'A', OVERWRITE)            // save the best match
        Line(1)
        Goto_Col(#6+1)
        Ins_Char(#31+'A', OVERWRITE)            // save 2nd best match
    }
    Buf_Switch(#22)                             // results buffer
Return

// Combine actual key from 1st and 2nd best Caesar key characters
// Use 1st key chars and (possibly) one character from 2nd key.
//  #4 = index of the char to be picked from 2nd key, -1 = none.
//  #5 = key length
//
:BUILD_KEY:
    Buf_Switch(#24)                     // table for key canditates
    BOF
    for (#6=0; #6<#5; #6++) {           // copy 1st key
        #8 = 130 + #6
        #@8 = Cur_Char
        Char(1)
    }
    if (#4 >= 0) {
        #8 = 130 + #4                   // pick one char from 2st key
        Line(1)
        Goto_Col(#4+1)
        #@8 = Cur_Char
    }
    Buf_Switch(#22)                     // results buffer
Return

// Decrypt text on current line
//   in: #5 = key length, #130...#189 = key
//
:DECRYPT_LINE:
    Num_Push(6,9)
    #6 = 0
    While (!At_EOL) {
       #9 = #6+130
       #7 = #@9
       #8 = (Cur_Char - #7 + #26) % #26 + 'A'   // decrypted char
       Ins_Char(#8, OVERWRITE)
       #6++
       if (#6 >= #5) {
           #6 = 0
       }
    }
    Num_Pop(6,9)
Return

// Find English words from text on current line
//  out: #37 = number of chars matched
//
:FIND_ENGLISH_WORDS:
    Buf_Switch(#23)                     // dictionary
    BOF
    While (!At_EOF) {
        Reg_Copy_Block(12, Cur_Pos, EOL_Pos)
        if (Reg_Size(12) > 2) {
            Buf_Switch(#22)             // buffer for results
            BOL
            while (Search_Block(@12, Cur_Pos, EOL_Pos, NOERR)) {
                Reg_Ins(12, OVERWRITE)
            }
            Buf_Switch(#23)
        }
        Line(1, ERRBREAK)
    }

    Buf_Switch(#22)
    BOL
    #37 = Search_Block("|V", Cur_Pos, EOL_Pos, ALL+NOERR)
Return

V (Vlang)

Translation of: Go
import strings
const encoded = 
    "MOMUD EKAPV TQEFM OEVHP AJMII CDCTI FGYAG JSPXY ALUYM NSMYH" +
    "VUXJE LEPXJ FXGCM JHKDZ RYICU HYPUS PGIGM OIYHF WHTCQ KMLRD" +
    "ITLXZ LJFVQ GHOLW CUHLO MDSOE KTALU VYLNZ RFGBX PHVGA LWQIS" +
    "FGRPH JOOFW GUBYI LAPLA LCAFA AMKLG CETDW VOELJ IKGJB XPHVG" +
    "ALWQC SNWBU BYHCU HKOCE XJEYK BQKVY KIIEH GRLGH XEOLW AWFOJ" +
    "ILOVV RHPKD WIHKN ATUHN VRYAQ DIVHX FHRZV QWMWV LGSHN NLVZS" +
    "JLAKI FHXUF XJLXM TBLQV RXXHR FZXGV LRAJI EXPRV OSMNP KEPDT" +
    "LPRWM JAZPK LQUZA ALGZX GVLKL GJTUI ITDSU REZXJ ERXZS HMPST" +
    "MTEOE PAPJH SMFNB YVQUZ AALGA YDNMP AQOWT UHDBV TSMUE UIMVH" +
    "QGVRW AEFSP EMPVE PKXZY WLKJA GWALT VYYOB YIXOK IHPDS EVLEV" +
    "RVSGB JOGYW FHKBL GLXYA MVKIS KIEHY IMAPX UOISK PVAGN MZHPW" +
    "TTZPV XFCCD TUHJH WLAPF YULTB UXJLN SIJVV YOVDJ SOLXG TGRVO" +
    "SFRII CTMKO JFCQF KTINQ BWVHG TENLH HOGCS PSFPV GJOKM SIFPR" +
    "ZPAAS ATPTZ FTPPD PORRF TAXZP KALQA WMIUD BWNCT LEFKO ZQDLX" +
    "BUXJL ASIMR PNMBF ZCYLV WAPVF QRHZV ZGZEF KBYIO OFXYE VOWGB" +
    "BXVCB XBAWG LQKCM ICRRX MACUO IKHQU AJEGL OIJHH XPVZW JEWBA" +
    "FWAML ZZRXJ EKAHV FASMU LVVUT TGK"
 
const freq = [
    0.08167, 0.01492, 0.02782, 0.04253, 0.12702, 0.02228, 0.02015,
    0.06094, 0.06966, 0.00153, 0.00772, 0.04025, 0.02406, 0.06749,
    0.07507, 0.01929, 0.00095, 0.05987, 0.06327, 0.09056, 0.02758,
    0.00978, 0.02360, 0.00150, 0.01974, 0.00074,
]
 
fn sum(a []f64) f64 {
    mut s := 0.0
    for f in a {
        s += f
    }
    return s
}
 
fn best_match(a []f64) int {
    s := sum(a)
    mut best_fit, mut best_rotate := 1e100, 0
    for rotate in 0..26 {
        mut fit := 0.0
        for i in 0..26 {
            d := a[(i+rotate)%26]/s - freq[i]
            fit += d * d / freq[i]
        }
        if fit < best_fit {
            best_fit, best_rotate = fit, rotate
        }
    }
    return best_rotate
}
 
fn freq_every_nth(msg []int, mut key []u8) f64 {
    l := msg.len
    interval := key.len
    mut out := []f64{len: 26}
    mut accu := []f64{len: 26}
    for j in 0..interval {
        for z in 0..26 {
            out[z] = 0.0
        }
        for i := j; i < l; i += interval {
            out[msg[i]]++
        }
        rot := best_match(out)
        key[j] = u8(rot + 65)
        for i := 0; i < 26; i++ {
            accu[i] += out[(i+rot)%26]
        }
    }
    s := sum(accu)
    mut ret := 0.0
    for i := 0; i < 26; i++ {
        d := accu[i]/s - freq[i]
        ret += d * d / freq[i]
    }
    return ret
}
 
fn decrypt(text string, key string) string {
    mut sb := strings.new_builder(128)
    mut ki := 0
    for c in text {
        if c < 'A'[0] || c > 'Z'[0] {
            continue
        }
        ci := (c - key[ki] + 26) % 26
        sb.write_rune(ci + 65)
        ki = (ki + 1) % key.len
    }
    return sb.str()
}
 
fn main() {
    enc := encoded.replace(" ", "")
    mut txt := []int{len: enc.len}
    for i in 0..txt.len {
        txt[i] = int(enc[i] - 'A'[0])
    }
    mut best_fit, mut best_key := 1e100, ""
    println("  Fit     Length   Key")
    for j := 1; j <= 26; j++ {
        mut key := []u8{len: j}
        fit := freq_every_nth(txt, mut key)
        s_key := key.bytestr()
        print("${fit:.6}    ${j:2}     $s_key")
        if fit < best_fit {
            best_fit, best_key = fit, s_key
            print(" <--- best so far")
        }
        println('')
    }
    println("\nBest key : $best_key")
    println("\nDecrypted text:\n${decrypt(enc, best_key)}")
}
Output:

Note: carriage returns inserted into decrypted text after every 80 characters to make it more readable.

  Fit     Length   Key
2.984348     1     E <--- best so far
2.483684     2     EC <--- best so far
2.642487     3     TEE
1.976651     4     THEC <--- best so far
2.356881     5     EEEPU
2.203129     6     TCECEC
1.051163     7     THECSAS <--- best so far
1.645763     8     TJQGAHET
2.001380     9     VEIZSEGNT
1.824476    10     ECEGAWQTDS
1.623083    11     TNLUSRXPTAJ
1.253527    12     XLECTHQGTHEC
1.399037    13     LJJTDGFNOTENR
0.152370    14     THECHESHIRECAT <--- best so far
1.533951    15     JNTOOEEXFTGQTNH
1.068182    16     TJTSAEETEXHPXHNE
1.034093    17     AZRAXUHEJLREEXIEE
1.443345    18     VNIZQPALEPTSXSEXUC
1.090977    19     FUCAITCSLVTEZDUDEHS
0.979868    20     EQXGAHWTTQECEWUGXHPI
0.789410    21     HVRCSAFTHEBDLSTAERSES
0.881380    22     TVIJTCIGKAQPELECRXPTNC
0.952456    23     KKEQXGPWTCQEELIEHXUWASV
0.715968    24     ELAIXHQTTIEDXJETTNTGAEPC
0.891258    25     OTJUUEGERDNQTUQEAGWUTIEOA
0.852784    26     IGITEGECAGAVUNLJAHASAVTETW

Best key : THECHESHIRECAT

Decrypted text:
THISWASTHEPOEMTHATALICEREADJABBERWOCKYTWASBRILLIGANDTHESLITHYTOVESDIDGYREANDGIMB
LEINTHEWABEALLMIMSYWERETHEBOROGOVESANDTHEMOMERATHSOUTGRABEBEWARETHEJABBERWOCKMYS
ONTHEJAWSTHATBITETHECLAWSTHATCATCHBEWARETHEJUBJUBBIRDANDSHUNTHEFRUMIOUSBANDERSNA
TCHHETOOKHISVORPALSWORDINHANDLONGTIMETHEMANXOMEFOEHESOUGHTSORESTEDHEBYTHETUMTUMT
REEANDSTOODAWHILEINTHOUGHTANDASINUFFISHTHOUGHTHESTOODTHEJABBERWOCKWITHEYESOFFLAM
ECAMEWHIFFLINGTHROUGHTHETULGEYWOODANDBURBLEDASITCAMEONETWOONETWOANDTHROUGHANDTHR
OUGHTHEVORPALBLADEWENTSNICKERSNACKHELEFTITDEADANDWITHITSHEADHEWENTGALUMPHINGBACK
ANDHASTTHOUSLAINTHEJABBERWOCKCOMETOMYARMSMYBEAMISHBOYOFRABJOUSDAYCALLOOHCALLAYHE
CHORTLEDINHISJOYTWASBRILLIGANDTHESLITHYTOVESDIDGYREANDGIMBLEINTHEWABEALLMIMSYWER
ETHEBOROGOVESANDTHEMOMERATHSOUTGRABEITSEEMSVERYPRETTYSHESAIDWHENSHEHADFINISHEDIT
BUTITSRATHERHARDTOUNDERSTAND

Wren

Translation of: Kotlin
Library: Wren-math
Library: Wren-iterate
Library: Wren-str
Library: Wren-fmt
import "./math" for Nums
import "./iterate" for Stepped
import "./str" for Char, Str
import "./fmt" for Fmt

var encoded = 
    "MOMUD EKAPV TQEFM OEVHP AJMII CDCTI FGYAG JSPXY ALUYM NSMYH" +
    "VUXJE LEPXJ FXGCM JHKDZ RYICU HYPUS PGIGM OIYHF WHTCQ KMLRD" +
    "ITLXZ LJFVQ GHOLW CUHLO MDSOE KTALU VYLNZ RFGBX PHVGA LWQIS" +
    "FGRPH JOOFW GUBYI LAPLA LCAFA AMKLG CETDW VOELJ IKGJB XPHVG" +
    "ALWQC SNWBU BYHCU HKOCE XJEYK BQKVY KIIEH GRLGH XEOLW AWFOJ" +
    "ILOVV RHPKD WIHKN ATUHN VRYAQ DIVHX FHRZV QWMWV LGSHN NLVZS" +
    "JLAKI FHXUF XJLXM TBLQV RXXHR FZXGV LRAJI EXPRV OSMNP KEPDT" +
    "LPRWM JAZPK LQUZA ALGZX GVLKL GJTUI ITDSU REZXJ ERXZS HMPST" +
    "MTEOE PAPJH SMFNB YVQUZ AALGA YDNMP AQOWT UHDBV TSMUE UIMVH" +
    "QGVRW AEFSP EMPVE PKXZY WLKJA GWALT VYYOB YIXOK IHPDS EVLEV" +
    "RVSGB JOGYW FHKBL GLXYA MVKIS KIEHY IMAPX UOISK PVAGN MZHPW" +
    "TTZPV XFCCD TUHJH WLAPF YULTB UXJLN SIJVV YOVDJ SOLXG TGRVO" +
    "SFRII CTMKO JFCQF KTINQ BWVHG TENLH HOGCS PSFPV GJOKM SIFPR" +
    "ZPAAS ATPTZ FTPPD PORRF TAXZP KALQA WMIUD BWNCT LEFKO ZQDLX" +
    "BUXJL ASIMR PNMBF ZCYLV WAPVF QRHZV ZGZEF KBYIO OFXYE VOWGB" +
    "BXVCB XBAWG LQKCM ICRRX MACUO IKHQU AJEGL OIJHH XPVZW JEWBA" +
    "FWAML ZZRXJ EKAHV FASMU LVVUT TGK"

var freq = [
    0.08167, 0.01492, 0.02782, 0.04253, 0.12702, 0.02228, 0.02015,
    0.06094, 0.06966, 0.00153, 0.00772, 0.04025, 0.02406, 0.06749,
    0.07507, 0.01929, 0.00095, 0.05987, 0.06327, 0.09056, 0.02758,
    0.00978, 0.02360, 0.00150, 0.01974, 0.00074
]

var bestMatch = Fn.new { |a|
    var sum = Nums.sum(a)
    var bestFit = 1e100
    var bestRotate = 0
    for (rotate in 0..25) {
        var fit = 0
        for (i in 0..25) {
            var d = a[(i + rotate) % 26] / sum - freq[i]
                fit = fit + d * d / freq[i]
        }
        if (fit < bestFit) {
            bestFit = fit
            bestRotate = rotate
        }
    }
    return bestRotate
}

var freqEveryNth = Fn.new { |msg, key|
    var len = msg.count
    var interval = key.count
    var out = List.filled(26, 0)
    var accu = List.filled(26, 0)
    for (j in 0...interval) {
        for (i in 0..25) out[i] = 0
        for (i in Stepped.new(j...len, interval)) out[msg[i]] = out[msg[i]] + 1
        var rot = bestMatch.call(out)
        key[j] = Char.fromCode(rot + 65)
        for (i in 0..25) accu[i] = accu[i] + out[(i + rot) % 26]
    }
    var sum = Nums.sum(accu)
    var ret = 0
    for (i in 0..25) {
        var d = accu[i] / sum - freq[i]
        ret = ret + d * d / freq[i]
    }
    return ret
}

var decrypt = Fn.new { |text, key|
    var sb = ""
    var ki = 0
    for (c in text) {
        if (Char.isAsciiUpper(c)) {
            var ci = (c.bytes[0] - key[ki].bytes[0] +  26) % 26
            sb = sb + Char.fromCode(ci + 65)
            ki = (ki + 1) % key.count
        }
    }
    return sb
}

var enc = encoded.replace(" ", "")
var txt = List.filled(enc.count, 0)
for (i in 0...txt.count) txt[i] = Char.code(enc[i]) - 65
var bestFit = 1e100
var bestKey = ""
var f = "$f    $2d     $s"
System.print("  Fit     Length   Key")
for (j in 1..26) {
    var key = List.filled(j, "")
    var fit = freqEveryNth.call(txt, key)
    var sKey = key.join("")
    Fmt.write(f, fit, j, sKey)
    if (fit < bestFit) {
       bestFit = fit
       bestKey = sKey
       System.write(" <--- best so far")
    }
    System.print()
}
System.print()
System.print("Best key : %(bestKey)")
System.print("\nDecrypted text:\n%(decrypt.call(enc, bestKey))")
Output:
  Fit     Length   Key
2.984348     1     E <--- best so far
2.483684     2     EC <--- best so far
2.642487     3     TEE
1.976651     4     THEC <--- best so far
2.356881     5     EEEPU
2.203129     6     TCECEC
1.051163     7     THECSAS <--- best so far
1.645763     8     TJQGAHET
2.001380     9     VEIZSEGNT
1.824476    10     ECEGAWQTDS
1.623083    11     TNLUSRXPTAJ
1.253527    12     XLECTHQGTHEC
1.399037    13     LJJTDGFNOTENR
0.152370    14     THECHESHIRECAT <--- best so far
1.533951    15     JNTOOEEXFTGQTNH
1.068182    16     TJTSAEETEXHPXHNE
1.034093    17     AZRAXUHEJLREEXIEE
1.443345    18     VNIZQPALEPTSXSEXUC
1.090977    19     FUCAITCSLVTEZDUDEHS
0.979868    20     EQXGAHWTTQECEWUGXHPI
0.789410    21     HVRCSAFTHEBDLSTAERSES
0.881380    22     TVIJTCIGKAQPELECRXPTNC
0.952456    23     KKEQXGPWTCQEELIEHXUWASV
0.715968    24     ELAIXHQTTIEDXJETTNTGAEPC
0.891258    25     OTJUUEGERDNQTUQEAGWUTIEOA
0.852784    26     IGITEGECAGAVUNLJAHASAVTETW

Best key : THECHESHIRECAT

Decrypted text:
THISWASTHEPOEMTHATALICEREADJABBERWOCKYTWASBRILLIGANDTHESLITHYTOVESDIDGYREANDGIMBLEINTHEWABEALLMIMSYWERETHEBOROGOVESANDTHEMOMERATHSOUTGRABEBEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCHBEWARETHEJUBJUBBIRDANDSHUNTHEFRUMIOUSBANDERSNATCHHETOOKHISVORPALSWORDINHANDLONGTIMETHEMANXOMEFOEHESOUGHTSORESTEDHEBYTHETUMTUMTREEANDSTOODAWHILEINTHOUGHTANDASINUFFISHTHOUGHTHESTOODTHEJABBERWOCKWITHEYESOFFLAMECAMEWHIFFLINGTHROUGHTHETULGEYWOODANDBURBLEDASITCAMEONETWOONETWOANDTHROUGHANDTHROUGHTHEVORPALBLADEWENTSNICKERSNACKHELEFTITDEADANDWITHITSHEADHEWENTGALUMPHINGBACKANDHASTTHOUSLAINTHEJABBERWOCKCOMETOMYARMSMYBEAMISHBOYOFRABJOUSDAYCALLOOHCALLAYHECHORTLEDINHISJOYTWASBRILLIGANDTHESLITHYTOVESDIDGYREANDGIMBLEINTHEWABEALLMIMSYWERETHEBOROGOVESANDTHEMOMERATHSOUTGRABEITSEEMSVERYPRETTYSHESAIDWHENSHEHADFINISHEDITBUTITSRATHERHARDTOUNDERSTAND

zkl

Translation of: Python
var[const] uppercase=["A".."Z"].pump(String),
   english_frequences=T( // A..Z
        0.08167, 0.01492, 0.02782, 0.04253, 0.12702, 0.02228, 0.02015,
        0.06094, 0.06966, 0.00153, 0.00772, 0.04025, 0.02406, 0.06749,
        0.07507, 0.01929, 0.00095, 0.05987, 0.06327, 0.09056, 0.02758,
        0.00978, 0.02360, 0.00150, 0.01974, 0.00074);
 
fcn vigenere_decrypt(target_freqs, input){ // ( (float,...), string)
   nchars,ordA   :=uppercase.len(),"A".toAsc();
   sorted_targets:=target_freqs.sort();
 
   frequency:='wrap(input){  // (n,n,n,n,...), n is ASCII index ("A"==65)
      result:=uppercase.pump(List(),List.fp1(0)); // ( ("A",0),("B",0) ...)
      foreach c in (input){ result[c - ordA][1] += 1 }
      result   // --> mutable list of mutable lists ( ("A",Int)...("Z",Int) )
   };
   correlation:='wrap(input){  // (n,n,n,n,...), n is ASCII index ("A"==65)
      result,freq:=0.0, frequency(input);
      freq.sort(fcn([(_,a)],[(_,b)]){ a<b });  // sort letters by frequency
      foreach i,f in (freq.enumerate()){ result+=sorted_targets[i]*f[1] }
      result	// -->Float
   };
 
   cleaned:=input.toUpper().pump(List,uppercase.holds,Void.Filter,"toAsc");
 
   best_len,best_corr := 0,-100.0;
    # Assume that if there are less than 20 characters
    # per column, the key's too long to guess
   foreach i in ([2..cleaned.len()/20]){
      pieces:=(i).pump(List,List.copy);		// ( (),() ... )
      foreach c in (cleaned){ pieces[__cWalker.idx%i].append(c) }
 
        # The correlation seems to increase for smaller
        # pieces/longer keys, so weigh against them a little
      corr:=-0.5*i + pieces.apply(correlation).sum(0.0);
      if(corr>best_corr) best_len,best_corr=i,corr;
   }
   if(best_len==0) return("Text is too short to analyze", "");
 
   pieces:=best_len.pump(List,List.copy);
   foreach c in (cleaned){ pieces[__cWalker.idx%best_len].append(c) }
 
   key,freqs := "",pieces.apply(frequency);
   foreach fr in (freqs){
      fr.sort(fcn([(_,a)],[(_,b)]){ a>b });  // reverse sort by freq
      m,max_corr := 0,0.0;
      foreach j in (nchars){
         corr,c := 0.0,ordA + j;
	 foreach frc in (fr){
	    d:=(frc[0].toAsc() - c + nchars) % nchars;
 	    corr+=target_freqs[d]*frc[1];
	    if(corr>max_corr) m,max_corr=j,corr;
	 }
      }
      key+=(m + ordA).toChar();
   }
 
   cleaned.enumerate().apply('wrap([(i,c])){
      ( (c - (key[i%best_len]).toAsc() + nchars)%nchars + ordA ).toChar()
   }).concat() : 
   T(key,_);
}
encryptedText:=
#<<<
"MOMUD EKAPV TQEFM OEVHP AJMII CDCTI FGYAG JSPXY ALUYM NSMYH
VUXJE LEPXJ FXGCM JHKDZ RYICU HYPUS PGIGM OIYHF WHTCQ KMLRD
ITLXZ LJFVQ GHOLW CUHLO MDSOE KTALU VYLNZ RFGBX PHVGA LWQIS
FGRPH JOOFW GUBYI LAPLA LCAFA AMKLG CETDW VOELJ IKGJB XPHVG
ALWQC SNWBU BYHCU HKOCE XJEYK BQKVY KIIEH GRLGH XEOLW AWFOJ
ILOVV RHPKD WIHKN ATUHN VRYAQ DIVHX FHRZV QWMWV LGSHN NLVZS
JLAKI FHXUF XJLXM TBLQV RXXHR FZXGV LRAJI EXPRV OSMNP KEPDT
LPRWM JAZPK LQUZA ALGZX GVLKL GJTUI ITDSU REZXJ ERXZS HMPST
MTEOE PAPJH SMFNB YVQUZ AALGA YDNMP AQOWT UHDBV TSMUE UIMVH
QGVRW AEFSP EMPVE PKXZY WLKJA GWALT VYYOB YIXOK IHPDS EVLEV
RVSGB JOGYW FHKBL GLXYA MVKIS KIEHY IMAPX UOISK PVAGN MZHPW
TTZPV XFCCD TUHJH WLAPF YULTB UXJLN SIJVV YOVDJ SOLXG TGRVO
SFRII CTMKO JFCQF KTINQ BWVHG TENLH HOGCS PSFPV GJOKM SIFPR
ZPAAS ATPTZ FTPPD PORRF TAXZP KALQA WMIUD BWNCT LEFKO ZQDLX
BUXJL ASIMR PNMBF ZCYLV WAPVF QRHZV ZGZEF KBYIO OFXYE VOWGB
BXVCB XBAWG LQKCM ICRRX MACUO IKHQU AJEGL OIJHH XPVZW JEWBA
FWAML ZZRXJ EKAHV FASMU LVVUT TGK";
#<<<
key,decoded:=vigenere_decrypt(english_frequences,encryptedText);
println("Key:", key);
println("Decoded text:", decoded);
Output:
Key:THECHESHIRECAT
Decoded text:THISWASTHEPOEMTHATALICEREADJABBERWOCKYTWASBRILLIGANDTHESLITHYTOVESDIDGYREANDGIMBLEINTHEWABEALLMIMSYWERETHEBOROGOVESANDTHEMOMERATHSOUTGRABEBEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCHBEWARETHEJUBJUBBIRDANDSHUNTHEFRUMIOUSBANDERSNATCHHETOOKHISVORPALSWORDINHANDLONGTIMETHEMANXOMEFOEHESOUGHTSORESTEDHEBYTHETUMTUMTREEANDSTOODAWHILEINTHOUGHTANDASINUFFISHTHOUGHTHESTOODTHEJABBERWOCKWITHEYESOFFLAMECAMEWHIFFLINGTHROUGHTHETULGEYWOODANDBURBLEDASITCAMEONETWOONETWOANDTHROUGHANDTHROUGHTHEVORPALBLADEWENTSNICKERSNACKHELEFTITDEADANDWITHITSHEADHEWENTGALUMPHINGBACKANDHASTTHOUSLAINTHEJABBERWOCKCOMETOMYARMSMYBEAMISHBOYOFRABJOUSDAYCALLOOHCALLAYHECHORTLEDINHISJOYTWASBRILLIGANDTHESLITHYTOVESDIDGYREANDGIMBLEINTHEWABEALLMIMSYWERETHEBOROGOVESANDTHEMOMERATHSOUTGRABEITSEEMSVERYPRETTYSHESAIDWHENSHEHADFINISHEDITBUTITSRATHERHARDTOUNDERSTAND