phpencryptioninisecret-keylibsodium

PHP Storing Secrets with sodium_crypto_secretbox_keygen Key and Nonce Defeats Purpose?


For my particular PHP (8.2) Web Application I am storing keys and secrets in an .ini file outside of root in a folder /private.

I have been requested to encrypt the data in the ini file (reason stating that the php code is accessing the key details without any security measures).

$cfg = parse_ini_file('../../private/config.ini');
$my_secret_key_123 = $cfg['secret_key_123'];
$my_secret_key_345 = $cfg['secret_key_345'];

I was thinking I could just encrypt all of the data using sodium:

$key = sodium_crypto_secretbox_keygen();
$nonce = random_bytes( SODIUM_CRYPTO_SECRETBOX_NONCEBYTES );
$encrypted_result = sodium_crypto_secretbox( 'secret_key_123', $nonce, $key );
$encoded_secret_key_123 = base64_encode( $nonce . $encrypted_result );

However, if I put that encoded secret key in my .ini file and call it, I will need to have the $key and $nonce used to decrypt it:

$decoded = base64_decode($encoded_secret_key_123, false);
$nonce = mb_substr($decoded, 0, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES, '8bit');
$encrypted_result = mb_substr($decoded, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES, null, '8bit');
$plaintext = sodium_crypto_secretbox_open($encrypted_result, $nonce, $key);

So the question arises...where and how would I store the key sodium_crypto_secretbox_keygen() without also encrypting that?

Perhaps this is simply overkill and I should just encode my .ini secrets with simple base64?


Solution

  • What I have ended up doing is storing the key produced from sodium_crypto_secretbox_keygen() in a .env file.

    $sodium_key = sodium_crypto_secretbox_keygen();
    var_dump( sodium_bin2hex($sodium_key)); // store as hex
    

    Store the above output to the .env file:

    so_key = 1234567890abcdefghijklmnopqrstuvwxyz
    

    One must use the PHP library dotenv to easily load the .env file which I put outside of root in a private folder.

    require '../../private/vendor/autoload.php'; //autoloader for dotenv
    $dotenv = Dotenv\Dotenv::createImmutable('../../private/'); //location of .env file
    $dotenv->load(); //allows for $_ENV environment variable to be called
    $so_key = sodium_hex2bin($_ENV['so_key']); //dont forget this is hex 2 bin
    

    What I ended up doing was encoding all of my secret keys and stored the encoding of them in the same .env file mentioned above.

    Here are the functions I made to either encode or decode the data utilizing sodium:

    // Encode your string
    function so_encode($encode, $so_key){
        $nonce = random_bytes( SODIUM_CRYPTO_SECRETBOX_NONCEBYTES );
        $encrypted_result = sodium_crypto_secretbox( $encode, $nonce, $so_key );
        $encoded = base64_encode( $nonce . $encrypted_result );
        return $encoded;
    }
    
    // Decode your string
    function so_decode($so_encoded,$so_key){
        $decoded = base64_decode($so_encoded, false);
        $nonce = mb_substr($decoded, 0, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES, '8bit');
        $encrypted_result = mb_substr($decoded, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES, null, '8bit');
        $plaintext = sodium_crypto_secretbox_open($encrypted_result, $nonce, $so_key);
        return $plaintext;
    }