MCrypt rijndael-128 to OpenSSL aes-128-ecb conversion
In your specific example I've found that by changing aes-128-ecb
to aes-256-ecb
, it produces the same output as the legacy mcrypt_encrypt
.
Convert mcrypt_generic to openssl_encrypt
Mcrypts: MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC
is equivalent to:
OPENSSL: AES-256-CBC
I have no idea why there's the difference, but changing the 128 to 256
solved it for me.
Migrate PHP AES encryption from mcrypt to openssl return different encrypted string
Both codes use different AES variants and paddings. The mcrypt code applies AES-128 and Zero padding, the openssl code AES-256 and PKCS7 padding. To make sure that both ciphertexts match, both codes must use the same AES variant and padding.
mcrypt identifies the AES variant from the key size. Since $key
is a 16 bytes key, AES-128 is used. openssl determines the AES variant based on the specification passed in the 2nd parameter. Keys that are too short are padded with 0 values to the required length, keys that are too long are truncated. Here, AES-256-CBC
is specified, i. e. AES-256 is used. The 16 bytes key $key
is therefore padded with 0 values and extended to a size of 32 bytes.
mcrypt implicitly uses Zero padding for encryption, which is not implicitly removed during decryption. PKCS7 padding is not supported. openssl implicitly applies PKCS7 padding for encryption, which is implicitly removed during decryption. Zero padding is not supported. If the openssl code should use Zero padding or the mcyrpt code PKCS7 padding, this must be implemented by yourself.
With regard to the migration from mcrypt to openssl, the openssl code is modified in the following to be functionally identical to the mcrypt code, i.e. AES-128 and Zero padding is used. With regard to the AES variant, only the specification AES-256-CBC
must be changed to AES-128-CBC
. Concerning padding, the default PKCS7 padding must be disabled using OPENSSL_ZERO_PADDING
and Zero padding itself must be implemented (note that the OPENSSL_ZERO_PADDING
flag only disables padding, but does not enable Zero padding; the name is badly chosen):
<?php
$str = "test";
$key = 'o6xSYYAVl2eapPI2';
$iv = 'fedcba9876543210';
function encrypt_openssl($str = NULL, $key, $iv) {
$encrypted = openssl_encrypt(
zeroPad($str, 16), // Zero pad plaintext
'AES-128-CBC', // Choose AES-128
$key,
OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, // Disable PKCS7 Padding
$iv);
return bin2hex(@$encrypted);
}
function zeroPad($text, $bs) {
$pad = $bs - strlen($text) % $bs;
return ($pad < 16) ? $text . str_repeat("\0", $pad) : $text;
}
echo 'Openssl:'.encrypt_openssl($str,$key,$iv); // Openssl:57c86f3089535b3acfbe65cecbb662b9
For a comparison with your result, note that you have confused the labels of the outputs, i.e. the openssl result is labeled Mcrypt
and vice versa!
A final note: In general, PKCS7 padding is more reliable than Zero padding, as the former contains the information of the padding length. This is not the case with Zero padding, so when removing the padding (i.e. after decryption) it is not possible to distinguish between regular and padding bytes. There are also different Zero padding variants, e.g. one does not pad if the length of the plaintext already corresponds to an integer multiple of the blocksize (this variant uses mcrypt), the other one pads with a complete block in this case.
openssl_encrypt VS mcrypt_encrypt
Two problems:
You aren't Base64 decoding the key, so you're passing a 24-byte (= 192-bit) key to both
openssl_encrypt
andmcrypt_encrypt
. Apparently, these functions interpret such a key in different ways!base64_decode
the key first for consistent results.Alternatively, if you really want to use the Base64-encoded string as a 192-bit key, pass
'aes-192-cbc'
as the method toopenssl_encrypt()
. This is what mcrypt is doing here. (Which is not the same as what would happen if you passedMCRYPT_RIJNDAEL_192
as the cipher -- that changes the block size, not the key size!)openssl_encrypt
uses PKCS5 padding automatically. Padding the data before passing it to this function ends up making the data get padded twice, leaving it one block longer than intended.
With these problems fixed, both functions now give the same result.
MCrypt rijndael-256 to OpenSSL aes-256-ecb conversion
Saddly, you are on the wrong way.
Refer to :
http://php.net/manual/en/function.mcrypt-encrypt.php#117667
MCRYPT_RIJNDAEL_256 is not AES-256, it's a different variant of the
Rijndael block cipher.
https://en.wikipedia.org/wiki/Advanced_Encryption_Standard
AES is a variant of Rijndael which has a fixed block size of 128 bits,
and a key size of 128, 192, or 256 bits. By contrast, the Rijndael
specification per se is specified with block and key sizes that may be
any multiple of 32 bits, with a minimum of 128 and a maximum of 256
bits.
So you can not use OpenSSL's AES-256 to decrypt the MCrypt's output.
Some possible methods:
Keep using mcrypt by PECL's mcrypt extension (luckily, it is still there), until you can replace the legacy data totally.
Rewrite a correct RIJNDAEL-256 cipher in PHP.
Related Topics
Will Enabling Xdebug on a Production Server Make PHP Slower
Simplest Way to Detect Client Locale in PHP
Create a Zip File and Download It
How to Check If the Request Is Made via Ajax in Codeigniter
Is It Secure to Store a Password in a Session
Pass Extra Parameters to Usort Callback
How to Send a Status Code in PHP, Without Maintaining an Array of Status Names
Checking If Your Code Is Running on 64-Bit PHP
PHP Daylight Saving Time Detection
_Construct() VS Sameasclassname() for Constructor in PHP
Laravel Error: Missing Required Parameters for Route
How to Convert PHP Date Formats to Gmt and Vice Versa