Reusing PBKDF2 salt for AES/GCM as IV: dangerous?
Asked Answered
H

1

5

I'm developing an encryption utility class to be reused for common operations.

A very common case is to encrypt a plaintext with a user-provided password.
In this case, I'm using PBKDF2 to derive a valid AES key, then use it in GCM mode to encrypt the plaintext.

Some code:

// IV_LEN = 96
// ITERATIONS = 1000 ~ 4000
// KEY_LEN = 128 ~ 256
// TAG_LEN = 128
public static String encrypt(byte[] plain, char[] password) throws GeneralSecurityException
{
    SecureRandom rng = SecureRandom.getInstanceStrong();
    byte[] iv = new byte[IV_LEN / 8];
    rng.nextBytes(iv);

    SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA512");
    SecretKey derivedKey = factory.generateSecret(new PBEKeySpec(password, iv, ITERATIONS, KEY_LEN));
    SecretKey secretKey = new SecretKeySpec(derivedKey.getEncoded(), "AES");

    Cipher c = Cipher.getInstance("AES/GCM/NoPadding");
    c.init(Cipher.ENCRYPT_MODE, secretKey, new GCMParameterSpec(TAG_LEN, iv));

    byte[] encrypted = c.doFinal(plain);

    Encoder encoder = Base64.getUrlEncoder().withoutPadding();

    return encoder.encodeToString(iv) + ":" + encoder.encodeToString(encrypted);
}

Currently, I'm using the PBKDF2 salt (96 bit - SecureRandom) also as the IV for AES/GCM encryption.

Both the salt and IV can be public, but they shouldn't be reused.

Is it to be understood that they shouldn't be reused within the same Feature/Service/Algorithm, or that they shouldn't be reused anywhere?

It's very easy to modify this method to generate different salt and IV, but is there a reason to do it?

Thanks

Hollands answered 9/2, 2018 at 16:2 Comment(9)
Is there any reason not to do it?Henequen
@Henequen Actually, no - It's just morbid curiosity... and the returned record is some byte shorter! :)Hollands
I would strongly recommend that you use a standard cryptographic message format, like CMS (PKCS #7), hopefully implemented by some well-reviewed and actively maintained library. If you do, it will carry parameters for both the content encryption cipher and the password-based key derivation. You won't save any bytes this way, but you are likely to have better security.Henequen
@Henequen thanks for the suggestion. Nevertheless there's not much on Java CMS PBE around. I found only some basic examples using asymmetric keys with BouncyCastle. I'll deepen.Hollands
@Henequen The problem with CMS (PKCS #7), presumably RFC 5084, is that the RFC is less than user-friendly and uses ASN.1. Do you have a better user oriented reference and examples? Without better information the uptake is going to be low.Longevity
@zaph: Agreed, PKCS#7 and its profiles (e.g. CMS) are disasters. I think you should write an RFC for a simple, useful, and secure message format and that doesn't try to be everything to everybody.Mateo
@James "I think you should write" Well, I do not have the experience or credentials to do that, you would be a much better candidate. 😉Longevity
@zaph: Too late, I nominated you. :)Mateo
@JamesKPolk Perhaps something like the following probably pulling some concepts from RFC 5084 and the like: { algorithm:{ name: mode: key_size: block_size: } mode: { name initializer } padding: { name: } key_derivation: { name: key: count: } authentication: { hash_name: key_method: } additional: { user defined key/value fields } } data But that is unwieldy for encryption just a block or two. Now your turn.Longevity
D
10

Note that you may not need to re-generate a random IV as long as you change the salt and therefore the resulting key. If you do not change the salt each time you (re-)encrypt then you do need a separate IV or you may leak information to an adversary.

You can keep the salt and IV the same. But it is generally easier to derive the IV together with the key from the password and salt. If you use PBKDF2 with a SHA-512 hash this is easy: just take 128, 192 or 256 bits of AES key from the resulting hash and then take another 128 subsequent bits as IV and use that.

If you need multiple keys or if you use a smaller hash then you may need to derive more keys from the result of PBKDF2. In that case it is best to mark the result of PBKDF2 as a master secret and perform N key derivations from it, one for each key and one for the IV. You could use e.g. HKDF for this, which Bouncy Castle has an implementation of (for which I provided the initial source code).

Dovecote answered 10/2, 2018 at 0:55 Comment(1)
So it should be safe. Actually, this method uses a one-time salt/iv and only one derived aes-key to encrypt a small message. None of these are reused/reusable, since the salt/iv is random-generated and aes-key is derived from random-salt/iv. Thanks for the suggestions: I didn't thought I can use part of derived key as aes-key and part as IV, it's simple and smart. Also I'll keep in mind HKDF slave keys in multi-key situations. ThanksHollands

© 2022 - 2025 — McMap. All rights reserved.