Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/usr/bin/perl
- # Encode/decode a file by doing:-
- #
- # cat infile | ./xor.pl encode KEY > outfile
- #
- # Remaining functions expect the encrypted file to be a local file called e
- #
- # First determine keylength by doing:-
- # ./xor.pl keylength
- # and looking for the likely candidates
- #
- # Frequency analysis (of possible keys) by doing (for an expected keylength of 12):-
- #
- # ./xor.pl freq 12
- #
- # Known plaintext of "function" analysis by doing (for expected keylength of 12):-
- #
- # ./xor.pl knownplain 12 function
- #
- # Interactive key changing and decryption by doing:-
- #
- # ./xor.pl interactive 12
- # See source for available commands
- use strict;
- use POSIX;
- if( $ARGV[0] ~~ [ "encode", "decode" ] ) {
- my $key=$ARGV[1];
- if( $key eq "" ) {
- print "error: no key provided for $ARGV[0]\n";
- exit;
- }
- my $data = readstdin();
- print encode( $key, $data, 0 );
- } elsif( $ARGV[0] eq "keylength" ) {
- my ( $min,$max ) = ( undef, undef );
- if( $ARGV[1] ne "" ) {
- $min=int($ARGV[1]);
- if( $ARGV[2] ne "" ) {
- $max=int($ARGV[2]);
- }
- }
- my $data = readdata();
- keylength( $min, $max, $data );
- } elsif( $ARGV[0] eq "freq" ) {
- if( $ARGV[1] ne "" ) {
- my $kl=int($ARGV[1]);
- my $data = readdata();
- freq( $kl, $data );
- } else {
- print "error: no keylength provided for freq\n";
- exit;
- }
- } elsif( $ARGV[0] eq "knownplain" ) {
- if( $ARGV[1] ne "" ) {
- my $kl=int($ARGV[1]);
- if( $ARGV[2] ne "" ) {
- my $word=$ARGV[2];
- my $data = readdata();
- knownplain( $kl, $word, $data );
- }
- } else {
- print "error: no keylength provided for knownplain\n";
- exit;
- }
- } elsif( $ARGV[0] eq "interactive" ) {
- if( $ARGV[1] ne "" ) {
- my $kl=int($ARGV[1]);
- my $data = readdata();
- interactive( $kl, $data );
- } else {
- print "error: no keylength provided for interactive\n";
- exit;
- }
- } else {
- print "error: unknown command [$ARGV[0]]\n";
- }
- exit;
- sub readdata {
- local $/=undef; # Unset line delimeter so that next read from file slurps in everything
- open( D, "<e" ) || die "Can't open file 'e' [$!]";
- my $d=<D>;
- close( D );
- return( $d );
- }
- sub readstdin{
- local $/=undef; # Unset line delimeter so that next read from file slurps in everything
- return( <STDIN> );
- }
- sub keylength {
- # Check frequency distribution for different keylengths
- # See how many unique characters there are at different intervals
- my ( $min, $max, $data ) = @_;
- my $data_len=length( $data );
- $min=1 if( !defined( $min ) );
- $max=20 if( !defined( $max ) );
- foreach my $kl ( $min..$max ) {
- my %k=();
- foreach my $ct ( 0..$data_len-1 ) {
- my $let=substr( $data, $ct, 1 );
- $k{$ct%$kl}{ord($let)}++;
- }
- print "keylength=$kl";
- foreach my $ct ( 0..$kl-1 ) {
- my $boxes=0;
- foreach my $n ( 0..255 ) {
- $boxes++ if( exists( $k{$ct}{$n} ) );
- }
- print " $boxes";
- }
- print "\n";
- }
- }
- sub encode {
- # Encoding is the same as decoding...
- my ( $key, $data, $cr ) = @_;
- my $kl=length( $key );
- my $ct=0;
- my $e="";
- foreach my $x ( split( //, $data ) ) {
- my $k=substr($key,$ct%$kl,1);
- my $l="$x"^"$k";
- if( $cr && !isprint( $l ) ) {
- $e .= "\\".ord($l);
- } else {
- $e.=$l;
- }
- $ct++;
- $e.="\n" if( $cr && ( $ct % $cr == 0 ) );
- }
- return( $e );
- }
- sub freq {
- # Do frequency analysis of likely keys given a key length
- my ( $kl, $data ) = @_;
- my $data_len=length($data);
- my %k=();
- foreach my $ct ( 0..$data_len-1 ) {
- my $let=substr( $data, $ct, 1 );
- foreach my $cn ( 0..255 ) {
- my $c=chr($cn);
- my $x="$let"^"$c";
- # If the result is printable then its a likely candidate
- if( isprint( $x ) ) {
- $k{$ct%$kl}{$cn}++;
- }
- }
- }
- # Print out the top likely candidates for each position based on frequency
- # Note that this is definitely not foolproof!
- foreach my $ct ( 0..$kl-1 ) {
- my $poss=""; my $poss_n=0;
- foreach my $n ( 0..255 ) {
- if( exists( $k{$ct}{$n} ) ) {
- if( $k{$ct}{$n} > $poss_n ) {
- $poss_n=$k{$ct}{$n};
- $poss=chr($n);
- } elsif( $k{$ct}{$n} == $poss_n ) {
- $poss.=chr($n);
- }
- if( 0 ) {
- print "$ct ".(isprint(chr($n))?chr($n):$n)." = $k{$ct}{$n}\n";
- }
- }
- }
- print "POSS:$ct: n=$poss_n chars=$poss\n";
- }
- }
- sub knownplain {
- # Given a keylength and a known plaintext string we check what are the most likely
- # keys assuming each possible substring is the given plaintext
- my ( $kl, $word, $data ) = @_;
- my $data_len=length($data);
- my $wl=length($word);
- my %k=();
- foreach my $ct ( 0..($data_len-$wl-1) ) { # Loop through all possible starts
- my $lets=substr( $data, $ct, $wl );
- my $x="$lets"^"$word";
- my @x=split( //, $x );
- foreach my $nct ( 0..$kl-1 ) {
- my $pos=($ct+$nct)%$kl;
- if( $nct < $wl ) {
- $k{$pos}{ord($x[$nct])}++;
- # print "POS $pos -> ".isprint($x[$nct])?$x[$nct]:ord($x[$nct])."\n";
- }
- }
- }
- foreach my $ct ( 0..$kl-1 ) {
- my @rows=();
- foreach my $cn ( 0..255 ) {
- if( exists( $k{$ct}{$cn} ) ) {
- my $printit=$cn;
- if( isprint( chr($cn) ) ) {
- $printit=chr($cn);
- }
- my @row=( $ct, $printit, $k{$ct}{$cn} );
- push( @rows, \@row );
- # print "POS $ct: $printit -> $k{$ct}{$cn}\n";
- }
- }
- my $top=3;
- print "POS: $ct:";
- foreach my $x ( sort { $b->[2] <=> $a->[2] } @rows ) {
- print " $x->[1]->$x->[2]";
- last if( --$top == 0 );
- }
- print "\n";
- }
- }
- sub interactive {
- # Interactive mode
- # k = print key
- # p = print output in blocks of keylength
- # P = print output verbatim
- # s n x = set key character n (starts from 0) to x
- # S xxxx = set entire key to S
- my ( $kl, $data ) = @_;
- my $k="a"x$kl;
- while( my $x = <STDIN> ) {
- chomp( $x );
- if( $x eq "p" ) {
- print encode( $k, $data, $kl );
- } elsif( $x eq "P" ) {
- print encode( $k, $data, 0 );
- } elsif( $x eq "k" ) {
- print "key is $k\n";
- } elsif( $x eq "x" || $x =~ /^q/ ) {
- exit;
- } elsif( $x =~ /^S (.*)$/ ) {
- my $oldlen=$kl;
- $k=$1;
- print "key is now $k\n";
- $kl=length( $k );
- print "WARNING: keylength changed from $oldlen to $kl\n" if( $kl != $oldlen );
- } elsif( $x =~ /^s (\d+) (.)$/ ) {
- my $pos=$1;
- my $c=$2;
- my @k=split( //, $k );
- $k[$pos]=$c;
- $k=join( '', @k );
- print "key is now $k\n";
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment