Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl: the Markov chain saw
 
PerlMonks  

Vigenere Cipher: Encode and Decode

by mrbbking (Hermit)
on Jan 18, 2002 at 06:14 UTC ( [id://139710]=sourcecode: print w/replies, xml ) Need Help??
Category: Cryptography
Author/Contact Info /msg mrbbking
Description:

This is a complete and historically accurate implementation of the Vigenere cipher. According to The Code Book, by Simon Singh, (Doubleday, 1999, ISBN 0385495315) Blaise de Vigenere formalized this cipher system based on the earlier work of Battista Alberti, Johannes Trithemius and Giovanni Porta.

This cipher is defined to function only on letters, and only with a key comprised exclusively of letters. Among this cipher's strengths is that only the encrypted letters are included in the ciphertext.
All punctuation and spaces are removed, so the ciphertext is an unbroken string of letters. No word breaks or punctuation to help in cryptanalysis.

Don't take that to mean this is secure against anyone serious.
It isn't.

There is a recent reference to a module called Crypt::Vigenere by Alistair Mills, but a CPAN search does not locate it as of 2002-01-13.
Discussion of the submission of that module is at: http://archive.develooper.com/modules@perl.org/msg08962.html

#!/usr/bin/perl -w
use strict;

# Vigenere cipher toolkit. Encrypt and Decrypt.
# Cracking not included.
# 

my $plaintext    = "This is not secure, but it's kind of fun.";
my $key            = 'perlmonks';        # By definition, letters only
+.
my $ciphertext;
my $derived_plaintext;

# For convenience, do the work in lowercase...
$plaintext = lc($plaintext);
$key       = lc($key);

# By definition, only encipher letters, and only use letters in the ke
+y...
$plaintext =~ s/[^a-z]//g;
$key       =~ s/[^a-z]//g;
if(length($key) < 1){
    die "Key must contain at least one letter.\n";
}

print "plaintext is [$plaintext]\n\n";
$ciphertext            = encrypt_string( $plaintext, $key);
$derived_plaintext    = decrypt_string( $ciphertext, $key );

print "Plaintext used      :$plaintext\n";
print "Ciphertext          :$ciphertext\n";
print "Recreated plaintext :$derived_plaintext\n";

sub encrypt_string{
    # encrypts a full string of plaintext, given the plaintext and the
+ key.
    # returns the encrypted string.
    my ($plaintext, $key) = @_;
    my $ciphertext;
    $key = $key x (length($plaintext) / length($key) + 1);
    for( my $i=0; $i<length($plaintext); $i++ ){
        $ciphertext .=
            encrypt_letter( (substr($plaintext,$i,1)),  (substr($key,$
+i,1)));
    }
    return $ciphertext;
}

sub decrypt_string{
    # decrypts a full string of ciphertext, given the ciphertext and t
+he key.
    # returns the plaintext string.
    my ($ciphertext, $key) = @_;
    my $plaintext;
    $key = $key x (length($ciphertext) / length($key) + 1);
    for( my $i=0; $i<length($ciphertext); $i++ ){
        $plaintext .=
            decrypt_letter( (substr($ciphertext,$i,1)),  (substr($key,
+$i,1)));
    }
    return $plaintext;
}


sub encrypt_letter{
    # encrypts a single letter of plaintext, given the plaintext
    # letter and the key to use for that letter's position.
    # The key is the first letter of the row to look in.
    my ($plain, $row) = @_;
    my $cipher;
    # in row n, ciphertext is plaintext + n, mod 26.
    $row     = ord(lc($row))   - ord('a');    # enable mod 26
    $plain  = ord(lc($plain)) - ord('a');    # enable mod 26
    $cipher = ($plain + $row) % 26;
    
    $cipher = chr($cipher + ord('a'));

    return uc($cipher);    #ciphertext in uppercase
}

sub decrypt_letter{
    # decrypts a single letter of ciphertext, given the ciphertext
    # letter and the key to use for that letter's position.
    # The key is the first letter of the row to look in.
    my ($cipher, $row) = @_;
    my $plain;
    # in row n, plaintext is ciphertext - n, mod 26.
    $row     = ord(lc($row))    - ord('a');    # enable mod 26
    $cipher = ord(lc($cipher)) - ord('a');    # enable mod 26
    $plain  = ($cipher - $row) % 26;
    
    $plain = chr($plain + ord('a'));

    return lc($plain);    #plaintext in lowercase
}
Replies are listed 'Best First'.
Re: Vigenere Cipher: Encode and Decode
by larryk (Friar) on Jan 19, 2002 at 01:25 UTC
    Having read and very much enjoyed this book a few years ago I took a stab at this particular cipher. Your letter crunching was a bit cleaner than mine so I adapted my old script - I split the key into an array to avoid having to create a second string the same size as the plaintext which may be quite large.
    #!/usr/bin/perl -lw use constant ENCRYPT => 1; use constant DECRYPT => -1; use strict; my $txt = 'A Perlmonk\'s work is never done!'; my $key = 'larryk'; $txt =~ s/[^a-z]//gi; print 'before : ',$txt; print 'encrypted: ',encrypt( $txt, $key ); print 'after : ',decrypt( encrypt( $txt, $key ), $key ); sub encrypt { my @txt = split '', shift; my @key = split '', shift; join '', map uc letter( ENCRYPT, $txt[$_], $key[$_%@key] ), 0..$#t +xt; } sub decrypt { my @txt = split '', shift; my @key = split '', shift; join '', map lc letter( DECRYPT, $txt[$_], $key[$_%@key] ), 0..$#t +xt; } sub letter { my ($direction,$cipherchar,$keychar) = @_; lc chr( 97 + ( (ord(lc $cipherchar) - 97) + $direction*(ord(lc $keychar ) - 97) ) % 26 ); }
       larryk                                          
    perl -le "s,,reverse killer,e,y,rifle,lycra,,print"
    
Re: Vigenere Cipher: Encode and Decode
by hossman (Prior) on Jan 26, 2002 at 12:31 UTC
    FYI: I noticed today that the above mentioned perl module was just released, but It's spelled wrong: Crypt::Vignere

    It has no documentation, and I haven't tried it out, but after skimming the code, it looks like the real thing.

    Pass the keyword to the constructor, call the encodeMessage, or decodeMessage to cipher/decipher.

      Actually, no, Vignere is the correct spelling. Vigenere is the typo. Alas, according to Google, this error also appears to be very widespread.

      The cypher was invented by one Blaise de Vignere. In English, you would pronounce his last name as roughly vin-yeah.

      hmm, no, actually, that is wrong. It is Vigénère. No lesser authority than Bruce Schneier, in Applied Cryptography has it this way. I should have checked there first. Oh well, if I ever run into the teacher who taught it that way, I'll be sure to update him.

      For what it's worth, the name would be pronounced visj-en-air, where the sj sound is like the s in Asia or measure.

      Man I hate when this happens

      --
      g r i n d e r
      print@_{sort keys %_},$/if%_=split//,'= & *a?b:e\f/h^h!j+n,o@o;r$s-t%t#u';
        Spelling of people names varies from language to language even if the orginal one is written in the latin alphabet.

        And it seems that a language is not even consistant in the way it spells something. Old arabic mathematicians are spellt in French "ibn something". For example we write ibn Musa al-Khawarizmi: this is the guy from which name the word "algorithm is derived (sorry of my convoluted English). But we say "Ben Laden". So much for rm -f /bin/laden in French. Go figure.

        (OT) Anyway, like any human being, if captured, Ben Laden is entitled to a fair trial. Very strange, America spoke of war before it was clear countries were involved but once it got people captured in what it called itself a war, it does not apply the Geneva convention. Probably good to read Chomsky to get things straight.

        -- stefp -- check out TeXmacs wiki

Re: Vigenere Cipher: Encode and Decode
by Anonymous Monk on Nov 06, 2003 at 14:55 UTC
    SHYNESSSYOOKYLCBLSMLWAYSEFUASDPLQEMJPLQE MJKOPQITRNQRYDCVLQJGIAFQQSJACDSFVMMDXZVK YYISEKMZIXFYRTIDZARXITFFUTSDZCCEHGNURTID RUCYSGDVMVIJJLWOSOYHTQCGLHLKQACRWQWKZYWQ WKZYRTVWVQSSWXLSJARWWVPFLWSBRFIJRUBARWWV PFLWTOCQWWRUBARWWVPFLWCPRFPWSVWILGJHWECW JWJQEKV

    2006-09-20 Edited by planetscape - added code tags to deal with excessively long lines

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: sourcecode [id://139710]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others drinking their drinks and smoking their pipes about the Monastery: (5)
As of 2024-03-29 14:00 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found