On Thu, 13 Feb 2003, Neil Fryer wrote: > Hi All > > I found this script on the net, and I am still learning, Perl, but I was > wondering, just to play around with, if this script encrypts, how would I > decrypt?
No. See attached. S. -- Shevek I am the Borg. sub AUTOLOAD{my$i=$AUTOLOAD;my$x=shift;$i=~s/^.*://;print"$x\n";eval qq{*$AUTOLOAD=sub{my\$x=shift;return unless \$x%$i;&{$x}(\$x);};};} foreach my $i (3..65535) { &{'2'}($i); }
#!/usr/bin/perl # Rijndael encrypt and base64 encode data. # Usage: cmd [-e | -d] file .... use strict; use Crypt::Rijndael; use MIME::Base64; use POSIX; use IPC::Open3; use Digest::MD5 qw(md5_hex); use Symbol; use IO::Handle; use Text::Wrap; use Data::Dumper; my $ESUFFIX = "rijndael"; # filename suffix - change if you want my $DSUFFIX = "decrypted"; # filename suffix - change if you want my $KEYLEN = 128; # key bits - do not change my $REQPASS = $KEYLEN / 8; # required password length my $MINPASS = $REQPASS / 2; # minimum password bytes - half key sub encrypt_rijndael { my ($password, $data) = @_; die "Data is already encrypted" if $data =~ /^XX-Encrypted/; my $engine = new Crypt::Rijndael $password, Crypt::Rijndael::MODE_CBC; my @header = ( "XX-Encrypted", "Algorithm: Rijndael", "Length: " . length($data), "DataMD5: " . md5_hex($data), "Notes: Use MIME::Base64 then Crypt::Rijndael to recover data", # "PasswordMD5: " . md5_hex($password), ); my $header = join("\n", @header) . "\n\n"; my $blocksize = $engine->blocksize; my $padlen = $blocksize - (length($data) % $blocksize); if ($padlen) { print "Padding data to blocksize $blocksize " . "with $padlen bytes.\n"; $data .= " " x $padlen; } $data = $engine->encrypt($data); $data = $header . encode_base64($data); return $data; } sub decrypt_rijndael { my ($password, $data) = @_; my $engine = new Crypt::Rijndael $password, Crypt::Rijndael::MODE_CBC; $data =~ s/^XX-Encrypted\n//ms or die "File does not appear to be encrypted"; $data =~ /^(.*?)\n\n(.*)/ms or die "Could find separator between header and data"; my $header = $1; $data = $2; my %header; foreach (split(/\n/, $header)) { $_ =~ /^([^:]*):\s*(.*)$/ or die "Invalid header line '$_'"; $header{$1} = $2; } if (exists $header{Algorithm}) { if ($header{Algorithm} ne 'Rijndael') { die "Algorithm incorrect: only support Rijndael."; } } if (exists $header{PasswordMD5}) { if (md5_hex($password) ne $header{PasswordMD5}) { die "Password incorrect: does not match hash in header."; } } my ($cipher, $length) = ($1, $2); $data = decode_base64($data); $data = $engine->decrypt($data); if (exists $header{Length}) { if (length($data) > $header{Length}) { my $padlen = length($data) - $header{Length}; print "Trimming data by $padlen bytes.\n"; $data = substr($data, 0, $header{Length}); } } if (exists $header{DataMD5}) { if (md5_hex($data) ne $header{DataMD5}) { die "Data incorrect: does not match hash in header. " . "Perhaps incorrect password?"; } } return $data; } sub filter_external { my ($data, $cmd, @args) = @_; die "External filter command '$cmd' does not exist." unless -f $cmd; die "External filter command '$cmd' not executable." unless -x $cmd; my ($rdr, $wtr, $err); $err = gensym; my $childpid = open3($wtr, $rdr, $err, $cmd, @args); print $wtr $data; close $wtr; my $out = <$rdr>; my $errs = <$err>; waitpid $childpid, 0; die "External filter command '$cmd' returned error:\n$errs" if $errs; return $out; } # For good measure, let's throw in a sub. sub readpass { my $prompt = shift; print $prompt; my $termios = new POSIX::Termios; $termios->getattr(fileno(STDIN)) or die "Failed to get terminal parameters: $!"; my $lflag = $termios->getlflag; $termios->setlflag($lflag & ~ECHO); $termios->setattr(fileno(STDIN), TCSANOW) or die "Failed to set terminal parameters: $!"; my $password = <STDIN>; chomp($password); $termios->setlflag($lflag); $termios->setattr(fileno(STDIN), TCSANOW) or die "Failed to set terminal parameters: $!"; print "\n"; return $password; } sub getpassword { my ($op) = @_; my $padpass = 1 unless $op eq 'r'; my $password; while (1) { $password = readpass("Password: "); # Allow decoding of old files with short passwords last if ($op ne 'e') || (length $password >= $MINPASS); print "Length of password must be at least $MINPASS characters.\n"; } if ($op eq 'e') { while (1) { my $confirm = readpass("Password (confirm): "); last if $confirm eq $password; print "Passwords do not match.\n"; exit 1; } } if ($op =~ /^[ed]$/) { if (length $password < $REQPASS) { print "Padding password to $REQPASS bytes for Rijndael\n"; $password .= "\0" x ($KEYLEN / 8); # 8 bits per byte $password = substr($password, 0, ($KEYLEN / 8)); } } return $password; } sub slurp { my $file = shift; print "Reading file '$file'\n"; die "File '$file' not found" unless -f $file; die "File '$file' not readable" unless -r $file; local $/ = undef; local *FH; open(FH, "<$file") or die "Failed to open '$file' for read: $!"; my $data = <FH>; close(FH) or die "Failed to close '$file': $!"; return $data; } sub spew { my ($file, $data, $op) = @_; print "Writing file '$file'\n"; # Overwrite only if encrypting my $overwrite = ($op eq 'e'); if (-f $file) { die "Output file '$file' already exists" unless $overwrite; unlink($file) or die "Failed to remove old file '$file': $!"; } local *FH; open(FH, ">$file") or die "Failed to open '$file' for write: $!"; print FH $data or die "Failed to write to '$file': $!"; close(FH) or die "Failed to close '$file': $!"; } sub usage { my %flags = ( e => "Encrypt <file> using Rijndael's algorithm, " . "save as '<file>.$ESUFFIX' and remove <file>.", d => "Decrypt <file> using Rijndael's algorithm, " . "removing the suffix '.$ESUFFIX' or adding " . "'.$DSUFFIX' if <file> does not end in '.$ESUFFIX'. " . "The target file must NOT exist.", h => "Display this help.", ); print "Usage: $0 [-e | -d | -r | -h] <file> ...\n"; print "Using Rijndael CBC mode, $KEYLEN bit key, " . "passwords must be at least $MINPASS chars\n"; # Gratuitous use of technology... foreach (sort keys %flags) { print wrap("\t-$_\t", "\t" x 2, $flags{$_}) . "\n"; } print wrap("", "", "Multiple files may be specified on the " . "command line. The same operation will be performed " . "on each with the same key.") . "\n"; } sub main { my $op = shift @ARGV; unless ($op =~ s/^-([edr])$/$1/) { # Not -h (hack!) usage; exit 1; } defined umask 0077 or die "Failed to set umask: Please get a proper Unix."; my $password = getpassword($op); my $outfile; foreach (@ARGV) { eval { # Generic exception trap my $data = slurp $_; if ($op eq 'e') { $data = encrypt_rijndael($password, $data); $outfile = "$_.$ESUFFIX"; } elsif ($op eq 'd') { $data = decrypt_rijndael($password, $data); $outfile = $_; $outfile =~ s/\.$ESUFFIX$//o or $outfile .= ".$DSUFFIX"; } else { die "FATAL: Unknown operator $op!"; } spew $outfile, $data, $op; if ($op eq 'e') { unlink($_) or die "Failed to remove plaintext file '$_': $!"; } }; if ($@) { my $err = $@; $err =~ s/ at [^\s]* line \d+(?:,.*)?\.//; print "While processing file $_, encountered error:\n" . "\t$err"; } } } main;