Storing values under different keys (e.g. during key rotation) If you are encrypting some secrets (database passwords, access tokens, etc).

When it comes to key rotation, you'll need to store those encrypted values twice, for a short period of time (under the old and new keys).

Could the encrypted secrets be stored in two files named after the hash of their keys? maybe sha256?

Or could those file names (if known) be used in a malicious way? perhaps making it easier to determine the key values?

An alternative would be to use the keys to encrypt a known plain-text value, and use that for the file names.

I'm currently considering using libsodium, and "IETF ChaCha20-Poly1305" (aead_chacha20poly1305_ietf), to encrypt the secrets.



Why I'm not using 'secrets.new' and 'secrets.old'...

This will be used for some websites, where the script running will simply be given a key to decrypt the secrets (via an environment variable), I'd like to avoid having to also say if it's the new or old key.

Secondly, lets assume the website also has this security vulnerability:

&lt;?php

    $path = '/path/to/file/' . $_GET['file'];

    readfile($path);

?&gt;


It might not be that obvious, but the attacker won't know what the file will be called if it's based on the key (you see a similar thing with the Firefox profile directory).



As a very rough implementation:

&lt;?php

//--------------------------------------------------
// Functions

    function secrets_set($key, $secrets) {

        $nonce = random_bytes(SODIUM_CRYPTO_AEAD_CHACHA20POLY1305_IETF_NPUBBYTES);

        $encrypted = sodium_crypto_aead_chacha20poly1305_ietf_encrypt(
                json_encode($secrets),
                $nonce,
                $nonce,
                $key
            );

        $name = hash('sha256', $key);

        $path = SECRETS_FOLDER . '/' . $name . '-' . bin2hex($nonce);

        file_put_contents($path, $encrypted);

    }

    function secrets_get($key) {

        $name = hash('sha256', $key);

        $prefix = SECRETS_FOLDER . '/' . $name . '-';
        $path = NULL;
        $nonce = NULL;
        $secrets = NULL;

        foreach (glob($prefix . '*') as $match) {
            if (($pos = strrpos($match, '-')) !== false) {
                $path = $match;
                $nonce = hex2bin(substr($match, ($pos + 1)));
            }
        }

        if ($path) {

            $secrets = file_get_contents($path);

            $secrets = sodium_crypto_aead_chacha20poly1305_ietf_decrypt(
                        $secrets,
                        $nonce,
                        $nonce,
                        $key
                    );

            $secrets = json_decode($secrets, true);

        }

        return $secrets;

    }

//--------------------------------------------------
// Store

    $key1 = sodium_crypto_aead_chacha20poly1305_ietf_keygen();

    secrets_set($key1, [
            'database' =&gt; 'u8syTtAvNWJbhwMNdFdRsfxJY',
            'api_key1' =&gt; 'y9f82wZdkahEPsyjXQAmy6nPh',
            'api_key2' =&gt; 'YtMp4pHR9EbHbGJXgRiniQixU',
        ]);

//--------------------------------------------------
// Get

    print_r(secrets_get($key1));

//--------------------------------------------------
// Re-key

    $key2 = sodium_crypto_aead_chacha20poly1305_ietf_keygen();

    secrets_set($key2, secrets_get($key1));

    print_r(secrets_get($key1));
    print_r(secrets_get($key2));

    // When $key1 is no longer in use, delete the old file.

?&gt;
ChaCha20 is a stream cipher, therefore, knowledge can be used. Let see what one can do.


  When it comes to key rotation, you'll need to store those encrypted values twice, for a short period of time (under the old and new keys).


This means that the attacker has a chance to see these $C_1 = P\oplus K_1$ and $C_2 = P\oplus K_2$. X-oring these two ciphertexts;

$$P\oplus K_1 \oplus P\oplus K_2 = K_1 \oplus K_2$$ results the x-or of the keys.

In other words, the attacker could get information about the X-or of new and old keys. As longs as the keys are select independently and uniformly from a good entropy source, this will give no information to the attacker.

Note that IV reuse under the same key will reveal information by crib dragging.

$$P_1\oplus K \oplus P_2\oplus K = P_1 \oplus P_2$$ this can ve exploited by crib-dragging.


  Could the encrypted secrets be stored in two files named after the hash of their keys? maybe sha256?


Using hash of the keys give additional information for the attacker. Today, or maybe in a foreseeable this cannot be exploited, however, don't do this. Just use the file name with .old .new extensions during the operation.


  Or could those file names (if known) be used in a malicious way? perhaps making it easier to determine the key values?


Already pointed above that the knowledge of the old and new file doesn't reveal the keys. 


  An alternative would be to use the keys to encrypt a known plain-text value, and use that for the file names.


This is fine.