I have the following AES encryption code in JavaScript, but I can't seem to get comparable result in Perl.
'use strict';
const CryptoJS = require('crypto-js');
const message = 's3cret';
const aesPassword = 'MyPassword';
const salt = CryptoJS.lib.WordArray.random(16);
const iv = CryptoJS.lib.WordArray.random(16);
const key = CryptoJS.PBKDF2(aesPassword, salt, {keySize: 128/32, iterations: 1000});
const ciphertext = CryptoJS.AES.encrypt(message, key, {iv: iv}).ciphertext.toString(CryptoJS.enc.Base64);
const encryptedMessage = Buffer.from(iv + '::' + salt + '::' + ciphertext).toString('base64');
console.log("encryptedMessage:", encryptedMessage);
encryptedMessage: NDNjOWNjYmE2MzBmZTFjZDYxZmMyYmRiOTAxMjFjNmY6OjVjNzg4YTQxNTg1MWU5MDlkOWM3OTUxNzE3NzE0MjA0OjpxVDFWdG9kN2loUzJ3dnR3bWxuUG93PT0=
(92 bytes before base64 encoding.)
Perl:
use strict;
use warnings;
use Crypt::CBC;
use Crypt::PBKDF2;
use MIME::Base64;
my $message = 's3cret';
my $aesPassword = 'MyPassword';
my $salt = Crypt::CBC->random_bytes(16);
my $iv = Crypt::CBC->random_bytes(16);
my $pbkdf2 = Crypt::PBKDF2->new(output_len=>128/32, iterations => 1000);
my $key = $pbkdf2->PBKDF2($aesPassword, $salt);
my $cipher = Crypt::CBC->new(-cipher=>'Cipher::AES', -pbkdf=>'pbkdf2', -key=>$key, -iv=>$iv, -header=>'none');
my $ciphertext = encode_base64( $cipher->encrypt($message), "" );
my $encryptedMessage = encode_base64( join('::', $iv, $salt, $ciphertext), "" );
print "encryptedMessage: $encryptedMessage";
encryptedMessage: tO/jlJ3NkuJG0ZA58EDR0Do6wUf4xHb/MwWm3iyT+ejYWDo6SllMSHB0S0ZuMDVYWDRzS3ZCWlRiZz09Cg==
(61 bytes before base64 encoding.)
encode_base64( ..., "" )
to avoid the addition of line breaks and a trailing LF. (Already fixed in the OP.)->PBKDF2
backwards.-pbkdf => 'none'
should be used.-keysize => length( $key )
should be used.[Thanks to @Topaco for identifying most of these.]
Fixed version:
use strict;
use warnings;
use feature qw( say );
use Crypt::CBC qw( );
use Crypt::PBKDF2 qw( );
use MIME::Base64 qw( encode_base64 );
use constant KEY_SIZE => 128 / 8;
my $plaintext = 's3cret';
my $password = 'MyPassword';
#my $iv = Crypt::CBC->random_bytes( 16 );
#my $salt = Crypt::CBC->random_bytes( 16 );
my $iv = pack( "H*", "43c9ccba630fe1cd61fc2bdb90121c6f" ); # For testing.
my $salt = pack( "H*", "5c788a415851e909d9c7951717714204" ); # For testing.
my $pbkdf2 = Crypt::PBKDF2->new(
output_len => KEY_SIZE,
iterations => 1000,
);
my $key = $pbkdf2->PBKDF2( $salt, $password );
my $cipher = Crypt::CBC->new(
-cipher => 'Cipher::AES',
-header => 'none',
-pbkdf => 'none',
-keysize => KEY_SIZE,
-key => $key,
-iv => $iv,
);
my $ciphertext = $cipher->encrypt( $plaintext );
my $ciphertext_base64 = encode_base64( $ciphertext, "" );
my $iv_hex = unpack( "H*", $iv );
my $salt_hex = unpack( "H*", $salt );
my $msg = join( '::', $iv_hex, $salt_hex, $ciphertext_base64 );
my $msg_base64 = encode_base64( $msg, "" );
say $msg;
say length( $msg );
say $msg_base64;
43c9ccba630fe1cd61fc2bdb90121c6f::5c788a415851e909d9c7951717714204::qT1Vtod7ihS2wvtwmlnPow==
92
NDNjOWNjYmE2MzBmZTFjZDYxZmMyYmRiOTAxMjFjNmY6OjVjNzg4YTQxNTg1MWU5MDlkOWM3OTUxNzE3NzE0MjA0OjpxVDFWdG9kN2loUzJ3dnR3bWxuUG93PT0=