Vigenère cipher/Cryptanalysis: Difference between revisions
Thundergnat (talk | contribs) (Rename Perl 6 -> Raku, alphabetize, minor clean-up) |
|||
Line 1: | Line 1: | ||
{{task|Encryption}} |
{{task|Encryption}} |
||
[[Category:String manipulation]] |
|||
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: |
|||
{{omit from|GUISS|would need to install an application that could do this}} |
|||
<pre> |
|||
{{omit from|Openscad}} |
|||
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 |
|||
</pre> |
|||
;Task: |
|||
Letter frequencies for English can be found [[wp:Letter_frequency|here]]. |
|||
Implement a [[wp:Vigen%C3%A8re_cipher|Vigenère cypher]], both encryption and decryption. |
|||
The program should handle keys and text of unequal length, |
|||
and should capitalize everything and discard non-alphabetic characters. <br> |
|||
(If your program handles non-alphabetic characters in another way, |
|||
make a note of it.) |
|||
;Related tasks: |
|||
* [[Caesar cipher]] |
|||
* [[Rot-13]] |
|||
* [[Substitution Cipher]] |
|||
<br><br> |
|||
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. |
|||
=={{header|Ada}}== |
=={{header|Ada}}== |
||
The program is not fully auto, but makes a small number of suggestions for the right key and plaintext. |
|||
<lang Ada>with Ada.Text_IO; |
|||
<lang Ada>WITH Ada.Text_IO, Ada.Characters.Handling; |
|||
procedure Vignere_Cryptanalysis is |
|||
USE Ada.Text_IO, Ada.Characters.Handling; |
|||
PROCEDURE Main IS |
|||
subtype Letter is Character range 'A' .. 'Z'; |
|||
SUBTYPE Alpha IS Character RANGE 'A' .. 'Z'; |
|||
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; |
|||
</lang> |
|||
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; |
|||
{{out}} |
|||
function "-"(X, Y: Letter) return Letter is |
|||
<pre>Beware the Jabberwock, my son! The jaws that bite, the claws that catch! |
|||
begin |
|||
VIGENERECIPHER |
|||
return Character'Val( ( (Character'Pos(X)-Character'Pos('A')) |
|||
Encrypted: WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY |
|||
- (Character'Pos(Y)-Character'Pos('A')) ) mod 26 |
|||
Decrypted: BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH</pre> |
|||
+ Character'Pos('A')); |
|||
end; |
|||
=={{header|ALGOL 68}}== |
|||
type Frequency_Array is array (Letter) of Float; |
|||
{{trans|C++}} Note: This specimen retains the original [[Vigenère_Cipher#C++|C++]] coding style. |
|||
{{works with|ALGOL 68|Revision 1 - no extensions to language used.}} |
|||
{{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].}} |
|||
{{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 := ""; |
|||
PROC vigenere cipher = (REF STRING key)VOID: |
|||
English: Frequency_Array := |
|||
( |
|||
( 0.08167, 0.01492, 0.02782, 0.04253, 0.12702, 0.02228, 0.02015, |
|||
FOR i FROM LWB key TO UPB key DO |
|||
0.06094, 0.06966, 0.00153, 0.00772, 0.04025, 0.02406, 0.06749, |
|||
IF key[i] >= "A" AND key[i] <= "Z" THEN |
|||
0.07507, 0.01929, 0.00095, 0.05987, 0.06327, 0.09056, 0.02758, |
|||
key +:= key[i] FI; |
|||
0.00978, 0.02360, 0.00150, 0.01974, 0.00074 ); |
|||
IF key[i] >= "a" AND key[i] <= "z" THEN |
|||
key +:= REPR(ABS key[i] + ABS"A" - ABS"a") FI |
|||
OD |
|||
); |
|||
PROC encrypt = (STRING text)STRING: |
|||
function Get_Frequency(S: String) return Frequency_Array is |
|||
( |
|||
Result: Frequency_Array := (others => 0.0); |
|||
STRING out := ""; |
|||
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; |
|||
INT j := LWB text; |
|||
function Remove_Whitespace(S: String) return String is |
|||
FOR i FROM LWB text TO UPB text DO |
|||
begin |
|||
CHAR c := text[i]; |
|||
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; |
|||
IF c >= "a" AND c <= "z" THEN |
|||
function Distance(A, B: Frequency_Array; |
|||
c := REPR(ABS c + (ABS"A" - ABS"a")) FI; |
|||
Offset: Character := 'A') return Float is |
|||
IF c >= "A" AND c <= "Z" THEN |
|||
out +:= REPR((ABS c + ABS key[j] - 2*ABS"A") MOD 26 + ABS"A"); |
|||
Diff: Float; |
|||
j := j MOD UPB key + 1 |
|||
begin |
|||
FI |
|||
for C in A'Range loop |
|||
OD; |
|||
Diff := A(C+Offset) - B(C); |
|||
Result := Result + (Diff * Diff); |
|||
end loop; |
|||
return Result; |
|||
end Distance; |
|||
out |
|||
function Find_Key(Cryptogram: String; Key_Length: Positive) return String is |
|||
); |
|||
PROC decrypt = (STRING text)STRING: |
|||
function Find_Caesar_Key(S: String) return Letter is |
|||
( |
|||
Frequency: Frequency_Array := Get_Frequency(S); |
|||
STRING out; |
|||
Candidate: Letter := 'A'; -- a fake candidate |
|||
Candidate_Dist : Float := Distance(Frequency, English, 'A'); |
|||
New_Dist: Float; |
|||
INT j := LWB text; |
|||
FOR i FROM LWB text TO UPB text DO |
|||
CHAR c := text[i]; |
|||
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] + 26) MOD 26 + ABS"A"); |
|||
j := j MOD UPB key + 1 |
|||
FI |
|||
OD; |
|||
end loop; |
|||
return Candidate; |
|||
end Find_Caesar_Key; |
|||
out |
|||
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; |
|||
main: |
|||
Key: String(1 .. Key_Length); |
|||
( |
|||
vigenere cipher(key:="VIGENERECIPHER"); |
|||
STRING original := "Beware the Jabberwock, my son! The jaws that bite, the claws that catch!"; |
|||
S: String renames Cryptogram; |
|||
STRING encrypted := encrypt(original); |
|||
STRING decrypted := decrypt(encrypted); |
|||
print((original, new line)); |
|||
begin |
|||
print(("Encrypted: ", encrypted, new line)); |
|||
for I in Key'Range loop |
|||
print(("Decrypted: ", decrypted, new line)) |
|||
Key(I) := Find_Caesar_Key(Get_Slide(S(S'First+I-1 .. S'Last), |
|||
)</lang> |
|||
Key_Length)); |
|||
{{out}} |
|||
end loop; |
|||
<pre> |
|||
return Key; |
|||
Beware the Jabberwock, my son! The jaws that bite, the claws that catch! |
|||
end Find_Key; |
|||
Encrypted: WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY |
|||
Decrypted: BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH |
|||
</pre> |
|||
=={{header|Applesoft BASIC}}== |
|||
function Key_Char(Key: String; Index: Positive) return Letter is |
|||
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. |
|||
begin |
|||
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. |
|||
if Index > Key'Last then |
|||
<lang Applesoft BASIC> |
|||
return Key_Char(Key, Index-Key'Last); |
|||
100 : |
|||
110 REM VIGENERE CIPHER |
|||
return Key(Index); |
|||
120 : |
|||
end if; |
|||
200 REM SET-UP |
|||
end Key_Char; |
|||
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 |
|||
=={{header|AutoHotkey}}== |
|||
Ciphertext: String := Remove_Whitespace( |
|||
<lang AutoHotkey>Key = VIGENERECIPHER |
|||
"MOMUD EKAPV TQEFM OEVHP AJMII CDCTI FGYAG JSPXY ALUYM NSMYH" & |
|||
Text= Beware the Jabberwock, my son! The jaws that bite, the claws that catch! |
|||
"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"); |
|||
out := "Input =" text "`nkey =" key "`nCiphertext =" (c := VigenereCipher(Text, Key)) "`nDecrypted =" VigenereDecipher(c, key) |
|||
Best_Plain: String := Ciphertext; |
|||
MsgBox % clipboard := out |
|||
Best_Dist: Float := Distance(English, Get_Frequency(Best_Plain)); |
|||
Best_Key: String := Ciphertext; |
|||
Best_Key_L: Natural := 0; |
|||
VigenereCipher(Text, Key){ |
|||
begin -- Vignere_Cryptanalysis |
|||
StringUpper, Text, Text |
|||
for I in 1 .. Ciphertext'Length/10 loop |
|||
Text := RegExReplace(Text, "[^A-Z]") |
|||
declare |
|||
Loop Parse, Text |
|||
Key: String(1 .. I) := Find_Key(Ciphertext, I); |
|||
{ |
|||
Plaintext: String(Ciphertext'Range); |
|||
a := Asc(A_LoopField) - Asc("A") |
|||
begin |
|||
b := Asc(SubStr(Key, 1+Mod(A_Index-1, StrLen(Key)), 1)) - Asc("A") |
|||
for I in Ciphertext'Range loop |
|||
out .= Chr(Mod(a+b,26)+Asc("A")) |
|||
Plaintext(I) := Ciphertext(I) - Key_Char(Key, I); |
|||
} |
|||
end loop; |
|||
return out |
|||
if Distance(English, Get_Frequency(Plaintext)) < Best_Dist then |
|||
} |
|||
Best_Plain := Plaintext; |
|||
Best_Dist := Distance(English, Get_Frequency(Plaintext)); |
|||
VigenereDecipher(Text, key){ |
|||
Best_Key(1 .. I) := Key; |
|||
Loop Parse, key |
|||
Best_Key_L := I; |
|||
decoderKey .= Chr(26-(Asc(A_LoopField)-65)+65) |
|||
if Best_dist < 0.01 then |
|||
return VigenereCipher(Text, decoderKey) |
|||
declare |
|||
}</lang> |
|||
use Ada.Text_IO; |
|||
{{out}} |
|||
begin |
|||
<pre>Input =Beware the Jabberwock, my son! The jaws that bite, the claws that catch! |
|||
Put_Line("Key =" & Best_Key(1 .. Best_Key_L)); |
|||
key =VIGENERECIPHER |
|||
Put_Line("Distance = " & Float'Image(Best_Dist)); |
|||
Ciphertext =WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY |
|||
New_Line; |
|||
Decrypted =BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH</pre> |
|||
Put_Line("Plaintext ="); |
|||
Put_Line(Best_Plain); |
|||
=={{header|BBC BASIC}}== |
|||
New_Line; New_Line; |
|||
<lang bbcbasic> key$ = "LEMON" |
|||
plaintext$ = "ATTACK AT DAWN" |
|||
ciphertext$ = FNencrypt(plaintext$, key$) |
|||
end if; |
|||
PRINT "Key = """ key$ """" |
|||
end; |
|||
PRINT "Plaintext = """ plaintext$ """" |
|||
end loop; |
|||
PRINT "Ciphertext = """ ciphertext$ """" |
|||
end Vignere_Cryptanalysis;</lang> |
|||
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> |
|||
=={{header|Befunge}}== |
|||
The text to encrypt is read from stdin. The key is the string literal at the start of the program. |
|||
<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> |
|||
{{out}} |
|||
<pre>Beware the Jabberwock, my son! The jaws that bite, the claws that catch! |
|||
WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY</pre> |
|||
The decrypter is essentially identical, except for a change of sign on the last line. |
|||
<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> |
|||
{{out}} |
|||
<pre>WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY |
|||
BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH</pre> |
|||
=={{header|C}}== |
=={{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. |
|||
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. |
|||
<lang C>#include <stdio.h> |
<lang C>#include <stdio.h> |
||
#include <stdlib.h> |
#include <stdlib.h> |
||
#include <string.h> |
#include <string.h> |
||
#include <stdbool.h> |
|||
#include <ctype.h> |
#include <ctype.h> |
||
#include < |
#include <getopt.h> |
||
#define NUMLETTERS 26 |
|||
const char *encoded = |
|||
#define BUFSIZE 4096 |
|||
"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"; |
|||
char *get_input(void); |
|||
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 main(int argc, char *argv[]) |
|||
int best_match(const double *a, const double *b) { |
|||
{ |
|||
double sum = 0, fit, d, best_fit = 1e100; |
|||
char const usage[] = "Usage: vinigere [-d] key"; |
|||
int i, rotate, best_rotate = 0; |
|||
char sign = 1; |
|||
char const plainmsg[] = "Plain text: "; |
|||
char const cryptmsg[] = "Cipher text: "; |
|||
for (rotate = 0; rotate < 26; rotate++) { |
|||
bool encrypt = true; |
|||
int opt; |
|||
for (i = 0; i < 26; i++) { |
|||
d = a[(i + rotate) % 26] / sum - b[i]; |
|||
fit += d * d / b[i]; |
|||
} |
|||
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; |
|||
} |
} |
||
} |
} |
||
if (argc - optind != 1) { |
|||
return best_rotate; |
|||
fprintf(stderr, "%s requires one argument and one only\n", argv[0]); |
|||
} |
|||
fprintf(stderr, "\n%s\n", usage); |
|||
return 1; |
|||
} |
|||
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; |
|||
// Convert argument into array of shifts |
|||
for (j = 0; j < interval; j++) { |
|||
char const *const restrict key = argv[optind]; |
|||
for (i = 0; i < 26; i++) |
|||
size_t const keylen = strlen(key); |
|||
char shifts[keylen]; |
|||
for (i = j; i < len; i += interval) |
|||
out[msg[i]]++; |
|||
char const *restrict plaintext = NULL; |
|||
key[j] = rot = best_match(out, freq); |
|||
for (size_t i = 0; i < keylen; i++) { |
|||
if (!(isalpha(key[i]))) { |
|||
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; |
|||
} |
} |
||
do { |
|||
for (i = 0, sum = 0; i < 26; i++) |
|||
fflush(stdout); |
|||
// Print "Plain text: " if encrypting and "Cipher text: " if |
|||
// decrypting |
|||
printf("%s", (encrypt) ? plainmsg : cryptmsg); |
|||
plaintext = get_input(); |
|||
if (plaintext == NULL) { |
|||
fprintf(stderr, "Error getting input\n"); |
|||
return 4; |
|||
} |
|||
} while (strcmp(plaintext, "") == 0); // Reprompt if entry is empty |
|||
size_t const plainlen = strlen(plaintext); |
|||
char* const restrict ciphertext = calloc(plainlen + 1, sizeof *ciphertext); |
|||
for (i = 0, ret = 0; i < 26; i++) { |
|||
if (ciphertext == NULL) { |
|||
d = accu[i] / sum - freq[i]; |
|||
fprintf(stderr, "Memory error\n"); |
|||
return 5; |
|||
} |
} |
||
for (size_t i = 0, j = 0; i < plainlen; i++) { |
|||
key[interval] = '\0'; |
|||
// Skip non-alphabetical characters |
|||
return ret; |
|||
if (!(isalpha(plaintext[i]))) { |
|||
ciphertext[i] = plaintext[i]; |
|||
continue; |
|||
} |
|||
// 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); |
|||
// Silence warnings about const not being maintained in cast to void* |
|||
free((char*) plaintext); |
|||
return 0; |
|||
} |
} |
||
char *get_input(void) { |
|||
char *const restrict buf = malloc(BUFSIZE * sizeof (char)); |
|||
int main() { |
|||
if (buf == NULL) { |
|||
return NULL; |
|||
} |
|||
double fit, best_fit = 1e100; |
|||
fgets(buf, BUFSIZE, stdin); |
|||
for (j = 0; encoded[j] != '\0'; j++) |
|||
if (isupper(encoded[j])) |
|||
txt[len++] = encoded[j] - 'A'; |
|||
// Get rid of newline |
|||
size_t const len = strlen(buf); |
|||
if (buf[len - 1] == '\n') buf[len - 1] = '\0'; |
|||
if (fit < best_fit) { |
|||
return buf; |
|||
best_fit = fit; |
|||
}</lang> |
|||
printf(" <--- best so far"); |
|||
{{out}} |
|||
<pre>$ ./vigenere VIGENERECIPHER |
|||
Plain text: Beware the Jabberwock, my son! The jaws that bite, the claws that catch! |
|||
Cipher text: Wmceei klg Rpifvmeugx, qp wqv! Ioi avey xuek fkbt, alv xtgaf xyev kpagy! |
|||
$ ./vigenere -d VIGENERECIPHER |
|||
Cipher text: Wmceei klg Rpifvmeugx, qp wqv! Ioi avey xuek fkbt, alv xtgaf xyev kpagy! |
|||
Plain text: Beware the Jabberwock, my son! The jaws that bite, the claws that catch!</pre> |
|||
=={{header|C sharp|C#}}== |
|||
<lang csharp> |
|||
using System; |
|||
namespace VigenereCipher |
|||
{ |
|||
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 |
|||
Encrypted: WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY |
|||
return 0; |
|||
Decrypted: BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH |
|||
}</lang> |
|||
</pre> |
|||
=={{header|C++}}== |
=={{header|C++}}== |
||
Not guaranteed to give a 100% correct answer, but it works here. Requires C++0x. |
|||
<lang cpp>#include <iostream> |
<lang cpp>#include <iostream> |
||
#include <string> |
#include <string> |
||
#include <vector> |
|||
#include <map> |
|||
#include <algorithm> |
|||
#include <array> |
|||
using namespace std; |
using namespace std; |
||
class Vigenere |
|||
typedef array<pair<char, double>, 26> FreqArray; |
|||
class VigenereAnalyser |
|||
{ |
{ |
||
public: |
|||
private: |
|||
string key; |
|||
array<double, 26> targets; |
|||
array<double, 26> sortedTargets; |
|||
FreqArray freq; |
|||
Vigenere(string key) |
|||
// Update the freqs array |
|||
FreqArray& frequency(const string& input) |
|||
{ |
{ |
||
for |
for(int i = 0; i < key.size(); ++i) |
||
{ |
|||
freq[c - 'A'] = make_pair(c, 0); |
|||
if(key[i] >= 'A' && key[i] <= 'Z') |
|||
this->key += key[i]; |
|||
for (size_t i = 0; i < input.size(); ++i) |
|||
else if(key[i] >= 'a' && key[i] <= 'z') |
|||
this->key += key[i] + 'A' - 'a'; |
|||
} |
|||
} |
} |
||
string encrypt(string text) |
|||
{ |
{ |
||
string out; |
|||
frequency(input); |
|||
for(int i = 0, j = 0; i < text.length(); ++i) |
|||
sort(freq.begin(), freq.end(), [](pair<char, double> u, pair<char, double> v)->bool |
|||
{ |
|||
{ 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'; |
|||
j = (j + 1) % key.length(); |
|||
} |
|||
return |
return out; |
||
} |
} |
||
string decrypt(string text) |
|||
public: |
|||
VigenereAnalyser(const array<double, 26>& targetFreqs) |
|||
{ |
{ |
||
string out; |
|||
sortedTargets = targets; |
|||
sort(sortedTargets.begin(), sortedTargets.end()); |
|||
} |
|||
for(int i = 0, j = 0; i < text.length(); ++i) |
|||
pair<string, string> analyze(string input) |
|||
{ |
|||
string cleaned; |
|||
for (size_t i = 0; i < input.size(); ++i) |
|||
{ |
{ |
||
char c = text[i]; |
|||
if(c >= 'a' && c <= 'z') |
|||
c += 'A' - 'a'; |
|||
else if(c < 'A' || c > 'Z') |
|||
continue; |
|||
out += (c - key[j] + 26) % 26 + 'A'; |
|||
j = (j + 1) % key.length(); |
|||
} |
} |
||
return out; |
|||
} |
|||
double bestCorr = -100.0; |
|||
}; |
|||
int main() |
|||
// Assume that if there are less than 20 characters |
|||
{ |
|||
// per column, the key's too long to guess |
|||
Vigenere cipher("VIGENERECIPHER"); |
|||
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]; |
|||
string original = "Beware the Jabberwock, my son! The jaws that bite, the claws that catch!"; |
|||
// The correlation increases artificially for smaller |
|||
string encrypted = cipher.encrypt(original); |
|||
// pieces/longer keys, so weigh against them a little |
|||
string decrypted = cipher.decrypt(encrypted); |
|||
double corr = -0.5*i; |
|||
for (size_t j = 0; j < i; ++j) |
|||
corr += correlation(pieces[j]); |
|||
cout << original << endl; |
|||
if (corr > bestCorr) |
|||
cout << "Encrypted: " << encrypted << endl; |
|||
{ |
|||
cout << "Decrypted: " << decrypted << endl; |
|||
bestLength = i; |
|||
}</lang> |
|||
bestCorr = corr; |
|||
} |
|||
} |
|||
{{out}} |
|||
if (bestLength == 0) |
|||
<pre> |
|||
return make_pair("Text is too short to analyze", ""); |
|||
Beware the Jabberwock, my son! The jaws that bite, the claws that catch! |
|||
Encrypted: WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY |
|||
Decrypted: BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH |
|||
</pre> |
|||
=={{header|Ceylon}}== |
|||
vector<string> pieces(bestLength); |
|||
<lang ceylon>shared void run() { |
|||
for (size_t i = 0; i < cleaned.size(); ++i) |
|||
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); |
|||
function decrypt(String cipherText, String key) => |
|||
vector<FreqArray> freqs; |
|||
crypt(cipherText, key, (Character a, Character b) => |
|||
for (size_t i = 0; i < bestLength; ++i) |
|||
('A'.integer + ((a.integer - b.integer + 26) % 26)).character); |
|||
freqs.push_back(frequency(pieces[i])); |
|||
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> |
|||
=={{header|Clojure}}== |
|||
string key = ""; |
|||
Requires Clojure 1.2. |
|||
for (size_t i = 0; i < bestLength; ++i) |
|||
<lang clojure>(ns org.rosettacode.clojure.vigenere |
|||
{ |
|||
(:require [clojure.string :as string])) |
|||
sort(freqs[i].begin(), freqs[i].end(), [](pair<char, double> u, pair<char, double> v)->bool |
|||
{ return u.second > v.second; }); |
|||
; convert letter to offset from \A |
|||
size_t m = 0; |
|||
(defn to-num [char] (- (int char) (int \A))) |
|||
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]; |
|||
} |
|||
; convert number to letter, treating it as modulo 26 offset from \A |
|||
if (corr > mCorr) |
|||
(defn from-num [num] (char (+ (mod num 26) (int \A)))) |
|||
{ |
|||
m = j; |
|||
mCorr = corr; |
|||
} |
|||
} |
|||
; Convert a string to a sequence of just the letters as uppercase chars |
|||
key += m + 'A'; |
|||
(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))))) |
|||
(defn crypt [op text key] |
|||
string result = ""; |
|||
(let [xcrypt1 (partial #'crypt1 op)] |
|||
for (size_t i = 0; i < cleaned.size(); ++i) |
|||
(apply #'str |
|||
result += (cleaned[i] - key[i % key.length()] + 26) % 26 + 'A'; |
|||
(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> |
|||
Demonstration code: |
|||
return make_pair(result, key); |
|||
<lang clojure>(ns org.rosettacode.clojure.test-vigenere |
|||
} |
|||
(:require [org.rosettacode.clojure.vigenere :as vigenere])) |
|||
}; |
|||
(let |
|||
int main() |
|||
[ plaintext "Beware the Jabberwock, my son! The jaws that bite, the claws that catch!" |
|||
{ |
|||
key "Vigenere cipher" |
|||
string input = |
|||
ciphertext (vigenere/encrypt plaintext key) |
|||
"MOMUD EKAPV TQEFM OEVHP AJMII CDCTI FGYAG JSPXY ALUYM NSMYH" |
|||
recovered (vigenere/decrypt ciphertext key) ] |
|||
"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"; |
|||
(doall (map (fn [[k v]] (printf "%9s: %s\n" k v)) |
|||
array<double, 26> english = { |
|||
[ ["Original" plaintext] ["Key" key] ["Encrypted" ciphertext] ["Decrypted" recovered] ]))) |
|||
0.08167, 0.01492, 0.02782, 0.04253, 0.12702, 0.02228, |
|||
</lang> |
|||
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}; |
|||
{{out}} |
|||
VigenereAnalyser va(english); |
|||
<pre> Original: Beware the Jabberwock, my son! The jaws that bite, the claws that catch! |
|||
pair<string, string> output = va.analyze(input); |
|||
Key: Vigenere cipher |
|||
Encrypted: WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY |
|||
Decrypted: BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH</pre> |
|||
=={{header|CoffeeScript}}== |
|||
cout << "Key: " << output.second << endl << endl; |
|||
{{trans|D}} |
|||
cout << "Text: " << output.first << endl; |
|||
<lang coffeescript># Simple helper since charCodeAt is quite long to write. |
|||
}</lang> |
|||
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}}== |
||
<lang d>import std.stdio, std.string; |
|||
{{trans|C++}} |
|||
<lang d>import std.stdio, std.algorithm, std.typecons, std.string, |
|||
std.array, std.numeric, std.ascii; |
|||
string |
string encrypt(in string txt, in string key) pure @safe |
||
in { |
|||
enum nAlpha = std.ascii.uppercase.length; |
|||
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 |
|||
in { |
|||
pure nothrow /*@safe*/ @nogc { |
|||
assert(key.removechars("^A-Z") == key); |
|||
uint[nAlpha] charCounts = 0; |
|||
} body { |
|||
foreach (immutable c; txt) |
|||
string res; |
|||
charCounts[c - 'A']++; |
|||
foreach (immutable i, immutable c; txt.toUpper.removechars("^A-Z")) |
|||
return charCounts[].sort().release.dotProduct(sTargets); |
|||
res ~= (c - key[i % $] + 26) % 26 + 'A'; |
|||
} |
|||
return res; |
|||
} |
|||
void main() { |
|||
static frequency(in string txt) pure nothrow @safe { |
|||
immutable key = "VIGENERECIPHER"; |
|||
auto freqs = new Tuple!(char,"c", uint,"d")[nAlpha]; |
|||
immutable original = "Beware the Jabberwock, my son!" ~ |
|||
foreach (immutable i, immutable c; std.ascii.uppercase) |
|||
" The jaws that bite, the claws that catch!"; |
|||
immutable encoded = original.encrypt(key); |
|||
foreach (immutable c; txt) |
|||
writeln(encoded, "\n", encoded.decrypt(key)); |
|||
freqs[c - 'A'].d++; |
|||
}</lang> |
|||
return freqs; |
|||
{{out}} |
|||
} |
|||
<pre>WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY |
|||
BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH</pre> |
|||
===Alternative Version=== |
|||
static string[2] decode(in string cleaned, in string key) |
|||
{{trans|Perl 6}} |
|||
pure nothrow @safe { |
|||
<lang d>import std.stdio, std.range, std.ascii, std.string, std.algorithm, |
|||
assert(!key.empty); |
|||
std.conv; |
|||
foreach (immutable i, immutable c; cleaned) |
|||
decoded ~= (c - key[i % $] + nAlpha) % nAlpha + 'A'; |
|||
return [key, decoded]; |
|||
} |
|||
immutable mod = (in int m, in int n) pure nothrow @safe @nogc => |
|||
static size_t findBestLength(in string cleaned, |
|||
((m % n) + n) % n; |
|||
in double[] sTargets) |
|||
pure nothrow /*@safe*/ { |
|||
size_t bestLength; |
|||
double bestCorr = -100.0; |
|||
immutable _s2v = (in string s) pure /*nothrow*/ @safe => |
|||
// Assume that if there are less than 20 characters |
|||
s.toUpper.removechars("^A-Z").map!q{ a - 'A' }; |
|||
// 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; |
|||
string _v2s(R)(R v) pure /*nothrow*/ @safe { |
|||
// The correlation seems to increase for smaller |
|||
return v.map!(x => uppercase[x.mod(26)]).text; |
|||
// pieces/longer keys, so weigh against them a little |
|||
} |
|||
double corr = -0.5 * i; |
|||
foreach (const p; pieces) |
|||
corr += correlation(p.data, sTargets); |
|||
immutable encrypt = (in string txt, in string key) pure /*nothrow*/ @safe => |
|||
if (corr > bestCorr) { |
|||
txt._s2v.zip(key._s2v.cycle).map!q{ a[0] + a[1] }._v2s; |
|||
bestLength = i; |
|||
bestCorr = corr; |
|||
} |
|||
} |
|||
immutable decrypt = (in string txt, in string key) pure /*nothrow*/ @safe => |
|||
return bestLength; |
|||
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 |
|||
Encrypted:WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY |
|||
static string findKey(in string cleaned, in size_t bestLength, |
|||
Decrypted:BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH |
|||
in double[] targetFreqs) pure nothrow @safe { |
|||
Press any key to continue.. |
|||
auto pieces = new string[bestLength]; |
|||
</pre> |
|||
foreach (immutable i, immutable c; cleaned) |
|||
pieces[i % bestLength] ~= c; |
|||
=={{header|Elixir}}== |
|||
string key; |
|||
{{trans|Ruby}} |
|||
foreach (fr; pieces.map!frequency) { |
|||
<lang elixir>defmodule VigenereCipher do |
|||
fr.sort!q{ a.d > b.d }; |
|||
@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 |
|||
plaintext = "Beware the Jabberwock, my son! The jaws that bite, the claws that catch!" |
|||
size_t m; |
|||
key = "Vigenere cipher" |
|||
double maxCorr = 0.0; |
|||
ciphertext = VigenereCipher.encrypt(plaintext, key) |
|||
foreach (immutable j, immutable c; uppercase) { |
|||
recovered = VigenereCipher.decrypt(ciphertext, key) |
|||
double corr = 0.0; |
|||
foreach (immutable frc; fr) { |
|||
IO.puts "Original: #{plaintext}" |
|||
immutable di = (frc.c - c + nAlpha) % nAlpha; |
|||
IO.puts "Encrypted: #{ciphertext}" |
|||
corr += frc.d * targetFreqs[di]; |
|||
IO.puts "Decrypted: #{recovered}"</lang> |
|||
} |
|||
{{out}} |
|||
if (corr > maxCorr) { |
|||
<pre> |
|||
m = j; |
|||
Original: Beware the Jabberwock, my son! The jaws that bite, the claws that catch! |
|||
maxCorr = corr; |
|||
Encrypted: WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY |
|||
} |
|||
Decrypted: BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH |
|||
} |
|||
</pre> |
|||
=={{header|Erlang}}== |
|||
key ~= m + 'A'; |
|||
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]). |
|||
% Utility functions for character tests and conversions |
|||
return key; |
|||
isupper([C|_]) -> isupper(C); |
|||
} |
|||
isupper(C) -> (C >= $A) and (C =< $Z). |
|||
islower([C|_]) -> islower(C); |
|||
immutable cleaned = input.toUpper.removechars("^A-Z"); |
|||
islower(C) -> (C >= $a) and (C =< $z). |
|||
isalpha([C|_]) -> isalpha(C); |
|||
//immutable sortedTargets = targetFreqs.sorted; |
|||
isalpha(C) -> isupper(C) or islower(C). |
|||
immutable sortedTargets = targetFreqs.dup.sort().release.idup; |
|||
toupper(S) when is_list(S) -> lists:map(fun toupper/1, S); |
|||
immutable bestLength = findBestLength(cleaned, sortedTargets); |
|||
toupper(C) when (C >= $a) and (C =< $z) -> C - $a + $A; |
|||
if (bestLength == 0) |
|||
toupper(C) -> C. |
|||
throw new Exception("Text is too short to analyze."); |
|||
% modulo function that normalizes into positive range for positive divisor |
|||
immutable string key = findKey(cleaned, bestLength, targetFreqs); |
|||
mod(X,Y) -> (X rem Y + Y) rem Y. |
|||
return decode(cleaned, key); |
|||
} |
|||
% convert letter to position in alphabet (A=0,B=1,...,Y=24,Z=25). |
|||
to_pos(L) when L >= $A, L =< $Z -> L - $A. |
|||
% convert position in alphabet back to letter |
|||
void main() { |
|||
from_pos(N) -> mod(N, 26) + $A. |
|||
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"; |
|||
% encode the given letter given the single-letter key |
|||
immutable englishFrequences = [0.08167, 0.01492, 0.02782, 0.04253, |
|||
encipher(P, K) -> from_pos(to_pos(P) + to_pos(K)). |
|||
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]; |
|||
% decode the given letter given the single-letter key |
|||
immutable key_dec = vigenereDecrypt(englishFrequences, encoded); |
|||
decipher(C, K) -> from_pos(to_pos(C) - to_pos(K)). |
|||
writefln("Key: %s\n\nText: %s", key_dec[0], key_dec[1]); |
|||
}</lang> |
|||
{{out|Output (cut)}} |
|||
<pre>Key: THECHESHIRECAT |
|||
% extend a list by repeating it until it is at least N elements long |
|||
Text: THISWASTHEPOEMTHATALICEREADJABBERWOCKYTWASBRILLIGANDTHESLITHY...</pre> |
|||
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 |
<lang go>package main |
||
import |
import "fmt" |
||
"fmt" |
|||
"strings" |
|||
) |
|||
type vkey string |
|||
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" |
|||
func newVigenère(key string) (vkey, bool) { |
|||
var freq = [26]float64{ |
|||
v := vkey(upperOnly(key)) |
|||
0.08167, 0.01492, 0.02782, 0.04253, 0.12702, 0.02228, 0.02015, |
|||
return v, len(v) > 0 // key length 0 invalid |
|||
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 |
func (k vkey) encipher(pt string) string { |
||
ct := upperOnly(pt) |
|||
for i, c := range ct { |
|||
ct[i] = 'A' + (c-'A'+k[i%len(k)]-'A')%26 |
|||
} |
} |
||
return |
return string(ct) |
||
} |
} |
||
func (k vkey) decipher(ct string) (string, bool) { |
|||
func bestMatch(a []float64) int { |
|||
pt := make([]byte, len(ct)) |
|||
for i := range pt { |
|||
c := ct[i] |
|||
if c < 'A' || c > 'Z' { |
|||
return "", false // invalid ciphertext |
|||
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 |
return string(pt), true |
||
} |
} |
||
// upperOnly extracts letters A-Z, a-z from a string and |
|||
func freqEveryNth(msg []int, key []byte) float64 { |
|||
// returns them all upper case in a byte slice. |
|||
l := len(msg) |
|||
// Useful for vkey constructor and encipher function. |
|||
interval := len(key) |
|||
func upperOnly(s string) []byte { |
|||
out := make([]float64, 26) |
|||
u := make([]byte, 0, len(s)) |
|||
for |
for i := 0; i < len(s); i++ { |
||
c := s[i] |
|||
if c >= 'A' && c <= 'Z' { |
|||
u = append(u, c) |
|||
} else if c >= 'a' && c <= 'z' { |
|||
u = append(u, c-32) |
|||
} |
} |
||
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 |
return u |
||
} |
} |
||
const testKey = "Vigenère Cipher" |
|||
func decrypt(text, key string) string { |
|||
const testPT = `Beware the Jabberwock, my son! |
|||
var sb strings.Builder |
|||
The jaws that bite, the claws that catch!` |
|||
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() { |
func main() { |
||
fmt.Println("Supplied key: ", testKey) |
|||
v, ok := newVigenère(testKey) |
|||
if !ok { |
|||
for i := 0; i < len(txt); i++ { |
|||
fmt.Println("Invalid key") |
|||
return |
|||
} |
} |
||
fmt.Println("Effective key:", v) |
|||
bestFit, bestKey := 1e100, "" |
|||
fmt.Println(" |
fmt.Println("Plain text:", testPT) |
||
ct := v.encipher(testPT) |
|||
fmt.Println("Enciphered:", ct) |
|||
key := make([]byte, j) |
|||
dt, ok := v.decipher(ct) |
|||
if !ok { |
|||
sKey := string(key) |
|||
fmt. |
fmt.Println("Invalid ciphertext") |
||
return |
|||
bestFit, bestKey = fit, sKey |
|||
fmt.Print(" <--- best so far") |
|||
} |
|||
fmt.Println() |
|||
} |
} |
||
fmt.Println(" |
fmt.Println("Deciphered:", dt) |
||
fmt.Printf("\nDecrypted text:\n%s\n", decrypt(enc, bestKey)) |
|||
}</lang> |
}</lang> |
||
{{out}} |
{{out}} |
||
Note: carriage returns inserted into decrypted text after every 80 characters to make it more readable. |
|||
<pre> |
<pre> |
||
Supplied key: Vigenère Cipher |
|||
Fit Length Key |
|||
Effective key: VIGENRECIPHER |
|||
2.984348 1 E <--- best so far |
|||
Plain text: Beware the Jabberwock, my son! |
|||
2.483684 2 EC <--- best so far |
|||
The jaws that bite, the claws that catch! |
|||
2.642487 3 TEE |
|||
Enciphered: WMCEEVXJMYHFSZZCSPBQAADUXYZRGAFKLCBQPXVOPKGYRAUBWHXTVBIL |
|||
1.976651 4 THEC <--- best so far |
|||
Deciphered: BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH |
|||
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 |
|||
</pre> |
</pre> |
||
=={{header|Haskell}}== |
=={{header|Haskell}}== |
||
<lang haskell> |
<lang haskell>import Data.Char |
||
import Text.Printf |
|||
import Data.List(transpose, nub, sort, maximumBy) |
|||
import Data.Ord (comparing) |
|||
import Data.Char (ord) |
|||
import Data.Map (Map, fromListWith, toList, findWithDefault) |
|||
-- Perform encryption or decryption, depending on f. |
|||
average :: Fractional a => [a] -> a |
|||
crypt f key = map toLetter . zipWith f (cycle key) |
|||
average as = sum as / fromIntegral (length as) |
|||
where toLetter = chr . (+) (ord 'A') |
|||
-- Encrypt or decrypt one letter. |
|||
-- Create a map from each entry in list to the number of occurrences of |
|||
enc k c = (ord k + ord c) `mod` 26 |
|||
-- that entry in the list. |
|||
dec k c = (ord c - ord k) `mod` 26 |
|||
countEntries :: Ord a => [a] -> Map a Int |
|||
countEntries = fromListWith (+) . fmap (,1) |
|||
-- |
-- Given a key, encrypt or decrypt an input string. |
||
encrypt = crypt enc |
|||
breakup :: Int -> [a] -> [[a]] |
|||
decrypt = crypt dec |
|||
breakup _ [] = [] |
|||
breakup n as = |
|||
let (h, r) = splitAt n as |
|||
in h:breakup n r |
|||
-- |
-- Convert a string to have only upper case letters. |
||
convert = map toUpper . filter isLetter |
|||
distribute :: [a] -> Int -> [[a]] |
|||
distribute as n = transpose $ breakup n as |
|||
main = do |
|||
-- The probability that members of a pair of characters taken randomly |
|||
let key = "VIGENERECIPHER" |
|||
-- from a given string are equal. |
|||
text = "Beware the Jabberwock, my son! The jaws that bite, " |
|||
coincidence :: (Ord a, Fractional b) => [a] -> b |
|||
++ "the claws that catch!" |
|||
coincidence str = |
|||
encr = encrypt key $ convert text |
|||
decr = decrypt key encr |
|||
printf " Input: %s\n Key: %s\nEncrypted: %s\nDecrypted: %s\n" |
|||
d = fromIntegral $ strln * (strln - 1) |
|||
text key encr decr</lang> |
|||
n = fromIntegral $ sum $ fmap (\cc -> cc * (cc-1)) charCounts |
|||
{{out}} |
|||
in n / d |
|||
<pre> |
|||
Input: Beware the Jabberwock, my son! The jaws that bite, the claws that catch! |
|||
Key: VIGENERECIPHER |
|||
Encrypted: WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY |
|||
Decrypted: BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH |
|||
</pre> |
|||
=={{header|Icon}} and {{header|Unicon}}== |
|||
-- Use the average probablity of coincidence for all the members of |
|||
<lang Icon>procedure main() |
|||
-- a distribution to rate the distribution - the higher the better. |
|||
ptext := "Beware the Jabberwock, my son! The jaws that bite, the claws that catch!" |
|||
-- The correlation increases artificially for smaller |
|||
write("Key = ",ekey := "VIGENERECIPHER") |
|||
-- pieces/longer keys, so weigh against them a little |
|||
write("Plain Text = ",ptext) |
|||
rate :: (Ord a, Fractional b) => [[a]] -> b |
|||
write("Normalized = ",GFormat(ptext := NormalizeText(ptext))) |
|||
rate d = average (fmap coincidence d) - fromIntegral (length d) / 3000.0 |
|||
write("Enciphered = ",GFormat(ctext := Vignere("e",ekey,ptext))) |
|||
write("Deciphered = ",GFormat(ptext := Vignere("d",ekey,ctext))) |
|||
end |
|||
procedure Vignere(mode,ekey,ptext,alpha) #: Vignere cipher |
|||
-- Multiply elements of lists together and add up the results. |
|||
/alpha := &ucase # default |
|||
dot :: Num a => [a] -> [a] -> a |
|||
if *alpha ~= *cset(alpha) then runerr(205,alpha) # no dups |
|||
dot v0 v1 = sum $ zipWith (*) v0 v1 |
|||
alpha ||:= alpha # unobstructed |
|||
every ctext:="" & p:=ptext[i := 1 to *ptext] & k:=ekey[(i-1)%*ekey+1] do |
|||
-- Given two lists of floats, rotate one of them by the number of |
|||
case mode of { |
|||
-- characters indicated by letter and then 'dot' them together. |
|||
"e"|"encrypt": |
|||
rotateAndDot :: Num a => [a] -> [a] -> Char -> a |
|||
ctext||:=map(p,alpha[1+:*alpha/2],alpha[find(k,alpha)+:(*alpha/2)]) |
|||
rotateAndDot v0 v1 letter = dot v0 (drop (ord letter - ord 'A') (cycle v1)) |
|||
"d"|"decrypt": |
|||
ctext||:=map(p,alpha[find(k,alpha)+:(*alpha/2)],alpha[1+:*alpha/2]) |
|||
default: runerr(205,mode) |
|||
} |
|||
return ctext |
|||
end</lang> |
|||
The following helper procedures will be of general use with classical cryptography tasks. |
|||
-- Find decoding offset that results in best match |
|||
<lang Icon> |
|||
-- between actual char frequencies and expected frequencies. |
|||
link strings |
|||
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'] |
|||
procedure NormalizeText(ptext,alpha) #: text/case classical crypto helper |
|||
main = do |
|||
/alpha := &ucase # default |
|||
let cr = filter (/=' ') crypt |
|||
if &lcase === (alpha := cset(alpha)) then ptext := map(ptext) # lower |
|||
-- Assume that if there are less than 20 characters |
|||
if &ucase === alpha then ptext := map(ptext,&lcase,&ucase) # upper |
|||
-- per column, the key's too long to guess |
|||
return deletec(ptext,&cset--alpha) # only alphas |
|||
distributions = fmap (distribute cr) [1..length cr `div` 20] |
|||
end |
|||
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] |
|||
procedure GFormat(text) #: 5 letter group formatting helper |
|||
englishFrequencies = |
|||
text ? (s := "", until pos(0) do s ||:= " " || move(5)|tab(0)) |
|||
[ 0.08167, 0.01492, 0.02782, 0.04253, |
|||
return s[2:0] |
|||
0.12702, 0.02228, 0.02015, 0.06094, |
|||
end</lang> |
|||
0.06966, 0.00153, 0.00772, 0.04025, |
|||
0.02406, 0.06749, 0.07507, 0.01929, |
|||
{{libheader|Icon Programming Library}} |
|||
0.00095, 0.05987, 0.06327, 0.09056, |
|||
[http://www.cs.arizona.edu/icon/library/src/procs/strings.icn strings.icn provides deletec] |
|||
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\ |
|||
\"</lang> |
|||
{{out}} |
{{out}} |
||
<pre>Key = VIGENERECIPHER |
|||
<pre style="font-size:80%"> |
|||
Plain Text = Beware the Jabberwock, my son! The jaws that bite, the claws that catch! |
|||
Key: THECHESHIRECAT |
|||
Normalized = BEWAR ETHEJ ABBER WOCKM YSONT HEJAW STHAT BITET HECLA WSTHA TCATCH |
|||
Decrypted Text: THISWASTHEPOEMTHATALICEREADJABBERWOCKYTWASBRILLIGANDTHESLITHYTOVESDIDGYREANDGIMBLEINTHEWABEALLMIMSYWERETHEBOROGOVESANDTHEMOMERATHSOUTGRABEBEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCHBEWARETHEJUBJUBBIRDANDSHUNTHEFRUMIOUSBANDERSNATCHHETOOKHISVORPALSWORDINHANDLONGTIMETHEMANXOMEFOEHESOUGHTSORESTEDHEBYTHETUMTUMTREEANDSTOODAWHILEINTHOUGHTANDASINUFFISHTHOUGHTHESTOODTHEJABBERWOCKWITHEYESOFFLAMECAMEWHIFFLINGTHROUGHTHETULGEYWOODANDBURBLEDASITCAMEONETWOONETWOANDTHROUGHANDTHROUGHTHEVORPALBLADEWENTSNICKERSNACKHELEFTITDEADANDWITHITSHEADHEWENTGALUMPHINGBACKANDHASTTHOUSLAINTHEJABBERWOCKCOMETOMYARMSMYBEAMISHBOYOFRABJOUSDAYCALLOOHCALLAYHECHORTLEDINHISJOYTWASBRILLIGANDTHESLITHYTOVESDIDGYREANDGIMBLEINTHEWABEALLMIMSYWERETHEBOROGOVESANDTHEMOMERATHSOUTGRABEITSEEMSVERYPRETTYSHESAIDWHENSHEHADFINISHEDITBUTITSRATHERHARDTOUNDERSTAND |
|||
Enciphered = WMCEE IKLGR PIFVM EUGXQ PWQVI OIAVE YXUEK FKBTA LVXTG AFXYE VKPAGY |
|||
</pre> |
|||
Deciphered = BEWAR ETHEJ ABBER WOCKM YSONT HEJAW STHAT BITET HECLA WSTHA TCATCH</pre> |
|||
=={{header| |
=={{header|J}}== |
||
'''Solution:'''<br> |
|||
{{trans|C}} |
|||
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 |
|||
) |
|||
ALPHA=: (65,:26) ];.0 a. NB. Character Set |
|||
<lang Java>public class Vig{ |
|||
preprocess=: (#~ e.&ALPHA)@toupper NB. force uppercase and discard non-alpha chars |
|||
static String encodedMessage = |
|||
vigEncryptRC=: 0 vig ALPHA preprocess |
|||
"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"; |
|||
vigDecryptRC=: 1 vig ALPHA preprocess</lang> |
|||
final static double freq[] = { |
|||
'''Example Use:''' |
|||
0.08167, 0.01492, 0.02782, 0.04253, 0.12702, 0.02228, 0.02015, |
|||
<lang j> 'VIGENERECIPHER' vigEncryptRC 'Beware the Jabberwock, my son! The jaws that bite, the claws that catch!' |
|||
0.06094, 0.06966, 0.00153, 0.00772, 0.04025, 0.02406, 0.06749, |
|||
WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY |
|||
0.07507, 0.01929, 0.00095, 0.05987, 0.06327, 0.09056, 0.02758, |
|||
'VIGENERECIPHER' vigDecryptRC 'WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY' |
|||
0.00978, 0.02360, 0.00150, 0.01974, 0.00074 |
|||
BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH</lang> |
|||
}; |
|||
=={{header|Java}}== |
|||
public static void main(String[] args) { |
|||
{{trans|D}} |
|||
int lenghtOfEncodedMessage = encodedMessage.length(); |
|||
<lang java>public class VigenereCipher { |
|||
char[] encoded = new char [lenghtOfEncodedMessage] ; |
|||
public static void main(String[] args) { |
|||
char[] key = new char [lenghtOfEncodedMessage] ; |
|||
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)); |
|||
} |
|||
static String encrypt(String text, final String key) { |
|||
encodedMessage.getChars(0, lenghtOfEncodedMessage, encoded, 0); |
|||
String res = ""; |
|||
int txt[] = new int[lenghtOfEncodedMessage]; |
|||
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) - 2 * 'A') % 26 + 'A'); |
|||
for (j = 0; j < lenghtOfEncodedMessage; j++) |
|||
j = ++j % key.length(); |
|||
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; |
|||
} |
} |
||
} |
|||
static String decrypt(String text, final String key) { |
static String decrypt(String text, final String key) { |
||
Line 944: | Line 1,309: | ||
return res; |
return res; |
||
} |
} |
||
}</lang> |
|||
<pre>WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY |
|||
static int best_match(final double []a, final double []b) { |
|||
BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH</pre> |
|||
double sum = 0, fit, d, best_fit = 1e100; |
|||
int i, rotate, best_rotate = 0; |
|||
=={{header|JavaScript}}== |
|||
for (i = 0; i < 26; i++) |
|||
<lang javascript>// helpers |
|||
sum += a[i]; |
|||
// helper |
|||
for (rotate = 0; rotate < 26; rotate++) { |
|||
function ordA(a) { |
|||
fit = 0; |
|||
return a.charCodeAt(0) - 65; |
|||
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; |
|||
} |
} |
||
// vigenere |
|||
static double freq_every_nth(final int []msg, int len, int interval, char[] key) { |
|||
function vigenere(text, key, decode) { |
|||
double sum, d, ret; |
|||
var i = 0, b; |
|||
double [] accu = new double [26]; |
|||
key = key.toUpperCase().replace(/[^A-Z]/g, ''); |
|||
double [] out = new double [26]; |
|||
return text.toUpperCase().replace(/[^A-Z]/g, '').replace(/[A-Z]/g, function(a) { |
|||
int i, j, rot; |
|||
b = key[i++ % key.length]; |
|||
return String.fromCharCode(((ordA(a) + (decode ? 26 - ordA(b) : ordA(b))) % 26 + 65)); |
|||
for (j = 0; j < interval; j++) { |
|||
}); |
|||
for (i = 0; i < 26; i++) |
|||
} |
|||
out[i] = 0; |
|||
for (i = j; i < len; i += interval) |
|||
// example |
|||
out[msg[i]]++; |
|||
var text = "The quick brown fox Jumped over the lazy Dog the lazy dog lazy dog dog"; |
|||
rot = best_match(out, freq); |
|||
var key = 'alex'; |
|||
try{ |
|||
var enc = vigenere(text,key); |
|||
key[j] = (char)(rot + 'A'); |
|||
var dec = vigenere(enc,key,true); |
|||
} catch (Exception e) { |
|||
System.out.print(e.getMessage()); |
|||
console.log(enc); |
|||
} |
|||
console.log(dec);</lang> |
|||
for (i = 0; i < 26; i++) |
|||
accu[i] += out[(i + rot) % 26]; |
|||
=={{header|Jsish}}== |
|||
} |
|||
From Javascript entry. |
|||
<lang javascript>/* Vigenère cipher, in Jsish */ |
|||
for (i = 0, sum = 0; i < 26; i++) |
|||
"use strict"; |
|||
sum += accu[i]; |
|||
function ordA(a:string):number { |
|||
for (i = 0, ret = 0; i < 26; i++) { |
|||
return a.charCodeAt(0) - 65; |
|||
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)); |
|||
}); |
|||
} |
} |
||
</lang> |
|||
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) |
|||
if keylen < msglen |
|||
<lang Julia># ciphertext block {{{1 |
|||
key = repeat(key, div(msglen - keylen, keylen) + 2)[1:msglen] |
|||
const ciphertext = filter(isalpha, """ |
|||
end |
|||
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 |
|||
""") |
|||
# }}} |
|||
enc = Vector{Char}(msglen) |
|||
# character frequencies {{{1 |
|||
const letters = Dict{Char, Float32}( |
|||
@inbounds for i in 1:length(msg) |
|||
'E' => 12.702, |
|||
enc[i] = Char((Int(msg[i]) + Int(key[i]) - 130) % 26 + 65) |
|||
'T' => 9.056, |
|||
end |
|||
'O' => 7.507, |
|||
return join(enc) |
|||
end |
|||
'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:: |
function decrypt(enc::AbstractString, key::AbstractString) |
||
enc = uppercase(join(filter(isalpha, collect(enc)))) |
|||
const enclen = length(enc) |
|||
key = uppercase(join(filter(isalpha, collect(key)))) |
|||
const keylen = length(key) |
|||
msglen = length(enc) |
|||
keylen = length(key) |
|||
if keylen < |
if keylen < msglen |
||
key = (key |
key = repeat(key, div(msglen - keylen, keylen) + 2)[1:msglen] |
||
end |
end |
||
msg = |
msg = Vector{Char}(msglen) |
||
for i |
@inbounds for i in 1:length(enc) |
||
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 |
||
return join(msg) |
|||
msg::Array{Char, 1} |
|||
end |
end |
||
const messages = ("Attack at dawn.", "Don't attack.", "The war is over.") |
|||
function cryptanalyze(enc::ASCIIString; maxkeylen::Integer = 20) |
|||
const key = "LEMON" |
|||
maxkey = "" |
|||
maxdec = "" |
|||
maxscore = 0.0 |
|||
for msg in messages |
|||
for keylen=1:maxkeylen |
|||
enc = encrypt(msg, key) |
|||
dec = decrypt(enc, key) |
|||
idx = filter(x -> x % keylen == 0, 1:enclen) - keylen + 1 |
|||
println("Original: $msg\n -> encrypted: $enc\n -> decrypted: $dec") |
|||
end</lang> |
|||
{{out}} |
|||
for i=1:keylen |
|||
maxsubscore = 0.0 |
|||
<pre>Original: Attack at dawn. |
|||
for j='A':'Z' |
|||
-> encrypted: LXFOPVEFRNHR |
|||
subscore = 0.0 |
|||
-> decrypted: ATTACKATDAWN |
|||
Original: Don't attack. |
|||
-> encrypted: OSZHNEXMQX |
|||
-> decrypted: DONTATTACK |
|||
Original: The war is over. |
|||
-> encrypted: ELQKNCMECIPV |
|||
-> decrypted: THEWARISOVER</pre> |
|||
=={{header|Kotlin}}== |
|||
for k in decrypt(enc[idx], ascii(string(j))) |
|||
<lang scala>// version 1.1.3 |
|||
subscore += get(letters, k, 0.0) |
|||
end |
|||
fun vigenere(text: String, key: String, encrypt: Boolean = true): String { |
|||
if subscore > maxsubscore |
|||
val t = if (encrypt) text.toUpperCase() else text |
|||
maxsubscore = subscore |
|||
val sb = StringBuilder() |
|||
key[i] = j |
|||
var ki = 0 |
|||
for (c in t) { |
|||
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() |
|||
} |
|||
fun main(args: Array<String>) { |
|||
idx += 1 |
|||
val key = "VIGENERECIPHER" |
|||
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> |
|||
{{out}} |
|||
key = join(key) |
|||
<pre> |
|||
const dec = decrypt(enc, key) |
|||
WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY |
|||
score = 0.0 |
|||
BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH |
|||
</pre> |
|||
=={{header|Liberty BASIC}}== |
|||
for i in dec |
|||
<lang lb> |
|||
score += get(letters, i, 0.0) |
|||
ori$ = "Beware the Jabberwock, my son! The jaws that bite, the claws that catch!" |
|||
end |
|||
key$ = filter$("vigenerecipher") |
|||
print ori$ |
|||
print key$ |
|||
enc$ = encrypt$(ori$, key$) |
|||
print enc$ |
|||
dec$ = decrypt$(enc$, key$) |
|||
print dec$ |
|||
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]) |
|||
function encrypt$(text$, key$) |
|||
if haskey(digraphs, digraph) |
|||
flt$ = filter$(text$) |
|||
score += 2 * get(digraphs, digraph, 0.0) |
|||
encrypt$ = "" |
|||
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 |
|||
function decrypt$(flt$, key$) |
|||
if haskey(trigraphs, trigraph) |
|||
decrypt$ = "" |
|||
score += 3 * get(trigraphs, trigraph, 0.0) |
|||
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 + 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 |
|||
for i = 1, #msg do |
|||
if msg[i] >= string.byte('A') and msg[i] <= string.byte('Z') then |
|||
maxkey = key |
|||
enc[k] = ( msg[i] + key[j] - 2*string.byte('A') ) % 26 + string.byte('A') |
|||
maxdec = dec |
|||
k = k + 1 |
|||
if j == #key then j = 1 else j = j + 1 end |
|||
end |
end |
||
end |
end |
||
return string.char( unpack(enc) ) |
|||
(maxkey, join(maxdec))::Tuple{ASCIIString, ASCIIString} |
|||
end |
end |
||
function Decrypt( _msg, _key ) |
|||
key, dec = cryptanalyze(ciphertext) |
|||
local msg = { _msg:byte( 1, -1 ) } |
|||
println("key: ", key, "\n\n", dec) |
|||
local key = { _key:upper():byte( 1, -1 ) } |
|||
local dec = {} |
|||
local j = 1 |
|||
# post-compilation profiling run |
|||
for i = 1, #msg do |
|||
gc() |
|||
dec[i] = ( msg[i] - key[j] + 26 ) % 26 + string.byte('A') |
|||
t = @elapsed cryptanalyze(ciphertext) |
|||
println("\nelapsed time: ", t, " seconds")</lang> |
|||
if j == #key then j = 1 else j = j + 1 end |
|||
end |
|||
return string.char( unpack(dec) ) |
|||
end |
|||
{{out}} |
|||
original = "Beware the Jabberwock, my son! The jaws that bite, the claws that catch!" |
|||
<pre>key: THECHESHIRECAT |
|||
key = "VIGENERECIPHER"; |
|||
encrypted = Encrypt( original, key ) |
|||
THISWASTHEPOEMTHATALICEREADJABBERWOCKYTWASBRILLIGANDTHESLITHY... |
|||
decrypted = Decrypt( encrypted, key ) |
|||
print( encrypted ) |
|||
elapsed time: 0.042894211 seconds</pre> |
|||
print( decrypted )</lang> |
|||
<pre>WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY |
|||
BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH</pre> |
|||
=={{header| |
=={{header|Mathematica}}== |
||
<lang Mathematica>encode[text_String, key_String] := |
|||
{{trans|C}} |
|||
Module[{textCode, keyCode}, |
|||
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. |
|||
textCode = |
|||
<lang scala>// version 1.1.3 |
|||
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]] |
|||
decode[text_String, key_String] := |
|||
val encoded = |
|||
Module[{textCode, keyCode}, |
|||
"MOMUD EKAPV TQEFM OEVHP AJMII CDCTI FGYAG JSPXY ALUYM NSMYH" + |
|||
textCode = |
|||
"VUXJE LEPXJ FXGCM JHKDZ RYICU HYPUS PGIGM OIYHF WHTCQ KMLRD" + |
|||
Cases[ToCharacterCode[ |
|||
"ITLXZ LJFVQ GHOLW CUHLO MDSOE KTALU VYLNZ RFGBX PHVGA LWQIS" + |
|||
ToUpperCase@ |
|||
"FGRPH JOOFW GUBYI LAPLA LCAFA AMKLG CETDW VOELJ IKGJB XPHVG" + |
|||
text], _?(IntervalMemberQ[Interval@{65, 90}, #] &)] - 65; |
|||
"ALWQC SNWBU BYHCU HKOCE XJEYK BQKVY KIIEH GRLGH XEOLW AWFOJ" + |
|||
keyCode = |
|||
"ILOVV RHPKD WIHKN ATUHN VRYAQ DIVHX FHRZV QWMWV LGSHN NLVZS" + |
|||
Cases[ToCharacterCode[ |
|||
"JLAKI FHXUF XJLXM TBLQV RXXHR FZXGV LRAJI EXPRV OSMNP KEPDT" + |
|||
ToUpperCase@ |
|||
"LPRWM JAZPK LQUZA ALGZX GVLKL GJTUI ITDSU REZXJ ERXZS HMPST" + |
|||
key], _?(IntervalMemberQ[Interval@{65, 90}, #] &)] - 65; |
|||
"MTEOE PAPJH SMFNB YVQUZ AALGA YDNMP AQOWT UHDBV TSMUE UIMVH" + |
|||
keyCode = |
|||
"QGVRW AEFSP EMPVE PKXZY WLKJA GWALT VYYOB YIXOK IHPDS EVLEV" + |
|||
If[Length[textCode] < Length[keyCode], |
|||
"RVSGB JOGYW FHKBL GLXYA MVKIS KIEHY IMAPX UOISK PVAGN MZHPW" + |
|||
keyCode[[;; Length@textCode]], |
|||
"TTZPV XFCCD TUHJH WLAPF YULTB UXJLN SIJVV YOVDJ SOLXG TGRVO" + |
|||
PadRight[keyCode, Length@textCode, keyCode]]; |
|||
"SFRII CTMKO JFCQF KTINQ BWVHG TENLH HOGCS PSFPV GJOKM SIFPR" + |
|||
FromCharacterCode[Mod[textCode - keyCode, 26] + 65]]</lang> |
|||
"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>key = "Vigenere Cipher"; |
|||
val freq = doubleArrayOf( |
|||
text = "Beware the Jabberwock, my son! The jaws that bite, the claws \ |
|||
0.08167, 0.01492, 0.02782, 0.04253, 0.12702, 0.02228, 0.02015, |
|||
that catch!"; |
|||
0.06094, 0.06966, 0.00153, 0.00772, 0.04025, 0.02406, 0.06749, |
|||
code = encode[text, key] |
|||
0.07507, 0.01929, 0.00095, 0.05987, 0.06327, 0.09056, 0.02758, |
|||
0.00978, 0.02360, 0.00150, 0.01974, 0.00074 |
|||
) |
|||
WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY |
|||
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 |
|||
} |
|||
decode[code, key] |
|||
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 |
|||
} |
|||
BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH |
|||
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() |
|||
} |
|||
</pre> |
|||
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)}") |
|||
}</lang> |
|||
=={{header|NetRexx}}== |
|||
{{out}} |
|||
<lang NetRexx>/* NetRexx */ |
|||
<pre> |
|||
options replace format comments java crossref savelog symbols nobinary |
|||
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 |
|||
pt = 'Attack at dawn!' |
|||
Best key : THECHESHIRECAT |
|||
key = 'LEMON' |
|||
test(key, pt) |
|||
key = 'N' -- rot-13 |
|||
Decrypted text: |
|||
test(key, pt) |
|||
THISWASTHEPOEMTHATALICEREADJABBERWOCKYTWASBRILLIGANDTHESLITHYTOVESDIDGYREANDGIMBLEINTHEWABEALLMIMSYWERETHEBOROGOVESANDTHEMOMERATHSOUTGRABEBEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCHBEWARETHEJUBJUBBIRDANDSHUNTHEFRUMIOUSBANDERSNATCHHETOOKHISVORPALSWORDINHANDLONGTIMETHEMANXOMEFOEHESOUGHTSORESTEDHEBYTHETUMTUMTREEANDSTOODAWHILEINTHOUGHTANDASINUFFISHTHOUGHTHESTOODTHEJABBERWOCKWITHEYESOFFLAMECAMEWHIFFLINGTHROUGHTHETULGEYWOODANDBURBLEDASITCAMEONETWOONETWOANDTHROUGHANDTHROUGHTHEVORPALBLADEWENTSNICKERSNACKHELEFTITDEADANDWITHITSHEADHEWENTGALUMPHINGBACKANDHASTTHOUSLAINTHEJABBERWOCKCOMETOMYARMSMYBEAMISHBOYOFRABJOUSDAYCALLOOHCALLAYHECHORTLEDINHISJOYTWASBRILLIGANDTHESLITHYTOVESDIDGYREANDGIMBLEINTHEWABEALLMIMSYWERETHEBOROGOVESANDTHEMOMERATHSOUTGRABEITSEEMSVERYPRETTYSHESAIDWHENSHEHADFINISHEDITBUTITSRATHERHARDTOUNDERSTAND |
|||
key = 'B' -- Caesar |
|||
test(key, pt) |
|||
pt = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' |
|||
key = 'A' |
|||
test(key, pt) |
|||
pt = sampledata() |
|||
key = 'Hamlet; Prince of Denmark' |
|||
test(key, pt) |
|||
return |
|||
method vigenere(meth, key, text) public static |
|||
select |
|||
when 'encipher'.abbrev(meth.lower, 1) then df = 1 |
|||
when 'decipher'.abbrev(meth.lower, 1) then df = -1 |
|||
otherwise signal IllegalArgumentException(meth 'must be "encipher" or "decipher"') |
|||
end |
|||
alpha = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' |
|||
text = stringscrubber(text) |
|||
key = stringscrubber(key) |
|||
code = '' |
|||
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_ |
|||
return code |
|||
method vigenere_encipher(key, plaintext) public static |
|||
return vigenere('encipher', key, plaintext) |
|||
method vigenere_decipher(key, ciphertext) public static |
|||
return vigenere('decipher', key, ciphertext) |
|||
method mod(N = int, D = int) private static |
|||
return (D + (N // D)) // D |
|||
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}} |
|||
<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 |
|||
....+....|....+....|....+....|....+....|....+....|....+....|....+....|....+....| |
|||
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| |
=={{header|Nim}}== |
||
<lang |
<lang nim>import strutils |
||
use warnings; |
|||
use feature 'say'; |
|||
proc isAlpha(c): bool = c in 'a'..'z' or c in 'A'..'Z' |
|||
# 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 |
|||
proc encrypt(msg, key): string = |
|||
sub myguess { |
|||
result = "" |
|||
var pos = 0 |
|||
my ($seqtext, @spacing, @factors, @sortedfactors, $pos, %freq, %Keys); |
|||
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 = |
|||
# Kasiski examination |
|||
result = "" |
|||
var pos = 0 |
|||
while ($seqtext =~ /(...).*\1/) { |
|||
for c in msg: |
|||
$seqtext = substr($seqtext, 1+index($seqtext, $1)); |
|||
result.add chr(((26 + ord(c) - ord(key[pos])) mod 26) + ord('A')) |
|||
push @spacing, 1 + index($seqtext, $1); |
|||
pos = (pos + 1) mod key.len |
|||
} |
|||
const text = "Beware the Jabberwock, my son! The jaws that bite, the claws that catch!" |
|||
for my $j (@spacing) { |
|||
const key = "VIGENERECIPHER" |
|||
push @factors, grep { $j % $_ == 0 } 2..$j; |
|||
} |
|||
$freq{$_}++ for @factors; |
|||
@sortedfactors = grep { $_ >= 4 } sort { $freq{$b} <=> $freq{$a} } keys %freq; # discard very short keys |
|||
let encr = encrypt(text, key) |
|||
for my $keylen ( @sortedfactors[0..$max_key_lengths-1] ) { |
|||
let decr = decrypt(encr, key) |
|||
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); |
|||
} |
|||
echo text |
|||
for my $subkey (@alphabet) { |
|||
echo encr |
|||
my $decrypted = mycrypt($mykey, $subkey); |
|||
echo decr</lang> |
|||
my $length = length($decrypted); |
|||
{{out}} |
|||
for my $char (@alphabet) { |
|||
<pre>Beware the Jabberwock, my son! The jaws that bite, the claws that catch! |
|||
my $expected = $English_letter_freq{$char} * $length / 100; |
|||
WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY |
|||
my $observed; |
|||
BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH</pre> |
|||
++$observed while $decrypted =~ /$char/g; |
|||
$chi_values{$subkey} += ($observed - $expected)**2 / $expected if $observed; |
|||
} |
|||
} |
|||
=={{header|Objeck}}== |
|||
$Keys{$keylen}{score} = $chi_values{'A'}; |
|||
{{trans|D}} |
|||
for my $sk (sort keys %chi_values) { |
|||
<lang objeck> |
|||
if ($chi_values{$sk} <= $Keys{$keylen}{score}) { |
|||
bundle Default { |
|||
$bestguess = $sk; |
|||
class VigenereCipher { |
|||
$Keys{$keylen}{score} = $chi_values{$sk}; |
|||
function : Main(args : String[]) ~ Nil { |
|||
key := "VIGENERECIPHER"; |
|||
ori := "Beware the Jabberwock, my son! The jaws that bite, the claws that catch!"; |
|||
$keyguess .= $bestguess; |
|||
enc := encrypt(ori, key); |
|||
IO.Console->Print("encrypt: ")->PrintLine(enc); |
|||
$Keys{$keylen}{key} = $keyguess; |
|||
IO.Console->Print("decrypt: ")->PrintLine(decrypt(enc, key)); |
|||
} |
|||
} |
|||
map { $Keys{$_}{key} } sort { $Keys{$a}{score} <=> $Keys{$b}{score}} keys %Keys; |
|||
} |
|||
function : native : encrypt(text : String, key : String) ~ String { |
|||
sub mycrypt { |
|||
res := ""; |
|||
text := text->ToUpper(); |
|||
my ($new_text, %values_numbers); |
|||
j := 0; |
|||
each(i : text) { |
|||
c := text->Get(i); |
|||
@values_numbers{@alphabet} = 0..25; |
|||
if(c >= 'A' & c <= 'Z') { |
|||
my %values_letters = reverse %values_numbers; |
|||
res->Append(((c + key->Get(j) - 2 * 'A') % 26 + 'A')->As(Char)); |
|||
j += 1; |
|||
j := j % key->Size(); |
|||
}; |
|||
}; |
|||
return res; |
|||
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)}; |
|||
function : native : decrypt(text : String, key : String) ~ String { |
|||
$new_text .= $values_letters{ $val % 26 }; |
|||
res := ""; |
|||
text := text->ToUpper(); |
|||
return $new_text; |
|||
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}}== |
|||
my $cipher_text = <<~'EOD'; |
|||
{{trans|C}} |
|||
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 |
|||
<lang ocaml>let cipher src key crypt = |
|||
my $text = uc($cipher_text) =~ s/[^@{[join '', @alphabet]}]//gr; |
|||
let str = String.uppercase src in |
|||
let key = String.uppercase key in |
|||
(* strip out non-letters *) |
|||
for my $key ( myguess($text) ) { |
|||
let len = String.length str in |
|||
say "Key $key\n" . |
|||
let rec aux i j = |
|||
"Key length " . length($key) . "\n" . |
|||
if j >= len then String.sub str 0 i else |
|||
"Plaintext " . substr(mycrypt($text, $key), 0, 80) . "...\n"; |
|||
if str.[j] >= 'A' && str.[j] <= 'Z' |
|||
}</lang> |
|||
then (str.[i] <- str.[j]; aux (succ i) (succ j)) |
|||
else aux i (succ j) |
|||
in |
|||
let res = aux 0 0 in |
|||
let slen = String.length res in |
|||
let klen = String.length key in |
|||
let d = int_of_char in |
|||
let f = |
|||
if crypt |
|||
then fun i -> d res.[i] - d 'A' + d key.[i mod klen] - d 'A' |
|||
else fun i -> d res.[i] - d key.[i mod klen] + 26 |
|||
in |
|||
for i = 0 to pred slen do |
|||
res.[i] <- char_of_int (d 'A' + (f i) mod 26) |
|||
done; |
|||
(res) |
|||
let () = |
|||
let str = "Beware the Jabberwock, my son! The jaws that bite, \ |
|||
the claws that catch!" in |
|||
let key = "VIGENERECIPHER" in |
|||
let cod = cipher str key true in |
|||
let dec = cipher cod key false in |
|||
Printf.printf "Text: %s\n" str; |
|||
Printf.printf "key: %s\n" key; |
|||
Printf.printf "Code: %s\n" cod; |
|||
Printf.printf "Back: %s\n" dec; |
|||
;;</lang> |
|||
Run: |
|||
<pre>$ ocaml vigenere_cipher.ml |
|||
Text: Beware the Jabberwock, my son! The jaws that bite, the claws that catch! |
|||
key: VIGENERECIPHER |
|||
Code: WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY |
|||
Back: BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH</pre> |
|||
=={{header|ooRexx}}== |
|||
{{trans|NetRexx}} |
|||
A reworking of the [[#NetRexx|NetRexx]] version using Open Object Rexx but shouldn't take much to translate to Classic Rexx. |
|||
<lang REXX>/* Rexx */ |
|||
Do |
|||
alpha = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' |
|||
key = 'LEMON' |
|||
pt = 'Attack at dawn!' |
|||
Call test key, pt |
|||
key = 'N' |
|||
Call test key, pt |
|||
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> |
|||
{{out}} |
{{out}} |
||
<pre style="height: 60ex; overflow: scroll;"> |
|||
<pre>Key THECHESHIRECAT |
|||
....+....|....+....|....+....|....+....|....+....|....+....|....+....|....+....| |
|||
Key length 14 |
|||
LXFOP VEFRN HR |
|||
Plaintext THISWASTHEPOEMTHATALICEREADJABBERWOCKYTWASBRILLIGANDTHESLITHYTOVESDIDGYREANDGIMB... |
|||
....+....|....+....|....+....|....+....|....+....|....+....|....+....|....+....| |
|||
Key THECHESCIRECATTHECHESHIRECAT |
|||
ATTAC KATDA WN |
|||
Key length 28 |
|||
Plaintext THISWASYHEPOEMTHATALICEREADJABBERWOHKYTWASBRILLIGANDTHESLITHYTOAESDIDGYREANDGIMB... |
|||
....+....|....+....|....+....|....+....|....+....|....+....|....+....|....+....| |
|||
Key TJGGAHET |
|||
NGGNP XNGQN JA |
|||
Key length 8 |
|||
Plaintext TFGODXGHWMNKEYIVLMBJACIPPTXWTBBNFRADSITFHCOSMGOTFYPOXCASLGRDFQCJTABEDSNFPTOBYIQZ... |
|||
....+....|....+....|....+....|....+....|....+....|....+....|....+....|....+....| |
|||
Key THECSAS |
|||
ATTAC KATDA WN |
|||
Key length 7 |
|||
Plaintext THISLESHIRRYENTHATPPIQFEGKDKABBEGAOQLLVGATBRILAMGOOQVRETLITHNXOJFFFSDHYREACHGWNO... |
|||
....+....|....+....|....+....|....+....|....+....|....+....|....+....|....+....| |
|||
Key THEC |
|||
BUUBD LBUEB XO |
|||
Key length 4 |
|||
Plaintext THISKXGYWOPOLYIMLODNHCIGPVZAABBEFTCHZITWHEQWTGOKFARSECAJLITHMQCATCDIKSNWPVQFFIQQ...</pre> |
|||
....+....|....+....|....+....|....+....|....+....|....+....|....+....|....+....| |
|||
=={{header|Perl 6}}== |
|||
ATTAC KATDA WN |
|||
{{trans|Perl}} |
|||
<lang perl6># 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) { |
|||
ABCDE FGHIJ KLMNO PQRST UVWXY Z |
|||
my ($seqtext, @spacing, @factors, $pos, %freq, %Keys); |
|||
....+....|....+....|....+....|....+....|....+....|....+....|....+....|....+....| |
|||
# Kasiski examination |
|||
ABCDE FGHIJ KLMNO PQRST UVWXY Z |
|||
$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 |
|||
AONPS KCFBG QFSYK EGUSK RLQGP WMXFV JJIHM HVGUS EYILQ CMGIY MZKRR YRWHR |
|||
(%freq.keys.grep(* > 3).sort({%freq{$_}}).tail(max_key_lengths)).race(:1batch).map: -> $keylen { |
|||
FVBAH QDPBC XANPH OWUSJ EOWYB TDLKX DLASQ VHZQI BDTFD HKQLV FHRON KRGYD |
|||
my $key-guess = ''; |
|||
WRMOW DYOGM PXHRV QDCCU SSFUN XOUDF SIFIF LVGXC XOIRB NFWVR QLRWQ PIFNI |
|||
loop (my $i = 0; $i < $keylen; $i++) { |
|||
SUWSF MYNOL NPELX WVIEV EQMHE APTYO AHAFW TCUVN VYFFO WUACB CAHME JETJP |
|||
my ($mykey, %chi-square, $best-guess); |
|||
VULSN UXBFI JKJOZ DYFBR BVQRR JYSHF LPDVB QHMLW VLGQH WJWSF XEVZA OEWIX |
|||
loop (my $j = 0; $j < $text.chars; $j += $keylen) { |
|||
EGMEE LOSFI GADIO HMMJX ATIMF VLSWX FSARZ XAHME WETVX BHHSF WLJTA KNYEM |
|||
$mykey ~= substr($text, ($j+$i) % $text.chars, 1); |
|||
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 |
|||
....+....|....+....|....+....|....+....|....+....|....+....|....+....|....+....| |
|||
for @alphabet -> $subkey { |
|||
TOBEO RNOTT OBETH ATIST HEQUE STION WHETH ERTIS NOBLE RINTH EMIND TOSUF |
|||
my $decrypted = mycrypt($mykey, $subkey); |
|||
FERTH ESLIN GSAND ARROW SOFOU TRAGE OUSFO RTUNE ORTOT AKEAR MSAGA INSTA |
|||
my $length = $decrypted.chars; |
|||
SEAOF TROUB LESAN DBYOP POSIN GENDT HEMTO DIETO SLEEP NOMOR EANDB YASLE |
|||
for @alphabet -> $char { |
|||
EPTOS AYWEE NDTHE HEART ACHEA NDTHE THOUS ANDNA TURAL SHOCK STHAT FLESH |
|||
my $expected = %English-letter-freq{$char} * $length / 100; |
|||
ISHEI RTOTI SACON SUMMA TIOND EVOUT LYTOB EWISH EDTOD IETOS LEEPT OSLEE |
|||
my $observed = $decrypted.comb.grep(* eq $char).elems; |
|||
PPERC HANCE TODRE AMAYT HERES THERU BFORI NTHAT SLEEP OFDEA THWHA TDREA |
|||
%chi-square{$subkey} += ($observed - $expected)² / $expected if $observed; |
|||
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 |
|||
%Keys{$keylen}{'score'} = %chi-square{@alphabet[0]}; |
|||
THEPA NGSOF DESPI SEDLO VETHE LAWSD ELAYT HEINS OLENC EOFOF FICEA NDTHE |
|||
for %chi-square.keys.sort -> $sk { |
|||
SPURN STHAT PATIE NTMER ITOFT HUNWO RTHYT AKESW HENHE HIMSE LFMIG HTHIS |
|||
if (%chi-square{$sk} <= %Keys{$keylen}{'score'}) { |
|||
QUIET USMAK EWITH ABARE BODKI NWHOW OULDF ARDEL SBEAR TOGRU NTAND SWEAT |
|||
$best-guess = $sk; |
|||
UNDER AWEAR YLIFE BUTTH ATTHE DREAD OFSOM ETHIN GAFTE RDEAT HTHEU NDISC |
|||
%Keys{$keylen}{'score'} = %chi-square{$sk}; |
|||
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 |
|||
$key-guess ~= $best-guess; |
|||
FRESO LUTIO NISSI CKLIE DOERW ITHTH EPALE CASTO FTHOU GHTAN DENTE RPRIS |
|||
} |
|||
EOFGR EATPI THAND MOMEN TWITH THISR EGARD THEIR CURRE NTSTU RNAWR YANDL |
|||
%Keys{$keylen}{'key'} = $key-guess; |
|||
OSETH ENAME OFACT IONSO FTYOU NOWTH EFAIR OPHEL IANYM PHINT HYORI SONSB |
|||
} |
|||
EALLM YSINS REMEM BERED |
|||
%Keys.keys.sort({ %Keys{$_}{'score'} }).map:{ %Keys{$_}{'key'} }; |
|||
</pre> |
|||
=={{header|Pascal}}== |
|||
<lang pascal> |
|||
// The Vigenere cipher in reasonably standard Pascal |
|||
// <no library functions: all conversions hand-coded> |
|||
PROGRAM Vigenere; |
|||
// get a letter's alphabetic position (A=0) |
|||
FUNCTION letternum(letter: CHAR): BYTE; |
|||
BEGIN |
|||
letternum := (ord(letter)-ord('A')); |
|||
END; |
|||
// convert a character to uppercase |
|||
FUNCTION uch(ch: CHAR): CHAR; |
|||
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; |
|||
VAR key: STRING = 'Vigenere cipher'; |
|||
msg: STRING = 'Beware the Jabberwock! The jaws that bite, the claws that catch!'; |
|||
vtx: STRING = ''; |
|||
ctx: STRING = ''; |
|||
ptx: STRING = ''; |
|||
BEGIN |
|||
// make Vigenere-compatible |
|||
vtx := vstr(msg); |
|||
key := vkey(vtx,key); |
|||
// 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. |
|||
</lang> |
|||
{{out}} |
|||
<pre> |
|||
Message : Beware the Jabberwock! The jaws that bite, the claws that catch! |
|||
Plaintext : BEWARETHEJABBERWOCKTHEJAWSTHATBITETHECLAWSTHATCATCH |
|||
Key : VIGENERECIPHERVIGENERECIPHERVIGENERECIPHERVIGENEREC |
|||
Ciphertext : WMCEEIKLGRPIFVMEUGXXYILILZXYVBHMGIKLGKAHAJOPGXPEKGJ |
|||
Plaintext : BEWARETHEJABBERWOCKTHEJAWSTHATBITETHECLAWSTHATCATCH |
|||
</pre> |
|||
=={{header|Perl}}== |
|||
<lang perl>if( @ARGV != 3 ){ |
|||
printHelp(); |
|||
} |
} |
||
# translate to upper-case, remove anything else |
|||
sub mycrypt ($text, $key) { |
|||
map( (tr/a-z/A-Z/, s/[^A-Z]//g), @ARGV ); |
|||
constant %values-numbers = @alphabet Z=> ^@alphabet; |
|||
constant %values-letters = %values-numbers.invert; |
|||
my $cipher_decipher = $ARGV[ 0 ]; |
|||
my ($new-text); |
|||
my $keylen = $key.chars; |
|||
if( $cipher_decipher !~ /ENC|DEC/ ){ |
|||
loop (my $i = 0; $i < $text.chars; $i++) { |
|||
printHelp(); # user should say what to do |
|||
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; |
|||
} |
} |
||
print "Key: " . (my $key = $ARGV[ 2 ]) . "\n"; |
|||
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 |
|||
if( $cipher_decipher =~ /ENC/ ){ |
|||
for myguess($cipher-text) -> $key { |
|||
print "Plain-text: " . (my $plain = $ARGV[ 1 ]) . "\n"; |
|||
print "Encrypted: " . Vigenere( 1, $key, $plain ) . "\n"; |
|||
}elsif( $cipher_decipher =~ /DEC/ ){ |
|||
"Plaintext {substr(mycrypt($cipher-text, $key), 0, 80)}...\n"; |
|||
print "Cipher-text: " . (my $cipher = $ARGV[ 1 ]) . "\n"; |
|||
print "Decrypted: " . Vigenere( -1, $key, $cipher ) . "\n"; |
|||
} |
|||
sub printHelp{ |
|||
print "Usage:\n" . |
|||
"Encrypting:\n perl cipher.pl ENC (plain text) (key)\n" . |
|||
"Decrypting:\n perl cipher.pl DEC (cipher text) (key)\n"; |
|||
exit -1; |
|||
} |
|||
sub Vigenere{ |
|||
my ($direction, $key, $text) = @_; |
|||
for( my $count = 0; $count < length $text; $count ++ ){ |
|||
$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> |
}</lang> |
||
{{out}} |
|||
<pre>Key THECHESHIRECAT |
|||
Key length 14 |
|||
Plaintext THISWASTHEPOEMTHATALICEREADJABBERWOCKYTWASBRILLIGANDTHESLITHYTOVESDIDGYREANDGIMB... |
|||
Demonstration: |
|||
Key THECHESCIRECATTHECHESHIRECAT |
|||
Key length 28 |
|||
Plaintext THISWASYHEPOEMTHATALICEREADJABBERWOHKYTWASBRILLIGANDTHESLITHYTOAESDIDGYREANDGIMB... |
|||
<pre>$ perl cipher.pl ENC 'Beware the Jabberwock, my son! The jaws that bite, the claws that catch!' VIGENERECIPHER |
|||
Key TJGGAHET |
|||
Key |
Key: VIGENERECIPHER |
||
Plain-text: BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH |
|||
Plaintext TFGODXGHWMNKEYIVLMBJACIPPTXWTBBNFRADSITFHCOSMGOTFYPOXCASLGRDFQCJTABEDSNFPTOBYIQZ... |
|||
Encrypted: WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY |
|||
$ perl cipher.pl DEC WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY VIGENERECIPHER |
|||
Key THECSAS |
|||
Key |
Key: VIGENERECIPHER |
||
Cipher-text: WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY |
|||
Plaintext THISLESHIRRYENTHATPPIQFEGKDKABBEGAOQLLVGATBRILAMGOOQVRETLITHNXOJFFFSDHYREACHGWNO... |
|||
Decrypted: BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH |
|||
$ perl cipher.pl FOO WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY VIGENERECIPHER |
|||
Key THEC |
|||
Usage: |
|||
Key length 4 |
|||
Encrypting: |
|||
Plaintext THISKXGYWOPOLYIMLODNHCIGPVZAABBEFTCHZITWHEQWTGOKFARSECAJLITHMQCATCDIKSNWPVQFFIQQ...</pre> |
|||
perl cipher.pl ENC (plain text) (key) |
|||
Decrypting: |
|||
perl cipher.pl DEC (cipher text) (key)</pre> |
|||
=={{header|Phix}}== |
=={{header|Phix}}== |
||
<lang Phix>enum type mode ENCRYPT = +1, DECRYPT = -1 end type |
|||
{{trans|Julia}} |
|||
<lang Phix>-- |
|||
-- demo\rosetta\Cryptanalysis.exw |
|||
-- |
|||
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"},{"",""}) |
|||
function Vigenere(string s, string key, mode m) |
|||
constant letters = new_dict( |
|||
string res = "" |
|||
{{'E',12.702}, |
|||
integer k = 1, ch |
|||
{'T',9.056}, |
|||
s = upper(s) |
|||
for i=1 to length(s) do |
|||
{'O',7.507}, |
|||
ch = s[i] |
|||
if ch>='A' and ch<='Z' then |
|||
{'N',6.749}, |
|||
res &= 'A'+mod(ch+m*(key[k]+26),26) |
|||
{'S',6.327}, |
|||
k = mod(k,length(key))+1 |
|||
{'H',6.094}, |
|||
end if |
|||
{'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 |
end for |
||
return |
return res |
||
end function |
end function |
||
constant key = "LEMON", |
|||
function cryptanalyze(string enc, integer maxkeylen=20) |
|||
s = "ATTACK AT DAWN", |
|||
e = Vigenere(s,key,ENCRYPT), |
|||
d = Vigenere(e,key,DECRYPT) |
|||
k1 = " " |
|||
atom maxscore = 0.0 |
|||
printf(1,"Original: %s\nEncrypted: %s\nDecrypted: %s\n",{s,e,d})</lang> |
|||
for keylen=1 to maxkeylen do |
|||
{{Out}} |
|||
string key = repeat(' ',keylen) |
|||
<pre> |
|||
sequence idx = {} |
|||
Original: ATTACK AT DAWN |
|||
for i=1 to enclen do |
|||
Encrypted: LXFOPVEFRNHR |
|||
if mod(i,keylen)=0 then |
|||
Decrypted: ATTACKATDAWN |
|||
idx &= i-keylen+1 |
|||
</pre> |
|||
end if |
|||
end for |
|||
=={{header|PHP}}== |
|||
for i=1 to keylen do |
|||
{{trans|C}} |
|||
atom maxsubscore = 0.0 |
|||
<lang PHP><?php |
|||
$str = "Beware the Jabberwock, my son! The jaws that bite, the claws that catch!"; |
|||
$key = "VIGENERECIPHER"; |
|||
printf("Text: %s\n", $str); |
|||
printf("key: %s\n", $key); |
|||
$cod = encipher($str, $key, true); printf("Code: %s\n", $cod); |
|||
$dec = encipher($cod, $key, false); printf("Back: %s\n", $dec); |
|||
function encipher($src, $key, $is_encode) |
|||
{ |
|||
$key = strtoupper($key); |
|||
$src = strtoupper($src); |
|||
$dest = ''; |
|||
/* strip out non-letters */ |
|||
for($i = 0; $i <= strlen($src); $i++) { |
|||
$char = substr($src, $i, 1); |
|||
if(ctype_upper($char)) { |
|||
$dest .= $char; |
|||
} |
|||
} |
|||
for($i = 0; $i <= strlen($dest); $i++) { |
|||
$char = substr($dest, $i, 1); |
|||
if(!ctype_upper($char)) { |
|||
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); |
|||
} |
|||
return $dest; |
|||
} |
|||
?> |
|||
</lang> |
|||
{{out}} |
|||
<pre>Text: Beware the Jabberwock, my son! The jaws that bite, the claws that catch! |
|||
key: VIGENERECIPHER |
|||
Code: WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY |
|||
Back: BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH</pre> |
|||
=={{header|PicoLisp}}== |
|||
<lang PicoLisp>(de vigenereKey (Str) |
|||
(extract |
|||
'((C) |
|||
(when (>= "Z" (uppc C) "A") |
|||
(- (char (uppc C)) 65) ) ) |
|||
(chop Str) ) ) |
|||
(de vigenereEncrypt (Str Key) |
|||
(pack |
|||
(mapcar |
|||
'((C K) |
|||
(char (+ 65 (% (+ C K) 26))) ) |
|||
(vigenereKey Str) |
|||
(apply circ (vigenereKey Key)) ) ) ) |
|||
(de vigenereDecrypt (Str Key) |
|||
(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" |
|||
: (vigenereDecrypt @ "VIGENERECIPHER") |
|||
-> "BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH"</pre> |
|||
=={{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. */ |
|||
t(1) = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; |
|||
do i = 2 to 26; |
|||
t(i) = substr(t(i-1), 2, 25) || substr(t(i-1), 1, 1); |
|||
end; |
|||
cypher = 'VIGILANCE'; |
|||
original = 'Meet me on Tuesday evening at seven.'; |
|||
put edit ('Message=', original) (a); |
|||
original = uppercase(original); |
|||
/* Create the cypher text, same length as original, or longer. */ |
|||
coder = repeat(cypher, length(original)/length(cypher)); |
|||
/* 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); |
|||
/* DECODING. */ |
|||
put skip list ('Decoded='); |
|||
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 |
|||
) |
|||
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 |
|||
begin |
|||
if subscore > maxsubscore then |
|||
{ |
|||
maxsubscore = subscore |
|||
$map = [char]'A'..[char]'Z' |
|||
} |
|||
end if |
|||
end for |
|||
process |
|||
idx = sq_add(idx,1) |
|||
{ |
|||
$Key = $Key -replace '[^a-zA-Z]','' |
|||
$Text = $Text -replace '[^a-zA-Z]','' |
|||
$keyChars = $Key.toUpper().ToCharArray() |
|||
$Chars = $Text.toUpper().ToCharArray() |
|||
function encode |
|||
{ |
|||
param |
|||
( |
|||
$Char, |
|||
$keyChar, |
|||
$Alpha = [char]'A'..[char]'Z' |
|||
) |
|||
$charIndex = $Alpha.IndexOf([int]$Char) |
|||
$keyIndex = $Alpha.IndexOf([int]$keyChar) |
|||
$NewIndex = ($charIndex + $KeyIndex) - $Alpha.Length |
|||
$Alpha[$NewIndex] |
|||
} |
|||
function decode |
|||
{ |
|||
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 |
|||
param |
|||
string {key, dec} = cryptanalyze(ciphertext) |
|||
( |
|||
printf(1,"key: %s\n\n%s\n\n", {key, fold(dec,80)}) |
|||
$Char, |
|||
$keyChar, |
|||
$Alpha = [char]'A'..[char]'Z' |
|||
) |
|||
$charIndex = $Alpha.IndexOf([int]$Char) |
|||
$keyIndex = $Alpha.IndexOf([int]$keyChar) |
|||
$int = $charIndex - $keyIndex |
|||
if ($int -lt 0) { $NewIndex = $int + $Alpha.Length } |
|||
else { $NewIndex = $int } |
|||
$Alpha[$NewIndex] |
|||
} |
|||
while ( $keyChars.Length -lt $Chars.Length ) |
|||
{ |
|||
$keyChars = $keyChars + $keyChars |
|||
} |
|||
for ( $i = 0; $i -lt $Chars.Length; $i++ ) |
|||
{ |
|||
if ( [int]$Chars[$i] -in $map -and [int]$keyChars[$i] -in $map ) |
|||
{ |
|||
if ($Decode) {$Chars[$i] = decode $Chars[$i] $keyChars[$i] $map} |
|||
else {$Chars[$i] = encode $Chars[$i] $keyChars[$i] $map} |
|||
$Chars[$i] = [char]$Chars[$i] |
|||
[string]$OutText += $Chars[$i] |
|||
} |
|||
} |
|||
$OutText |
|||
printf(1,"elapsed time: %3.2f seconds",{time()-t0})</lang> |
|||
$OutText = $null |
|||
{{Out}} |
|||
} |
|||
}</lang> |
|||
Usage examples: |
|||
<pre> |
<pre> |
||
Encode: |
|||
key: THECHESHIRECAT |
|||
PS C:\> Get-VigenereCipher 'We attack at dawn.' 'lemon' |
|||
HIMHGLGWOGOEIB |
|||
Decode: |
|||
THISWASTHEPOEMTHATALICEREADJABBERWOCKYTWASBRILLIGANDTHESLITHYTOVESDIDGYREANDGIM |
|||
PS C:\> Get-VigenereCipher 'HIMHGLGWOGOEIB' 'lemon' -Decode |
|||
BLEINTHEWABEALLMIMSYWERETHEBOROGOVESANDTHEMOMERATHSOUTGRABEBEWARETHEJABBERWOCKM |
|||
WEATTACKATDAWN |
|||
YSONTHEJAWSTHATBITETHECLAWSTHATCATCHBEWARETHEJUBJUBBIRDANDSHUNTHEFRUMIOUSBANDER |
|||
SNATCHHETOOKHISVORPALSWORDINHANDLONGTIMETHEMANXOMEFOEHESOUGHTSORESTEDHEBYTHETUM |
|||
TUMTREEANDSTOODAWHILEINTHOUGHTANDASINUFFISHTHOUGHTHESTOODTHEJABBERWOCKWITHEYESO |
|||
FFLAMECAMEWHIFFLINGTHROUGHTHETULGEYWOODANDBURBLEDASITCAMEONETWOONETWOANDTHROUGH |
|||
ANDTHROUGHTHEVORPALBLADEWENTSNICKERSNACKHELEFTITDEADANDWITHITSHEADHEWENTGALUMPH |
|||
INGBACKANDHASTTHOUSLAINTHEJABBERWOCKCOMETOMYARMSMYBEAMISHBOYOFRABJOUSDAYCALLOOH |
|||
CALLAYHECHORTLEDINHISJOYTWASBRILLIGANDTHESLITHYTOVESDIDGYREANDGIMBLEINTHEWABEAL |
|||
LMIMSYWERETHEBOROGOVESANDTHEMOMERATHSOUTGRABEITSEEMSVERYPRETTYSHESAIDWHENSHEHAD |
|||
FINISHEDITBUTITSRATHERHARDTOUNDERSTAND |
|||
elapsed time: 0.42 seconds |
|||
</pre> |
</pre> |
||
=={{header| |
=={{header|PureBasic}}== |
||
<lang PureBasic>Procedure prepString(text.s, Array letters(1)) |
|||
{{trans|D}} |
|||
;convert characters to an ordinal (0-25) and remove non-alphabetic characters, |
|||
<lang python>from string import uppercase |
|||
;returns dimension size of result array letters() |
|||
from operator import itemgetter |
|||
Protected *letter.Character, index |
|||
Dim letters(Len(text)) |
|||
text = UCase(text) |
|||
*letter = @text |
|||
While *letter\c |
|||
Select *letter\c |
|||
Case 'A' To 'Z' |
|||
letters(index) = *letter\c - 65 |
|||
index + 1 |
|||
EndSelect |
|||
*letter + SizeOf(Character) |
|||
Wend |
|||
If index > 0 |
|||
Redim letters(index - 1) |
|||
EndIf |
|||
ProcedureReturn index - 1 |
|||
EndProcedure |
|||
Procedure.s VC_encrypt(text.s, keyText.s, reverse = 0) |
|||
def vigenere_decrypt(target_freqs, input): |
|||
;if reverse <> 0 then reverse the key (decrypt) |
|||
nchars = len(uppercase) |
|||
Protected *letter.Character |
|||
ordA = ord('A') |
|||
Dim text(0) |
|||
sorted_targets = sorted(target_freqs) |
|||
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 |
|||
Procedure.s VC_decrypt(cypherText.s, keyText.s) |
|||
def frequency(input): |
|||
ProcedureReturn VC_encrypt(cypherText, keyText.s, 1) |
|||
result = [[c, 0.0] for c in uppercase] |
|||
EndProcedure |
|||
for c in input: |
|||
result[c - ordA][1] += 1 |
|||
return result |
|||
If OpenConsole() |
|||
def correlation(input): |
|||
Define VignereCipher.s, plainText.s, encryptedText.s, decryptedText.s |
|||
result = 0.0 |
|||
freq = frequency(input) |
|||
VignereCipher.s = "VIGNERECIPHER" |
|||
freq.sort(key=itemgetter(1)) |
|||
plainText = "The quick brown fox jumped over the lazy dogs.": PrintN(RSet("Plain text = ", 17) + #DQUOTE$ + plainText + #DQUOTE$) |
|||
encryptedText = VC_encrypt(plainText, VignereCipher): PrintN(RSet("Encrypted text = ", 17) + #DQUOTE$ + encryptedText + #DQUOTE$) |
|||
decryptedText = VC_decrypt(encryptedText, VignereCipher): PrintN(RSet("Decrypted text = ", 17) + #DQUOTE$ + decryptedText + #DQUOTE$) |
|||
Print(#CRLF$ + #CRLF$ + "Press ENTER to exit"): Input() |
|||
CloseConsole() |
|||
EndIf</lang> |
|||
{{out}} |
|||
<pre> Plain text = "The quick brown fox jumped over the lazy dogs." |
|||
Encrypted text = "OPKDYZGMJGVAEAWDWYDTGLDCIIOPKYEQCFWVZ" |
|||
Decrypted text = "THEQUICKBROWNFOXJUMPEDOVERTHELAZYDOGS"</pre> |
|||
=={{header|Python}}== |
|||
for i, f in enumerate(freq): |
|||
{{Works with|Python|3}} |
|||
result += f[1] * sorted_targets[i] |
|||
{{trans|Haskell}} |
|||
return result |
|||
<lang python>'''Vigenere encryption and decryption''' |
|||
from itertools import starmap, cycle |
|||
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) |
|||
def encrypt(message, key): |
|||
# The correlation seems to increase for smaller |
|||
'''Vigenere encryption of message using key.''' |
|||
# pieces/longer keys, so weigh against them a little |
|||
corr = -0.5 * i + sum(correlation(p) for p in pieces) |
|||
# Converted to uppercase. |
|||
if corr > best_corr: |
|||
# Non-alpha characters stripped out. |
|||
best_len = i |
|||
message = filter(str.isalpha, message.upper()) |
|||
best_corr = corr |
|||
def enc(c, k): |
|||
'''Single letter encryption.''' |
|||
return ("Text is too short to analyze", "") |
|||
return chr(((ord(k) + ord(c) - 2 * ord('A')) % 26) + ord('A')) |
|||
pieces = [[] for _ in xrange(best_len)] |
|||
for i, c in enumerate(cleaned): |
|||
pieces[i % best_len].append(c) |
|||
return ''.join(starmap(enc, zip(message, cycle(key)))) |
|||
freqs = [frequency(p) for p in pieces] |
|||
key = "" |
|||
for fr in freqs: |
|||
fr.sort(key=itemgetter(1), reverse=True) |
|||
def decrypt(message, key): |
|||
m = 0 |
|||
'''Vigenere decryption of message using key.''' |
|||
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] |
|||
def dec(c, k): |
|||
if corr > max_corr: |
|||
'''Single letter decryption.''' |
|||
max_corr = corr |
|||
return chr(((ord(c) - ord(k) - 2 * ord('A')) % 26) + ord('A')) |
|||
return ''.join(starmap(dec, zip(message, cycle(key)))) |
|||
r = (chr((c - ord(key[i % best_len]) + nchars) % nchars + ordA) |
|||
for i, c in enumerate(cleaned)) |
|||
return (key, "".join(r)) |
|||
def main(): |
def main(): |
||
'''Demonstration''' |
|||
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""" |
|||
text = 'Beware the Jabberwock, my son! The jaws that bite, ' + ( |
|||
english_frequences = [ |
|||
'the claws that catch!' |
|||
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, |
|||
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] |
|||
encr = encrypt(text, key) |
|||
(key, decoded) = vigenere_decrypt(english_frequences, encoded) |
|||
decr = decrypt(encr, key) |
|||
print "\nText:", decoded |
|||
print(text) |
|||
main()</lang> |
|||
print(encr) |
|||
print(decr) |
|||
=={{header|Racket}}== |
|||
if __name__ == '__main__': |
|||
=== Simple method === |
|||
main() |
|||
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> |
|||
{{out}} |
|||
<pre>Beware the Jabberwock, my son! The jaws that bite, the claws that catch! |
|||
WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY |
|||
BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH</pre> |
|||
=={{header|R}}== |
|||
<lang Racket> |
|||
<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) |
|||
(define max-keylen 30) |
|||
as.integer(Filter(Negate(is.na), |
|||
factor(levels = LETTERS, strsplit(toupper(s), "")[[1]]))) |
|||
vigen = function(input, key, decrypt = F) |
|||
(define text |
|||
{input = str2ints(input) |
|||
@~a{MOMUD EKAPV TQEFM OEVHP AJMII CDCTI FGYAG JSPXY ALUYM NSMYH |
|||
key = rep(str2ints(key), len = length(input)) - 1 |
|||
VUXJE LEPXJ FXGCM JHKDZ RYICU HYPUS PGIGM OIYHF WHTCQ KMLRD |
|||
paste(collapse = "", LETTERS[ |
|||
ITLXZ LJFVQ GHOLW CUHLO MDSOE KTALU VYLNZ RFGBX PHVGA LWQIS |
|||
mod1(input + (if (decrypt) -1 else 1)*key, length(LETTERS))])} |
|||
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}) |
|||
message(vigen("Beware the Jabberwock, my son! The jaws that bite, the claws that catch!", "vigenerecipher")) |
|||
(define first-char (char->integer #\A)) |
|||
# WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY |
|||
(define chars# (- (char->integer #\Z) first-char -1)) |
|||
message(vigen("WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY", "vigenerecipher", decrypt = T)) |
|||
# BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH</lang> |
|||
=={{header|Racket}}== |
|||
(define freqs ; english letter frequencies from wikipedia |
|||
<lang racket> |
|||
((compose1 list->vector (curry map (curryr / 100000.0))) |
|||
#lang racket |
|||
'(8167 1492 2782 4253 12702 2228 2015 6094 6966 153 772 4025 2406 |
|||
(define chr integer->char) |
|||
6749 7507 1929 95 5987 6327 9056 2758 978 2360 150 1974 74))) |
|||
(define ord char->integer) |
|||
(define (encrypt msg key) |
|||
(define text* (for/vector ([c (regexp-replace* #px"\\s+" text "")]) |
|||
(define cleaned |
|||
(- (char->integer c) first-char))) |
|||
(list->string |
|||
(define N (vector-length text*)) |
|||
(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 ( |
(define (decrypt msg key) |
||
( |
(list->string |
||
(for/list ([c msg] [k (in-cycle key)]) |
|||
(chr (+ (modulo (- (ord c) (ord k)) 26) (ord #\A)))))) |
|||
(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))))) |
|||
(decrypt (encrypt "Beware the Jabberwock, my son! The jaws that bite, the claws that catch!" |
|||
(define best-key |
|||
"VIGENERECIPHER") |
|||
(cdr (argmin car |
|||
"VIGENERECIPHER") |
|||
(for/list ([len (range 1 (add1 max-keylen))]) |
|||
</lang> |
|||
(define guesses (col-guesses len)) |
|||
{{out}} |
|||
(cons (/ (apply + (map car guesses)) len) (map cdr guesses)))))) |
|||
<lang racket> |
|||
"BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH" |
|||
</lang> |
|||
=={{header|Raku}}== |
|||
(printf "Best key found: ") |
|||
(formerly Perl 6) |
|||
(for ([c best-key]) (display (integer->char (+ c first-char)))) |
|||
{{Works with|rakudo|2015-11-14}} |
|||
(newline) |
|||
<lang perl6>sub s2v ($s) { $s.uc.comb(/ <[ A..Z ]> /)».ord »-» 65 } |
|||
sub v2s (@v) { (@v »%» 26 »+» 65)».chr.join } |
|||
sub blacken ($red, $key) { v2s(s2v($red) »+» s2v($key)) } |
|||
(printf "Decoded text:\n") |
|||
sub redden ($blk, $key) { v2s(s2v($blk) »-» s2v($key)) } |
|||
(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) |
|||
</lang> |
|||
my $red = "Beware the Jabberwock, my son! The jaws that bite, the claws that catch!"; |
|||
Output: |
|||
my $key = "Vigenere Cipher!!!"; |
|||
<pre> |
|||
Best key found: THECHESHIRECAT |
|||
Decoded text: |
|||
THISW ASTHE POEMT HATAL ICERE ADJAB BERWO CKYTW ASBRI LLIGA |
|||
... |
|||
</pre> |
|||
say $red; |
|||
=== An attempted more complete implementation === |
|||
say my $black = blacken($red, $key); |
|||
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... |
|||
say redden($black, $key);</lang> |
|||
{{out}} |
|||
<pre>Beware the Jabberwock, my son! The jaws that bite, the claws that catch! |
|||
WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY |
|||
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. |
|||
=={{header|Red}}== |
|||
<lang Racket> |
|||
note: this program is much longer than it needed to be - because i couldn't resist |
|||
#lang at-exp racket |
|||
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. |
|||
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. |
|||
<lang Red>Red [needs: 'view] |
|||
CRLF: copy "^M^/" ;; constant for 0D 0A line feed |
|||
(define max-keylen 30) |
|||
;;------------------------------------ |
|||
crypt: func ["function to en- or decrypt message from textarea tx1" |
|||
/decrypt "decrypting switch/refinement" ][ |
|||
;;------------------------------------ |
|||
;; when decrypting we have to remove the superflous newlines |
|||
(define text |
|||
;; and undo the base64 encoding first ... |
|||
@~a{MOMUD EKAPV TQEFM OEVHP AJMII CDCTI FGYAG JSPXY ALUYM NSMYH |
|||
txt: either decrypt [ ;; message to en- or decrypt |
|||
VUXJE LEPXJ FXGCM JHKDZ RYICU HYPUS PGIGM OIYHF WHTCQ KMLRD |
|||
s: copy tx1/text |
|||
ITLXZ LJFVQ GHOLW CUHLO MDSOE KTALU VYLNZ RFGBX PHVGA LWQIS |
|||
;; newline could be single 0a byte or crlf sequence when copied from clipboard... |
|||
FGRPH JOOFW GUBYI LAPLA LCAFA AMKLG CETDW VOELJ IKGJB XPHVG |
|||
debase replace/all s either find s CRLF [CRLF ] [ newline ] "" |
|||
ALWQC SNWBU BYHCU HKOCE XJEYK BQKVY KIIEH GRLGH XEOLW AWFOJ |
|||
] [ |
|||
ILOVV RHPKD WIHKN ATUHN VRYAQ DIVHX FHRZV QWMWV LGSHN NLVZS |
|||
tx1/text ;; plaintext message |
|||
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}) |
|||
txt: to-binary txt ;; handle message as binary |
|||
(define first-char (char->integer #\A)) |
|||
key: to-binary key1/text ;; handle key also as binary |
|||
(define chars# (- (char->integer #\Z) first-char -1)) |
|||
bin: copy either decrypt [ "" ][ #{} ] ;; buffer for output |
|||
(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))) |
|||
code: copy #{} ;; temp field to collect utf8 bytes when decrypting |
|||
(define (n*n-1 n) (* n (sub1 n))) |
|||
;; loop over length of binary! message ... |
|||
(define text* (for/vector ([c (regexp-replace* #px"\\s+" text "")]) |
|||
repeat pos length? txt [ |
|||
(- (char->integer c) first-char))) |
|||
k: to-integer key/(1 + modulo pos length? key) ;; get corresponding key byte |
|||
(define N (vector-length text*)) |
|||
c: to-integer txt/:pos ;; get integer value from message byte at position pos |
|||
(define (get-col-length+freqs width offset) |
|||
(define text (for/list ([i (in-range offset N width)]) (vector-ref text* i))) |
|||
either decrypt [ ;; decrypting ? |
|||
(define cN (length text)) |
|||
c: modulo ( 256 + c - k ) 256 ;; compute original byte value |
|||
(define freqs (make-vector chars# 0)) |
|||
case [ |
|||
(for ([c (in-list text)]) (vector-set! freqs c (add1 (vector-ref freqs c)))) |
|||
;; byte starting with 11.... ( >= 192 dec ) is utf8 startbyte |
|||
(values cN freqs)) |
|||
;; 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 |
|||
either decrypt [ ;; collect utf-8 characters |
|||
(define expected-IC (* chars# (for*/sum ([x freqs]) (* x x)))) |
|||
append bin to-char code ;; append last code |
|||
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> |
|||
=={{header|REXX}}== |
|||
;; maps key lengths to average index of coincidence |
|||
===uppercase text only=== |
|||
(define keylen->ICs |
|||
<lang rexx>/*REXX program encrypts (and displays) uppercased text using the Vigenère cypher.*/ |
|||
(for/vector ([len (in-range 1 (add1 (* max-keylen 2)))]) |
|||
@.1 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' |
|||
(for/sum ([ofs len]) |
|||
L=length(@.1) |
|||
(define-values [cN cfreqs] (get-col-length+freqs len ofs)) |
|||
do j=2 to L; jm=j-1; q=@.jm |
|||
(/ (for/sum ([i chars#]) (n*n-1 (vector-ref cfreqs i))) |
|||
@.j=substr(q, 2, L - 1)left(q, 1) |
|||
end /*j*/ |
|||
cypher = space('WHOOP DE DOO NO BIG DEAL HERE OR THERE', 0) |
|||
;; given a key length find the key that minimizes errors from alphabet freqs, |
|||
oMsg = 'People solve problems by trial and error; judgement helps pick the trial.' |
|||
;; return (cons average-error key) |
|||
oMsgU = oMsg; upper oMsgU |
|||
(define (guess-key len) |
|||
cypher_= copies(cypher, length(oMsg) % length(cypher) ) |
|||
(define guesses |
|||
say ' original text =' oMsg |
|||
(for/list ([ofs len]) |
|||
xMsg= Ncypher(oMsgU); say ' cyphered text =' xMsg |
|||
(define-values [cN cfreqs] (get-col-length+freqs len ofs)) |
|||
bMsg= Dcypher(xMsg) ; say 're-cyphered text =' bMsg |
|||
(for ([i chars#]) (vector-set! cfreqs i (/ (vector-ref cfreqs i) cN))) |
|||
exit |
|||
(argmin car |
|||
/*──────────────────────────────────────────────────────────────────────────────────────*/ |
|||
(for/list ([d chars#]) |
|||
Ncypher: parse arg x; nMsg=; #=1 /*unsupported char? ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓*/ |
|||
(cons (for/sum ([i chars#]) |
|||
( |
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 |
|||
/*──────────────────────────────────────────────────────────────────────────────────────*/ |
|||
(cons (/ (apply + (map car guesses)) len) (map cdr guesses))) |
|||
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= 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=== |
|||
;; look for a key length that minimizes error from expected-IC, with some |
|||
This version supports all characters on the IBM Model M keyboard, including blanks, but any other |
|||
;; stupid consideration of multiples of the length (which should also have low |
|||
<br>characters can be added as long as they're viewable. |
|||
;; 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 |
|||
Additional characters can be added by simply appending them to the <big>'''@.1'''</big> variable. |
|||
;; ways) and return the winner key |
|||
<lang rexx>/*REXX program encrypts (and displays) most text using the Vigenère cypher. */ |
|||
(define best-key |
|||
@abc= 'abcdefghijklmnopqrstuvwxyz'; @abcU=@abc; upper @abcU |
|||
((compose1 cdr (curry argmin car)) |
|||
@.1 = @abcU || @abc'0123456789~`!@#$%^&*()_-+={}|[]\:;<>?,./" ''' |
|||
(for/list ([i (* max-keylen 2)]) |
|||
L=length(@.1) |
|||
;; get the error from the expected-IC for the length and its multiples, |
|||
do j=2 to length(@.1); jm=j - 1; q=@.jm |
|||
;; with decreasing weights for the multiples |
|||
@.j=substr(q, 2, L - 1)left(q, 1) |
|||
(define with-multiples |
|||
end /*j*/ |
|||
(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))))) |
|||
cypher = space('WHOOP DE DOO NO BIG DEAL HERE OR THERE', 0) |
|||
(printf "Best key found: ") |
|||
oMsg = 'Making things easy is just knowing the shortcuts. --- Gerard J. Schildberger' |
|||
(for ([c best-key]) (display (integer->char (+ c first-char)))) |
|||
cypher_= copies(cypher, length(oMsg) % length(cypher) ) |
|||
(newline) |
|||
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= 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}}== |
|||
(printf "Decoded text:\n") |
|||
<lang ring> |
|||
(define decode-num |
|||
# Project : Vigenère cipher |
|||
(let ([cur '()]) |
|||
(λ(n) (when (null? cur) (set! cur best-key)) |
|||
key = "LEMON" |
|||
(begin0 (modulo (- n (car cur)) chars#) (set! cur (cdr cur)))))) |
|||
plaintext = "ATTACK AT DAWN" |
|||
(for ([c text]) |
|||
ciphertext = encrypt(plaintext, key) |
|||
(define n (- (char->integer c) first-char)) |
|||
see "key = "+ key + nl |
|||
(if (not (< -1 n chars#)) (display c) |
|||
see "plaintext = " + plaintext + nl |
|||
(display (integer->char (+ first-char (decode-num n)))))) |
|||
see "ciphertext = " + ciphertext + nl |
|||
(newline) |
|||
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> |
</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}}== |
||
<lang rust>use std::ascii::AsciiExt; |
|||
{{trans|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 [https://doc.rust-lang.org/std/primitive.char.html subchapter on strings]. |
|||
<lang Rust> |
|||
use std::iter::FromIterator; |
|||
static A: u8 = 'A' as u8; |
|||
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"; |
|||
fn uppercase_and_filter(input: &str) -> Vec<u8> { |
|||
const FREQUENCIES: [f32; 26] = [ |
|||
let alphabet = b"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; |
|||
0.08167, 0.01492, 0.02202, 0.04253, 0.12702, 0.02228, 0.02015, 0.06094, 0.06966, 0.00153, |
|||
let mut result = Vec::new(); |
|||
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, |
|||
]; |
|||
for c in input.chars() { |
|||
fn best_match(a: &[f32]) -> u8 { |
|||
// Ignore anything that is not in our short list of chars. We can then safely cast to u8. |
|||
let sum: f32 = a.iter().sum(); |
|||
if alphabet.iter().any(|&x| x as char == c) { |
|||
let mut best_fit = std::f32::MAX; |
|||
result.push(c.to_ascii_uppercase() as u8); |
|||
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; |
|||
} |
} |
||
} |
} |
||
return result; |
|||
} |
} |
||
fn |
fn vigenere(key: &str, text: &str, is_encoding: bool) -> String { |
||
let len = msg.len(); |
|||
let |
let key_bytes = uppercase_and_filter(key); |
||
let |
let text_bytes = uppercase_and_filter(text); |
||
for j in 0..interval { |
|||
let mut result_bytes = Vec::new(); |
|||
for i in (j..len).step_by(interval) { |
|||
for (i, c) in text_bytes.iter().enumerate() { |
|||
let idx = msg[i] as usize; |
|||
let c2 = if is_encoding { |
|||
(c + key_bytes[i % key_bytes.len()] - 2 * A) % 26 + A |
|||
} |
|||
} else { |
|||
(c + 26 - key_bytes[i % key_bytes.len()]) % 26 + A |
|||
}; |
|||
result_bytes.push(c2); |
|||
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 |
|||
} |
|||
String::from_utf8(result_bytes).unwrap() |
|||
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() { |
fn main() { |
||
let text = "Beware the Jabberwock, my son! The jaws that bite, the claws that catch!"; |
|||
let enc = CRYPTOGRAM |
|||
let key = "VIGENERECIPHER"; |
|||
.split_ascii_whitespace() |
|||
.collect::<Vec<_>>() |
|||
println!("Text: {}", text); |
|||
println!("Key: {}", key); |
|||
let cryptogram: Vec<u8> = enc.as_bytes().iter().map(|b| u8::from(b - b'A')).collect(); |
|||
let mut best_fit = std::f32::MAX; |
|||
let |
let encoded = vigenere(key, text, true); |
||
println!("Code: {}", encoded); |
|||
for j in 1..=26 { |
|||
let decoded = vigenere(key, &encoded, false); |
|||
println!("Back: {}", decoded); |
|||
let fit = freq_every_nth(&cryptogram, &mut key); |
|||
}</lang> |
|||
let s_key = String::from_iter(key); // 'from_iter' is imported from std::iter::FromIterator; |
|||
if fit < best_fit { |
|||
=={{header|Scala}}== |
|||
best_fit = fit; |
|||
Valid characters for messages: A through Z, zero, 1 to 9, and full-stop (.) |
|||
best_key = s_key; |
|||
<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 |
|||
} |
|||
} |
} |
||
return result |
|||
println!("best key: {}", &best_key); |
|||
} |
|||
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 |
|||
} |
|||
} |
} |
||
println("Encrypt text ABC => " + Vigenere.encrypt("ABC", "KEY")) |
|||
println("Decrypt text KFA => " + Vigenere.decrypt("KFA", "KEY")) |
|||
</lang> |
</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> |
||
Input: Beware the Jabberwock, my son! The jaws that bite, the claws that catch! |
|||
best key: THECHESHIRECAT |
|||
key: VIGENERECIPHER |
|||
Encrypted: WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY |
|||
Decrypted: BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH |
|||
</pre> |
|||
=={{header|Sidef}}== |
|||
Decrypted text: |
|||
{{trans|Perl 6}} |
|||
THISWASTHEPOEMTHATALICEREADJABBERWOCKYTWASBRILLIGANDTHESLITHYTOVESDIDGYREANDGIMBLEINTHEWABEALLMIMSYWERETHEBOROGOVESANDTHEMOMERATHSOUTGRABEBEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCHBEWARETHEJUBJUBBIRDANDSHUNTHEFRUMIOUSBANDERSNATCHHETOOKHISVORPALSWORDINHANDLONGTIMETHEMANXOMEFOEHESOUGHTSORESTEDHEBYTHETUMTUMTREEANDSTOODAWHILEINTHOUGHTANDASINUFFISHTHOUGHTHESTOODTHEJABBERWOCKWITHEYESOFFLAMECAMEWHIFFLINGTHROUGHTHETULGEYWOODANDBURBLEDASITCAMEONETWOONETWOANDTHROUGHANDTHROUGHTHEVORPALBLADEWENTSNICKERSNACKHELEFTITDEADANDWITHITSHEADHEWENTGALUMPHINGBACKANDHASTTHOUSLAINTHEJABBERWOCKCOMETOMYARMSMYBEAMISHBOYOFRABJOUSDAYCALLOOHCALLAYHECHORTLEDINHISJOYTWASBRILLIGANDTHESLITHYTOVESDIDGYREANDGIMBLEINTHEWABEALLMIMSYWERETHEBOROGOVESANDTHEMOMERATHSOUTGRABEITSEEMSVERYPRETTYSHESAIDWHENSHEHADFINISHEDITBUTITSRATHERHARDTOUNDERSTAND |
|||
<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| |
=={{header|Smalltalk}}== |
||
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.. |
|||
{{trans|Python}} |
|||
{{works with|Smalltalk/X}} |
|||
<lang tcl>package require Tcl 8.6 |
|||
<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. |
|||
crypted -> 'WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY' |
|||
oo::class create VigenereAnalyzer { |
|||
plain2 -> 'BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH' |
|||
variable letterFrequencies sortedTargets |
|||
</lang> |
|||
constructor {{frequencies { |
|||
0.08167 0.01492 0.02782 0.04253 0.12702 0.02228 0.02015 |
|||
=={{header|Swift}}== |
|||
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 |
|||
Can support a larger range of characters, if desired |
|||
0.00978 0.02360 0.00150 0.01974 0.00074 |
|||
}}} { |
|||
<lang swift>public func convertToUnicodeScalars( |
|||
set letterFrequencies $frequencies |
|||
str: String, |
|||
set sortedTargets [lsort -real $frequencies] |
|||
minChar: UInt32, |
|||
if {[llength $frequencies] != 26} { |
|||
maxChar: UInt32 |
|||
error "wrong length of frequency table" |
|||
) -> [UInt32] { |
|||
} |
|||
var scalars = [UInt32]() |
|||
for scalar in str.unicodeScalars { |
|||
let val = scalar.value |
|||
guard val >= minChar && val <= maxChar else { |
|||
continue |
|||
} |
} |
||
scalars.append(val) |
|||
### Utility methods |
|||
} |
|||
# Find the value of $idxvar in the range [$from..$to) that maximizes the value |
|||
# in $scorevar (which is computed by evaluating $body) |
|||
return scalars |
|||
method Best {idxvar from to scorevar body} { |
|||
} |
|||
upvar 1 $idxvar i $scorevar s |
|||
set bestI $from |
|||
public struct Vigenere { |
|||
for {set i $from} {$i < $to} {incr i} { |
|||
private let keyScalars: [UInt32] |
|||
uplevel 1 $body |
|||
private let smallestScalar: UInt32 |
|||
if {![info exist bestS] || $bestS < $s} { |
|||
private let largestScalar: UInt32 |
|||
set bestI $i |
|||
private let sizeAlphabet: UInt32 |
|||
set bestS $s |
|||
} |
|||
public init?(key: String, smallestCharacter: Character = "A", largestCharacter: Character = "Z") { |
|||
} |
|||
let smallScalars = smallestCharacter.unicodeScalars |
|||
return $bestI |
|||
let largeScalars = largestCharacter.unicodeScalars |
|||
guard smallScalars.count == 1, largeScalars.count == 1 else { |
|||
return nil |
|||
} |
} |
||
# Simple list map |
|||
self.smallestScalar = smallScalars.first!.value |
|||
method Map {var list body} { |
|||
self.largestScalar = largeScalars.first!.value |
|||
upvar 1 $var v |
|||
self.sizeAlphabet = (largestScalar - smallestScalar) + 1 |
|||
set result {} |
|||
foreach v $list {lappend result [uplevel 1 $body]} |
|||
let scalars = convertToUnicodeScalars(str: key, minChar: smallestScalar, maxChar: largestScalar) |
|||
return $result |
|||
guard !scalars.isEmpty else { |
|||
return nil |
|||
} |
} |
||
# Simple partition of $list into $groups groups; thus, the partition of |
|||
self.keyScalars = scalars |
|||
# {a b c d e f} into 3 produces {a d} {b e} {c f} |
|||
method Partition {list groups} { |
|||
} |
|||
foreach val $list { |
|||
public func decrypt(_ str: String) -> String? { |
|||
dict lappend result $i $val |
|||
let txtBytes = convertToUnicodeScalars(str: str, minChar: smallestScalar, maxChar: largestScalar) |
|||
if {[incr i] >= $groups} { |
|||
set i 0 |
|||
guard !txtBytes.isEmpty else { |
|||
} |
|||
return nil |
|||
} |
|||
return [dict values $result] |
|||
} |
} |
||
var res = "" |
|||
# Get the actual counts of different types of characters in the given list |
|||
for (i, c) in txtBytes.enumerated() where c >= smallestScalar && c <= largestScalar { |
|||
method Frequency cleaned { |
|||
guard let char = |
|||
UnicodeScalar((c &+ sizeAlphabet &- keyScalars[i % keyScalars.count]) % sizeAlphabet &+ smallestScalar) |
|||
dict set tbl $i 0 |
|||
else { |
|||
} |
|||
return nil |
|||
foreach ch $cleaned { |
|||
} |
|||
dict incr tbl [expr {[scan $ch %c] - 65}] |
|||
} |
|||
res += String(char) |
|||
return $tbl |
|||
} |
} |
||
return res |
|||
# Get the correlation factor of the characters in a given list with the |
|||
} |
|||
# class-specified language frequency corpus |
|||
method Correlation cleaned { |
|||
public func encrypt(_ str: String) -> String? { |
|||
set result 0.0 |
|||
let txtBytes = convertToUnicodeScalars(str: str, minChar: smallestScalar, maxChar: largestScalar) |
|||
set freq [lsort -integer [dict values [my Frequency $cleaned]]] |
|||
foreach f $freq s $sortedTargets { |
|||
guard !txtBytes.isEmpty else { |
|||
set result [expr {$result + $f * $s}] |
|||
return nil |
|||
} |
|||
return $result |
|||
} |
} |
||
var res = "" |
|||
# Compute an estimate for the key length |
|||
method GetKeyLength {cleaned {required 20}} { |
|||
for (i, c) in txtBytes.enumerated() where c >= smallestScalar && c <= largestScalar { |
|||
# Assume that we need at least 20 characters per column to guess |
|||
guard let char = |
|||
set bestLength [my Best i 2 [expr {[llength $cleaned] / $required}] corr { |
|||
UnicodeScalar((c &+ keyScalars[i % keyScalars.count] &- 2 &* smallestScalar) % sizeAlphabet &+ smallestScalar) |
|||
set corr [expr {-0.5 * $i}] |
|||
else { |
|||
foreach chars [my Partition $cleaned $i] { |
|||
return nil |
|||
set corr [expr {$corr + [my Correlation $chars]}] |
|||
} |
|||
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 |
|||
} |
} |
||
method encrypt {text} { |
|||
# Compute the key from the given frequency tables and the class-specified |
|||
set out "" |
|||
# language frequency corpus |
|||
set j 0 |
|||
method GetKeyFromFreqs freqs { |
|||
foreach |
foreach c [split $text ""] { |
||
if {[regexp {[^a-zA-Z]} $c]} continue |
|||
scan [string toupper $c] %c c |
|||
set corr 0.0 |
|||
append out [format %c [expr {($c+[lindex $key $j]-130)%26+65}]] |
|||
foreach {ch count} $f { |
|||
set j [expr {($j+1) % [llength $key]}] |
|||
set corr [expr {$corr + $count*[lindex $letterFrequencies $d]}] |
|||
} |
|||
}] |
|||
append key [format %c [expr {65 + $m}]] |
|||
} |
} |
||
return $ |
return $out |
||
} |
} |
||
method decrypt {text} { |
|||
##### The main analyzer method ##### |
|||
set out "" |
|||
method analyze input { |
|||
set j 0 |
|||
# Turn the input into a clean letter sequence |
|||
foreach c [split $text ""] { |
|||
set cleaned [regexp -all -inline {[A-Z]} [string toupper $input]] |
|||
if {[regexp {[^A-Z]} $c]} continue |
|||
# Get the (estimated) key length |
|||
scan $c %c c |
|||
set bestLength [my GetKeyLength $cleaned] |
|||
append out [format %c [expr {($c-[lindex $key $j]+26)%26+65}]] |
|||
# Get the frequency mapping for the partitioned input text |
|||
set j [expr {($j+1) % [llength $key]}] |
|||
set freqs [my Map p [my Partition $cleaned $bestLength] {my Frequency $p}] |
|||
} |
|||
# Get the key itself |
|||
return |
return $out |
||
} |
} |
||
}</lang> |
}</lang> |
||
Demonstrating: |
|||
Demonstration (that assumes that the Tcl solution to [[Vigenère cipher#Tcl|Vigenère cipher]] task is present): |
|||
<lang tcl>set |
<lang tcl>set cypher [Vigenere new "Vigenere Cipher"] |
||
set original "Beware the Jabberwock, my son! The jaws that bite, the claws that catch!" |
|||
MOMUD EKAPV TQEFM OEVHP AJMII CDCTI FGYAG JSPXY ALUYM NSMYH |
|||
set encrypted [$cypher encrypt $original] |
|||
VUXJE LEPXJ FXGCM JHKDZ RYICU HYPUS PGIGM OIYHF WHTCQ KMLRD |
|||
set decrypted [$cypher decrypt $encrypted] |
|||
ITLXZ LJFVQ GHOLW CUHLO MDSOE KTALU VYLNZ RFGBX PHVGA LWQIS |
|||
puts $original |
|||
FGRPH JOOFW GUBYI LAPLA LCAFA AMKLG CETDW VOELJ IKGJB XPHVG |
|||
puts "Encrypted: $encrypted" |
|||
ALWQC SNWBU BYHCU HKOCE XJEYK BQKVY KIIEH GRLGH XEOLW AWFOJ |
|||
puts "Decrypted: $decrypted"</lang> |
|||
ILOVV RHPKD WIHKN ATUHN VRYAQ DIVHX FHRZV QWMWV LGSHN NLVZS |
|||
{{out}} |
|||
JLAKI FHXUF XJLXM TBLQV RXXHR FZXGV LRAJI EXPRV OSMNP KEPDT |
|||
<pre> |
|||
LPRWM JAZPK LQUZA ALGZX GVLKL GJTUI ITDSU REZXJ ERXZS HMPST |
|||
Beware the Jabberwock, my son! The jaws that bite, the claws that catch! |
|||
MTEOE PAPJH SMFNB YVQUZ AALGA YDNMP AQOWT UHDBV TSMUE UIMVH |
|||
Encrypted: WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY |
|||
QGVRW AEFSP EMPVE PKXZY WLKJA GWALT VYYOB YIXOK IHPDS EVLEV |
|||
Decrypted: BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH |
|||
RVSGB JOGYW FHKBL GLXYA MVKIS KIEHY IMAPX UOISK PVAGN MZHPW |
|||
</pre> |
|||
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"</lang> |
|||
=={{header| |
=={{header|TXR}}== |
||
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. |
|||
<lang txr>@(next :args) |
|||
The text to be analysed must be in current edit buffer. A new buffer is opened to display the results. |
|||
@(do |
|||
(defun vig-op (plus-or-minus) |
|||
(op + #\A [mod [plus-or-minus (- @1 #\A) (- @2 #\A)] 26])) |
|||
(defun vig (msg key encrypt) |
|||
To automatically find the best key, a dictionary is used to find English words within the decrypted text. |
|||
(mapcar (vig-op [if encrypt + -]) msg (repeat key)))) |
|||
I have used unixdict.txt, but if you do not have it available, you can use the Scribe English dictionary that comes with Vedit. |
|||
@(coll)@{key /[A-Za-z]/}@(end) |
|||
However, that is unnecessarily big. A smaller dictionary is faster and may actually give better results. |
|||
@(coll)@{msg /[A-Za-z]/}@(end) |
|||
It might be good idea to use dictionary that only contains the most common English words. |
|||
@(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> |
|||
Here, the TXR pattern language is used to scan letters out of two arguments, |
|||
This implementation finds the best and 2nd best Caesar key for each key position. |
|||
and convert them to upper case. |
|||
It then checks key combinations where max one char is taken from 2nd best Caesar key. |
|||
The embedded TXR Lisp dialect handles the Vigenère logic, |
|||
If this does not solve some encrypted text, you could increase the number of key combinations to be checked. |
|||
in just a few lines of code. |
|||
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. |
|||
<lang vedit>// (1) Copy text into tmp buffer and remove non-alpha chars. |
|||
Run: |
|||
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 |
|||
<pre>$ txr vigenere.txr 'vigenere cipher' 'Beware the Jabberwock... The jaws that... the claws that catch!' |
|||
#20 = Buf_Num // buffer for text being analyzed |
|||
text: BEWARETHEJABBERWOCKTHEJAWSTHATTHECLAWSTHATCATCH |
|||
#21 = Buf_Free // buffer for English frequency list (A-Z) |
|||
key: VIGENERECIPHER |
|||
Buf_Switch(#21) |
|||
enc: WMCEEIKLGRPIFVMEUGXXYILILZXYVBZLRGCEYAIOEKXIZGU |
|||
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") |
|||
dec: GWQWEACDCBLUXNWOIYXPQAHSHLPQFLNDRYUWUKEAWCHSNYU |
|||
File_Open("unixdict.txt") // or use "|(MACRO_DIR)\scribe\english.vdf" |
|||
check: BEWARETHEJABBERWOCKTHEJAWSTHATTHECLAWSTHATCATCH</pre> |
|||
#23 = Buf_Num // buffer for dictionary |
|||
#24 = Buf_Free // buffer for key canditates |
|||
=={{header|TypeScript}}== |
|||
Buf_Switch(#24) |
|||
<lang JavaScript>class Vigenere { |
|||
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 |
|||
key: string |
|||
#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 |
|||
/** Create new cipher based on key */ |
|||
constructor(key: string) { |
|||
this.key = Vigenere.formatText(key) |
|||
} |
|||
/** Enrypt a given text using key */ |
|||
Buf_Switch(#22) // buffer for results |
|||
encrypt(plainText: string): string { |
|||
Ins_Text("KeyLen Kp dist ") Ins_Newline |
|||
return Array.prototype.map.call(Vigenere.formatText(plainText), (letter: string, index: number): string => { |
|||
Ins_Text("-----------------") Ins_Newline |
|||
return String.fromCharCode((letter.charCodeAt(0) + this.key.charCodeAt(index % this.key.length) - 130) % 26 + 65) |
|||
#13 = Cur_Pos |
|||
}).join('') |
|||
#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 |
|||
/** Decrypt ciphertext based on key */ |
|||
// (3) Check the best 4 key lengths to find which one gives the best decrypt result |
|||
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('') |
|||
} |
|||
/** Converts to uppercase and removes non characters */ |
|||
#38 = 0 // max number of correct characters found |
|||
private static formatText(text: string): string { |
|||
#19 = 1 // best key length |
|||
return text.toUpperCase().replace(/[^A-Z]/g, "") |
|||
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() |
|||
} |
} |
||
/** Example usage */ |
|||
Ins_Text("Using key length: ") Num_Ins(#19) Ins_Newline |
|||
(() => { |
|||
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." |
|||
Call("FIND_KEYS") // find Caesar key for each key character |
|||
console.log(`Original: ${original}`) |
|||
// (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. |
|||
let vig: Vigenere = new Vigenere("vigenere") |
|||
#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 |
|||
} |
|||
let encoded: string = vig.encrypt(original) |
|||
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 |
|||
console.log(`After encryption: ${encoded}`) |
|||
// 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 |
|||
let back: string = vig.decrypt(encoded) |
|||
// 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 |
|||
console.log(`After decryption: ${back}`) |
|||
// 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) |
|||
</lang> |
|||
Buf_Switch(#21) Buf_Quit(OK) |
|||
Buf_Switch(#23) Buf_Quit(OK) |
|||
Buf_Switch(#24) Buf_Quit(OK) |
|||
=={{header|VBA}}== |
|||
Statline_Message("Done!") |
|||
<lang vb>Option Explicit |
|||
Return |
|||
Sub test() |
|||
///////////////////////////////////////////////////////////////////////////// |
|||
Dim Encryp As String |
|||
// |
|||
Encryp = Vigenere("Beware the Jabberwock, my son! The jaws that bite, the claws that catch!", "vigenerecipher", True) |
|||
// Caesar decrypt current line and count character frequencies. |
|||
Debug.Print "Encrypt:= """ & Encryp & """" |
|||
// in: #5 = step size, #7 = encryption key, #26 = num of chars in alphabet |
|||
Debug.Print "Decrypt:= """ & Vigenere(Encryp, "vigenerecipher", False) & """" |
|||
// out: #65...#90 = frequencies, #60 = number of chars |
|||
End Sub |
|||
Private Function Vigenere(sWord As String, sKey As String, Enc As Boolean) As String |
|||
:CHARACTER_FREQUENCIES: |
|||
Dim bw() As Byte, bk() As Byte, i As Long, c As Long |
|||
Save_Pos |
|||
Const sW As String = "ÁÂÃÄÅÇÈÉÊËÌÍÎÏÑÒÓÔÕÖÙÚÛÜÝ" |
|||
for (#8 = 'A'; #8<='Z'; #8++) { |
|||
Const sWo As String = "AAAAACEEEEIIIINOOOOOUUUUY" |
|||
#@8 = 0 // reset frequency counters |
|||
Const A As Long = 65 |
|||
} |
|||
Const N As Long = 26 |
|||
#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 |
|||
c = Len(sKey) |
|||
// Calculate Index of Coincidence (Kp). |
|||
i = Len(sWord) |
|||
// in: character frequencies in #65...#90, #60 = num of chars |
|||
sKey = Left(IIf(c < i, StrRept(sKey, (i / c) + 1), sKey), i) |
|||
// out: #51 = IC * 10000 |
|||
sKey = StrConv(sKey, vbUpperCase) 'Upper case |
|||
// |
|||
sWord = StrConv(sWord, vbUpperCase) |
|||
:INDEX_OF_COINCIDENCE: |
|||
sKey = StrReplace(sKey, sW, sWo) 'Replace accented characters |
|||
Num_Push(10,15) |
|||
sWord = StrReplace(sWord, sW, sWo) |
|||
#10 = 0 |
|||
sKey = RemoveChars(sKey) 'Remove characters (numerics, spaces, comas, ...) |
|||
for (#11 = 'A'; #11<='Z'; #11++) { |
|||
sWord = RemoveChars(sWord) |
|||
#10 += (#@11 * (#@11-1)) // Calculate sigma{ni * (ni-1)} |
|||
bk = CharToAscii(sKey) 'To work with Bytes instead of String |
|||
} |
|||
bw = CharToAscii(sWord) |
|||
#12 = #60 * (#60-1) // #12 = N * (N-1) |
|||
For i = LBound(bw) To UBound(bw) |
|||
#51 = #10 * 10000 / #12 // #51 = Kp * 10000 |
|||
Vigenere = Vigenere & Chr((IIf(Enc, ((bw(i) - A) + (bk(i) - A)), ((bw(i) - A) - (bk(i) - A)) + N) Mod N) + A) |
|||
Num_Pop(10,15) |
|||
Next i |
|||
Return |
|||
End Function |
|||
Private Function StrRept(s As String, N As Long) As String |
|||
// Find best and 2nd best Caesar key for each character position of Vigenère key. |
|||
Dim j As Long, c As String |
|||
// in: #5=step size (key length) |
|||
For j = 1 To N |
|||
// out: keys in buffer #24 |
|||
c = c & s |
|||
// |
|||
Next |
|||
:FIND_KEYS: |
|||
StrRept = c |
|||
for (#6 = 0; #6 < #5; #6++) { // for each char position in the key |
|||
End Function |
|||
#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) |
|||
} |
|||
Private Function StrReplace(s As String, What As String, By As String) As String |
|||
if (#35 < #32) { // found better match? |
|||
Dim t() As String, u() As String, i As Long |
|||
#33 = #32 |
|||
t = SplitString(What) |
|||
#32 = #35 |
|||
u = SplitString(By) |
|||
#31 = #30 |
|||
StrReplace = s |
|||
For i = LBound(t) To UBound(t) |
|||
StrReplace = Replace(StrReplace, t(i), u(i)) |
|||
if (#35 < #33) { // 2nd best match? |
|||
Next i |
|||
#33 = #35 |
|||
End Function |
|||
#31 = #7 |
|||
} |
|||
Private Function SplitString(s As String) As String() |
|||
} |
|||
SplitString = Split(StrConv(s, vbUnicode), Chr(0)) |
|||
} |
|||
End Function |
|||
Buf_Switch(#24) // table for key canditates |
|||
BOF |
|||
Private Function RemoveChars(str As String) As String |
|||
Goto_Col(#6+1) |
|||
Dim b() As Byte, i As Long |
|||
Ins_Char(#30+'A', OVERWRITE) // save the best match |
|||
b = CharToAscii(str) |
|||
For i = LBound(b) To UBound(b) |
|||
If b(i) >= 65 And b(i) <= 90 Then RemoveChars = RemoveChars & Chr(b(i)) |
|||
Ins_Char(#31+'A', OVERWRITE) // save 2nd best match |
|||
Next i |
|||
End Function |
|||
Buf_Switch(#22) // results buffer |
|||
Return |
|||
Private Function CharToAscii(s As String) As Byte() |
|||
CharToAscii = StrConv(s, vbFromUnicode) |
|||
End Function</lang> |
|||
{{Out}} |
|||
<pre>Encrypt:= "WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY" |
|||
Decrypt:= "BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH"</pre> |
|||
=={{header|VBScript}}== |
|||
{{trans|Liberty BASIC}} |
|||
<lang vb> |
|||
Function Encrypt(text,key) |
|||
text = OnlyCaps(text) |
|||
key = OnlyCaps(key) |
|||
j = 1 |
|||
For i = 1 To Len(text) |
|||
ms = Mid(text,i,1) |
|||
m = Asc(ms) - Asc("A") |
|||
ks = Mid(key,j,1) |
|||
k = Asc(ks) - Asc("A") |
|||
j = (j Mod Len(key)) + 1 |
|||
c = (m + k) Mod 26 |
|||
c = Chr(Asc("A")+c) |
|||
Encrypt = Encrypt & c |
|||
Next |
|||
End Function |
|||
Function Decrypt(text,key) |
|||
key = OnlyCaps(key) |
|||
j = 1 |
|||
For i = 1 To Len(text) |
|||
ms = Mid(text,i,1) |
|||
m = Asc(ms) - Asc("A") |
|||
ks = Mid(key,j,1) |
|||
k = Asc(ks) - 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 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 |
|||
'testing the functions |
|||
orig_text = "Beware the Jabberwock, my son! The jaws that bite, the claws that catch!" |
|||
orig_key = "vigenerecipher" |
|||
WScript.StdOut.WriteLine "Original: " & orig_text |
|||
WScript.StdOut.WriteLine "Key: " & orig_key |
|||
WScript.StdOut.WriteLine "Encrypted: " & Encrypt(orig_text,orig_key) |
|||
WScript.StdOut.WriteLine "Decrypted: " & Decrypt(Encrypt(orig_text,orig_key),orig_key) |
|||
</lang> |
|||
{{Out}} |
|||
<pre> |
|||
Original: Beware the Jabberwock, my son! The jaws that bite, the claws that catch! |
|||
Key: vigenerecipher |
|||
Encrypted: WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY |
|||
Decrypted: BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH |
|||
</pre> |
|||
An alternate implementation using RegExp to filter the input |
|||
<lang vb> |
|||
'vigenere cypher |
|||
option explicit |
|||
const asca =65 'ascii(a) |
|||
function filter(s) |
|||
with new regexp |
|||
.pattern="[^A-Z]" |
|||
.global=1 |
|||
filter=.replace(ucase(s),"") |
|||
end with |
|||
end function |
|||
function vigenere (s,k,sign) |
|||
dim s1,i,a,b |
|||
for i=0 to len(s)-1 |
|||
a=asc(mid(s,i+1,1))-asca |
|||
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 |
|||
function encrypt(s,k): encrypt=vigenere(s,k,1) :end function |
|||
function decrypt(s,k): decrypt=vigenere(s,k,-1) :end function |
|||
'test-------------------------- |
|||
dim plaintext,filtered,key,encoded |
|||
key="VIGENERECYPHER" |
|||
plaintext = "Beware the Jabberwock, my son! The jaws that bite, the claws that catch!" |
|||
filtered= filter(plaintext) |
|||
wscript.echo filtered |
|||
encoded=encrypt(filtered,key) |
|||
wscript.echo encoded |
|||
wscript.echo decrypt(encoded,key) |
|||
</lang> |
|||
=={{header|Vedit macro language}}== |
|||
Encrypts and then decrypts one line of text on current edit buffer, |
|||
starting from cursor location. |
|||
The user enters the keyword (upper or lower case). |
|||
<lang vedit>Get_Input(10, "Key: ", STATLINE+NOCR) // @10 = key |
|||
Reg_Copy_Block(11, Cur_Pos, EOL_Pos) // @11 = copy of original text |
|||
EOL Ins_Newline |
|||
Ins_Text("Key = ") Reg_Ins(10) Ins_Newline |
|||
// Prepare the key into numeric registers #130..: |
|||
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) |
|||
Ins_Text("Encrypted: ") |
|||
#4 = Cur_Pos |
|||
Reg_Ins(11) // copy of original text |
|||
Replace_Block("|!|A", "", #4, EOL_Pos, BEGIN+ALL+NOERR) // remove non-alpha chars |
|||
Case_Upper_Block(#4, EOL_Pos) // convert to upper case |
|||
Goto_Pos(#4) |
|||
#1 = 1; Call("ENCRYPT_DECRYPT") // Encrypt the line |
|||
Reg_Copy_Block(11, #4, Cur_Pos) // Copy encrypted text text to next line |
|||
Ins_Newline |
|||
Ins_Text("Decrypted: ") |
|||
Reg_Ins(11, BEGIN) |
|||
#1 = -1; Call("ENCRYPT_DECRYPT") // Decrypt the line |
|||
// 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 |
Return |
||
// |
// Encrypt or decrypt text on current line in-place, starting from cursor position. |
||
// in: # |
// in: #1 = direction (1=encrypt, -1=decrypt) |
||
// #2 = key length, #130...#189 = the key |
|||
// |
// |
||
:ENCRYPT_DECRYPT: |
|||
:DECRYPT_LINE: |
|||
Num_Push(6,9) |
Num_Push(6,9) |
||
#6 = 0 |
#6 = 0 |
||
While (!At_EOL) { |
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(# |
Ins_Char(#9, OVERWRITE) // write the converted char |
||
#6+ |
#6 = (#6+1) % #2 |
||
if (#6 >= #5) { |
|||
#6 = 0 |
|||
} |
|||
} |
} |
||
Num_Pop(6,9) |
Num_Pop(6,9) |
||
Return |
Return </lang> |
||
{{out}} |
|||
// Find English words from text on current line |
|||
<pre> |
|||
// out: #37 = number of chars matched |
|||
Beware the Jabberwock, my son! The jaws that bite, the claws that catch! |
|||
// |
|||
Key = vigenerecipher |
|||
:FIND_ENGLISH_WORDS: |
|||
Encrypted: WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY |
|||
Buf_Switch(#23) // dictionary |
|||
Decrypted: BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH |
|||
BOF |
|||
</pre> |
|||
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) |
|||
} |
|||
=={{header|XPL0}}== |
|||
Buf_Switch(#22) |
|||
The KEYWORD must be UPPERCASE. Precede it with a minus sign to decrypt a file. |
|||
BOL |
|||
Usage: vigenere KEYWORD <infile.txt >outfile.xxx |
|||
#37 = Search_Block("|V", Cur_Pos, EOL_Pos, ALL+NOERR) |
|||
Return </lang> |
|||
<lang XPL0>code ChIn=7, ChOut=8; |
|||
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> |
|||
=={{header|zkl}}== |
=={{header|zkl}}== |
||
{{trans| |
{{trans|C}} |
||
<lang zkl>fcn encipher(src,key,is_encode){ |
|||
<lang zkl>var[const] uppercase=["A".."Z"].pump(String), |
|||
upperCase:=["A".."Z"].pump(String); |
|||
english_frequences=T( // A..Z |
|||
src=src.toUpper().inCommon(upperCase); // only uppercase |
|||
0.08167, 0.01492, 0.02782, 0.04253, 0.12702, 0.02228, 0.02015, |
|||
key=key.toUpper().inCommon(upperCase).pump(List,"toAsc"); |
|||
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, |
|||
const A="A".toAsc(); |
|||
0.00978, 0.02360, 0.00150, 0.01974, 0.00074); |
|||
klen:=Walker.cycle(key.len()); // 0,1,2,3,..,keyLen-1,0,1,2,3, ... |
|||
src.pump(String,'wrap(c){ i:=klen.next(); c=c.toAsc(); |
|||
(A + ( if(is_encode) c - A + key[i] - A; |
|||
else c - key[i] + 26 ) % 26).toChar() |
|||
}); |
|||
}</lang> |
|||
<lang zkl>str := "Beware the Jabberwock, my son! The jaws that bite, " |
|||
"the claws that catch!"; |
|||
key := "Vigenere Cipher"; |
|||
println("Text: ", str); |
|||
println("key: ", key); |
|||
cod := encipher(str, key, True); println("Code: ", cod); |
|||
fcn vigenere_decrypt(target_freqs, input){ // ( (float,...), string) |
|||
dec := encipher(cod, key, False); println("Back: ", dec);</lang> |
|||
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,_); |
|||
}</lang> |
|||
<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);</lang> |
|||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Text: Beware the Jabberwock, my son! The jaws that bite, the claws that catch! |
|||
Key:THECHESHIRECAT |
|||
key: Vigenere Cipher |
|||
Decoded text:THISWASTHEPOEMTHATALICEREADJABBERWOCKYTWASBRILLIGANDTHESLITHYTOVESDIDGYREANDGIMBLEINTHEWABEALLMIMSYWERETHEBOROGOVESANDTHEMOMERATHSOUTGRABEBEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCHBEWARETHEJUBJUBBIRDANDSHUNTHEFRUMIOUSBANDERSNATCHHETOOKHISVORPALSWORDINHANDLONGTIMETHEMANXOMEFOEHESOUGHTSORESTEDHEBYTHETUMTUMTREEANDSTOODAWHILEINTHOUGHTANDASINUFFISHTHOUGHTHESTOODTHEJABBERWOCKWITHEYESOFFLAMECAMEWHIFFLINGTHROUGHTHETULGEYWOODANDBURBLEDASITCAMEONETWOONETWOANDTHROUGHANDTHROUGHTHEVORPALBLADEWENTSNICKERSNACKHELEFTITDEADANDWITHITSHEADHEWENTGALUMPHINGBACKANDHASTTHOUSLAINTHEJABBERWOCKCOMETOMYARMSMYBEAMISHBOYOFRABJOUSDAYCALLOOHCALLAYHECHORTLEDINHISJOYTWASBRILLIGANDTHESLITHYTOVESDIDGYREANDGIMBLEINTHEWABEALLMIMSYWERETHEBOROGOVESANDTHEMOMERATHSOUTGRABEITSEEMSVERYPRETTYSHESAIDWHENSHEHADFINISHEDITBUTITSRATHERHARDTOUNDERSTAND |
|||
Code: WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY |
|||
Back: BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH |
|||
</pre> |
</pre> |
Revision as of 20:45, 14 March 2020
You are encouraged to solve this task according to the task description, using any language you may know.
- Task
Implement a Vigenère cypher, both encryption and decryption.
The program should handle keys and text of unequal length,
and should capitalize everything and discard non-alphabetic characters.
(If your program handles non-alphabetic characters in another way,
make a note of it.)
- Related tasks
Ada
<lang Ada>WITH Ada.Text_IO, Ada.Characters.Handling; USE Ada.Text_IO, Ada.Characters.Handling;
PROCEDURE Main IS
SUBTYPE Alpha IS Character RANGE 'A' .. 'Z'; 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;
</lang>
- Output:
Beware the Jabberwock, my son! The jaws that bite, the claws that catch! VIGENERECIPHER Encrypted: WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY Decrypted: BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH
ALGOL 68
Note: This specimen retains the original C++ coding style.
<lang algol68>STRING key := "";
PROC vigenere cipher = (REF STRING key)VOID: (
FOR i FROM LWB key TO UPB key DO 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
);
PROC encrypt = (STRING text)STRING: (
STRING out := "";
INT j := LWB text; FOR i FROM LWB text TO UPB text DO CHAR c := text[i];
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;
out
);
PROC decrypt = (STRING text)STRING: (
STRING out;
INT j := LWB text; FOR i FROM LWB text TO UPB text DO CHAR c := text[i];
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] + 26) MOD 26 + ABS"A"); j := j MOD UPB key + 1 FI OD;
out
);
main: (
vigenere cipher(key:="VIGENERECIPHER");
STRING original := "Beware the Jabberwock, my son! The jaws that bite, the claws that catch!"; STRING encrypted := encrypt(original); STRING decrypted := decrypt(encrypted);
print((original, new line)); print(("Encrypted: ", encrypted, new line)); print(("Decrypted: ", decrypted, new line))
)</lang>
- Output:
Beware the Jabberwock, my son! The jaws that bite, the claws that catch! Encrypted: WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY Decrypted: BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH
Applesoft BASIC
Lines 340,350,430,440
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.
I have not used the DEF FN MOD(A) function in line 450
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>
- Output:
KEY: LEMON PLAIN TEXT: ATTACK AT DAWN CIPHER TEXT: LXFOPVEFRNHR DECRYPTED TEXT: ATTACKATDAWN
AutoHotkey
<lang AutoHotkey>Key = VIGENERECIPHER Text= Beware the Jabberwock, my son! The jaws that bite, the claws that catch!
out := "Input =" text "`nkey =" key "`nCiphertext =" (c := VigenereCipher(Text, Key)) "`nDecrypted =" VigenereDecipher(c, key) MsgBox % clipboard := out
VigenereCipher(Text, Key){
StringUpper, Text, Text Text := RegExReplace(Text, "[^A-Z]") Loop Parse, Text { 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
}
VigenereDecipher(Text, key){
Loop Parse, key decoderKey .= Chr(26-(Asc(A_LoopField)-65)+65) return VigenereCipher(Text, decoderKey)
}</lang>
- Output:
Input =Beware the Jabberwock, my son! The jaws that bite, the claws that catch! key =VIGENERECIPHER Ciphertext =WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY Decrypted =BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH
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>
- Output:
Key = "LEMON" Plaintext = "ATTACK AT DAWN" Ciphertext = "LXFOPVEFRNHR" Decrypted = "ATTACKATDAWN"
Befunge
The text to encrypt is read from stdin. The key is the string literal at the start of the program.
<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>
- Output:
Beware the Jabberwock, my son! The jaws that bite, the claws that catch! WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY
The decrypter is essentially identical, except for a change of sign on the last line.
<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>
- Output:
WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH
C
This program skips non-alphabetical characters, preserves case, and when run with the -d
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>
- define NUMLETTERS 26
- define BUFSIZE 4096
char *get_input(void);
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;
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; } }
if (argc - optind != 1) { fprintf(stderr, "%s requires one argument and one only\n", argv[0]); fprintf(stderr, "\n%s\n", usage); return 1; }
// Convert argument into array of shifts char const *const restrict key = argv[optind]; size_t const keylen = strlen(key); char shifts[keylen];
char const *restrict plaintext = NULL; for (size_t i = 0; i < keylen; i++) { if (!(isalpha(key[i]))) { 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; }
do { fflush(stdout); // Print "Plain text: " if encrypting and "Cipher text: " if // decrypting printf("%s", (encrypt) ? plainmsg : cryptmsg); plaintext = get_input(); if (plaintext == NULL) { fprintf(stderr, "Error getting input\n"); return 4; } } while (strcmp(plaintext, "") == 0); // Reprompt if entry is empty
size_t const plainlen = strlen(plaintext);
char* const restrict ciphertext = calloc(plainlen + 1, sizeof *ciphertext); if (ciphertext == NULL) { fprintf(stderr, "Memory error\n"); return 5; }
for (size_t i = 0, j = 0; i < plainlen; i++) { // Skip non-alphabetical characters if (!(isalpha(plaintext[i]))) { ciphertext[i] = plaintext[i]; continue; } // 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); // Silence warnings about const not being maintained in cast to void* free((char*) plaintext); return 0;
} char *get_input(void) {
char *const restrict buf = malloc(BUFSIZE * sizeof (char)); if (buf == NULL) { return NULL; }
fgets(buf, BUFSIZE, stdin);
// Get rid of newline size_t const len = strlen(buf); if (buf[len - 1] == '\n') buf[len - 1] = '\0';
return buf;
}</lang>
- Output:
$ ./vigenere VIGENERECIPHER Plain text: Beware the Jabberwock, my son! The jaws that bite, the claws that catch! Cipher text: Wmceei klg Rpifvmeugx, qp wqv! Ioi avey xuek fkbt, alv xtgaf xyev kpagy! $ ./vigenere -d VIGENERECIPHER Cipher text: Wmceei klg Rpifvmeugx, qp wqv! Ioi avey xuek fkbt, alv xtgaf xyev kpagy! Plain text: Beware the Jabberwock, my son! The jaws that bite, the claws that catch!
C#
<lang csharp> using System;
namespace VigenereCipher {
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(); } }
} </lang>
- Output:
Beware the Jabberwock, my son! The jaws that bite, the claws that catch! VIGENERECIPHER Encrypted: WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY Decrypted: BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH
C++
<lang cpp>#include <iostream>
- include <string>
using namespace std;
class Vigenere { public:
string key;
Vigenere(string key) { for(int i = 0; i < key.size(); ++i) { if(key[i] >= 'A' && key[i] <= 'Z') this->key += key[i]; else if(key[i] >= 'a' && key[i] <= 'z') this->key += key[i] + 'A' - 'a'; } }
string encrypt(string text) { string out;
for(int i = 0, j = 0; i < text.length(); ++i) { 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'; j = (j + 1) % key.length(); }
return out; }
string decrypt(string text) { string out;
for(int i = 0, j = 0; i < text.length(); ++i) { char c = text[i]; if(c >= 'a' && c <= 'z') c += 'A' - 'a'; else if(c < 'A' || c > 'Z') continue;
out += (c - key[j] + 26) % 26 + 'A'; j = (j + 1) % key.length(); }
return out; }
};
int main() {
Vigenere cipher("VIGENERECIPHER");
string original = "Beware the Jabberwock, my son! The jaws that bite, the claws that catch!"; string encrypted = cipher.encrypt(original); string decrypted = cipher.decrypt(encrypted);
cout << original << endl; cout << "Encrypted: " << encrypted << endl; cout << "Decrypted: " << decrypted << endl;
}</lang>
- Output:
Beware the Jabberwock, my son! The jaws that bite, the claws that catch! Encrypted: WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY Decrypted: BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH
Ceylon
<lang ceylon>shared void run() {
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);
function decrypt(String cipherText, String key) => crypt(cipherText, key, (Character a, Character b) => ('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>
Clojure
Requires Clojure 1.2. <lang clojure>(ns org.rosettacode.clojure.vigenere
(:require [clojure.string :as string]))
- convert letter to offset from \A
(defn to-num [char] (- (int char) (int \A)))
- convert number to letter, treating it as modulo 26 offset from \A
(defn from-num [num] (char (+ (mod num 26) (int \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)))))
(defn crypt [op text key]
(let [xcrypt1 (partial #'crypt1 op)] (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>
Demonstration code: <lang clojure>(ns org.rosettacode.clojure.test-vigenere
(:require [org.rosettacode.clojure.vigenere :as vigenere]))
(let
[ plaintext "Beware the Jabberwock, my son! The jaws that bite, the claws that catch!" key "Vigenere cipher" ciphertext (vigenere/encrypt plaintext key) recovered (vigenere/decrypt ciphertext key) ]
(doall (map (fn k v (printf "%9s: %s\n" k v)) [ ["Original" plaintext] ["Key" key] ["Encrypted" ciphertext] ["Decrypted" recovered] ])))
</lang>
- Output:
Original: Beware the Jabberwock, my son! The jaws that bite, the claws that catch! Key: Vigenere cipher Encrypted: WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY Decrypted: BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH
CoffeeScript
<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>
Original : Beware the Jabberwock, my son! The jaws that bite, the claws that catch! Encrypted : WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY Decrypted : BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH
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>
- Output:
msg: Beware the Jabberwock... The jaws that... the claws that catch! enc: WMCEEIKLGRPIFVMEUGXXYILILZXYVBZLRGCEYAIOEKXIZGU dec: BEWARETHEJABBERWOCKTHEJAWSTHATTHECLAWSTHATCATCH
D
<lang d>import std.stdio, std.string;
string encrypt(in string txt, in string key) pure @safe 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 in {
assert(key.removechars("^A-Z") == key);
} body {
string res; foreach (immutable i, immutable c; txt.toUpper.removechars("^A-Z")) res ~= (c - key[i % $] + 26) % 26 + 'A'; return res;
}
void main() {
immutable key = "VIGENERECIPHER"; 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>
- Output:
WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH
Alternative Version
<lang d>import std.stdio, std.range, std.ascii, std.string, std.algorithm,
std.conv;
immutable mod = (in int m, in int n) pure nothrow @safe @nogc =>
((m % n) + n) % n;
immutable _s2v = (in string s) pure /*nothrow*/ @safe =>
s.toUpper.removechars("^A-Z").map!q{ a - 'A' };
string _v2s(R)(R v) pure /*nothrow*/ @safe {
return v.map!(x => uppercase[x.mod(26)]).text;
}
immutable encrypt = (in string txt, in string key) pure /*nothrow*/ @safe =>
txt._s2v.zip(key._s2v.cycle).map!q{ a[0] + a[1] }._v2s;
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.
Elena
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>
- Output:
Beware the Jabberwock, my son! The jaws that bite, the claws that catch! VIGENERECIPHER Encrypted:WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY Decrypted:BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH Press any key to continue..
Elixir
<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
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)
IO.puts "Original: #{plaintext}" IO.puts "Encrypted: #{ciphertext}" IO.puts "Decrypted: #{recovered}"</lang>
- Output:
Original: Beware the Jabberwock, my son! The jaws that bite, the claws that catch! Encrypted: WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY Decrypted: BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH
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]).
% Utility functions for character tests and conversions isupper([C|_]) -> isupper(C); isupper(C) -> (C >= $A) and (C =< $Z).
islower([C|_]) -> islower(C); islower(C) -> (C >= $a) and (C =< $z).
isalpha([C|_]) -> isalpha(C); isalpha(C) -> isupper(C) or islower(C).
toupper(S) when is_list(S) -> lists:map(fun toupper/1, S); toupper(C) when (C >= $a) and (C =< $z) -> C - $a + $A; toupper(C) -> C.
% modulo function that normalizes into positive range for positive divisor 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.
% convert position in alphabet back to letter from_pos(N) -> mod(N, 26) + $A.
% encode the given letter given the single-letter key encipher(P, K) -> from_pos(to_pos(P) + to_pos(K)).
% decode the given letter given the single-letter key decipher(C, K) -> from_pos(to_pos(C) - to_pos(K)).
% 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>
- Output:
Ciphertext: WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY Decrypted: BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH
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>
C:\src\fsharp>fsi vigenere.fsx WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH
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>
- Output:
Key: Vigenere cipher Input: Beware the Jabberwock, my son! The jaws that bite, the claws that catch! Encrypted: WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY Decrypted: BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH
Fortran
<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>
- Output:
Beware the Jabberwock, my son! The jaws that bite, the claws that catch! WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH
Go
<lang go>package main
import "fmt"
type vkey string
func newVigenère(key string) (vkey, bool) {
v := vkey(upperOnly(key)) return v, len(v) > 0 // key length 0 invalid
}
func (k vkey) encipher(pt string) string {
ct := upperOnly(pt) for i, c := range ct { ct[i] = 'A' + (c-'A'+k[i%len(k)]-'A')%26 } return string(ct)
}
func (k vkey) decipher(ct string) (string, bool) {
pt := make([]byte, len(ct)) for i := range pt { c := ct[i] if c < 'A' || c > 'Z' { return "", false // invalid ciphertext } pt[i] = 'A' + (c-k[i%len(k)]+26)%26 } return string(pt), true
}
// upperOnly extracts letters A-Z, a-z from a string and // returns them all upper case in a byte slice. // Useful for vkey constructor and encipher function. func upperOnly(s string) []byte {
u := make([]byte, 0, len(s)) for i := 0; i < len(s); i++ { c := s[i] if c >= 'A' && c <= 'Z' { u = append(u, c) } else if c >= 'a' && c <= 'z' { u = append(u, c-32) } } return u
}
const testKey = "Vigenère Cipher" const testPT = `Beware the Jabberwock, my son!
The jaws that bite, the claws that catch!`
func main() {
fmt.Println("Supplied key: ", testKey) v, ok := newVigenère(testKey) if !ok { fmt.Println("Invalid key") return } fmt.Println("Effective key:", v) fmt.Println("Plain text:", testPT) ct := v.encipher(testPT) fmt.Println("Enciphered:", ct) dt, ok := v.decipher(ct) if !ok { fmt.Println("Invalid ciphertext") return } fmt.Println("Deciphered:", dt)
}</lang>
- Output:
Supplied key: Vigenère Cipher Effective key: VIGENRECIPHER Plain text: Beware the Jabberwock, my son! The jaws that bite, the claws that catch! Enciphered: WMCEEVXJMYHFSZZCSPBQAADUXYZRGAFKLCBQPXVOPKGYRAUBWHXTVBIL Deciphered: BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH
Haskell
<lang haskell>import Data.Char import Text.Printf
-- Perform encryption or decryption, depending on f. crypt f key = map toLetter . zipWith f (cycle key)
where toLetter = chr . (+) (ord 'A')
-- Encrypt or decrypt one letter. enc k c = (ord k + ord c) `mod` 26 dec k c = (ord c - ord k) `mod` 26
-- Given a key, encrypt or decrypt an input string. encrypt = crypt enc decrypt = crypt dec
-- Convert a string to have only upper case letters. convert = map toUpper . filter isLetter
main = do
let key = "VIGENERECIPHER" text = "Beware the Jabberwock, my son! The jaws that bite, " ++ "the claws that catch!" encr = encrypt key $ convert text decr = decrypt key encr printf " Input: %s\n Key: %s\nEncrypted: %s\nDecrypted: %s\n" text key encr decr</lang>
- Output:
Input: Beware the Jabberwock, my son! The jaws that bite, the claws that catch! Key: VIGENERECIPHER Encrypted: WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY Decrypted: BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH
Icon and Unicon
<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
procedure Vignere(mode,ekey,ptext,alpha) #: Vignere cipher
/alpha := &ucase # default if *alpha ~= *cset(alpha) then runerr(205,alpha) # no dups alpha ||:= alpha # unobstructed
every ctext:="" & p:=ptext[i := 1 to *ptext] & k:=ekey[(i-1)%*ekey+1] do case mode of { "e"|"encrypt": ctext||:=map(p,alpha[1+:*alpha/2],alpha[find(k,alpha)+:(*alpha/2)]) "d"|"decrypt": ctext||:=map(p,alpha[find(k,alpha)+:(*alpha/2)],alpha[1+:*alpha/2]) 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
procedure NormalizeText(ptext,alpha) #: text/case classical crypto helper
/alpha := &ucase # default if &lcase === (alpha := cset(alpha)) then ptext := map(ptext) # lower if &ucase === alpha then ptext := map(ptext,&lcase,&ucase) # upper return deletec(ptext,&cset--alpha) # only alphas
end
procedure GFormat(text) #: 5 letter group formatting helper
text ? (s := "", until pos(0) do s ||:= " " || move(5)|tab(0)) return s[2:0]
end</lang>
- Output:
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
J
Solution:
Using vig
from the 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
)
ALPHA=: (65,:26) ];.0 a. NB. Character Set preprocess=: (#~ e.&ALPHA)@toupper NB. force uppercase and discard non-alpha chars vigEncryptRC=: 0 vig ALPHA preprocess vigDecryptRC=: 1 vig ALPHA preprocess</lang>
Example Use: <lang j> 'VIGENERECIPHER' vigEncryptRC 'Beware the Jabberwock, my son! The jaws that bite, the claws that catch!' WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY
'VIGENERECIPHER' vigDecryptRC 'WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY'
BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH</lang>
Java
<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)); }
static String encrypt(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) - 2 * 'A') % 26 + 'A'); j = ++j % key.length(); } return res; }
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; }
}</lang>
WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH
JavaScript
<lang javascript>// helpers // helper function ordA(a) {
return a.charCodeAt(0) - 65;
}
// vigenere function vigenere(text, key, decode) {
var i = 0, b; key = key.toUpperCase().replace(/[^A-Z]/g, ); return text.toUpperCase().replace(/[^A-Z]/g, ).replace(/[A-Z]/g, function(a) { b = key[i++ % key.length]; return String.fromCharCode(((ordA(a) + (decode ? 26 - ordA(b) : ordA(b))) % 26 + 65)); });
}
// example var text = "The quick brown fox Jumped over the lazy Dog the lazy dog lazy dog dog"; var key = 'alex'; var enc = vigenere(text,key); var dec = vigenere(enc,key,true);
console.log(enc); console.log(dec);</lang>
Jsish
From Javascript entry. <lang javascript>/* Vigenère cipher, in Jsish */ "use strict";
function ordA(a:string):number {
return a.charCodeAt(0) - 65;
}
// 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)); });
}
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>
- Output:
prompt$ jsish -u vigenereCipher.jsi [PASS] vigenereCipher.jsi
Julia
<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)
if keylen < msglen key = repeat(key, div(msglen - keylen, keylen) + 2)[1:msglen] end
enc = Vector{Char}(msglen)
@inbounds for i in 1:length(msg) enc[i] = Char((Int(msg[i]) + Int(key[i]) - 130) % 26 + 65) end
return join(enc)
end
function decrypt(enc::AbstractString, key::AbstractString)
enc = uppercase(join(filter(isalpha, collect(enc)))) key = uppercase(join(filter(isalpha, collect(key)))) msglen = length(enc) keylen = length(key)
if keylen < msglen key = repeat(key, div(msglen - keylen, keylen) + 2)[1:msglen] end
msg = Vector{Char}(msglen)
@inbounds for i in 1:length(enc) msg[i] = Char((Int(enc[i]) - Int(key[i]) + 26) % 26 + 65) end
return join(msg)
end
const messages = ("Attack at dawn.", "Don't attack.", "The war is over.") const key = "LEMON"
for msg in messages
enc = encrypt(msg, key) dec = decrypt(enc, key) println("Original: $msg\n -> encrypted: $enc\n -> decrypted: $dec")
end</lang>
- Output:
Original: Attack at dawn. -> encrypted: LXFOPVEFRNHR -> decrypted: ATTACKATDAWN Original: Don't attack. -> encrypted: OSZHNEXMQX -> decrypted: DONTATTACK Original: The war is over. -> encrypted: ELQKNCMECIPV -> decrypted: THEWARISOVER
Kotlin
<lang scala>// version 1.1.3
fun vigenere(text: String, key: String, encrypt: Boolean = true): String {
val t = if (encrypt) text.toUpperCase() else text val sb = StringBuilder() var ki = 0 for (c in t) { 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()
}
fun main(args: Array<String>) {
val key = "VIGENERECIPHER" 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>
- Output:
WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH
Liberty BASIC
<lang lb> 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$
end
function encrypt$(text$, key$)
flt$ = filter$(text$) encrypt$ = "" 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
function decrypt$(flt$, key$)
decrypt$ = "" 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 + 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
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 for i = 1, #msg do if msg[i] >= string.byte('A') and msg[i] <= string.byte('Z') then 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 return string.char( unpack(enc) )
end
function Decrypt( _msg, _key )
local msg = { _msg:byte( 1, -1 ) } local key = { _key:upper():byte( 1, -1 ) } local dec = {}
local j = 1 for i = 1, #msg do dec[i] = ( msg[i] - key[j] + 26 ) % 26 + string.byte('A') if j == #key then j = 1 else j = j + 1 end end return string.char( unpack(dec) )
end
original = "Beware the Jabberwock, my son! The jaws that bite, the claws that catch!"
key = "VIGENERECIPHER";
encrypted = Encrypt( original, key ) decrypted = Decrypt( encrypted, key )
print( encrypted ) print( decrypted )</lang>
WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH
Mathematica
<lang Mathematica>encode[text_String, key_String] :=
Module[{textCode, keyCode}, 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]]
decode[text_String, key_String] :=
Module[{textCode, keyCode}, 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]]</lang>
key = "Vigenere Cipher"; text = "Beware the Jabberwock, my son! The jaws that bite, the claws \ that catch!"; code = encode[text, key] WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY decode[code, key] BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH
NetRexx
<lang NetRexx>/* NetRexx */ options replace format comments java crossref savelog symbols nobinary
pt = 'Attack at dawn!' key = 'LEMON' test(key, pt)
key = 'N' -- rot-13 test(key, pt)
key = 'B' -- Caesar test(key, pt)
pt = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' key = 'A' test(key, pt)
pt = sampledata() key = 'Hamlet; Prince of Denmark' test(key, pt)
return
method vigenere(meth, key, text) public static
select when 'encipher'.abbrev(meth.lower, 1) then df = 1 when 'decipher'.abbrev(meth.lower, 1) then df = -1 otherwise signal IllegalArgumentException(meth 'must be "encipher" or "decipher"') end
alpha = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
text = stringscrubber(text) key = stringscrubber(key) code = 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_
return code
method vigenere_encipher(key, plaintext) public static
return vigenere('encipher', key, plaintext)
method vigenere_decipher(key, ciphertext) public static
return vigenere('decipher', key, ciphertext)
method mod(N = int, D = int) private static
return (D + (N // D)) // D
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>
- Output:
....+....|....+....|....+....|....+....|....+....|....+....|....+....|....+....| 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 ....+....|....+....|....+....|....+....|....+....|....+....|....+....|....+....| 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
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>
- Output:
Beware the Jabberwock, my son! The jaws that bite, the claws that catch! WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH
Objeck
<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>
encrypt: WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY decrypt: BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH
OCaml
<lang ocaml>let cipher src key crypt =
let str = String.uppercase src in let key = String.uppercase key in
(* strip out non-letters *) let len = String.length str in let rec aux i j = if j >= len then String.sub str 0 i else if str.[j] >= 'A' && str.[j] <= 'Z' then (str.[i] <- str.[j]; aux (succ i) (succ j)) else aux i (succ j) in let res = aux 0 0 in
let slen = String.length res in let klen = String.length key in
let d = int_of_char in let f = if crypt then fun i -> d res.[i] - d 'A' + d key.[i mod klen] - d 'A' else fun i -> d res.[i] - d key.[i mod klen] + 26 in for i = 0 to pred slen do res.[i] <- char_of_int (d 'A' + (f i) mod 26) done; (res)
let () =
let str = "Beware the Jabberwock, my son! The jaws that bite, \ the claws that catch!" in let key = "VIGENERECIPHER" in
let cod = cipher str key true in let dec = cipher cod key false in
Printf.printf "Text: %s\n" str; Printf.printf "key: %s\n" key; Printf.printf "Code: %s\n" cod; Printf.printf "Back: %s\n" dec;
- </lang>
Run:
$ ocaml vigenere_cipher.ml Text: Beware the Jabberwock, my son! The jaws that bite, the claws that catch! key: VIGENERECIPHER Code: WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY Back: BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH
ooRexx
A reworking of the NetRexx version using Open Object Rexx but shouldn't take much to translate to Classic Rexx. <lang REXX>/* Rexx */ Do
alpha = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' key = 'LEMON'
pt = 'Attack at dawn!' Call test key, pt
key = 'N' Call test key, pt
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>
- Output:
....+....|....+....|....+....|....+....|....+....|....+....|....+....|....+....| 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 ....+....|....+....|....+....|....+....|....+....|....+....|....+....|....+....| 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
Pascal
<lang pascal> // The Vigenere cipher in reasonably standard Pascal // <no library functions: all conversions hand-coded> PROGRAM Vigenere;
// get a letter's alphabetic position (A=0) FUNCTION letternum(letter: CHAR): BYTE; BEGIN letternum := (ord(letter)-ord('A')); END;
// convert a character to uppercase FUNCTION uch(ch: CHAR): CHAR; 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;
VAR key: STRING = 'Vigenere cipher';
msg: STRING = 'Beware the Jabberwock! The jaws that bite, the claws that catch!';
vtx: STRING = ;
ctx: STRING = ;
ptx: STRING = ;
BEGIN // make Vigenere-compatible vtx := vstr(msg); key := vkey(vtx,key); // 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.
</lang>
- Output:
Message : Beware the Jabberwock! The jaws that bite, the claws that catch! Plaintext : BEWARETHEJABBERWOCKTHEJAWSTHATBITETHECLAWSTHATCATCH Key : VIGENERECIPHERVIGENERECIPHERVIGENERECIPHERVIGENEREC Ciphertext : WMCEEIKLGRPIFVMEUGXXYILILZXYVBHMGIKLGKAHAJOPGXPEKGJ Plaintext : BEWARETHEJABBERWOCKTHEJAWSTHATBITETHECLAWSTHATCATCH
Perl
<lang perl>if( @ARGV != 3 ){
printHelp();
}
# translate to upper-case, remove anything else
map( (tr/a-z/A-Z/, s/[^A-Z]//g), @ARGV );
my $cipher_decipher = $ARGV[ 0 ];
if( $cipher_decipher !~ /ENC|DEC/ ){
printHelp(); # user should say what to do
}
print "Key: " . (my $key = $ARGV[ 2 ]) . "\n";
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";
}
sub printHelp{
print "Usage:\n" . "Encrypting:\n perl cipher.pl ENC (plain text) (key)\n" . "Decrypting:\n perl cipher.pl DEC (cipher text) (key)\n"; exit -1;
}
sub Vigenere{
my ($direction, $key, $text) = @_; for( my $count = 0; $count < length $text; $count ++ ){ $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>
Demonstration:
$ perl cipher.pl ENC 'Beware the Jabberwock, my son! The jaws that bite, the claws that catch!' VIGENERECIPHER Key: VIGENERECIPHER Plain-text: BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH Encrypted: WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY $ perl cipher.pl DEC WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY VIGENERECIPHER Key: VIGENERECIPHER Cipher-text: WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY Decrypted: BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH $ perl cipher.pl FOO WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY VIGENERECIPHER Usage: Encrypting: perl cipher.pl ENC (plain text) (key) Decrypting: perl cipher.pl DEC (cipher text) (key)
Phix
<lang Phix>enum type mode ENCRYPT = +1, DECRYPT = -1 end type
function Vigenere(string s, string key, mode m) string res = "" integer k = 1, ch
s = upper(s) for i=1 to length(s) do ch = s[i] if ch>='A' and ch<='Z' then res &= 'A'+mod(ch+m*(key[k]+26),26) k = mod(k,length(key))+1 end if end for return res
end function
constant key = "LEMON",
s = "ATTACK AT DAWN", e = Vigenere(s,key,ENCRYPT), d = Vigenere(e,key,DECRYPT)
printf(1,"Original: %s\nEncrypted: %s\nDecrypted: %s\n",{s,e,d})</lang>
- Output:
Original: ATTACK AT DAWN Encrypted: LXFOPVEFRNHR Decrypted: ATTACKATDAWN
PHP
<lang PHP><?php
$str = "Beware the Jabberwock, my son! The jaws that bite, the claws that catch!"; $key = "VIGENERECIPHER";
printf("Text: %s\n", $str); printf("key: %s\n", $key);
$cod = encipher($str, $key, true); printf("Code: %s\n", $cod); $dec = encipher($cod, $key, false); printf("Back: %s\n", $dec);
function encipher($src, $key, $is_encode) {
$key = strtoupper($key); $src = strtoupper($src); $dest = ;
/* strip out non-letters */ for($i = 0; $i <= strlen($src); $i++) { $char = substr($src, $i, 1); if(ctype_upper($char)) { $dest .= $char; } }
for($i = 0; $i <= strlen($dest); $i++) { $char = substr($dest, $i, 1); if(!ctype_upper($char)) { 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); }
return $dest;
}
?> </lang>
- Output:
Text: Beware the Jabberwock, my son! The jaws that bite, the claws that catch! key: VIGENERECIPHER Code: WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY Back: BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH
PicoLisp
<lang PicoLisp>(de vigenereKey (Str)
(extract '((C) (when (>= "Z" (uppc C) "A") (- (char (uppc C)) 65) ) ) (chop Str) ) )
(de vigenereEncrypt (Str Key)
(pack (mapcar '((C K) (char (+ 65 (% (+ C K) 26))) ) (vigenereKey Str) (apply circ (vigenereKey Key)) ) ) )
(de vigenereDecrypt (Str Key)
(pack (mapcar '((C K) (char (+ 65 (% (+ 26 (- C K)) 26))) ) (vigenereKey Str) (apply circ (vigenereKey Key)) ) ) )</lang>
Test:
: (vigenereEncrypt "Beware the Jabberwock, my son! The jaws that bite, the claws that catch!" "VIGENERECIPHER" ) -> "WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY" : (vigenereDecrypt @ "VIGENERECIPHER") -> "BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH"
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. */ t(1) = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; do i = 2 to 26; t(i) = substr(t(i-1), 2, 25) || substr(t(i-1), 1, 1); end;
cypher = 'VIGILANCE'; original = 'Meet me on Tuesday evening at seven.'; put edit ('Message=', original) (a); original = uppercase(original);
/* Create the cypher text, same length as original, or longer. */ coder = repeat(cypher, length(original)/length(cypher));
/* 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);
/* DECODING. */ put skip list ('Decoded='); 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>
- Output:
Message=Meet me on Tuesday evening at seven. ENCODED='HMKBXEBPXPMYLLYRXIIQTOLTFGZZV'; Decoded= MEETMEONTUESDAYEVENINGATSEVEN
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]',
$keyChars = $Key.toUpper().ToCharArray() $Chars = $Text.toUpper().ToCharArray() function encode {
param ( $Char, $keyChar, $Alpha = [char]'A'..[char]'Z' )
$charIndex = $Alpha.IndexOf([int]$Char) $keyIndex = $Alpha.IndexOf([int]$keyChar) $NewIndex = ($charIndex + $KeyIndex) - $Alpha.Length $Alpha[$NewIndex]
} function decode {
param ( $Char, $keyChar, $Alpha = [char]'A'..[char]'Z' )
$charIndex = $Alpha.IndexOf([int]$Char) $keyIndex = $Alpha.IndexOf([int]$keyChar) $int = $charIndex - $keyIndex if ($int -lt 0) { $NewIndex = $int + $Alpha.Length } else { $NewIndex = $int } $Alpha[$NewIndex] }
while ( $keyChars.Length -lt $Chars.Length ) { $keyChars = $keyChars + $keyChars }
for ( $i = 0; $i -lt $Chars.Length; $i++ ) {
if ( [int]$Chars[$i] -in $map -and [int]$keyChars[$i] -in $map ) { if ($Decode) {$Chars[$i] = decode $Chars[$i] $keyChars[$i] $map} else {$Chars[$i] = encode $Chars[$i] $keyChars[$i] $map}
$Chars[$i] = [char]$Chars[$i] [string]$OutText += $Chars[$i] }
} $OutText $OutText = $null }
}</lang> Usage examples:
Encode: PS C:\> Get-VigenereCipher 'We attack at dawn.' 'lemon' HIMHGLGWOGOEIB Decode: PS C:\> Get-VigenereCipher 'HIMHGLGWOGOEIB' 'lemon' -Decode WEATTACKATDAWN
PureBasic
<lang PureBasic>Procedure prepString(text.s, Array letters(1))
;convert characters to an ordinal (0-25) and remove non-alphabetic characters, ;returns dimension size of result array letters() Protected *letter.Character, index Dim letters(Len(text)) text = UCase(text) *letter = @text While *letter\c Select *letter\c Case 'A' To 'Z' letters(index) = *letter\c - 65 index + 1 EndSelect *letter + SizeOf(Character) Wend If index > 0 Redim letters(index - 1) EndIf ProcedureReturn index - 1
EndProcedure
Procedure.s VC_encrypt(text.s, keyText.s, reverse = 0)
;if reverse <> 0 then reverse the key (decrypt) Protected *letter.Character Dim text(0) 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
Procedure.s VC_decrypt(cypherText.s, keyText.s)
ProcedureReturn VC_encrypt(cypherText, keyText.s, 1)
EndProcedure
If OpenConsole()
Define VignereCipher.s, plainText.s, encryptedText.s, decryptedText.s VignereCipher.s = "VIGNERECIPHER" plainText = "The quick brown fox jumped over the lazy dogs.": PrintN(RSet("Plain text = ", 17) + #DQUOTE$ + plainText + #DQUOTE$) encryptedText = VC_encrypt(plainText, VignereCipher): PrintN(RSet("Encrypted text = ", 17) + #DQUOTE$ + encryptedText + #DQUOTE$) decryptedText = VC_decrypt(encryptedText, VignereCipher): PrintN(RSet("Decrypted text = ", 17) + #DQUOTE$ + decryptedText + #DQUOTE$) Print(#CRLF$ + #CRLF$ + "Press ENTER to exit"): Input() CloseConsole()
EndIf</lang>
- Output:
Plain text = "The quick brown fox jumped over the lazy dogs." Encrypted text = "OPKDYZGMJGVAEAWDWYDTGLDCIIOPKYEQCFWVZ" Decrypted text = "THEQUICKBROWNFOXJUMPEDOVERTHELAZYDOGS"
Python
<lang python>Vigenere encryption and decryption
from itertools import starmap, cycle
def encrypt(message, key):
Vigenere encryption of message using key.
# Converted to uppercase. # Non-alpha characters stripped out. message = filter(str.isalpha, message.upper())
def enc(c, k): Single letter encryption.
return chr(((ord(k) + ord(c) - 2 * ord('A')) % 26) + ord('A'))
return .join(starmap(enc, zip(message, cycle(key))))
def decrypt(message, key):
Vigenere decryption of message using key.
def dec(c, k): Single letter decryption.
return chr(((ord(c) - ord(k) - 2 * ord('A')) % 26) + ord('A'))
return .join(starmap(dec, zip(message, cycle(key))))
def main():
Demonstration
text = 'Beware the Jabberwock, my son! The jaws that bite, ' + ( 'the claws that catch!' ) key = 'VIGENERECIPHER'
encr = encrypt(text, key) decr = decrypt(encr, key)
print(text) print(encr) print(decr)
if __name__ == '__main__':
main()
</lang>
- Output:
Beware the Jabberwock, my son! The jaws that bite, the claws that catch! WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH
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>
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>
- Output:
<lang racket> "BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH" </lang>
Raku
(formerly Perl 6)
<lang perl6>sub s2v ($s) { $s.uc.comb(/ <[ A..Z ]> /)».ord »-» 65 } sub v2s (@v) { (@v »%» 26 »+» 65)».chr.join }
sub blacken ($red, $key) { v2s(s2v($red) »+» s2v($key)) } sub redden ($blk, $key) { v2s(s2v($blk) »-» s2v($key)) }
my $red = "Beware the Jabberwock, my son! The jaws that bite, the claws that catch!"; my $key = "Vigenere Cipher!!!";
say $red; say my $black = blacken($red, $key); say redden($black, $key);</lang>
- Output:
Beware the Jabberwock, my son! The jaws that bite, the claws that catch! WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH
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.
Red
note: this program is much longer than it needed to be - because i couldn't resist 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.
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
red.exe -c vign1.red
or
red.exe -r vign1.red
which creates a single .exe file whithout the need for any .dll . should be working on windows , linux ( under wine ) and mac OS.
<lang Red>Red [needs: 'view]
CRLF: copy "^M^/" ;; constant for 0D 0A line feed
- ------------------------------------
crypt: func ["function to en- or decrypt message from textarea tx1"
/decrypt "decrypting switch/refinement" ][
- ------------------------------------
- when decrypting we have to remove the superflous newlines
- and undo the base64 encoding first ...
txt: either decrypt [ ;; message to en- or decrypt
s: copy tx1/text ;; newline could be single 0a byte or crlf sequence when copied from clipboard... debase replace/all s either find s CRLF [CRLF ] [ newline ] ""
] [
tx1/text ;; plaintext message
]
txt: to-binary txt ;; handle message as binary key: to-binary key1/text ;; handle key also as binary
bin: copy either decrypt [ "" ][ #{} ] ;; buffer for output
code: copy #{} ;; temp field to collect utf8 bytes when decrypting
- loop over length of binary! message ...
repeat pos length? txt [
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
either decrypt [ ;; collect utf-8 characters
append bin to-char code ;; append last code 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
Beware the Jabberwock, my son! The jaws that bite, the claws that catch!
with key "VIGENERECIPHER" translates to
i6y8r7e3ZbextWiPs7irrLfFtLWwb2m9wWXFxbdo ZaKtt2Wtqse7Zca+qrtlsK7Gqm9pxLCqcrm1qLzBZcatpL1wq6bGubFo
decrypting returns the original message
Beware the Jabberwock, my son! The jaws that bite, the claws that catch!
REXX
uppercase text only
<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>
- output when using the default internal fields:
original text = People solve problems by trial and error; judgement helps pick the trial. cyphered text = LLCDAHWRZJRDSWHOIMDICKVWREHRUINYCFYXHJSARBUPKOTSAPGBXVVMYMRP re-cyphered text = PEOPLESOLVEPROBLEMSBYTRIALANDERRORJUDGEMENTHELPSPICKTHETRIAL
supports most characters
This version supports all characters on the IBM Model M keyboard, including blanks, but any other
characters can be added as long as they're viewable.
Additional characters can be added by simply appending them to the @.1 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>
- output when using the default internal fields:
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
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:
key = LEMON plaintext = ATTACK AT DAWN ciphertext = LXFOPVEFRNHR decrypted = ATTACKATDAWN
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>
- Output:
Original: Beware the Jabberwock, my son! The jaws that bite, the claws that catch! Encrypted: WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY Decrypted: BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH
Rust
<lang rust>use std::ascii::AsciiExt;
static A: u8 = 'A' as u8;
fn uppercase_and_filter(input: &str) -> Vec<u8> {
let alphabet = b"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; let mut result = Vec::new();
for c in input.chars() { // Ignore anything that is not in our short list of chars. We can then safely cast to u8. if alphabet.iter().any(|&x| x as char == c) { result.push(c.to_ascii_uppercase() as u8); } }
return result;
}
fn vigenere(key: &str, text: &str, is_encoding: bool) -> String {
let key_bytes = uppercase_and_filter(key); let text_bytes = uppercase_and_filter(text);
let mut result_bytes = Vec::new();
for (i, c) in text_bytes.iter().enumerate() { let c2 = if is_encoding { (c + key_bytes[i % key_bytes.len()] - 2 * A) % 26 + A } else { (c + 26 - key_bytes[i % key_bytes.len()]) % 26 + A }; result_bytes.push(c2); }
String::from_utf8(result_bytes).unwrap()
}
fn main() {
let text = "Beware the Jabberwock, my son! The jaws that bite, the claws that catch!"; let key = "VIGENERECIPHER";
println!("Text: {}", text); println!("Key: {}", key);
let encoded = vigenere(key, text, true); println!("Code: {}", encoded); let decoded = vigenere(key, &encoded, false); println!("Back: {}", decoded);
}</lang>
Scala
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 } }
return result }
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 }
}
println("Encrypt text ABC => " + Vigenere.encrypt("ABC", "KEY")) println("Decrypt text KFA => " + Vigenere.decrypt("KFA", "KEY")) </lang>
- Output:
scala> Encrypt text ABC => KFA scala> Decrypt text KFA => ABC
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>
- Output:
Input: Beware the Jabberwock, my son! The jaws that bite, the claws that catch! key: VIGENERECIPHER Encrypted: WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY Decrypted: BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH
Sidef
<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>
- Output:
Beware the Jabberwock, my son! The jaws that bite, the claws that catch! WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH
Smalltalk
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..
<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.
crypted -> 'WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY' plain2 -> 'BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH' </lang>
Swift
Can support a larger range of characters, if desired
<lang swift>public func convertToUnicodeScalars(
str: String, minChar: UInt32, maxChar: UInt32
) -> [UInt32] {
var scalars = [UInt32]()
for scalar in str.unicodeScalars { let val = scalar.value
guard val >= minChar && val <= maxChar else { continue }
scalars.append(val) }
return scalars
}
public struct Vigenere {
private let keyScalars: [UInt32] private let smallestScalar: UInt32 private let largestScalar: UInt32 private let sizeAlphabet: UInt32
public init?(key: String, smallestCharacter: Character = "A", largestCharacter: Character = "Z") { let smallScalars = smallestCharacter.unicodeScalars let largeScalars = largestCharacter.unicodeScalars
guard smallScalars.count == 1, largeScalars.count == 1 else { return nil }
self.smallestScalar = smallScalars.first!.value self.largestScalar = largeScalars.first!.value self.sizeAlphabet = (largestScalar - smallestScalar) + 1
let scalars = convertToUnicodeScalars(str: key, minChar: smallestScalar, maxChar: largestScalar)
guard !scalars.isEmpty else { return nil }
self.keyScalars = scalars
}
public func decrypt(_ str: String) -> String? { let txtBytes = convertToUnicodeScalars(str: str, minChar: smallestScalar, maxChar: largestScalar)
guard !txtBytes.isEmpty else { return nil }
var res = ""
for (i, c) in txtBytes.enumerated() where c >= smallestScalar && c <= largestScalar { guard let char = UnicodeScalar((c &+ sizeAlphabet &- keyScalars[i % keyScalars.count]) % sizeAlphabet &+ smallestScalar) else { return nil }
res += String(char) }
return res }
public func encrypt(_ str: String) -> String? { let txtBytes = convertToUnicodeScalars(str: str, minChar: smallestScalar, maxChar: largestScalar)
guard !txtBytes.isEmpty else { return nil }
var res = ""
for (i, c) in txtBytes.enumerated() where c >= smallestScalar && c <= largestScalar { guard let char = UnicodeScalar((c &+ keyScalars[i % keyScalars.count] &- 2 &* smallestScalar) % sizeAlphabet &+ smallestScalar) else { 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>
- Output:
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 😃
Tcl
<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] } }
}
method encrypt {text} {
set out "" set j 0 foreach c [split $text ""] { if {[regexp {[^a-zA-Z]} $c]} continue scan [string toupper $c] %c c append out [format %c [expr {($c+[lindex $key $j]-130)%26+65}]] set j [expr {($j+1) % [llength $key]}] } return $out
}
method decrypt {text} {
set out "" set j 0 foreach c [split $text ""] { if {[regexp {[^A-Z]} $c]} continue scan $c %c c append out [format %c [expr {($c-[lindex $key $j]+26)%26+65}]] set j [expr {($j+1) % [llength $key]}] } return $out
}
}</lang> Demonstrating: <lang tcl>set cypher [Vigenere new "Vigenere Cipher"] set original "Beware the Jabberwock, my son! The jaws that bite, the claws that catch!" set encrypted [$cypher encrypt $original] set decrypted [$cypher decrypt $encrypted] puts $original puts "Encrypted: $encrypted" puts "Decrypted: $decrypted"</lang>
- Output:
Beware the Jabberwock, my son! The jaws that bite, the claws that catch! Encrypted: WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY Decrypted: BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH
TXR
<lang txr>@(next :args) @(do
(defun vig-op (plus-or-minus) (op + #\A [mod [plus-or-minus (- @1 #\A) (- @2 #\A)] 26]))
(defun vig (msg key encrypt) (mapcar (vig-op [if encrypt + -]) msg (repeat key))))
@(coll)@{key /[A-Za-z]/}@(end) @(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>
Here, the TXR pattern language is used to scan letters out of two arguments, and convert them to upper case. The embedded TXR Lisp dialect handles the Vigenère logic, in just a few lines of code.
Lisp programmers may do a "double take" at what is going on here: yes mapcar
can operate on strings and return strings in TXR Lisp. (repeat key)
produces an infinite lazy list; but that's okay because mapcar
stops after the shortest input runs out of items.
Run:
$ txr vigenere.txr 'vigenere cipher' 'Beware the Jabberwock... The jaws that... the claws that catch!' text: BEWARETHEJABBERWOCKTHEJAWSTHATTHECLAWSTHATCATCH key: VIGENERECIPHER enc: WMCEEIKLGRPIFVMEUGXXYILILZXYVBZLRGCEYAIOEKXIZGU dec: GWQWEACDCBLUXNWOIYXPQAHSHLPQFLNDRYUWUKEAWCHSNYU check: BEWARETHEJABBERWOCKTHEJAWSTHATTHECLAWSTHATCATCH
TypeScript
<lang JavaScript>class Vigenere {
key: string
/** Create new cipher based on key */ constructor(key: string) { this.key = Vigenere.formatText(key) }
/** Enrypt a given text using key */ encrypt(plainText: string): string { return Array.prototype.map.call(Vigenere.formatText(plainText), (letter: string, index: number): string => { return String.fromCharCode((letter.charCodeAt(0) + this.key.charCodeAt(index % this.key.length) - 130) % 26 + 65) }).join() }
/** 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() }
/** Converts to uppercase and removes non characters */ private static formatText(text: string): string { return text.toUpperCase().replace(/[^A-Z]/g, "") }
}
/** Example usage */ (() => {
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."
console.log(`Original: ${original}`)
let vig: Vigenere = new Vigenere("vigenere")
let encoded: string = vig.encrypt(original)
console.log(`After encryption: ${encoded}`)
let back: string = vig.decrypt(encoded)
console.log(`After decryption: ${back}`)
})() </lang>
VBA
<lang vb>Option Explicit
Sub test() Dim Encryp As String
Encryp = Vigenere("Beware the Jabberwock, my son! The jaws that bite, the claws that catch!", "vigenerecipher", True) Debug.Print "Encrypt:= """ & Encryp & """" Debug.Print "Decrypt:= """ & Vigenere(Encryp, "vigenerecipher", False) & """"
End Sub
Private Function Vigenere(sWord As String, sKey As String, Enc As Boolean) As String Dim bw() As Byte, bk() As Byte, i As Long, c As Long Const sW As String = "ÁÂÃÄÅÇÈÉÊËÌÍÎÏÑÒÓÔÕÖÙÚÛÜÝ" Const sWo As String = "AAAAACEEEEIIIINOOOOOUUUUY" Const A As Long = 65 Const N As Long = 26
c = Len(sKey) i = Len(sWord) sKey = Left(IIf(c < i, StrRept(sKey, (i / c) + 1), sKey), i) sKey = StrConv(sKey, vbUpperCase) 'Upper case sWord = StrConv(sWord, vbUpperCase) sKey = StrReplace(sKey, sW, sWo) 'Replace accented characters sWord = StrReplace(sWord, sW, sWo) sKey = RemoveChars(sKey) 'Remove characters (numerics, spaces, comas, ...) sWord = RemoveChars(sWord) bk = CharToAscii(sKey) 'To work with Bytes instead of String bw = CharToAscii(sWord) For i = LBound(bw) To UBound(bw) Vigenere = Vigenere & Chr((IIf(Enc, ((bw(i) - A) + (bk(i) - A)), ((bw(i) - A) - (bk(i) - A)) + N) Mod N) + A) Next i
End Function
Private Function StrRept(s As String, N As Long) As String Dim j As Long, c As String
For j = 1 To N c = c & s Next StrRept = c
End Function
Private Function StrReplace(s As String, What As String, By As String) As String Dim t() As String, u() As String, i As Long
t = SplitString(What) u = SplitString(By) StrReplace = s For i = LBound(t) To UBound(t) StrReplace = Replace(StrReplace, t(i), u(i)) Next i
End Function
Private Function SplitString(s As String) As String()
SplitString = Split(StrConv(s, vbUnicode), Chr(0))
End Function
Private Function RemoveChars(str As String) As String Dim b() As Byte, i As Long
b = CharToAscii(str) For i = LBound(b) To UBound(b) If b(i) >= 65 And b(i) <= 90 Then RemoveChars = RemoveChars & Chr(b(i)) Next i
End Function
Private Function CharToAscii(s As String) As Byte()
CharToAscii = StrConv(s, vbFromUnicode)
End Function</lang>
- Output:
Encrypt:= "WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY" Decrypt:= "BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH"
VBScript
<lang vb> Function Encrypt(text,key) text = OnlyCaps(text) key = OnlyCaps(key) j = 1 For i = 1 To Len(text) ms = Mid(text,i,1) m = Asc(ms) - Asc("A") ks = Mid(key,j,1) k = Asc(ks) - Asc("A") j = (j Mod Len(key)) + 1 c = (m + k) Mod 26 c = Chr(Asc("A")+c) Encrypt = Encrypt & c Next End Function
Function Decrypt(text,key) key = OnlyCaps(key) j = 1 For i = 1 To Len(text) ms = Mid(text,i,1) m = Asc(ms) - Asc("A") ks = Mid(key,j,1) k = Asc(ks) - 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 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
'testing the functions orig_text = "Beware the Jabberwock, my son! The jaws that bite, the claws that catch!" orig_key = "vigenerecipher" WScript.StdOut.WriteLine "Original: " & orig_text WScript.StdOut.WriteLine "Key: " & orig_key WScript.StdOut.WriteLine "Encrypted: " & Encrypt(orig_text,orig_key) WScript.StdOut.WriteLine "Decrypted: " & Decrypt(Encrypt(orig_text,orig_key),orig_key) </lang>
- Output:
Original: Beware the Jabberwock, my son! The jaws that bite, the claws that catch! Key: vigenerecipher Encrypted: WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY Decrypted: BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH
An alternate implementation using RegExp to filter the input <lang vb> 'vigenere cypher option explicit const asca =65 'ascii(a)
function filter(s)
with new regexp .pattern="[^A-Z]" .global=1 filter=.replace(ucase(s),"") end with
end function
function vigenere (s,k,sign) dim s1,i,a,b
for i=0 to len(s)-1 a=asc(mid(s,i+1,1))-asca 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
function encrypt(s,k): encrypt=vigenere(s,k,1) :end function function decrypt(s,k): decrypt=vigenere(s,k,-1) :end function
'test-------------------------- dim plaintext,filtered,key,encoded key="VIGENERECYPHER" plaintext = "Beware the Jabberwock, my son! The jaws that bite, the claws that catch!" filtered= filter(plaintext) wscript.echo filtered encoded=encrypt(filtered,key) wscript.echo encoded wscript.echo decrypt(encoded,key)
</lang>
Vedit macro language
Encrypts and then decrypts one line of text on current edit buffer, starting from cursor location. The user enters the keyword (upper or lower case). <lang vedit>Get_Input(10, "Key: ", STATLINE+NOCR) // @10 = key Reg_Copy_Block(11, Cur_Pos, EOL_Pos) // @11 = copy of original text EOL Ins_Newline Ins_Text("Key = ") Reg_Ins(10) Ins_Newline
// Prepare the key into numeric registers #130..: 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)
Ins_Text("Encrypted: ")
- 4 = Cur_Pos
Reg_Ins(11) // copy of original text Replace_Block("|!|A", "", #4, EOL_Pos, BEGIN+ALL+NOERR) // remove non-alpha chars Case_Upper_Block(#4, EOL_Pos) // convert to upper case Goto_Pos(#4)
- 1 = 1; Call("ENCRYPT_DECRYPT") // Encrypt the line
Reg_Copy_Block(11, #4, Cur_Pos) // Copy encrypted text text to next line Ins_Newline Ins_Text("Decrypted: ") Reg_Ins(11, BEGIN)
- 1 = -1; Call("ENCRYPT_DECRYPT") // Decrypt the line
Return
// 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)
Return </lang>
- Output:
Beware the Jabberwock, my son! The jaws that bite, the claws that catch! Key = vigenerecipher Encrypted: WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY Decrypted: BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH
XPL0
The KEYWORD must be UPPERCASE. Precede it with a minus sign to decrypt a file. Usage: vigenere KEYWORD <infile.txt >outfile.xxx
<lang XPL0>code ChIn=7, ChOut=8; 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>
- Output:
KEYWORD = ACE infile = Pack my box with five dozen liquor jugs. outfile = PCGKOCBQBWKXHHMVGHOBINNMQWSRLYGU KEYWORD = -ACE outfile = PACKMYBOXWITHFIVEDOZENLIQUORJUGS
zkl
<lang zkl>fcn encipher(src,key,is_encode){
upperCase:=["A".."Z"].pump(String); src=src.toUpper().inCommon(upperCase); // only uppercase key=key.toUpper().inCommon(upperCase).pump(List,"toAsc");
const A="A".toAsc(); klen:=Walker.cycle(key.len()); // 0,1,2,3,..,keyLen-1,0,1,2,3, ... src.pump(String,'wrap(c){ i:=klen.next(); c=c.toAsc(); (A + ( if(is_encode) c - A + key[i] - A; else c - key[i] + 26 ) % 26).toChar() });
}</lang> <lang zkl>str := "Beware the Jabberwock, my son! The jaws that bite, "
"the claws that catch!";
key := "Vigenere Cipher";
println("Text: ", str); println("key: ", key);
cod := encipher(str, key, True); println("Code: ", cod); dec := encipher(cod, key, False); println("Back: ", dec);</lang>
- Output:
Text: Beware the Jabberwock, my son! The jaws that bite, the claws that catch! key: Vigenere Cipher Code: WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY Back: BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH
- Programming Tasks
- Encryption
- String manipulation
- GUISS/Omit
- Openscad/Omit
- Ada
- ALGOL 68
- Applesoft BASIC
- AutoHotkey
- BBC BASIC
- Befunge
- C
- C sharp
- C++
- Ceylon
- Clojure
- CoffeeScript
- Common Lisp
- D
- Elena
- Elixir
- Erlang
- F Sharp
- Factor
- Fortran
- Go
- Haskell
- Icon
- Unicon
- Icon Programming Library
- J
- Java
- JavaScript
- Jsish
- Julia
- Kotlin
- Liberty BASIC
- Lua
- Mathematica
- NetRexx
- Nim
- Objeck
- OCaml
- OoRexx
- Pascal
- Perl
- Phix
- PHP
- PicoLisp
- PL/I
- PowerShell
- PureBasic
- Python
- R
- Racket
- Raku
- Red
- REXX
- Ring
- Ruby
- Rust
- Scala
- Seed7
- Sidef
- Smalltalk
- Swift
- Tcl
- TXR
- TypeScript
- VBA
- VBScript
- Vedit macro language
- XPL0
- Zkl