2

I have 2 unique random 256-bit keys, 1 is public, 1 is secret that need to be combined into 1 secret key.

In my search, I found that HMAC is more suited for this purpose and does not require an iteration count.

Does this mean that if PBKDF2 is used with the two input keys as the passphrase and salt, the iteration count can be set to only 1 since the passphrase is not password-based and is practically impossible to bruteforce?

3
  • 2
    PBKDF2 (and much better modern PBKDFs such as Bcrypt, Scrypt, Argon2) are used to make user passwords, which are commonly comparably low on entropy, a bit more cryptographically strong. If your secret key is not based on a user chosen password but instead is randomly generated or derived from a cryptographic key, then you have no need for PBKDF2. HMAC sounds like a better choice or maybe even HKDF.
    – n-l-i
    Commented Oct 24 at 4:18
  • 2
    I second what @n-l-i said. HMAC is also commonly used for combining keys as a dual-PRF in major Internet protocols. For example, to combine a pre-shared key or for a post-quantum hybrid key exchange. You just need to ensure that the HMAC key parameter is fixed in length and that you use a collision-resistant hash function with HMAC (e.g., SHA-256). In your case, use the public key in the message parameter. Commented Oct 24 at 17:04
  • Combining a secret key and a public key is unusual, except when combining a public key certificate (which includes a public key) and the corresponding private key per PKCS#12. And then this PKCS#12 combination is essentially a reversible concatenation + encapsulation, not a derivation of a new key as HMAC and PBKDF2 would do. Independently: a public key is not random, even if it appears to be so.
    – fgrieu
    Commented Oct 25 at 9:29

2 Answers 2

1

I have 2 unique random 256-bit keys, 1 is public, 1 is secret that need to be combined into 1 secret key.

That's weird, since we don't expect keys to be public, outsize of public key cryptography which uses asymmetric algorithms such as RSA. Usually public keys are not input to derive new keys.

In my search, I found that HMAC is more suited for this purpose and does not require an iteration count.

What you are looking for is a KDF or Key Derivation Function. There are two common KDF types: PBKDF's and KBKDF's:

  • PBKDF's such as PBKDF2, bcrypt, Argon etc. take a password or -phrase. Due to the limited entropy they require a work factor; the iteration count is the work factor parameter of PBKDF2. This can extend the work for an adversary so that the security is about 20 bits higher than before, assuming one million as iteration count.
  • KBKDF's are less well known. There are some particular ones such as HKDF, counter based KDF's from NIST and more modern KDF's build from e.g. SHAKE.

Quite often KBKDF's are not named as KDF's. Instead they are proprietary functions build on top of primitives such as HMAC. This is for instance the case of the unnamed KDF (or PRF) of TLS 1.2, which is specified directly in the TLS RFC and configured using the hash algorithm at the end of the cipher suite name. In contrast TLS 1.3 directly uses HKDF.

Does this mean that if PBKDF2 is used with the two input keys as the passphrase and salt, the iteration count can be set to only 1 since the passphrase is not password-based and is practically impossible to bruteforce?

That's a poor mans option for those that do not have direct access to a KBKDF such as HKDF. The same goes for the direct use of HMAC instead of a well-defined KDF.

EDIT: Both options would probably be considered secure as long as the secret would be set as the password or key, possibly as part of a concatenation with the public key. Using standardized algorithms is however recommended.


Personally I would try and find a HKDF implementation based on your API of HMAC and use that. If it is not available then it is best to build it yourself; HMAC is the only cryptographic primitive used for HKDF. Test vectors are included in the linked-to RFC.

The security should not rely on the "public key". I would find it more logical to use the public key as (part of) the Info parameter. The secret key would be the input keying material or IKM.

It's always wise with regards to security to include a random salt, but it depends on the use case if that's a good option.


The assumption here is that your secret key contains at least 128 bits of entropy. That's for instance the case if there are at least 128 to 245 fully random bits within that secret key.

0

Qualitatively, there are four levels of entropic secrets:

  • PIN (a few digits): very short, negligible entropy. This can be brute-forced in any offline attack, so this kind of secret is only viable if all attacks are online attacks. For example, it's ok for a smart card that will block itself after three attempts, but not for a software wallet that can be copied and attacked on a different computer.
  • Memorable password or passphrase: low, but not negligible entropy. The limits of human memory mean that brute force attacks are feasible if the calculations for each attempt are quick. This is why such secrets must be processed through key stretching functions. Key stretching functions are designed to consume significant resources for each attempt. They are also randomized through a salt, which is public but distinct for each user, to prevent mass attempts where an adversary spends significant time on brute-force calculations but those calculations are valid for many accounts at once. PBKDF2 is an example of a key stretching function.
  • High-entropy secret (of sufficient size, at least about 100 bits): high entropy, but not uniform. A typical example is the direct result of a Diffie-Hellman key agreement. Brute force attacks are not possible. However, the secret is not directly usable for cryptography because it's biased, and in some scenarios those biases matter. Also, the secret might not be the right size. To process such secrets, any key derivation function is fine. You don't need to worry about making the attacker's life more difficult, there's already enough randomness, you just need to spread it around.
  • Uniformly random secret (of sufficient size, at least about 100 bits — almost always at least 128 bits): this can be used for any purpose. You don't need any pre-processing if the secret is long enough, but you can use a key derivation function to get more secret material. (If you use a secret as the input of a KDF, don't also use it for another purpose! That could be devastating if the KDF happens to use similar mechanisms to that other purpose. Instead, generate as much KDF output as you need for all the purposes.)

What you have is a high-entropy secret: a 512-bit string S||P out of which 256 bits S are uniformly random and secret (256 bits of entropy), and 256 bits P are uniformly random but public (0 bits of entropy since it's public). Since you have a secret with 256 bits of entropy, pass it to any KDF to get as much full-entropy secret material as you need.

HMAC(S||P, \mathtt{""}) is good enough as a KDF. So is HMAC(\mathtt{""}, S||P), or HMAC(S, P), or HMAC(P, S). Even H(S||P) is good enough, where H is any well-regarded cryptographic hash such as a SHA-2 or SHA-3 variant. Considering those to be good enough relies on somewhat strong assumptions about the hash function, and limits the output to the size of the hash. For more peace of mind and more flexibility, use a “proper” KDF such as HKDF or one of the hash-based KDF from SP 800-108.

You can use PBKDF2 with the iteration count set to 1 as an ordinary KDF. It's typically more complex to implement than key derivation functions that don't have stretching capabilities. There are protocols that do that because they use PBKDF2 in stretching mode for another purpose, but I wouldn't recommend it if you aren't already using PBKDF2.

\endgroup

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.