2

I collect entropy from the following sources:

  • system_entropy = System provided crypto entropy stream (CryptGenRandom on Windows)
  • user_entropy = User-provided entropy - in a form of a byte stream of serialized random mouse movements, key strokes etc (this is manually entered by the user, similar to how TrueCrypt collects entropy)

To generate a key from these sources, is the following construct appropriate?

my_random_key = HKDF(salt, system_entropy || user_entropy)

Where HKDF is a RFC 5869 construct (both extract and expand steps, but since I don't use "info", just extract is sufficient also) based on HMAC-SHA256.

To my understanding, it should be perfectly fine to just append the user entropy to the system entropy, even under the assumption that the user entropy can be entirely controlled by an adversary, right? Because in that case, the adversary will just destroy the "user_entropy" contribution to the security of the key, but assuming the "system_entropy" is sufficient, then it's ok? In a sense, I assume the "system_entropy" to be already secure, but I want to provide "user_entropy" for additional hardening. So I just want to throw as much random junk at the HKDF as possible.

Paya
  • 189
  • 10
  • This is security theater. First, CryptGenRandom already collects entropy from mouse movements, keystroke timings, etc — and using a much more well-tuned algorithm than you are likely to. Second, if Microsoft is untrustworthy and CryptGenRandom is backdoored, you're already screwed. Just use the output of CryptGenRandom and spend your leftover time addressing attack scenarios with a higher ratio of risk vs mitigation effort. – Stephen Touset May 22 '15 at 23:04
  • 2
    @StephenTouset: I don't agree. System RNGs have been known to suffer from serious implementation errors (like the Android RNG bug) in the past, not to mention being potentially tempting targets for subversion attacks, and their correct operation is difficult if not impossible for a caller to verify. The safe approach, where possible, is to maintain your own entropy pool, and to treat the system RNG as just another potentially unreliable entropy source for it. – Ilmari Karonen May 22 '15 at 23:40
  • @StephenTouset The app is multiplatform and so CryptGenRandom is used only on Windows. I have no idea what the library uses on other platforms. The purpose is to give the users an option for additional hardening in case the library does not do a great job at using the system's native crypto RNG. In such case, the method I suggested in my question is appropriate. – Paya May 22 '15 at 23:42
  • 1
    @StephenTouset In the context of IlmariKaronen's response, I would like to mention the Dual_EC_DRBG CSPRNG backdoor. – Paya May 23 '15 at 01:18
  • Again, if you are trying to defend against an operating system that is actively working against you, you have already lost. CryptGenRandom may very well be backdoored. If it is, you have no reasonable expectation that any other function of the operating system is acting faithfully. – Stephen Touset May 24 '15 at 03:39
  • 1
    @StephenTouset Bugs and broken designs are also an option (Android's SecureRandom). Just shrugging and betting everything on MS/Google/Apple that they got it right seems ridiculous, when in fact I can do something about it with no risk of messing up (HKDF). – Paya May 24 '15 at 12:07
  • Both any new cryptographic concept added to a system and any line of cryptographic code written brings non-negligible risk of messing it up. Cryptographers strive to use the absolute minimum necessary to provide the required security to a system. – Stephen Touset May 26 '15 at 17:36

1 Answers1

2

Yes, that should be secure. It seems however that your problem lies with the secure random number generator and that you are using a KDF to overcome those. Basically you are using a KDF as key generator; no keys are derived from another / master key.

It seems more obvious to use a DRBG / CPRNG (deterministic random bit generator / cryptographically secure pseudo random number generator - there are probably more names) and seed it with random values from the system and the user. After that you can just extract the key bytes, and you would still be left with a (fast) RNG that you can reuse / reseed - something you will likely need later on.

Many API's already provide these out of the box, and usually they are pre-seeded as well, so you may just have to add your user generated entropy to the state by mixing in additional seed data. Nothing stops you from adding HKDF + OtherInfo in addition to the DRBG of course, but that is not required.

Maarten Bodewes
  • 92,551
  • 13
  • 161
  • 313
  • The following answer seems to provide the same conclusion. (linked for reference) – Paya May 23 '15 at 12:09
  • @Paya I didn't know that that answer existed, but it is nice to know that I'm being backed up by Thomas :) Your idea isn't bad or anything, but if you want to have more random numbers than just for the key (and you usually do) then a PRNG makes a bit more sense. – Maarten Bodewes May 23 '15 at 12:20
  • It depends. I don't need the "info" just for the extraction, but it seems to come in handy in my specific environment. PRG is certainly an option (as well as PRF like HMAC; and you can build PRG using HKDF anyway as mentioned in the HKDF paper), but I tend to prefer less crypto primitives rather than more, because it makes it less likely to screw up somewhere because various primitives have various assumptions and requirements. HKDF was specifically designed to be pretty much universal solution and has very few assumptions. – Paya May 23 '15 at 13:22
  • In your solution you are using a key derivation method as key generator. DRBG's, KDF's and key generators are closely related, but they differ on the details. As it seems that your issue is with the random generator, it seems more logical to replace that. Changed the answer a bit to reflect this. – Maarten Bodewes May 23 '15 at 20:24
  • Honestly I think DRBG is not what I need. The 'info' in HKDF actually turned out to be extremely useful. I would accept your answer, but the way it's written seems like I think DRBG is the correct solution, which I do not agree with for my particular case. :-) HKDF has the extremely useful property that if I use it as a generator and I loose/need just the 1000th key, then I do HKDF(key, 1000) and grab the key I need, instead of seeding a generator and skipping 999 keys. Furthermore HKDF key generation is completely parallelizable unlike (most?) DRBGs. It's like CBC vs CTR. – Paya May 25 '15 at 18:42
  • I do wonder however if there is a construction based entirely on AES, that would give me the same properties as HKDF expand phase. Something like AES-KDF(key, info, output_len) - analogy of the HKDF-Expand(key, info, output_len). The Intel CPU AES instructions are really hot. :-) – Paya May 25 '15 at 18:48
  • 1
    I have proposed an "edit" for this answer but was rejected. For that reason, I have to state here that I accepted the answer because of the "yes it is secure" statement and the hint that CSPRNG is yet another option to use. I do not agree with the rest of the first paragraph, but apparently random people who rejected my edit know better. – Paya Jun 16 '15 at 16:33
  • @Paya You can write (and accept) your own answer. You should however not substantially change other answers, such as mine. So those "random people" may even agree with your ideas, but not with the change. Of course, you may risk downvotes if your answer is not accepted by anybody else (just like I risk downvotes with my answers). – Maarten Bodewes Jun 16 '15 at 17:10
  • I could never do that, you deserve all the rep. My answer would not provide any additional information, just rephrase yours a bit (90% copy & paste). – Paya Jun 16 '15 at 18:20
  • Hmm, well, I'll upvote your comment so people will see it. Probably best to leave it at that. You can of course do whatever you want with your code. – Maarten Bodewes Jun 16 '15 at 18:25