openssl_cipher_iv_length error on php 7.4 - php

how to fix openssl_cipher_iv_length error on php 7.4 its working normally on php 7.2?
$key = pack('H*','5e4888f3b85db60b53303483581c2b42112788e5e1b2d18c45cf70b867ca0721');
$method = 'aes-256-ecb';
$iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length($method));
$encrypted = openssl_encrypt($data, $method, $key, OPENSSL_RAW_DATA, $iv);
$encrypted = strtoupper(implode(null, unpack('H*', $encrypted)));
return $encrypted;
in PHP 7.4 i get this error Fatal error: Uncaught Error: Length must be greater than 0
In Php 7.2 Everything is work

We need add a condition in order to find out if $ivSize is greater than zero. If $ivSize will be return zero $iv will stay empty.
Here is fixed code for PHP 7.4 and newer.
$key = pack('H*','5e4888f3b85db60b53303483581c2b42112788e5e1b2d18c45cf70b867ca0721');
$method = 'aes-256-ecb';
$ivSize = openssl_cipher_iv_length($method);
$iv = '';
if ($ivSize > 0) {
$iv = openssl_random_pseudo_bytes($ivSize);
}
$encrypted = openssl_encrypt($data, $method, $key, OPENSSL_RAW_DATA, $iv);
$encrypted = strtoupper(implode(null, unpack('H*', $encrypted)));
return $encrypted;

Related

How to replace mcrypt with openssl?

I am currently upgrading an existing PHP application from PHP 5.4 to PHP 8.1. I have managed to restore all functionality except for encryption and decryption of data. My application communicates with a third party server, so just running an old PHP version to decrypt using mcrypt and reencrypt using openssl is not possible. I have seen a lot of similar threads, was however unable to find a solution to my issue.
This is the old set of functions (using mcrypt):
static function encrypt($key, $plain, $salt = null)
{
if (is_null($salt))
{
$salt = QuickBooks_Encryption::salt();
}
$plain = serialize(array( $plain, $salt ));
$crypt = mcrypt_module_open('rijndael-256', '', 'ofb', '');
if (false !== stripos(PHP_OS, 'win') and
version_compare(PHP_VERSION, '5.3.0') == -1)
{
$iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($crypt), MCRYPT_RAND);
}
else
{
$iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($crypt), MCRYPT_DEV_URANDOM);
}
$ks = mcrypt_enc_get_key_size($crypt);
$key = substr(md5($key), 0, $ks);
mcrypt_generic_init($crypt, $key, $iv);
$encrypted = base64_encode($iv . mcrypt_generic($crypt, $plain));
mcrypt_generic_deinit($crypt);
mcrypt_module_close($crypt);
return $encrypted;
}
static function decrypt($key, $encrypted)
{
$crypt = mcrypt_module_open('rijndael-256', '', 'ofb', '');
$iv_size = mcrypt_enc_get_iv_size($crypt);
$ks = mcrypt_enc_get_key_size($crypt);
$key = substr(md5($key), 0, $ks);
//print('before base64 [' . $encrypted . ']' . '<br />');
$encrypted = base64_decode($encrypted);
//print('given key was: ' . $key);
//print('iv size: ' . $iv_size);
//print('decrypting [' . $encrypted . ']' . '<br />');
mcrypt_generic_init($crypt, $key, substr($encrypted, 0, $iv_size));
$decrypted = trim(mdecrypt_generic($crypt, substr($encrypted, $iv_size)));
mcrypt_generic_deinit($crypt);
mcrypt_module_close($crypt);
//print('decrypted: [[**(' . $salt . ')');
//print_r($decrypted);
//print('**]]');
$tmp = unserialize($decrypted);
$decrypted = current($tmp);
return $decrypted;
}
And this is my best approximation using openssl:
static function new_encrypt($key, $plain, $salt = null)
{
if (is_null($salt))
{
$salt = QuickBooks_Encryption::salt();
}
$plain = serialize(array( $plain, $salt ));
$method = "AES-256-OFB";
$iv_len = openssl_cipher_iv_length($method);
$iv = openssl_random_pseudo_bytes($iv_len);
$key = substr(md5($key), 0, 32);
$encrypted = openssl_encrypt($plain, $method, $key, OPENSSL_RAW_DATA, $iv);
return base64_encode($iv . $encrypted);
}
static function new_decrypt($key, $encrypted)
{
$iv_size = openssl_cipher_iv_length('aes-256-ofb');
$key = substr(md5($key), 0, 32);
$encrypted = base64_decode($encrypted);
$iv = substr($encrypted, 0, $iv_size);
$encrypted = substr($encrypted, $iv_size);
$decrypted = openssl_decrypt($encrypted, 'aes-256-ofb', $key, OPENSSL_RAW_DATA, $iv);
$tmp = unserialize($decrypted);
$decrypted = current($tmp);
return $decrypted;
}
Both function sets can encrypt and decrypt data; however they are not compatible with each other.
What am I missing here?
First and foremost: Rijndael is not AES.
While AES is descended from/closely related to Rjindael, and may even have certain compatible implementations under very strict interpretations, more often than not they are not compatible at all. The implementations of Rijndael in mcrypt and AES OpenSSL are not compatible. [note: not a cryptographer, some amount of this paragraph might be BS aside from the words 'not compatible']
That said, you can use a library like phpseclib/mcrypt_compat to shim Rijndael and other functionality back into PHP8 and above.
However, since this library code will be running in userspace rather than a compiled extension the performance will likely be noticeably worse. My suggestion would be to use mcrypt_compat to migrate older encryption versions to something OpenSSL-compatible, or at least more current and broadly used/implemented, like AES.

