Perl Beginner01 has asked for the wisdom of the Perl Monks concerning the following question:

Hello Monks, I want write a program in Perl that can do encryption and decryption of text. An example of encryption is that "a" becomes "z", and "b" becomes "y" and so on, or whatever shifting algorithm you can devise. The input file is any readable text file that is to be encrypted. When this input file is run against the encryption program, it encrypts the file with your encryption algorithm and saves the processed file to an encrypted file with same file name but with an extension of ".enc". When you run the decryption program, it reads the encrypted file and decrypts (or reverses) it and saves it to same filename but with an extension of ".dec" which stands for decrypted file Can anyone please help me

Replies are listed 'Best First'.
Re: Encryption/Decryption Program:
by FloydATC (Deacon) on May 07, 2014 at 07:10 UTC

    If this is meant just as an exercise because you just started learning Perl, you should start by looking into the Perl documentation about how to open, read and write files. From there, processing text and binary data is limited only by your imagination.

    If, on the other hand, you require actual strong and reliable encryption, I'd recommend looking into existing modules on CPAN under the Crypt:: namespace rather than try to reinvent the wheel. For instance, I've found Crypt::Blowfish very useful.

    -- FloydATC

    Time flies when you don't know what you're doing

Re: Encryption/Decryption Program:
by trizen (Hermit) on May 07, 2014 at 10:03 UTC
    Here is a piece of code that I wrote about two years ago which does this (and more). Feel free to adjust it for your needs:
    use 5.010; use strict; use warnings; sub encode_decode ($$) { my ($encode, $text) = @_; my $i = 1; my $output = ''; LOOP_1: foreach my $c (map ord, split //, $text) { foreach my $o ([32, 121]) { if ($c > $o->[0] && $c <= $o->[1]) { my $ord = $encode ? $c + ($i % 2 ? $i : -$i) : $c - ($i % 2 ? $i : -$i); if ($ord > $o->[1]) { $ord = $o->[0] + ($ord - $o->[1]); } elsif ($ord <= $o->[0]) { $ord = $o->[1] - ($o->[0] - $ord); } $output .= chr $ord; ++$i; next LOOP_1; } } $output .= chr($c); $i = 1; } return $output; } my $enc = encode_decode(1, q{this is a test}); my $dec = encode_decode(0, $enc); say "Enc: ", $enc; say "Dec: ", $dec; __END__ Enc: uflo jq b ucvp Dec: this is a test
    Also, please see: http://rosettacode.org/wiki/Caesar_cipher#Perl

      Simpler:

      use v5.14; sub encode_decode { shift =~ tr/A-Za-z/ZYXWVUTSRQPONMLKJIHGFEDCBAzyxwvutsrqponmlkjihgf +edcba/r; } my $enc = encode_decode("this is a test"); my $dec = encode_decode($enc); say "Enc: ", $enc; say "Dec: ", $dec; __END__ Enc: gsrh rh z gvhg Dec: this is a test
      use Moops; class Cow :rw { has name => (default => 'Ermintrude') }; say Cow->new->name
Re: Encryption/Decryption Program:
by Anonymous Monk on May 07, 2014 at 07:11 UTC
Re: Encryption/Decryption Program:
by davido (Cardinal) on May 07, 2014 at 18:43 UTC

    For extra credit, propose code that can be used to automatically break the substitution cipher. See this explanation for a starting point. At some point you'll end up with some good guesses on what might be the most likely substitutions.

    The article mentions that "E", "I", and "A" are most common for English. Here are a few other heuristics you might apply:

    • Q is nearly always followed by "U", and is very uncommon.
    • "TH" often appear together.
    • "NG" often appear together, and often at the end of words. When at the end of the word, usually preceded by "I".
    • "SH" often appear together.
    • "A" and "I" are the two most likely to occur alone.

    I haven't investigated strategies more than to just think about it a bit, but I suppose you would work out probabilities, and then start testing assumptions against a dictionary to see if they work out. Then you can test those assumptions against the original string to see if they turn it into something recognizable.

    Rotation ciphers are even easier, as the number of possibilities allows for brute force testing.


    Dave

Re: Encryption/Decryption Program:
by mr_mischief (Monsignor) on May 07, 2014 at 14:25 UTC

    For "Whatever shifting algorithm" I'll use rot13 which by nature with English text is self-reversing.

    Here's a basic one-liner that requires you to deal with input and output redirection.:

    perl -pe 'tr/a-zA-Z/n-za-mN-ZA-M/;'

    Here's a bit more complex example. It doesn't take fancy arguments. It figures out what to do based on the end of the filename (the "extension"). It has some error handling but that could be improved.

    #!/usr/bin/perl use strict; use warnings; die "Run with argument." unless defined $ARGV[0]; my $file = $ARGV[0]; if ( $file =~ /\.enc/ ) { decrypt( $file ); } else { encrypt( $file ); } exit; sub encrypt { my $f = shift; my $enc = $f . '.enc'; files( $f, $enc ); } sub decrypt { my $f = shift; my $dec = $f; $dec =~ s/\.enc$/.dec/; files( $f, $dec ); } sub files { my ( $in_file, $out_file ) = @_; open my $in, '<', $in_file or die "Cannot read input file $in_file + : $!\n"; open my $out, '>', $out_file or die "Cannot write to output file $ +out_file : $!\n"; rotate( $in, $out ); close $in; close $out or die "Failed to complete write to output file $out_fi +le : $!\n"; } sub rotate { my ( $fh_in, $fh_out ) = @_; while ( my $text = <$fh_in> ) { $text =~ tr/a-zA-Z/n-za-mN-ZA-M/; print { $fh_out } $text; } }

    I used the program to encode itself and then decode that, and there's no difference.:

    $ perl foo foo $ perl foo foo.enc $ diff foo foo.dec $

    Substitution ciphers are pretty simple and are not secure. For example rot13 is built into some newsgroup and mail client software, because it's really only good to obscure spoilers. It might fool some simplistic address harvesters, too.

    By the way, I'd be remiss not to mention archival storage in this context. That is almost as popular as my Tux the penguin with an AR-15 on the other arm.

Re: Encryption/Decryption Program:
by kcott (Archbishop) on May 07, 2014 at 16:38 UTC

    G'day Perl Beginner01,

    Welcome to the monastery.

    "An example of encryption is that "a" becomes "z", and "b" becomes "y" and so on, or whatever shifting algorithm you can devise."

    Here's an example of that I wrote about nine months ago: "Re: Caesar Cipher". You may find other nodes in that thread have useful information.

    For the I/O part, see "perlintro: Files and I/O". While that should have sufficient information for your stated needs, it does provide links to more detailed discussions.

    -- Ken

Re: Encryption/Decryption Program:
by oiskuu (Hermit) on May 07, 2014 at 18:32 UTC

    An example little filter. Don't forget to specify the secret key when encoding. :-)

    use List::Util q(shuffle); use Getopt::Std; getopts('ds:'); $opt_s and srand $opt_s; @T{@$_} = shuffle @$_ for ([A..Z],[a..z]); $opt_d and %T = reverse %T; s{.}{$T{$&}//$&}eg, print for <>;

    Now, could someone please determine if a pair of keys exist that cancel each other (decode without -d, that is)?

Re: Encryption/Decryption Program:
by GotToBTru (Prior) on May 07, 2014 at 15:51 UTC

    A simple example:

    use strict; use warnings; my $plaintext = 'We are discovered. Flee at once!'; my $key = 'CorrectBatteryHorseStaple'; print "Original message: $plaintext\n"; my $ciphertext = cypher($plaintext,$key); my $ucode = pack("u",$ciphertext); print " Encoded message: $ucode (uuencoded)\n"; my $decoded = cypher($ciphertext,$key); print " Decoded message: $decoded\n"; sub cypher { my $plain = shift; my $key = shift; my $i=0; $key x= ( 1 + length($plain)/length($key) ); return $plain ^ substr($key,0,length($plain)); }

    It requires a key that is XORd with the plaintext to produce the ciphertext. Calling the subroutine again with the ciphertext and the same key will reproduce the plaintext.

    Update: copied example into response, against future changes to scratchpad. Updated again to use uuencode to display key, also removed unnecessary loop.

    1 Peter 4:10