Cryptographically Secure Random number on Windows without using CryptoAPI


Historically, we always told developers not to use functions such as rand to generate keys, nonces and passwords, rather they should use functions like CryptGenRandom, which creates cryptographically secure random numbers. The problem with CryptGenRandom is you need to pull in CryptoAPI (CryptAcquireContext and such) which is fine if you’re using other crypto functions.

On a default Windows XP and later install, CryptGenRandom calls into a function named ADVAPI32!RtlGenRandom, which does not require you load all the CryptAPI stuff. In fact, the new Whidbey CRT function, rand_s calls RtlGenRandom.

The following snippet shows how to call the function.

HMODULE hLib=LoadLibrary(“ADVAPI32.DLL”);
if (hLib) {
 BOOLEAN (APIENTRY *pfn)(void*, ULONG) =
     
(BOOLEAN (APIENTRY *)(void*,ULONG))GetProcAddress(hLib,”SystemFunction036″);
 if (pfn) {
  char buff[32];
  ULONG ulCbBuff = sizeof(buff);
  if(pfn(buff,ulCbBuff)) {

   // use buff full of random goop
   
  }
 }

 FreeLibrary(hLib);
}

The good news is you can get good random numbers, without the memory overhead of pulling in all of CryptoAPI!

RtlGenRandom is documented at http://msdn.microsoft.com/library/en-us/seccrypto/security/rtlgenrandom.asp.

Comments (17)

  1. Ilya says:

    So, it is available in w2k, nice. Can you give a details on what is behind RtlGenRandom, how does it works? Something like SHA1/MD5 against the pool of entropy collected from the system events.

  2. Michael Howard says:

    There’s a full explanation (including diagrams) in Writing Secure Code 2nd, so if you can lay your hand on a copy, take a look.

    The RNG generates as specified in FIPS 186-2 appendix 3.1 with SHA-1 as the G function. With entropy from:

    The current process ID (GetCurrentProcessID).

    The current thread ID (GetCurrentThreadID).

    The ticks since boot (GetTickCount).

    The current time (GetLocalTime).

    Various high-precision performance counters (QueryPerformanceCounter).

    An MD4 hash of the user’s environment block, which includes username, computer name, and search path. MD4 is a hashing algorithm that creates a 128-bit message digest from input data to verify data integrity.

    High-precision internal CPU counters, such as RDTSC, RDMSR, RDPMC

    Low-level system information: Idle Process Time, Io Read Transfer Count, I/O Write Transfer Count, I/O Other Transfer Count, I/O Read Operation Count, I/O Write Operation Count, I/O Other Operation Count, Available Pages, Committed Pages, Commit Limit, Peak Commitment, Page Fault Count, Copy On Write Count, Transition Count, Cache Transition Count, Demand Zero Count, Page Read Count, Page Read I/O Count, Cache Read Count, Cache I/O Count, Dirty Pages Write Count, Dirty Write I/O Count, Mapped Pages Write Count, Mapped Write I/O Count, Paged Pool Pages, Non Paged Pool Pages, Paged Pool Allocated space, Paged Pool Free space, Non Paged Pool Allocated space, Non Paged Pool Free space, Free System page table entry, Resident System Code Page, Total System Driver Pages, Total System Code Pages, Non Paged Pool Lookaside Hits, Paged Pool Lookaside Hits, Available Paged Pool Pages, Resident System Cache Page, Resident Paged Pool Page, Resident System Driver Page, Cache manager Fast Read with No Wait, Cache manager Fast Read with Wait, Cache manager Fast Read Resource Missed, Cache manager Fast Read Not Possible, Cache manager Fast Memory Descriptor List Read with No Wait, Cache manager Fast Memory Descriptor List Read with Wait, Cache manager Fast Memory Descriptor List Read Resource Missed, Cache manager Fast Memory Descriptor List Read Not Possible, Cache manager Map Data with No Wait, Cache manager Map Data with Wait, Cache manager Map Data with No Wait Miss, Cache manager Map Data Wait Miss, Cache manager Pin-Mapped Data Count, Cache manager Pin-Read with No Wait, Cache manager Pin Read with Wait, Cache manager Pin-Read with No Wait Miss, Cache manager Pin-Read Wait Miss, Cache manager Copy-Read with No Wait, Cache manager Copy-Read with Wait, Cache manager Copy-Read with No Wait Miss, Cache manager Copy-Read with Wait Miss, Cache manager Memory Descriptor List Read with No Wait, Cache manager Memory Descriptor List Read with Wait, Cache manager Memory Descriptor List Read with No Wait Miss, Cache manager Memory Descriptor List Read with Wait Miss, Cache manager Read Ahead IOs, Cache manager Lazy-Write IOs, Cache manager Lazy-Write Pages, Cache manager Data Flushes, Cache manager Data Pages, Context Switches, First Level Translation buffer Fills, Second Level Translation buffer Fills, and System Calls.

    System exception information consisting of Alignment Fix up Count, Exception Dispatch Count, Floating Emulation Count, and Byte Word Emulation Count.

    System lookaside information consisting of Current Depth, Maximum Depth, Total Allocates, Allocate Misses, Total Frees, Free Misses, Type, Tag, and Size.

    System interrupt information consisting of context switches, deferred procedure call count, deferred procedure call rate, time increment, deferred procedure call bypass count, and asynchronous procedure call bypass count.

    System process information consisting of Next Entry Offset, Number Of Threads, Create Time, User Time, Kernel Time, Image Name, Base Priority, Unique Process ID, Inherited from Unique Process ID, Handle Count, Session ID, Page Directory Base, Peak Virtual Size, Virtual Size, Page Fault Count, Peak Working Set Size, Working Set Size, Quota Peak Paged Pool Usage, Quota Paged Pool Usage, Quota Peak Non Paged Pool Usage, Quota Non Paged Pool Usage, Page file Usage, Peak Page file Usage, Private Page Count, Read Operation Count, Write Operation Count, Other Operation Count, Read Transfer Count, Write Transfer Count, and Other Transfer Count.

  3. Mike Dunn says:

    hmm, I don’t see a SystemFunction036 on my Win 2K’s advapi32.dll. The numbers skip from 035 to 040.

  4. Ilya says:

    Nice. Thanks, Michael

  5. Michael Howard says:

    Did you run the code on Windows 2000? Which service pack are you using? If you still have noy joy I’ll look at it on monday.

  6. Peter Torr says:

    I like the fact that the parameters are called "RandomBuffer" and "RandomBufferLength." Maybe I should write:

    char *buff = new char[rand()];

    RtlGenRandom(buff, rand());

    <ducks>

  7. Mike Dunn says:

    D’oh, sorry I forgot to check. (I have XP and 2K on the same box, I was in XP at the time and just looking at the exports in my 2K install.) I’ll check when I get home tonight.

  8. Mike Dunn says:

    Here’s the info: Win2K pro SP3, advapi32.dll is version 5.0.2195.5385 and it doesn’t have an export SystemFunction036.

  9. AC says:

    Also on SP4+all recent security updates, dll version 5.00.2195.6876, as far as I can see there’s no SystemFunction036. There is 035 and then 040.

  10. Michael Howard says:

    So I stand corrected – this is in WinXP and later… sincere apologies for the mixup. The MSDN docs are correct, and I am wrong.

  11. El uso de los numeros al azar es importante, si es para un juego, la clase Random esta bien, pero si…