Is mcrypt_encrypt() function not working in PHP 7.2?

I have encryption code as below & it was working in PHP version 5.6. But it is not working in PHP version 7.2.
**
Warning : Use of undefined constant MCRYPT_RIJNDAEL_128 - assumed
'MCRYPT_RIJNDAEL_128' (this will throw an Error in a future version of
PHP)
**
Any alternative of this?
$serviceid="2951";
$secretkey = "fQ5FHy0qzM6ljp97";
function pkcs5_pad ($text, $blocksize)
{
$pad = $blocksize - (strlen($text) % $blocksize);
return $text . str_repeat(chr($pad), $pad);
}
function encrypt($plaintext, $key) {
$plaintext = pkcs5_pad($plaintext, 16);
$ciphertext = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $plaintext, MCRYPT_MODE_ECB);
$ciphertext_base64 = base64_encode($ciphertext);
$ciphertext_base64;
}
$data = $serviceid;
$auth= encrypt($data ,$secretkey);
Value of encryption is AGchNk2xOnHHxhgYv02XJw==
I tried with below code in PHP 7.2
function encrypt($plaintext, $key)
{
$iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length('aes-128-cbc'));
$encrypted = openssl_encrypt($plaintext, 'aes-128-cbc', $key, 0, $iv);
return base64_encode($encrypted . '::' . $iv);
}
but output keeps changing
As you can see into documentation mcrypt_encrypt is REMOVED from PHP 7.2.0
Here an SO question for best alternative
I have found solution of my query. Please check below
function encrypt($plaintext,$key)
{
return base64_encode(openssl_encrypt($plaintext, 'aes-128-ecb', $key, OPENSSL_RAW_DATA));
}

Why can't I decrypt an mcrypt encrypted text with opnssl using blowfisch an PHP 7.x

