Search code examples
c#.netencryptionencryption-symmetric

Downsides to Using the Same Value for Key and IV?


I am implementing some classes for .NET that (among other things) simplify encryption and decryption.

My current algorithm creates an 8-byte salt, and uses that salt with the password to generate both the key and IV. I then store the salt, unencrypted, with my encrypted data.

This is nice because the salt appears to always be 8 bytes and that's all the overhead it adds to my encrypted data. However, is there any downside to using the same value for both my key and IV? Is there a better way?

Relevant code:

SymmetricAlgorithm algorithm = CreateAlgorithm();
byte[] salt = CreateSalt();
byte[] keyBytes = DeriveBytes(salt, algorithm.KeySize >> 3);
byte[] ivBytes = DeriveBytes(salt, algorithm.BlockSize >> 3);

Supporting code:

private static readonly int SaltLength = 8;

internal byte[] CreateSalt()
{
    byte[] salt = new byte[SaltLength];
    using (RNGCryptoServiceProvider generator = new RNGCryptoServiceProvider())
    {
        generator.GetBytes(salt);
    }
    return salt;
}

public byte[] DeriveBytes(byte[] salt, int bytes)
{
    Rfc2898DeriveBytes derivedBytes = new Rfc2898DeriveBytes(Password, salt, 1000);
    return derivedBytes.GetBytes(bytes);
}

Solution

  • OK, as long as you use a new, randomly created salt for each message, you are close to what I might do. The random salt means the IV will change with each new message, and this means that the exact same message will be different crypto-text each transmission. All good. The one thing I would change if I were you is instead of using DeriveBytes to get the key and then to get the IV, I would have DeriveBytes give a set of bytes the size of the key and IV together, then split them and use them separately. The IV should not have to be secret from anyone. The key must be. So if you DeriveBytes once from the same salt and password, then split those bytes into key and IV, the attacker is still no closer to knowing the key after looking at the IV than he was before.

    Alternatively, you could use a nonce to create a known permutation between the IV bytes and the key bytes. For example, excuse my pseudocode:

    IV = DeriveBytes(salt + password + "IV")
    key = DeriveBytes(salt + password + "key")
    

    Either way is secure. But I would just DeriveBytes on, say, 32 bytes and then use 16 of them for the IV and 16 of them for the key. There is no information in the first 16 bytes that will help an attacker calculate the next 16 bytes.