Link to home
Start Free TrialLog in
Avatar of Jorge Batres
Jorge BatresFlag for United States of America

asked on

Moving from Mcrypt to OpenSSL

Hi, I am currently encrypting some fields on my reservation forms using Mcrypt. Since I am running PHP 7.1.2, I can see that Mcrypt has already been deprecated, and I would like to be ready for PHP 7.2, where Mcrypt will be obsolete.

For that reason, I'm moving to OpenSSL encryption, and here is where I need your help.

I currently use two files for encryption/decryption. the first file loads session variables to my forms and contains the encryption key, class and functions, and the second file, is the admin file for my reservations database which also contains the encryption/decryption class, key and functions.

This is what I currently have on my files:

Encrypting code included in the file used by my forms to upload to database:

class Cipher {
    private $securekey, $iv;
    function __construct() {
        $this->securekey = hash('sha256',"my private key",TRUE);
		
        $this->iv = mcrypt_create_iv(32, MCRYPT_RAND);
    }
    function encrypt($input) {
        return base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $this->securekey, $input, MCRYPT_MODE_ECB, $this->iv));
    }
    function decrypt($input) {
        return trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $this->securekey, base64_decode($input), MCRYPT_MODE_ECB, $this->iv));
    }
}

Open in new window


To encrypt form fields:

$_POST['Card_Number'] = $Cipher->encrypt($_POST['Card_Number']);
$_POST['Card_Holder'] = $Cipher->encrypt($_POST['Card_Holder']);
$_POST['Card_Expiration'] = $Cipher->encrypt($_POST['Card_Expiration']);

Open in new window


Code included in the admin file for the database:

To decrypt fields:

$record['Card_Number'] = $Cipher->decrypt($record['Card_Number']);
						$record['Card_Holder'] = $Cipher->decrypt($record['Card_Holder']);
						$record['Card_Expiration'] = $Cipher->decrypt($record['Card_Expiration']);

Open in new window


Could you please tell me the code I need to use to replace this with OpenSSL?

Thanks,

Jorge
Avatar of Ray Paseur
Ray Paseur
Flag of United States of America image

We have an article here at E-E that should point the right way!

The encryption parts are about halfway down.  Examples are included for mCrypt and OpenSSL.
https://www.experts-exchange.com/articles/28835/Keeping-Secrets-with-PHP.html
Avatar of Jorge Batres

ASKER

Thank Ray, I read your article before and that is way I want to go with OpenSSL; however, I don't have the knowledge to use that example and apply it to my script where I need to upload to a database.
What is the issue?  Is it uploading information or encrypting information?  The encryption steps are almost exactly the same as what you have in the code samples here.

Basically, here is how I would go about such a conversion.

1. Write a specialized script that takes the current information and decrypts it.  Test this thoroughly.
2. Write another specialized script that encrypts the clear-text information.  Obviously, test this well, too.
3. Using a test data set, integrate these two scripts into a third script that reads the database, decrypts the data, encrypts with OpenSSL and updates the database with the new information.  I would not update the same columns, instead I would add new columns for the OpenSSL values.

Once you're happy with these scripts, use ALTER TABLE to add columns as needed to the live database.  Then run the update script against the live database.  Once it's done you can rename the columns to the names you're using now, and you should be OK.

There may be some other considerations -- column width, and PHP stuff, but I don't think there is much that can go wrong with the process.
Thank Ray, the problem is encrypting, I can upload the information fine. I will try replacing the current steps I have in my script with OpenSSL as much as I can, but I don't know if I can use the same key I currently have.

I have an exact replica of the live database, so I could test OpenSSL encryption there, and once I get it working, I don't care about the existing encrypted info in the live database since I have to delete that data anyway.

My challenge is going to be applying the OpenSSL code to my script.
ASKER CERTIFIED SOLUTION
Avatar of Member_2_248744
Member_2_248744
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Thank you so much Slick812, I will try to modify what I have, and I will update this question as I hopefully progress.
I looked at what I had posted, and I was incorrectly using the openssl_decrypt( ) in my descriptions, I should have been showin the  openssl_encrypt( ) , the Encrypt of  openssl_encrypt( )  function returns a base64 encoded string, but the  openssl_decrypt( )   returns  the plain text , that is NOT changed, No base64 from the   openssl_decrypt( )   function.   Sorry bout that.
Thank you for the clarification Slick812, so I'm going to replace the existing code in my test script and database with the OpenSSL code you gave me, but how do I implement this to encrypt this: openssl_encrypt ?

