Vigenère cipher
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.)
You are encouraged to solve this task according to the task description, using any language you may know.
See also:
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
C
<lang c>#include <stdio.h>
- include <stdlib.h>
- include <string.h>
- include <ctype.h>
typedef const char *vigenere_t;
// for -std=c99
- if !defined(_BSD_SOURCE) && !defined(_SVID_SOURCE) && !defined(_XOPEN_SOURCE)
- define isascii(V) ((V) >= 0 && (V) <= 127 ? 1 : 0)
- endif
vigenere_t vigenere(char *key) {
int i, j = 0; const size_t l = strlen(key); char *r = malloc(l);
if (r != NULL) { for(i = 0; i < l; i++) { if ( isalpha(toupper(key[i])) && isascii(key[i]) ) {
r[j] = toupper(key[i]); j++;
} } r[j] = 0; } return (vigenere_t)r;
}
void vigenere_delete(vigenere_t v) {
free((void *)v);
}
char *vigenere_encrypt(vigenere_t v, const char *s) {
const char *k = (const char *)v; int i, j, ri = 0; const size_t l = strlen(s); const size_t kl = strlen(k); char *r = malloc(l); if (r != NULL) { for(i = 0, j = 0; i < l; i++) { char c = toupper(s[i]); if (!isascii(s[i]) || !isalpha(s[i])) continue; r[ri] = (c + k[j] - 2*'A') % 26 + 'A'; j = (j + 1) % kl; ri++; } r[ri] = 0; }
return r;
}
char *vigenere_descrypt(vigenere_t v, const char *s) {
const char *k = (const char *)v; int i, j, ri = 0; const size_t l = strlen(s); const size_t kl = strlen(k); char *r = malloc(l);
if (r != NULL) { for(i = 0, j = 0; i < l; i++) { char c = toupper(s[i]); if (!isascii(s[i])) continue; r[ri] = (c - k[j] + 26) % 26 + 'A'; j = (j + 1) % kl; ri++; } }
return r;
}
// testing
const static char *original = "Beware the Jabberwock, my son! The jaws that bite, the claws that catch!";
int main() {
vigenere_t v = vigenere("VIGENERECIPHER");
char *enc, *dec;
enc = vigenere_encrypt(v, original); dec = vigenere_descrypt(v, enc);
printf("%s\n" "Encrypted: %s\n" "Decrypted: %s\n", original, enc, dec);
free(enc); free(dec);
vigenere_delete(v); return 0;
}</lang>
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
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
D
ASCII only: <lang d>import std.stdio, std.string;
string encrypt(string text, in string key) {
string encoded; foreach (i, c; text.toupper().removechars("^A-Z")) encoded ~= (c + key[i % $] - 2 * 'A') % 26 + 'A'; return encoded;
}
string decrypt(string encoded, in string key) {
string decoded; foreach (i, c; encoded.toupper().removechars("^A-Z")) decoded ~= (c - key[i % $] + 26) % 26 + 'A'; return decoded;
}
void main() {
auto key = "VIGENERECIPHER"; auto original = "Beware the Jabberwock, my son!" ~ " The jaws that bite, the claws that catch!"; auto encoded = encrypt(original, key); writeln(encoded, "\n", decrypt(encoded, key));
}</lang> Output:
WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY 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 d>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
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
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"
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> Sample output:
Plain text = "The quick brown fox jumped over the lazy dogs." Encrypted text = "OPKDYZGMJGVAEAWDWYDTGLDCIIOPKYEQCFWVZ" Decrypted text = "THEQUICKBROWNFOXJUMPEDOVERTHELAZYDOGS"
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