After reading bliako's post, I was curious.
I wanted to experiment a bit with his "I want to be asked for a password/key at encryption stage and then asked just once" requirement. I didn't get it working with PAR, or any ability to also encrypt used modules, so it's not acceptable as an answer there. Might be useful to play with though. Works in a way that's similar to Acme::Bleach, other than I don't overwrite the original file. You'll need to have a working openssl binary in your PATH somewhere.
Feedback welcome.
Save this as "AESFilter.pm"...
package AESFilter;
use IPC::Open2;
our $openssl="openssl enc -aes-256-cbc -a";
our $marker = '#AESFilter';
sub encrypt {
$_[0]=~s/$marker//gs;
my $pid=open2(my $rdr,my $wrt,"$openssl 2>>/dev/null");
print $wrt $_[0];
close $wrt;
my $output;
while(<$rdr>) {$output.=$_};
close $rdr;
waitpid($pid,0);
my $status=$?>>8;
if ($status !=0) {
die("Exit status $status from openssl, encryption failed\n");
}
return $output;
}
sub decrypt {
my $pid=open2(my $rdr,my $wrt,"$openssl -d 2>>/dev/null");
print $wrt $_[0]."\n";
close $wrt;
my $output;
while(<$rdr>) {$output.=$_};
close $rdr;
waitpid($pid,0);
my $status=$?>>8;
if ($status != 0) {
die("Exit status $status from openssl, decryption failed\n");
}
return $output;
}
open(IN,$0) or die "Can't open [$0]: $!\n";
my $prior='';
my $code='';
my $seen=0;
while(<IN>) {
if ($seen) {
chomp;
$code .= $_;
next;
}
$prior .= $_;
if (/use AESFilter;/) { $seen=1}
}
close IN;
if ($code =~ s/^$marker//gm) {
my $clear=decrypt($code);
eval($prior.$clear);
print STDERR $@ if $@;
exit;
}
my $outfile=$0.".enc";
die "Encrypted file [$outfile] already exists\n" if (-e $outfile);
my $encrypted=encrypt($code);
open(OUT,">$outfile") or die "Can't open [$outfile] for write: $!\n";
printf OUT "%s%s\n%s",$prior,$marker,$encrypted;
close OUT;
exit;
1;
To play with it, create a script like what's below. The first time you run it, it will create an encrypted script, with an extension of ".enc". So, if your script is called "foo", it creates a new file called "foo.enc" that's encrypted. It's calling openssl to get a password, so you'll be prompted for a password.
#!/usr/bin/perl
# so that you don't have to install AESFilter.pm, just
# have it in your current dir
use lib ".";
# anything before the next line will be in the output in cleartext
# ...anything after will be encrypted
use AESFilter;
print "test123\n";
print "again\n";
for ("one","two","three","four") {
print $_."\n";
}
If you save the code in a file called "foo", and run it once (with a password of '0'), it will produce a file called "foo.enc", that looks like this:
#!/usr/bin/perl
# so that you don't have to install AESFilter.pm, just
# have it in your current dir
use lib ".";
# anything before the next line will be in the output in cleartext
# anything after will be encrypted
use AESFilter;
#AESFilter
U2FsdGVkX1/CjxWDKOh4Xdw/7c0PoKnkUFQsf5gxo3F7RXqcEtmdsAgeEmb1g/QO
qd82hklpUxP/SNzbs34Z2NdzEStaDpeTlke1unf18gAw/2hlu78CIIItHVuAZlrH
ovJhqCBhP0Rck1RwXt3cJw==
And, if you run that code, it will prompt for the password.