$_POST['Card_Number'] = $Cipher->encrypt($_POST['Card_Number']);
$_POST['Card_Holder'] = $Cipher->encrypt($_POST['Card_Holder']);
$_POST['Card_Expiration'] = $Cipher->encrypt($_POST['Card_Expiration']);

Open in new window


or to decrypt this: openssl_decrypt ?

$record['Card_Number'] = $Cipher->decrypt($record['Card_Number']);
$record['Card_Holder'] = $Cipher->decrypt($record['Card_Holder']);
$record['Card_Expiration'] = $Cipher->decrypt($record['Card_Expiration']);

Open in new window

Should I do it like this?

$_SESSION['Card_Number'] = $enc = openssl_encrypt(($_SESSION['Card_Number']),'AES-256-ECB',$keyE);

Open in new window

Slick812, Thank you so much!!!!!  I'm almost there!
Using your code, I was able to write encrypted data to the database, and I was able to decrypt it in the administrations section of my script.

Now, in the admin script if I need to  edit the data, I need to be able to write to the database, and as soon as I type something, all data is erased from the database (only the encrypted data).

from the form I use this line to write to the database successfully:
$_SESSION['Card_Number'] = $enc = openssl_encrypt(($_SESSION['Card_Number']),'AES-256-ECB',$keyE);

Open in new window

in the admin, I use this line to write/edit to the database:
$_POST['Card_Number'] = $enc = openssl_encrypt(($POST['Card_Number']),'AES-256-ECB',$keyE);

Open in new window

In the admin file I placed both keys E and D and this line:
$enc = $row[$record];

Open in new window

This works for viewing the encrypted data, but I think it is conflicting when editing / writing to the database from the admin script.
Could you please help me with this last bit of code?
Thanks
OK, ? ?
You did not show your CLASS code
I might do like this -
class Cipher {
  function __construct() {
    $this->key = '-Rv@'.chr(193).'3#>'.chr(166).'ncf'.chr(150).'H'.chr(198).
        ',!dcS'.chr(200).'([I'.chr(244).'5Ax'.chr(214).'vM)';
  }

  function encrypt($plain) {
    return openssl_encrypt($plain ,'AES-256-ECB',$this->key);
  }
  
  function decrypt($encode64) {
    $de = openssl_decrypt($encode64,'AES-256-ECB',$this->key);
    if (!$de) trigger_error('Decryption FAILED in Cipher Class', E_USER_WARNING);
  return $de;
  }
}

$_POST['Card_Number'] = '+0ZERO123Fast?';
$Cipher = new Cipher();
$_POST['Card_Number'] = $Cipher->encrypt($_POST['Card_Number']);
echo '<br>ENCRYPT Cipher= ',$_POST['Card_Number'];
$re = $Cipher->decrypt($_POST['Card_Number']);
echo '<br>DECRYPT Cipher= ',$re;

Open in new window


that works for me, I am not really sure what your question envolved, , you can use the -
    $_SESSION['Card_Number'] = openssl_encrypt(($_SESSION['Card_Number']),'AES-256-ECB',$keyE);

without a Class or function to hold the openssl_encrypt( ) and openssl_decrypt( ), , it seems like you might be better without any CLASS wrapper, since it's just a single line o code, , BUT I can not say one is better than the other.
Sorry, you posted that last one before I could read it, , YOU only need a single KEY, , I used two different ones (Identical vales) just to show the encrypt and decrypt are in two different "phases" of code work.

I can not tell why you have trouble in the admin script with the database,
you say -



"all data is erased from the database"
so you have something that does that, but I can not figure what it could be?
Thank you Slick812, I used the class example you gave me and the original code you gave me and it is writing now from the admin as well, but it is not decrypting. I get this message mod_fcgid: stderr: PHP Warning: Decryption FAILED in Cipher Class I made a few test reservations with the same credit card and same expiration, and I can see the non-decrypted code in all reservations is the exact same, so I can see that the encrypting / writing and updating is working but I can decrypt, so I'm guessing if it could be the cipher suites I use in my server. A few weeks ago I worked on straightening  my server for security and I do not see ECB among the cipher suites, can I change to one of the two suites I have here?
Thank you so much Slick812, I'm encrypting/decrypting with OpenSSL
Thanks for the award, ,
I looked at the page from your link, this is about a test for HSTS and SSL hyerlink transfer security, , as I know about it, this has nothing to do with the PHP and or database, but with the HTTP certificate SSL communication through secure HTTPS.

