10

I am developing a platform that uses several secret keys for several usages: key1 for hashing passwords (using pbkdf2-hmac-sha256), key2 to generate non-repeating unpredictable uuids (using aes-128 and a counter), etc.

Instead of storing different keys, I thought to generate them from a single key, i.e.:

key1 = HMAC(primary_key, "key1");
key2 = HMAC(primary_key, "key2");
...

Is there any critical flaw in doing that? Is this programming pattern common? Generating the keys separately obviously gives a small advantage that there are no mathematical dependencies between the keys. However, from what I understand even if an attacker finds key1 he will not be able to find primary_key or key2, right?

Thanks

Oren
  • 243
  • 2
  • 5
  • 4
    Take a look at HKDF. It's a standardized KDF, pretty similar to what you're doing. – CodesInChaos Jan 14 '15 at 16:31
  • Great! I am actually following a very similar code to http://webee.technion.ac.il/~hugo/kdf (figure 1): PRK=primary_key (I use a stored value instead of calculating it from XTS, SKM), CTXInfo="key1","key2",..., and I do not concatenate the CTXInfo with an index since I do not need long results (I am using HMAC-SHA256 and I do not need keys longer than 256 bit - so I never need to calculate beyond K(1)). – Oren Jan 14 '15 at 16:50

1 Answers1

2

Short answer: yes you are right and you can do this.

To be on the safe side however, you must ensure not to lower the HMAC function security by using it properly and not putting wrong expectation on the function used.

By design HMAC functions expects one parameter to be a secret key, and the other being a message which could be public (you can find more information here and there). This means that the arguments are not be freely interchangeable, the exact order depending on the language used.

A secret key is a key:

  • Which is composed of computer chosen random characters,
  • Whose minimum length is the length of the resulting hash,
  • Which is never known by the remote user, even a part of it,
  • Which cannot be controlled or influenced in any way by the remote user.

Depending on your actual need and implementation, all parameters you will provide to the HMAC function may not be usable as a secret key:

  • primary_key might be a service or domain name for which you will need to derive several keys, in which case it might be a public string accessible to the end-user,
  • keyn (key1, key2, etc.) may also be a predictable string corresponding for instance to the internal service for which the key need to be generated.

Applied to your question, we have then the following possibilities:

  • None of the parameters can be considered as a truly secure key but one of them is a password or equivalent: if your primary_key is a user provided password (ie. a potentially human generated random string), you can remain safe by using a password dedicated hash function. Such primary_key may be vulnerable to dictionary attacks & co., but this threat will be mitigated by the use of a proper hash function at the expense of the application performance (such hash functions are designed to be slow).
  • None of the parameters can be considered as a truly secure key and they do not even include a password: an example of such situation would be if primary_key reflects or is deduced from user's provided domain name and keyn contains the name of the service or server (or is deduced from such info) for which the final key will be generated. Then consider your system as flawed, end of story. Your system is wrong and not secure.
  • One of these parameters can be considered as a secure key: pay attention to pass this parameter through the proper argument where the secret key is expected by the HMAC function. Not doing so may impair the cryptographic strongness of the HMAC function. For instance, let's say that primary_key is a service or domain name, while keyn is a secure key, compared with your question you may need to revert your arguments: key1 = HMAC("secret_key_1", primary_key);, refer to your language documentation in case of doubt,
  • Both of these parameters can be considered as secure keys: Then you have the highest security you could expect from this scheme, the arguments can be passed in any order without increasing or decreasing the security (the resulting keys will be obviously different but with the same security properties).

As a side note, HMAC RFC also mentions the possibility to truncate the resulting hash to reduce the information available to an attacker who would try to deduce primary_key starting from a hash. The same RFC admits however that while some research "show some analytical advantages of truncating the output of hashed-based MAC functions", "the results in this area are not absolute". As far as your initial keys are secure, I have the personal feeling that you may have more to loose in such truncation due to shorter resulting keys. In all case, this RFC recommends to keep the leftmost part of the resulting hash and to keep at least half of it.

WhiteWinterWolf
  • 19,142
  • 4
  • 59
  • 107