Notice: I am not an encryption expert! I didn’t like having my SMTP email password being stored in my database in plain text, so this was my solution. If you are doing something similar, this should be fine. If you are storing SSN or credit card data, you will want to consult with an encryption expert!
The php manual is currently lacking documentation for the “openssl_encrypt” and “openssl_decrypt” functions, so it took me awhile to piece together what I needed to do to get these functions working as a replacement for mcrypt, which has been unmaintained since 2003. Hopefully this will help you get to where you need to go with encrypting and decrypting your data.
First, you will need to generate a pseudo-random string of bytes that you will use as a 256 bit encryption key. The requested length will be 32 (since 32 bytes = 256 bits). If you echo out the key, you will notice that your browser chokes. In order to avoid possible corruption when storing the key in a file or database, we will base64_encode it. Use the code below to generate your key(s). The key will need to be saved since the data has to be encoded and decoded using the same key. If your encrypted data is being stored in a database, your encryption key will most likely need to be stored in a configuration file.
1 |
$encryption_key_256bit = base64_encode(openssl_random_pseudo_bytes(32)); |
Now that we have our key, we will create the encryption function. We will pass our data to be encoded, and our key, into the function. In addition to our key, there is a secondary random string we will create and use called an initialization vector (IV) that helps to help strengthen the encryption.
1 2 3 4 5 6 7 8 9 10 |
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); } |
Now for the decryption function:
1 2 3 4 5 6 7 |
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); } |
Putting it all together:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
<?php //$key is our base64 encoded 256bit key that we created earlier. You will probably store and define this key in a config file. $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); } //our data to be encoded $password_plain = 'abc123'; echo $password_plain . "<br>"; //our data being encrypted. This encrypted data will probably be going into a database //since it's base64 encoded, it can go straight into a varchar or text database field without corruption worry $password_encrypted = my_encrypt($password_plain, $key); echo $password_encrypted . "<br>"; //now we turn our encrypted data back to plain text $password_decrypted = my_decrypt($password_encrypted, $key); echo $password_decrypted . "<br>"; |
The code above will output the following. Note that the encrypted string in the middle will change each time you run the code thanks to our initialization vector:
1 2 3 |
abc123 K3gzWkxySUd6VkgvQTNJUUtZMjV2UT09Ojpia3sh1zglO3DYodw84855 abc123 |
Hope this helps!
Very helpful function! Thank you for providing examples that use openssl_random_pseudo_bytes and sha256, as they are more up-to-date for php7 than the deprecated mcrypt method most tutorials seem to use.
This was super helpful! I used this to encrypt/decrypt a pdf file. Thanks!
Thanks a lot, it useful
Really nice tutorial. Very helpful
Thank you
great info! helpful and saved me a long time coding. just replaced the functions from php5!
And another THANK YOU ! Finally I got the pieces together…
Awesome job in explaining how to encrypt and decrypt. This really helped me big time.
Thanks!! It helped me a lot
What you are doing is wrong. You must HASH passwords instead of encrypting. (I hope you are not doing this in a production environment) Use sha256 with a SALT. Encryption is never meat to be for password storing.
Yes and no. Yes, user passwords should be salted and hashed in the database since only the user needs to know what the plain password is. In this case, no, the password needs to be encrypted. If it’s hashed, the server will not be able to “unhash” it and use it. With encryption, the server can unencrypt the password and use it whenever it needs to send out an email.
Thank you! It helped me.:)
I like the clever way you handle $iv So there is no need for an extra storing.
Hi, it was helpful. But what would decrypt func. return if the key is incorrect?
Add this before return in ‘my_decrypt’ => if(strlen($iv)>16) $iv = substr($iv,0,16);
Thanks for sharing.