0
votes

I have a PHP and MySQL system and I need to encrypt user data with AES-256. I know how to encrypt and decrypt the data using AES-encrypt/decrypt but I'm not sure how to securely store the AES encryption key. Would it be recommended to store the key inside of a file outside of the public website folder, then use

<?php include('')?>

to call the key for the encryption?

Thanks

3
This should be in information security. Which already has an answer: security.stackexchange.com/a/12334/155074 - Spoody
do you need to only encrypt/decrypt user data after when user logged in? - Afshin
Yes, only once the user is logged in. I'm thinking of using <?php include('')?> to include the key file, and then from that creating a special key for the user which is a combination of the $key stored in that file, and their password. - Noah Sinist3rSaint
Whom are you trying to protect what from exactly…? If you just want at-rest encryption in the database, your database may already have that built-in. - deceze♦
It is a MySQL database that will be storing medical information. Because of country standards the information needs to be encrypted. - Noah Sinist3rSaint

3 Answers

0
votes

Access to your data should currently be constrained by a username/password for MySQL - Where do you store that?

Adding encryption into the mix raises the possibility of splitting the things-you-need-to-know-to-access-the-data across different substrates - with different exposures.

The link in the comment by Mehdi covers some of the options at a fairly abstract level. It doesn't mention, for example, storing the key at the client. But the choice of which method(s) you use depends on the infrastructure, code management, deployment and operational processes in place. The right choice for a low end shared web-hosting service is not the right choice for a dedicated datacentre and vice versa.

You do propose a specific method for managing the key: storing it outside the document root limits access. If you go further and store it in something which is recognized as PHP code by your webserver then access via the webserver should only expose the output of the PHP code - conversely if it were stored in a text file, and someone could get the webserver to serve the file, they would have access to the key.

OTOH its not a great solution if the key hows up in your github repository, or if other people have access to your filesystem/backups/logs.

You need to think about about how you develop code, whom should be able to use the key, whom should be able to see the key itself, whom should definitely not be able to see the key, how your backups are managed, whom has access to your storage.....

It is impossible to provide sufficient information in a question here on SO to get an informed and definitive answer.

0
votes

At the bottom of the above answer, I've added:

    /* 
    $key will store in the database in refrence of this content and this key will use to decrypt the data as given below
    $
*/
$content = 'blahlol';
$aes = new AES_Encrypt();
$encryptedData = $aes->setData($content)->encrypt()->getEncryptedString();
$key = $aes->getKey();
echo $encryptedData;
echo '<br>';
$decryptedData = $aes->setData($encryptedData)->decrypt()->getDecryptedString();
echo $decryptedData;
//The code above outputs an encrypted string followed by "blahlol" which is my     $content variable.

//Below, I'm trying to grab the encrypted string from the database and decrypt it. However it outputs nothing
echo '<br><br><br><br>Database:<br><br>';
$sql = "SELECT * from data WHERE id = '1'";
$result = $con->query($sql);
while($rowLol = $result->fetch_assoc()) {
        echo $rowLol['data']; //Outputs encrypted string
        $aes = new AES_Encrypt($key);
$decryptedData = $aes->setData($rowLol['data'])->decrypt()->getDecryptedString();
echo $decryptedData; //Meant to output decrypted string (blahlol)
}
?>

At the top, it outputs the encrypted string of "blahlol" followed by plaintext "blahlol" after decryption. However I'm trying to decrypt it by getting the encrypted string for the database. As noted in the code, the decrypted part outputs nothing.

-1
votes

There are two way you can keep encrypted data.

  1. File
  2. Databse

If data is less you can manage encrypted data in the database and if data is large then it is good to store encrypted data in file outside the public folder. To make data more secure, use unique key to encrypt every data and save that unique key in the database including data reference value, so when you will decrypt data using referred unique key from the database.

Create php class to handle this.

<?php
class AES_Encrypt {
    /**
     * @var string 
     */
    private $key;

    /**
     * 
     * @var String 
     */
    private $string;

    /**
     *
     * @var String
     */
    private $encryptedString;

    /**
     *
     * @var String
     */
    private $decryptedString;

    /**
     * Constructor
     */
    public function __construct($key = null) {
        if (empty($key)) {
            $this->setKey(md5($this->randomStr(5)) . '.' . base64_encode(openssl_random_pseudo_bytes(32)));
        } else {
            $this->setKey($key);
        }
    }

    /**
     * 
     * @param String $key
     * @return \AES_Encrypt
     */
    public function setKey($key) {
        $this->key = $key;

        return $this;
    }

    /**
     * Return security key
     * @return string
     */
    public function getKey() {

        return $this->key;
    }

    /**
     * 
     * @param type $string
     * @return \AES_Encrypt
     */
    public function setData($string) {
        $this->string = $string;

        return $this;
    }

    /**
     * 
     * @return string
     */
    public function getData() {

        return $this->string;
    }

    /**
     * Convert encrypt string from plain
     * @return \AES_Encrypt
     */
    public function encrypt() {
        $privateKey = explode('.', $this->getKey(), 2);
        // Remove the base64 encoding from our key
        $encryption_key = base64_decode($privateKey[1]);
        // 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($this->getData(), '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 (::)
        $this->encryptedString = base64_encode($encrypted . '::' . $iv);

        return $this;
    }

    /**
     * 
     * @return string
     */
    public function getEncryptedString() {

        return $this->encryptedString;
    }

    /**
     * 
     * @return string
     */
    public function getDecryptedString() {

        return $this->decryptedString;
    }

    /**
     * Convert decrypt string
     */
    public function decrypt() {
        $privateKey = explode('.', $this->getKey(), 2);
        // Remove the base64 encoding from our key
        $encryption_key = base64_decode($privateKey[1]);
        // To decrypt, split the encrypted data from our IV - our unique separator used was "::"
        list($encrypted_data, $iv) = explode('::', base64_decode($this->getData()), 2);
        $this->decryptedString = openssl_decrypt($encrypted_data, 'aes-256-cbc', $encryption_key, 0, $iv);

        return $this;
    }

    /**
     * 
     * @param type $length
     * @return string
     */
    public function randomStr($length = 5) {
        $string = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
        $charactersLength = strlen($string);
        $str = '';
        for ($i = 0; $i < $length; $i++) {
            $str .= $string[rand(0, $charactersLength - 1)];
        }
        return $str;
    }

}

$aes = new AES_Encrypt();
$encryptedData = $aes->setData($content)->encrypt()->getEncryptedString();
$key = $aes->getKey();

/* 
    $key will store in the databse in refrence of this content and this key will use to decrypt the data as given below

*/
$aes = new AES_Encrypt($key);
$decryptedData = $aes->setData($encryptedContent)->decrypt()->getDecryptedString();