1

I swear, this seems to be changing every time I check the MSDN documentation. When I coded my executable Microsoft was suggesting to use RtlGenRandom API to generate cryptographically strong random numbers.

Now when I'm checking documentation for RtlGenRandom, the note there suggests using CryptGenRandom instead. But then another note for CryptGenRandom states this:

Important: This API is deprecated. New and existing software should start using Cryptography Next Generation APIs. Microsoft may remove this API in future releases.

So can someone show an example in C of how to use those "Cryptography Next Generation APIs" to generate a byte array of random numbers that Microsoft recommends now?

c00000fd
  • 20,994
  • 29
  • 177
  • 400
  • 1
    There's 3 examples here: https://msdn.microsoft.com/en-us/library/windows/desktop/bb204779(v=vs.85).aspx Did you try them out? – Retired Ninja Feb 20 '18 at 00:02
  • 1
    [`BCryptGenRandom`](https://msdn.microsoft.com/en-us/library/windows/desktop/aa375458(v=vs.85).aspx) – RbMm Feb 20 '18 at 00:03
  • @RetiredNinja: Did you? – c00000fd Feb 20 '18 at 00:27
  • @RbMm: Very nice. Thank you. I guess doing `BCryptGenRandom(NULL, buffer, sizeof(buffer), BCRYPT_USE_SYSTEM_PREFERRED_RNG);` would be the way now. hah? It doesn't say anything about its cryptographic strength though. – c00000fd Feb 20 '18 at 00:29
  • Lol... I know what you mean. It only gets worse when you start working on Microsoft's mobile and phone platforms. Also see [Random numbers for Windows Phone 8 and Windows Store 8?](https://stackoverflow.com/q/36974545/608639) – jww Feb 22 '18 at 03:43

1 Answers1

8

It does not really matter, on Windows XP and later the default providers end up calling the same function. The RNG on 2000 and unpatched XP mainly use SHA1+RC4 internally and it has some security issues.

I just did some experiments on Windows 8 and this is what I found:

  • RtlGenRandom (AKA advapi32!SystemFunction036) calls CRYPTBASE!SystemFunction036 >>> bcryptPrimitives!ProcessPrng >>> bcryptPrimitives!AesRNG*.
  • CryptGenRandom calls CRYPTSP!CryptGenRandom >>> %provider%!CPGenRandom >>> CRYPTBASE!SystemFunction036. %provider% was rsaenh or dssenh in my tests but could possibly be a different implementation if you specifically ask for a 3rd-party provider.
  • BCryptGenRandom calls bcryptPrimitives!MSCryptGenRandom >>> bcryptPrimitives!GenRandomAes >>> bcryptPrimitives!AesRNG* with the BCRYPT_RNG_ALGORITHM CNG Algorithm Identifier (BCRYPT_RNG_DUAL_EC_ALGORITHM ends up in bcryptPrimitives!GenRandomDualEcc instead).

This is of course undocumented implementation details that could change but I don't really think you need to worry about which function you pick. If your target is Vista+ you can use BCrypt. CryptGenRandom will never be removed, it would break too many applications and you should pick it if you support < Vista.

Anders
  • 97,548
  • 12
  • 110
  • 164
  • Thanks for sharing your research. My implementation is basically LoadLibrary()+GetProcAddr() for newer APIs, otherwise fallback to XP ones. Hmm, interesting. I wish Microsoft documented how exactly they're using AES to generate random numbers. – c00000fd Feb 20 '18 at 02:52
  • A good encryption algorithm produces cipher text "indistinguishable from random noise". The entropy pool in the old implementation is filled with data from sources listed in a comment @ https://blogs.msdn.microsoft.com/michael_howard/2005/01/14/cryptographically-secure-random-number-on-windows-without-using-cryptoapi/ The AES implementation might use similar sources for its key & data, I did not really care so I did not step that deep into the implementation. – Anders Feb 20 '18 at 03:16
  • What bugs me the most about Microsoft implementation of crypto is that they treat it as some sort of a black box, coupled with a bunch of confusing and contradicting documentation. And the only way we can know what they're doing is by reversing it. So yeah, I appreciate your efforts! As for that link you gave from 2005, idk, man. It's an awful old for crypto. I'm sure in 2005 most of software on the market was stiff "satisfied" with calling C's `rand()` as a PRNG. – c00000fd Feb 20 '18 at 04:20
  • I also tried reading all the docs from their suggested CNG APIs, and idk. I think I'll stick with Intel's hardware-based [RDRAND and RDSEED](https://software.intel.com/en-us/blogs/2012/11/17/the-difference-between-rdrand-and-rdseed) where supported. There's more and more CPUs these days that will have support for it. It involves writing some asm code but it's worth it. Otherwise, possibly a fallback to the PRNG from a library, such as Crypto++. Otherwise WinAPIs for the sake of crypto -- still suck. Even on Win10. – c00000fd Feb 20 '18 at 04:23
  • 2
    https://crypto.stackexchange.com/questions/10486/does-microsoft-use-dual-ec-drbg-by-default both answers there answer that the RNG is SP800-90 AES-CTR-DRBG – bartonjs Feb 20 '18 at 15:39