Jorge Batres
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:
To encrypt form fields:
Code included in the admin file for the database:
To decrypt fields:
Could you please tell me the code I need to use to replace this with OpenSSL?
Thanks,
Jorge
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));
}
}
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']);
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']);
Could you please tell me the code I need to use to replace this with OpenSSL?
Thanks,
Jorge
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.
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.
ASKER
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.
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
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
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.
ASKER
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 ?
or to decrypt this: openssl_decrypt ?
$_POST['Card_Number'] = $Cipher->encrypt($_POST['Card_Number']);
$_POST['Card_Holder'] = $Cipher->encrypt($_POST['Card_Holder']);
$_POST['Card_Expiration'] = $Cipher->encrypt($_POST['Card_Expiration']);
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']);
ASKER
Should I do it like this?
$_SESSION['Card_Number'] = $enc = openssl_encrypt(($_SESSION['Card_Number']),'AES-256-ECB',$keyE);
ASKER
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:
Could you please help me with this last bit of code?
Thanks
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);
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);
In the admin file I placed both keys E and D and this line:$enc = $row[$record];
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 -
that works for me, I am not really sure what your question envolved, , you can use the -
$_SESSION['Card_Number'] = openssl_encrypt(($_SESSION ['Card_Num ber']),'AE S-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.
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;
that works for me, I am not really sure what your question envolved, , you can use the -
$_SESSION['Card_Number'] = openssl_encrypt(($_SESSION
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?
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?
ASKER
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?
ASKER
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).
used like
$enc = EncryptAES('Plain Text.');
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;
}
used like
$enc = EncryptAES('Plain Text.');
ASKER
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 :)
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 "";
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 "";
ASKER
Thank you so very much Slick812, this is working to perfection for me!
Thanks again.
Thanks again.
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