Why can't I decrypt an mcrypt encrypted text with openssl
I have encrypted information in the database and in apps on mobile devices.
So far, these have been encrypted and decrypted on a server with PHP 7.0 and mcrypt.
- The deprecated message is already displayed there.
There will be no mcrypt in the next PHP versions. So I tried to do that with openssl.
Although I also use blowfish with mode CFB at openssl, it doesn't work.
What am I doing wrong?
#
# mcrypt on Server with PHP 7.0
/**
* encrypt with Blowfish and mcrypt
*/
function mcrypt_encrypt($plaintext, $key)
{
$td = mcrypt_module_open(MCRYPT_BLOWFISH, '', MCRYPT_MODE_CFB, '');
$ivsize = mcrypt_enc_get_iv_size($td);
$iv = mcrypt_create_iv($ivsize, MCRYPT_RAND);
mcrypt_generic_init($td, $key, $iv);
$crypttext = mcrypt_generic($td, $plaintext);
mcrypt_generic_deinit($td);
return $iv . $crypttext;
}
/**
* decrypt with Blowfish and mcrypt
*/
function mcrypt_decrypt($crypttext, $key)
{
$td = mcrypt_module_open(MCRYPT_BLOWFISH, '', MCRYPT_MODE_CFB, '');
$ivsize = mcrypt_enc_get_iv_size($td);
$iv = substr($crypttext, 0, $ivsize);
$crypttext = substr($crypttext, $ivsize);
mcrypt_generic_init($td, $key, $iv);
$plaintext = mdecrypt_generic($td, $crypttext);
mcrypt_generic_deinit($td);
return $plaintext;
}
This works on PHP 7.0:
$plaintext = 'Hello World';
$mcrypt_crypttext = mcrypt_encrypt($plaintext,'secret');
$mcrypt_plaintext = mcrypt_decrypt($mcrypt_crypttext,'secret');
# $plaintext == $mcrypt_plaintext;
The new funktions with OpenSSL:
#
# openssl on Server with PHP 7.2
/**
* encrypt with Blowfish and openssl
*/
function openssl_encrypt($plaintext, $key)
{
$ivlen = openssl_cipher_iv_length('bf-cfb');
$iv = openssl_random_pseudo_bytes($ivlen);
$crypttext = openssl_encrypt($plaintext, 'bf-cfb', $key, OPENSSL_RAW_DATA, $iv);
return $iv . $crypttext;
}
/**
* decrypt with Blowfish and openssl
*/
function openssl_decrypt($crypttext, $key)
{
$ivlen = openssl_cipher_iv_length('bf-cfb');
$iv = substr($data, 0, $ivlen);
$crypttext = substr($data, $ivlen);
$plaintext = openssl_decrypt($crypttext, 'bf-cfb', $key, OPENSSL_RAW_DATA, $iv);
return $plaintext;
}
This works also:
$openssl_crypttext = openssl_encrypt($plaintext,'secret');
$openssl_plaintext = openssl_decrypt($openssl_crypttext,'secret');
# $plaintext == $openssl_plaintext;
But this goes wrong - decrypting the mcrypt encrypted text:
$openssl_plaintext = openssl_decrypt($mcrypt_crypttext,'secret');
# $plaintext != $openssl_plaintext
Is there a way to decrypt mcrypted data with PHP7.2?

Replacing mcrypt_encrypt using MCRYPT_RIJNDAEL_256 with openssl_encrypt

As you guys probably know, the extension mcrypt will be deprecated on php 7.1.
I use to maintain a "legacy" application that I want to migrate eventually to this version so I ran the tests and verified that I can't get 100% of coverage anymore, since there's a piece of code that use the following code:
$key = 'sA*(DH';
// initialization vector
$iv = md5(md5($key));
$output = base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, md5($key), $string, MCRYPT_MODE_CBC, $iv));
I tried to port this piece of code to openssl_encrypt using this code
$key = md5('sA*(DH');
$iv = md5($key);
echo base64_encode(openssl_encrypt($data, "aes-256-cbc", $key, OPENSSL_RAW_DATA, $iv));
But I have 2 problems with this:
The IV lenght should be 16 chars (and md5 gives me 32), so I get a PHP Warning
The output it's not the same (even if I truncate to 16 chars)
Anyone had similar problems (or know how to fix it?)
BTW: I'm using the dev master version of PHP (supposed to be 7.1.0 alpha 3).
Yet another tested solution taking and returning ANSI text to replace Mcrypt function with the openssl_encrypt() and openssl_decrypt():
//Return encrypted string
public function stringEncrypt ($plainText, $cryptKey = '7R7zX2Urc7qvjhkr') {
$cipher = 'aes-128-cbc';
if (in_array($cipher, openssl_get_cipher_methods()))
{
$ivlen = openssl_cipher_iv_length($cipher);
$iv = openssl_random_pseudo_bytes($ivlen);
$ciphertext_raw = openssl_encrypt(
$plainText, $cipher, $cryptKey, $options=OPENSSL_RAW_DATA, $iv);
$hmac = hash_hmac('sha256', $ciphertext_raw, $cryptKey, $as_binary=true);
$encodedText = base64_encode( $iv.$hmac.$ciphertext_raw );
}
return $encodedText;
}
//Return decrypted string
public function stringDecrypt ($encodedText, $cryptKey = '7R7zX2Urc7qvjhkr') {
$c = base64_decode($encodedText);
$cipher = 'aes-128-cbc';
if (in_array($cipher, openssl_get_cipher_methods()))
{
$ivlen = openssl_cipher_iv_length($cipher);
$iv = substr($c, 0, $ivlen);
$hmac = substr($c, $ivlen, $sha2len=32);
$ivlenSha2len = $ivlen+$sha2len;
$ciphertext_raw = substr($c, $ivlen+$sha2len);
$plainText = openssl_decrypt(
$ciphertext_raw, $cipher, $cryptKey, $options=OPENSSL_RAW_DATA, $iv);
}
return $plainText;
}
More read in openssl documentation
You should really get out of the habit of using md5 for anything.
$iv = openssl_random_pseudo_bytes(16);
$key = substr(hash('sha256', 'sA*(DH'), 0, 32)
mcrypt_encrypt and openssl_encrypt will not output the same crypttext given the same plaintext and key.
also, mcrypt is deprecated in PHP 7.1, not removed...so you can update to 7.1 without changing from mcrypt to openssl ... but it is a good idea to remove mcrypt in general.
There are 2 problems :
MCrypt uses zero padding while Openssl uses by default PKCS#7
Openssl needs the input string to be of proper length (multiple of block length)
To solve this problems :
add OPENSSL_ZERO_PADDING flag to openssl_encrypt/openssl_decrypt
if input string length is not multiple of block length then append to the input string zero chars "\0" [aka chr(0)];
That being said this should solve the problem:
// key/iv in ASCII binary data, $str base64
function decrypt_stuff($key, $str, $iv) {
// $plaintext_dec = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, base64_decode($str), MCRYPT_MODE_CBC, $iv);
$plaintext_dec = openssl_decrypt(base64_decode($str), "aes-256-cbc", $key, OPENSSL_RAW_DATA|OPENSSL_ZERO_PADDING, $iv);
return $plaintext_dec;
}
// key/iv in ascii binary data, $str ascii
function encrypt_stuff($key, $str, $iv) {
// $ciphertext = base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $str, MCRYPT_MODE_CBC, $iv));
if (($l = (strlen($str) & 15)) > 0) { $str .= str_repeat(chr(0), 16 - $l); }
$ciphertext = base64_encode(openssl_encrypt($str, "aes-256-cbc", $key, OPENSSL_RAW_DATA|OPENSSL_ZERO_PADDING, $iv));
return $ciphertext;
}

