I'm developing an application with PHP that stores some customer details in a MySQL database. (Name, email address, phone number, mailing address) I'm not storing any 'sensitive' information like banking/credit card details, SSN/SIN, DOB, etc. Just basic customer details.
But while obviously security precautions will be in place, should a hacker ever get a copy of the database, I want a decent and relatively simple method to make this data very difficult to be useful (by having it encrypted).
I've read that performing the encryption in the MySQL query is less secure, since the encryption key will be cached in query logs on the database.
So that something like this is not recommended:
UPDATE customers SET email = AES_ENCRYPT('[email protected]', SHA2('encryption key here', 512));
I've looked at numerous questions on Stack Overflow along with other resources. However, many suggestions are at least 5 years old, and there might be simpler best practices now with PHP 7.2 (and later).
I've looked at Defuse, but I tend to avoid third-party libraries where I don't absolutely need them. (I prefer to understand the code and minimize it to my needs.)
Looking at the PHP documentation (https://www.php.net/manual/en/function.openssl-encrypt.php) I found this user contributed suggestion, which looks fairly simple and easy enough to implement:
--- Create Two Random Keys And Save Them In Your Configuration File ---
<?php
// Create The First Key
echo base64_encode(openssl_random_pseudo_bytes(32));
// Create The Second Key
echo base64_encode(openssl_random_pseudo_bytes(64));
?>
--------------------------------------------------------
<?php
// Save The Keys In Your Configuration File
define('FIRSTKEY', 'Lk5Uz3slx3BrAghS1aaW5AYgWZRV0tIX5eI0yPchFz4=');
define('SECONDKEY', 'EZ44mFi3TlAey1b2w4Y7lVDuqO+SRxGXsa7nctnr/JmMrA2vN6EJhrvdVZbxaQs5jpSe34X3ejFK/o9+Y5c83w==');
?>
--------------------------------------------------------
<?php
function secured_encrypt($data)
{
$first_key = base64_decode(FIRSTKEY);
$second_key = base64_decode(SECONDKEY);
$method = "aes-256-cbc";
$iv_length = openssl_cipher_iv_length($method);
$iv = openssl_random_pseudo_bytes($iv_length);
$first_encrypted = openssl_encrypt($data, $method, $first_key, OPENSSL_RAW_DATA, $iv);
$second_encrypted = hash_hmac('sha3-512', $first_encrypted, $second_key, TRUE);
$output = base64_encode($iv.$second_encrypted.$first_encrypted);
return $output;
}
?>
--------------------------------------------------------
<?php
function secured_decrypt($input)
{
$first_key = base64_decode(FIRSTKEY);
$second_key = base64_decode(SECONDKEY);
$mix = base64_decode($input);
$method = "aes-256-cbc";
$iv_length = openssl_cipher_iv_length($method);
$iv = substr($mix, 0, $iv_length);
$second_encrypted = substr($mix, $iv_length, 64);
$first_encrypted = substr($mix, $iv_length+64);
$data = openssl_decrypt($first_encrypted, $method, $first_key, OPENSSL_RAW_DATA, $iv);
$second_encrypted_new = hash_hmac('sha3-512', $first_encrypted, $second_key, TRUE);
if (hash_equals($second_encrypted, $second_encrypted_new))
return $data;
return false;
}
?>
Do you think this is fairly secure? I was thinking I'd probably specify AES-256-GCM instead, since I gather that GCM is better than CBC.
Is such encryption overkill for my needs? (Again, no highly sensitive customer details are being stored, and 'hopefully' this level of security (database fields encrypted at rest) is redundant anyway.)
What if I would I skip the hash_hmac sha3-512 portion and just use the openssl_encrypt function?