Skip to content

Instantly share code, notes, and snippets.

@guillaumef
Created January 14, 2018 13:06
Show Gist options
  • Save guillaumef/3a8bce93a42210ec81ba8d96065ebd8c to your computer and use it in GitHub Desktop.
Save guillaumef/3a8bce93a42210ec81ba8d96065ebd8c to your computer and use it in GitHub Desktop.
Perl - low level AES 256 crypt/decrypt using Crypt::Rijndael compatible with 'openssl enc' format
#!/usr/bin/perl
#
# Perl - low level AES 256 crypt/decrypt using Crypt::Rijndael
# compatible with 'openssl enc' format
#
# Key: 32
# IV : 16
#
# Padding: PKCS7
# EVP_BytesToKey: SHA256
#
# Magic: Salted__
#
# Need: libcrypt-rijndael-perl
#
# Author: Guillaume Fougnies
#
use strict;
use MIME::Base64();
use Digest::SHA qw/sha256/;
use Crypt::Rijndael();
#
# Salt + Passwd => key + iv
#
# OpenSSL fmt
#
sub EVP_BytesToKey {
my ($salt, $passphrase, $nkey, $niv) = @_;
my $md_buf = "";
my $key = "";
my $iv = "";
my $addmd = 0;
while (length($key) < $nkey || length($iv) < $niv) {
my $sha = Digest::SHA->new(256);
if ($addmd) {
$sha->add( $md_buf );
} else {
$addmd ++;
}
$sha->add( $passphrase );
$sha->add( $salt );
$md_buf = $sha->digest();
my $md_buf2 = $md_buf;
if (length($key) < $nkey) {
my $pos = $nkey - length($key);
$key .= substr($md_buf2, 0, $pos);
$md_buf2 = substr($md_buf2, $pos);
}
if (length($iv) < $niv) {
$iv .= substr($md_buf2, 0, $niv - length($iv));
}
}
#print STDOUT 'Key: '.uc(unpack("H*",$key))."\n";
#print STDOUT 'IV : '.uc(unpack("H*",$iv))."\n";
return ($key, $iv);
}
#
# Get random bytes from urandom
#
sub RAND_Read {
my ($sz) = @_;
my $dev;
foreach (qw/urandom random/) {
if (-e "/dev/$_") { $dev = "/dev/$_"; last; }
}
die "Unable to get a random device" unless $dev;
my $bytes;
open (DEV, $dev) or die "Cannot open file: $!";
read (DEV, $bytes, $sz);
return $bytes;
}
#
# Encode
#
sub encrypt {
my ($passwd, $data) = @_;
my $pad = 16 - length($data) % 16;
my $crypttext = "Salted__";
my $salt = &RAND_Read( 8 );
$crypttext .= $salt;
my ($key, $iv) = &EVP_BytesToKey( $salt, $passwd, 32, 16 );
my $cipher = Crypt::Rijndael->new( $key, Crypt::Rijndael::MODE_CBC() );
$cipher->set_iv($iv);
# PKCS7 - pad
$data .= chr($pad) x $pad;
$crypttext .= $cipher->encrypt( $data );
return MIME::Base64::encode_base64( $crypttext, "" );
}
#
# Decode
#
sub decrypt {
my ($passwd, $data) = @_;
my $data = MIME::Base64::decode_base64( $data );
my $magic = substr($data, 0, 8);
my $salt = substr($data, 8, 8);
$data = substr($data, 16);
if ($magic ne "Salted__") {
print STDOUT "Unknown magic\n";
return undef;
}
my ($key, $iv) = &EVP_BytesToKey( $salt, $passwd, 32, 16 );
my $cipher = Crypt::Rijndael->new( $key, Crypt::Rijndael::MODE_CBC() );
$cipher->set_iv($iv);
my $plaintext = $cipher->decrypt( $data );
my $pchar = substr( $plaintext, -1, 1 );
if ($pchar =~ /[\x00-\x16]*/) {
#print "Padding char: ".unpack("H*",$pchar)."\n";
$plaintext =~ s/$pchar*$//g;
}
return $plaintext;
}
##########################################
sub usage { print "$0 [-e|-d|-ed] <passwd> <txt>\n"; exit(1); }
my ($mode, $passwd, $data) = @ARGV;
if (defined($passwd) && defined($data) && $mode =~ /^-[ed][d]*$/) {
if ($mode eq '-ed') {
my $v = &encrypt( $passwd, $data );
print STDOUT "Enc: $v\n";
my $v2 = &decrypt( $passwd, $v );
print STDOUT "Dec: $v2\n";
}
elsif ($mode eq '-e') {
print STDOUT "Enc: ".&encrypt( $passwd, $data )."\n";
}
else {
print STDOUT "Dec: ".&decrypt( $passwd, $data )."\n";
}
}
else {
&usage();
}
exit(0);
1;
__END__
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment