Reputation: 10828
I have written encryption functionality in Perl and I am trying to get to work same way in PHP.
In PERL:
#!/usr/bin/perl
use strict;
use warnings;
use Crypt::CBC;
use Crypt::Rijndael;
my $cryptkey = '_PRIVATE_';
my $cipher = Crypt::CBC->new( -key => $cryptkey,
-salt => 1,
-cipher => 'Rijndael',
);
my $data = "hello";
my $ciphertext = $cipher->encrypt_hex($data);
print "HEX_KEY: '$ciphertext' \n";
Output:
HEX_KEY: '53616c7465645f5fc36630f5364619c31ac26e44809c81bf84ae995c22be45ce'
I am trying to get to work in PHP and output same HEX but it is not the same, what went wrong?
class Test {
public function Encypt($data, $cryptkey) {
$encrypted = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $cryptkey, $data, MCRYPT_MODE_CBC);
return bin2hex($encrypted);
}
}
$data = "hello";
$test = new Test();
$cryptkey = "_PRIVATE_";
$hex = $test->Encypt($data, $cryptkey);
echo $hex;
Output
2bab1b8874692176d213e4c23565b304
Upvotes: 3
Views: 835
Reputation: 57640
Crypt::CBC
and mcrypt_encrypt
use different defaults, which lead to this mismatch.
For mcrypt_encrypt
, the documentation offers this information:
string mcrypt_encrypt ( string $cipher , string $key , string $data , string $mode [, string $iv ] )
$cipher
is the algorithm name.$key
is the encryption key, if it is too short it will be padded with NUL bytes.$data
is the data to be encrypted, if it is too short it will be padded with NUL bytes.$mode
is the mode of operation, here"cbc"
is correct.$iv
is the initialization vector, if not provided it will be initialized as NUL bytes.
For Crypt::CBC
, we get this behaviour instead:
Crypt::CBC->new(KEYWORD_OPTIONS)
-key => STRING
is the passphrase from which the encryption key is generated by some hashing operations.-literal_key => BOOL
If set, this skips the hashing for the-key
and uses it as a literal key.-cipher => CIPHER
the name of a cipher, or a pre-initialized cipher object.-salt => 1 | STRING
If set to"1"
, this will produce a random salt. Any other values are taken as the literal salt. This defaults to-salt => 1
if a salt is needed. Or something like that, the docs are a bit confusing here. The salt is not needed if both the-iv
andliteral_key
options are set.-iv => STRING
is the initialization vector, which is usually generated from the salt.-header => STRING
controls what kind of header is prepended to the output. This defaults to"salt"
, but can also be set to"none"
.
Note further that RIJNDAEL_128
implies a keylength of 16, whereas Crypt::CBC
assumes a keylength of 32
.
Using Crypt::Rijndael
without the Crypt::CBC
wrapper is probably preferable, because this allows us to easily set the required options to the same defaults which PHP uses:
use Crypt::Rijndael;
my $key = "_PRIVATE_";
my $data = "hello";
# pad the $key to 16 bytes
$key .= "\0" x (16 - length $key);
# pad the $data to a multiple of 16 bytes:
if (my $distance = length($data) % 16) {
$data .= "\0" x (16 - $distance);
}
my $crypt = Crypt::Rijndael->new($key, Crypt::Rijndael::MODE_CBC);
$crypt->set_iv("\0" x 16);
my $binary = $crypt->encrypt($data);
print unpack("H*", $binary), "\n";
Which then outputs 2bab1b8874692176d213e4c23565b304
.
Upvotes: 3