#!/usr/bin/perl use strict; use warnings; # this information is known to the attacker my ($ciphertext, $known_plaintext, $keylen); { # secret stuff in here my $key = "Shaken"; print "Secret key is '$key'\n"; $keylen = length($key); open F, $0 or die; # read test data from this script - why not? my $plaintext; read F, $plaintext, 1024 or die; close F; $known_plaintext = substr($plaintext, 0, 8); $ciphertext = encrypt_blk($plaintext, $key); } # secret stuff in here print "Guessing key bytes\n"; my $plain_bits = length($known_plaintext)*8; my $cipher_bits = length($ciphertext)*8 - 1; foreach my $keypos (0 .. $keylen-1) { print "key byte $keypos\n"; my $first = $keypos > 1 ? $keypos - 1 : $keylen + $keypos - 1; foreach my $keybyte (0x20 .. 0x7e) { my $keyval = ($keybyte >= 0x30 && $keybyte <= 0x39) ? $keybyte-0x2f : $keybyte+1; my $hits = 0; my $trials = 0; for (my $bitpos = $first; $bitpos < $plain_bits; $bitpos += $keylen) { my $pos = ($bitpos * $keyval) % $cipher_bits; $trials++; $hits++ if vec($known_plaintext,$bitpos,1) == vec($ciphertext,$pos,1); } my $thresh = int($trials * .8); print "'",chr($keybyte),"' : $hits\n" if $hits > $thresh; } } sub encrypt_blk { my ($inblk, $key) = @_; my @key = map { (/\d/ ? $_ : ord) + 1 } split(//, $key); my $blkbytes = length($inblk); my $blkbits = $blkbytes * 8; my $outblk = "\0" x $blkbytes; my $used = "\0" x $blkbytes; my $keypos = 0; my $newpos; for (my $blkpos = 0; $blkpos < $blkbits; $blkpos++) { ++$keypos >= @key and $keypos = 0; $newpos = ($key[$keypos] * $blkpos) % ($blkbits - 1); while (vec($used, $newpos, 1)) { ++$newpos >= $blkbits and $newpos = 0; } vec($used, $newpos, 1) = 1; vec($outblk, $newpos, 1) = vec($inblk, $blkpos, 1); } return $outblk; } # encrypt_blk