#!/usr/bin/perl -w # # caesar v0.51 # This program attempts to decode Caesar cyphers. # Copyright (C) 1999-2000, James Yolkowski (ajy@sentex.net). # Originally written 11/16/1999. # Minor fixes made 12/6/1999, 2/20/2000, 3/6/2000, 12/11/2000, 12/31/2000. # =head1 NAME caesar - decrypt caesar cyphers =head1 SYNOPSIS caesar [rotation] =head1 DESCRIPTION The caesar utility attempts to decrypt caesar cyphers using English letter frequency statistics. caesar reads from the standard input and writes to the standard output. The optional argument rotation is a numerical value between 0 and 25. If present, then that specific rotation value is used. This can be used to decode ROT-13 encoded messages. =head1 BUGS Letter frequency analysis can only do so much. Small messages or ones whose plaintext contains many "unusual" characters might be decrypted incorrectly. =head1 AUTHOR James Yolkowski (ajy@sentex.net) =head1 COPYRIGHT and LICENSE This program is Copyright (C) 1999-2001, James Yolkowski. This program is free and open software. You may use, modify, distribute and sell this program (and any modified variants) in any way you wish, provided you do not restrict others to do the same. =cut # %freq contains letter frequencies as taken from the caesar man page. %freq = (E => 13, T => 10.5, A => 8.1, O => 7.9, N => 7.1, R => 6.8, I => 6.3, S => 6.1, H => 5.2, D => 3.8, L => 3.4, F => 2.9, C => 2.7, M => 2.5, U => 2.4, G => 2, P => 1.9, Y => 1.9, W => 1.5, B => 1.4, V => .9, K => .4, X => .15, J => .13, Q => .11, Z => .07); @score = (0) x 26; if (@ARGV) { # Obtain the rotation value specified on the command line. ($rot = shift) =~ /^\d+$/ or die <<''; Syntax: caesar [rotation] rotation is an integer between 0 and 25. } # If our input comes from a file, slurp it all in. # If our input comes from the console, just read one line. -t or undef $/; $_ = ; defined or exit; unless (defined $rot) { # Count the number of occurrences for each letter, and for # each of the 26 rotations, calculate a score which mostly # reflects the frequency of common letters in that rotation. # For example, award 13 points for each E, 10.5 for each T, etc. for $i ('A' .. 'Z') { $lcount = eval "y/\l$i$i//"; for $j ('A' .. 'Z') { $score[(ord($j) - ord($i)) % 26] += $lcount * $freq{$j}; } } # Find the possibility which obtained the highest score. $rot = (sort {$score[$a] <=> $score[$b]} 0 .. 25)[-1]; } # We've got our rotation value. Rotate and print the result. $newletters = substr((join '', 'A' .. 'Z') x 2, $rot % 26, 26); eval "y/A-Za-z/$newletters\L$newletters/"; print;