Upgrading My Encryption Library from Mcrypt to Openssl

Upgrading my encryption library from Mcrypt to OpenSSL

This code for your decryption routine works for me:

public function decrypt($data, $key) {
$salt = substr($data, 0, 128);
$enc = substr($data, 128, -64);
$mac = substr($data, -64);

list ($cipherKey, $macKey, $iv) = $this->getKeys($salt, $key);

if ($mac !== hash_hmac('sha512', $enc, $macKey, true)) {
return false;
}

$dec = openssl_decrypt($enc, $this->cipher, $cipherKey, OPENSSL_RAW_DATA, $iv);

return $dec;
}

Test:

$keys = [
'this is a secret key.',
'G906m70p(IhzA5T&5x7(w0%a631)u)%D6E79cIYJQ!iP2U(xT13q6)tJ6gZ3D2wi&0")7cP5',
chr(6) . chr(200) . chr(16) . 'my key ' . chr(3) . chr(4) . chr(192) . chr(254) . ' zyx0987!!',
'and finally one more key to test with here:',
];


$data = [
'A',
'This is a test',
'now test encrypting something a little bit longer with 1234567890.',
'$length = mcrypt_get_block_size(MCRYPT_BLOWFISH, MCRYPT_MODE_CBC); $last = ord($data[strlen($data) - 1]);',
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec sit amet pharetra urna. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Ut fringilla, quam sed eleifend eleifend, justo turpis consectetur tellus, quis tristique eros erat at nibh. Nunc dictum neque vel diam molestie fermentum. Pellentesque dignissim dui quis tortor eleifend, ut maximus elit egestas. Donec posuere odio et auctor porta. Quisque placerat condimentum maximus. Curabitur luctus dolor eget sem luctus, in dignissim tortor venenatis. Mauris eget nulla nisl.',
];

$failures = 0;

foreach ($data as $datum) {
foreach ($keys as $key) {
$enc = new Encryption(MCRYPT_BLOWFISH, MCRYPT_MODE_CBC);

$encrypted = $enc->encrypt($datum, $key);

$dec = new EncryptionOpenSsl('bf-cbc');

$decrypted = $dec->decrypt($encrypted, $key);

if (strcmp($datum, $decrypted) !== 0) {
echo "Encryption with key '$key' of '$datum' failed. '$decrypted' != '$datum'<br><br>\n\n";
$failures++;
}
}
}

if ($failures) {
echo "$failures tests failed.<br>\n";
} else {
echo "ALL OKAY<br>\n";
}

If you can confirm it works for you as well I can tidy up the answer and add final working code.

Upgrade mcrypt to OpenSSL encryption in SagePay form

First, this is a bad scheme. Using a (real) password as the key for modern cryptography, even where it is sort of possible, is almost always insecure. Passwords and keys are different things that are designed and specified differently. Of course some people who don't know what they're doing call something that is actually a key a password, and since I don't know SagePay (and of course you don't give a real value) I don't know if that's the case here. Further, using the key (or password) as IV is grossly nonstandard. The whole point of an IV is to be different for every encryption (or at least every data value) under a given key, while a given key by definition is the same as itself. This is so silly I don't recall seeing any analysis of whether and what attacks it enables, although as a general rule violating the 'security contract' usually does lead to problems. Using any fixed value for IV, a rather more common error, is only moderately bad for CBC mode, although it is much worse for some other modes.

However, you apparently don't have the option to change this scheme, and if you did, it would not really be a programming Q and would belong instead on security.SX or maybe crypto.SX depending.

Also FYI it is meangingless to say "AES-128 with a 128-bit block". AES always uses an 128-bit block; that was part of the rules of the competition that established it. Rijndael does have options for other block sizes, which is why mcrypt, which implements Rijndael more-or-less, specifies the block size, but OpenSSL implements AES, which does not need to and does not specify the block size -- only the key size.

Second, your proposed new code is nonsense. First you try to redefine a standard function, which is not allowed, and then the logic you propose was clearly designed to decrypt, not encrypt, a substantially different scheme, not the one you present, and then mangled.

mcrypt_encrypt zero-pads the plaintext, and in older versions the key and iv, as needed. For Rijndael it also chooses the key size based on the supplied key; since you say you want AES-128 (i.e. a 128-bit key) the so-called 'password' must not be more than 128-bits but may be less. The code you posted does explicit PKCS5 padding of the data, so mcrypt's zero padding isn't used, and as Peter commented, openssl_encrypt (and the OpenSSL routines it uses underneath) do PCKS5/7 padding by default, so all you need is:

function encryptAes_new ($string, $key) {
$key = str_pad($key,16,"\0"); # if supplied key is, or may be, less than 16 bytes
$crypt = openssl_encrypt($string, 'aes-128-cbc', $key, OPENSSL_RAW_DATA, $key);
// Perform hex encoding and return.
return "@" . strtoupper(bin2hex($crypt));
}

(Note: Original PKCS5 padding only handled 64-bit/8-byte blocks, and PKCS7 extended it to other sizes, but PKCS5v2.1 in 2017 also extended it referencing CMS which is the IETF version of PKCS7, so they are now the same.)

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.

How to migrate Mcrypt to openssl function to encrypt with PHP7.3

This is the working code:

$cipher = "aes-128-ecb";
$ciphertext = openssl_encrypt(trim($strToEncode), $cipher, $key, OPENSSL_RAW_DATA);

Convert framework from mcrypt to openssl

So after doing some learning and research, I have come up with my own working openssl version which achieves similar results.

private function encrypt( $data, $key ) {
$salt = 'cH!swe!retReGu7W6bEDRup7usuDUh9THeD2CHeGE*ewr4n39=E@rAsp7c-Ph@pH';
$iv_size = openssl_cipher_iv_length( "AES-256-CBC-HMAC-SHA256" );
$hash = hash( 'sha256', $salt . $key . $salt );
$iv = substr( $hash, strlen( $hash ) - $iv_size );
$key = substr( $hash, 0, 32 );
$encrypted = base64_encode( openssl_encrypt( $data, "AES-256-CBC-HMAC-SHA256", $key, OPENSSL_RAW_DATA, $iv ) );

return $encrypted;
}

private function decrypt( $data, $key ) {
$salt = 'cH!swe!retReGu7W6bEDRup7usuDUh9THeD2CHeGE*ewr4n39=E@rAsp7c-Ph@pH';
$iv_size = openssl_cipher_iv_length( "AES-256-CBC-HMAC-SHA256" );
$hash = hash( 'sha256', $salt . $key . $salt );
$iv = substr( $hash, strlen( $hash ) - $iv_size );
$key = substr( $hash, 0, 32 );
$decrypted = openssl_decrypt( base64_decode( $data ), "AES-256-CBC-HMAC-SHA256", $key, OPENSSL_RAW_DATA, $iv );
$decrypted = rtrim( $decrypted, "\0" );

return $decrypted;
}


Related Topics



Leave a reply



Submit