For me, when using PHP encryption, 99 out of 100 times, when it does not decrypt correctly and the code has worked before, it's the KEY, , , the en and de crypt KEY must be EXACTLY the same, any change in the KEY string will result in Failed decryption.

Just so you know, due to incorrect Field Types in the database table, if you use BINARY strings for encrypted data, the database will change the output from the table, different than the Input to the table, this is mostly due to having a UTF-8 on a field, when the field should be a BINARY type field.
Since this uses a base64 encoded string, you should not have problems with the UTF-8 mess.

Not that you need these functions, but I had some time, and I did two functions that encrypt and decrypt using a more effective MODE of CBC, for this you have to use a new randomized IV string with each and every encryption pass, and this random string, has to be sent with the cypher text to the decryption function. The CBC is sort of the standard used mode for encryption, because of the advantage of total cypher text randomization, even if the same plain text and same key are used, the cypher text will be different (randomized).

function EncryptAES($plain) {
  $ran15 = openssl_random_pseudo_bytes(15);
  $key = '*Hv@'.chr(13).'3#>'.chr(166).'ncf'.chr(150).'H'.chr(198).
    ',!dcS'.chr(222).'([I'.chr(249).'5Ax'.chr(214).'vM)';
  $plain = openssl_encrypt($plain,'AES-256-CBC',$key,0,$ran15.':');
  $ran15=base64_encode($ran15);
  return $ran15.$plain;
}


function DecryptAES($enc64) {
  $ran15 = substr($enc64 ,0,20);
  $ran15 = base64_decode($ran15);
  $enc64 = substr($enc64 ,20);
  $key = '*Hv@'.chr(13).'3#>'.chr(166).'ncf'.chr(150).'H'.chr(198).
    ',!dcS'.chr(222).'([I'.chr(249).'5Ax'.chr(214).'vM)';
  $enc64 = openssl_decrypt($enc64,'AES-256-CBC',$key,0,$ran15.':');
  if (!$enc64) trigger_error('Decryption FAILED in DecryptAES()', E_USER_WARNING);
  return $enc64;
}

Open in new window


used like
    $enc = EncryptAES('Plain Text.');
Thank you Slick812, not that really matters but, when I delete a field from the database like credit card number, and I go back and see the record, since it is now empty, I get this warning: PHP Warning: openssl_decrypt(): IV passed is only 1 bytes long, cipher expects an IV of precisely 16 bytes, padding with \\0.
I imagine it is because now the field is empty and the decryption function is looking for something to decrypt, but I was wondering if something can be added to the function to avoid that. Like I said before, everything works as it is supposed to, and the warning is in the background of course.
Thank you again for your valuable help, as I think I'm ready for PHP 7.2 :)
OK,, , But you may need to have your development thinkin about "Error Control" be used here. You say the table field has no data in it - "since it is now empty" - You should be thinking "If there's nothing there, I should IF TEST for empty and then do Nothing, since I can't do anything with nothing (empty) anyway" - -

Fortunately the PHP Warning has alerted you to using the  openssl_decrypt( ) with incorrect crap (empty as you say)-
I could have added an IF TEST for no $enc64 to the decrypt code, But I did not, because you get the warning from PHP, And if I did add the -
        if (!$enc64) { }
WHAT was I suppose to do if it was empty? ? was I suppose to exception out, throw warning, just return false, return an empty string, I have no Idea what your Error Control measures may or may not be, but IF the INPUT for the decrypt code could be something that's NOT a string Data (false, empty string, a number, and array) you should have tested the input before sending it to the decrypt code, and then take other code operations to deal with the data value that will cause problems in the decrypt code

- - - - - - - - - - -

if all you need is a quick fix, you can just add this line to the TOP of the decrypt code progression -
      if (!$enc64) return "";
Thank you so very much Slick812, this is working to perfection for me!
Thanks again.