Vigenère Encryption Cipher in Perl
The following implementation of the Vigenère Cipher in Perl is adjusted to the Finnish alphabet, using the programming ideas from my earlier implementation of the Affine Cipher. This Vigenère implementation also incorporates a simple columnar transposition function, making the ciphertext just slightly more difficult to crack. However, this implementation uses direct standard alphabets in a linear manner and its security is therefore inherently weak.
The summary
As we know, any monoalphabetic cipher (e.g. Affine Cipher) can be solved by means of letter frequency analysis, repetition patterns and the information on the way letters combine with each other. These are of course very language-dependent characteristics. The Vigenère cipher is based on an encipherment square (see below) where successive rows consist of the normal alphabet shifted by 1 position. Here any particular cipherletter may represent different plaintext letters, depending on its position in the message. Systems like these are called polyalphabetic ciphers.
The Vigenère Square
Plain A B C D E F G H I J K L M N O P Q R S T U V W X Y Z Å Ä Ö C A B C D E F G H I J K L M N O P Q R S T U V W X Y Z Å Ä Ö i B C D E F G H I J K L M N O P Q R S T U V W X Y Z Å Ä Ö A p C D E F G H I J K L M N O P Q R S T U V W X Y Z Å Ä Ö A B h D E F G H I J K L M N O P Q R S T U V W X Y Z Å Ä Ö A B C e E F G H I J K L M N O P Q R S T U V W X Y Z Å Ä Ö A B C D r F G H I J K L M N O P Q R S T U V W X Y Z Å Ä Ö A B C D E G H I J K L M N O P Q R S T U V W X Y Z Å Ä Ö A B C D E F H I J K L M N O P Q R S T U V W X Y Z Å Ä Ö A B C D E F G I J K L M N O P Q R S T U V W X Y Z Å Ä Ö A B C D E F G H J K L M N O P Q R S T U V W X Y Z Å Ä Ö A B C D E F G H I K L M N O P Q R S T U V W X Y Z Å Ä Ö A B C D E F G H I J L M N O P Q R S T U V W X Y Z Å Ä Ö A B C D E F G H I J K M N O P Q R S T U V W X Y Z Å Ä Ö A B C D E F G H I J K L N O P Q R S T U V W X Y Z Å Ä Ö A B C D E F G H I J K L M O P Q R S T U V W X Y Z Å Ä Ö A B C D E F G H I J K L M N P Q R S T U V W X Y Z Å Ä Ö A B C D E F G H I J K L M N O Q R S T U V W X Y Z Å Ä Ö A B C D E F G H I J K L M N O P R S T U V W X Y Z Å Ä Ö A B C D E F G H I J K L M N O P Q S T U V W X Y Z Å Ä Ö A B C D E F G H I J K L M N O P Q R T U V W X Y Z Å Ä Ö A B C D E F G H I J K L M N O P Q R S U V W X Y Z Å Ä Ö A B C D E F G H I J K L M N O P Q R S T V W X Y Z Å Ä Ö A B C D E F G H I J K L M N O P Q R S T U W X Y Z Å Ä Ö A B C D E F G H I J K L M N O P Q R S T U V X Y Z Å Ä Ö A B C D E F G H I J K L M N O P Q R S T U V W Y Z Å Ä Ö A B C D E F G H I J K L M N O P Q R S T U V W X Z Å Ä Ö A B C D E F G H I J K L M N O P Q R S T U V W X Y Å Ä Ö A B C D E F G H I J K L M N O P Q R S T U V W X Y Z Ä Ö A B C D E F G H I J K L M N O P Q R S T U V W X Y Z Å Ö A B C D E F G H I J K L M N O P Q R S T U V W X Y Z Å ÄTo encipher a message, the user chooses a keyword, say PARIS. Then he chooses the corresponding cipher rows from the encipherment square above as follows (of course, to decipher a message you only need the same rows):
Plain A B C D E F G H I J K L M N O P Q R S T U V W X Y Z Å Ä Ö P Q R S T U V W X Y Z Å Ä Ö A B C D E F G H I J K L M N O A B C D E F G H I J K L M N O P Q R S T U V W X Y Z Å Ä Ö R S T U V W X Y Z Å Ä Ö A B C D E F G H I J K L M N O P Q I J K L M N O P Q R S T U V W X Y Z Å Ä Ö A B C D E F G H S T U V W X Y Z Å Ä Ö A B C D E F G H I J K L M N O P Q RLet us assume our message to be enciphered is:
ON MONTA HYVÄÄ SYYTÄ JÄÄDÄ SATEELLA KOTIIN(translation: There are many good reasons to stay home when it rains.)
The enciphering process starts by finding the first letter O of the message in the cipher row starting with P. We see the cipherletter is A. Then the plainletter N is found the cipher row starting with A, thus N is -- N. The plainletter M becomes A (on the cipher row R), O becomes W, and N becomes C. When we have used the cipher row S (the last letter in the keyword), we start again from the cipher row P.
Finally, after all substitutions, we will get:
Key: PA RISPA RISPA RISPA RISPA RISPARIS PARISP Plain: ON MONTA HYVÄÄ SYYTÄ JÄÄDÄ SATEELLA KOTIIN Cipher: AN AWCFA YDKNÄ GDNFÄ ÅGQSÄ GIITEÖTS ZOHQÅÖStandard mode
To achieve the result above with our Perl script, you will say:
echo "on monta hyvää syytä jäädä sateella kotiin" |./vigenere.pl -v -k paris Plain: onmontahyvääsyytäjäädäsateellakotiin Cipher: anawcfaydknägdnfäågqsägiiteötszohqåöColumnar transposition
The standard mode is pretty vulnerable to attack if the keyword is extremely weak. Consider the following:
echo "on monta hyvää syytä jäädä sateella kotiin" | ./vigenere.pl -v -k aaaaa Plain: onmontahyvääsyytäjäädäsateellakotiin Cipher: onmontahyvääsyytäjäädäsateellakotiinThe keyword AAAAA is absolutely useless because it exposes the entire plaintext! However, we can make the ciphertext slightly more obscure by using columnar transposition (the command option -t) as follows:
echo "on monta hyvää syytä jäädä sateella kotiin" | ./vigenere.pl -v -t -k aaaaa Plain: onmontahyvääsyytäjäädäsateellakotiin Cipher: onmontahyvääsyytäjäädäsateellakotiin Transp: otätdeknnaäääeomhsjsltoyyäalinvyätaiThe transposed ciphertext is constructed in the following way:
Key A A A A A - - - - - O N M O N T A H Y V Ä Ä S Y Y T Ä J Ä Ä D Ä S A T E E L L A K O T I I NWe take the keyword and place the ciphertext underneath row by row. Then we take the first column, the second column and so on, and join them together into one row.
Finally, to apply this technique to our original example with the keyword PARIS:
echo "on monta hyvää syytä jäädä sateella kotiin" | ./vigenere.pl -v -t -k paris Plain: onmontahyvääsyytäjäädäsateellakotiin Cipher: anawcfaydknägdnfäågqsägiiteötszohqåö Transp: afnfstzönaäääeoaygågöhwddgitqcknqisåSee the columnar presentation of the ciphertext before transposition:
Key P A R I S - - - - - A N A W C F A Y D K N Ä G D N F Ä Å G Q S Ä G I I T E Ö T S Z O H Q Å Ö... and just to make it look neat and polished, use the group Perl utility as follows:
echo "on monta hyvää syytä jäädä sateella kotiin" | ./vigenere.pl -t -k paris | ./group -u -g AFNFS TZÖNA ÄÄÄEO AYGÅG ÖHWDD GITQC KNQIS ÅThe syntax
Vigenère Cipher: polyalphabetic substitution Options: -k WORD Keyword for enciphering -t Do columnar transposition by keyword -v Verbose: show the plaintext and the ciphertext(s). -h Show this help. Files: Multiple files are accepted. No files means using STDIN.The code
#!/usr/bin/perl # 27 Mar 06: Initial Code. # 28 Mar 06: Added simple columnar transposition. # Author: Jari Perkiömäki, jpe@uwasa.fi # $kw = $byte = $plain = $cipher = $tcipher = $ct = ""; $help = $i = $ki = $j = $le = $trans = $verbose = 0; use Getopt::Long; GetOptions ('h' => \$help, # help 'k=s' => \$kw, # keyword 't' => \$trans, # columnar transposition by keyword 'v' => \$verbose); # show plain/ciphertext help() if ($help || $kw eq ""); chomp $kw; foreach ('a' .. 'z', 'å', 'ä', 'ö') { $abc{$_} = $i++; } @keyword = split(//, $kw); $le = @keyword; %cba = reverse %abc; undef $/; while(<>) { tr/A-ZÅÄÖ/a-zåäö/; tr|/#+%&=,;:!\?\.\"\'\-<>\(\)\[\]@\\_| |; s/\s+//g; $plain = $_; foreach $byte (split //) { $j = 0 if ($j == $le); $i = $abc{$byte}; if ($j < $le) { $ki = $abc{$keyword[$j]}; $ct = $cba{(($i + $ki) % 29)}; $s[$j] .= $ct; $cipher .= $ct; $j++; } } for ($t = 0; $t < $le; $t++) { $tcipher .= $s[$t]; } } if ($verbose) { $trans ? print "Plain: $plain\nCipher: $cipher\nTransp: $tcipher\n" : print "Plain: $plain\nCipher: $cipher\n"; } else { $trans ? print "$tcipher\n" : print "$cipher\n" ; } sub help { print <<EOF; Usage: $0 [options] [files] Vigenère Cipher: polyalphabetic substitution Options: -k WORD Keyword for enciphering -t Do columnar transposition by keyword -v Verbose: show the plaintext and the ciphertext. -h Show this help. Files: Multiple files are accepted. No files means using STDIN. EOF exit(1); }