How to Encrypt-Decrypt .pdf, .docx files in php?

I am trying to encrypt/decrypt files in PHP. So far I am successful with .txt files but when it comes to .pdf and .doc or .docx my code fails, i.e. it gives absurd results. Can anyone suggest modification/alternative in my code? Thanks in advance!
Here's the encryption function
function encryptData($value)
{
$key = "Mary has one cat";
$text = $value;
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_ECB);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$crypttext = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $text, MCRYPT_MODE_ECB, $iv);
return $crypttext;
}
Here's the decryption function
function decryptData($value)
{
$key = "Mary has one cat";
$crypttext = $value;
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_ECB);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$decrypttext = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $crypttext, MCRYPT_MODE_ECB, $iv);
return trim($decrypttext);
}
I used this blog to help me encrypt/decrypt pdf files on my local machine using openssl_encrypt because mcrypt is deprecated in php7.
First, you get the file contents of the pdf:
$msg = file_get_contents('example.pdf');
Then I called the encryption function written in the blog post:
$msg_encrypted = my_encrypt($msg, $key);
Then I open the file I want to write to and write the new encrypted msg:
$file = fopen('example.pdf', 'wb');
fwrite($file, $msg_encrypted);
fclose($file);
For reference, in case that blog goes down, here are the encryption and decryption functions from the blog:
$key = 'bRuD5WYw5wd0rdHR9yLlM6wt2vteuiniQBqE70nAuhU=';
function my_encrypt($data, $key) {
// Remove the base64 encoding from our key
$encryption_key = base64_decode($key);
// Generate an initialization vector
$iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length('aes-256-cbc'));
// Encrypt the data using AES 256 encryption in CBC mode using our encryption key and initialization vector.
$encrypted = openssl_encrypt($data, 'aes-256-cbc', $encryption_key, 0, $iv);
// The $iv is just as important as the key for decrypting, so save it with our encrypted data using a unique separator (::)
return base64_encode($encrypted . '::' . $iv);
}
function my_decrypt($data, $key) {
// Remove the base64 encoding from our key
$encryption_key = base64_decode($key);
// To decrypt, split the encrypted data from our IV - our unique separator used was "::"
list($encrypted_data, $iv) = explode('::', base64_decode($data), 2);
return openssl_decrypt($encrypted_data, 'aes-256-cbc', $encryption_key, 0, $iv);
}

Categories