Peter Gutmann (pgut001@cs.auckland.ac.nz)
Tue, 26 Jan 1999 15:38:38 (NZDT)
For the CSPRNG I described at the Usenix security symposium in January I'm
currently seeding the entropy pool under Windows NT using the NT performance
counters. Over the last year or so I've found more and more problems with this
approach which arise from the fact that the NT function which obtains this
information, RegQueryValueEx(), is so incredibly flaky that it's just too
dangerous to use to obtain randomness. First of all, here's the code:
PPERF_DATA_BLOCK pPerfData;
int cbPerfData = PERFORMANCE_BUFFER_SIZE;
pPerfData = ( PPERF_DATA_BLOCK ) malloc( cbPerfData );
while( pPerfData != NULL )
{
dwSize = cbPerfData;
status = RegQueryValueEx( HKEY_PERFORMANCE_DATA, "Global", NULL,
NULL, ( LPBYTE ) pPerfData, &dwSize );
if( status == ERROR_SUCCESS )
{
if( !memcmp( pPerfData->Signature, L"PERF", 8 ) )
addRandomBuffer( ( BYTE * ) pPerfData, dwSize );
free( pPerfData );
pPerfData = NULL;
}
else
if( status == ERROR_MORE_DATA )
{
cbPerfData += PERFORMANCE_BUFFER_STEP;
pPerfData = ( PPERF_DATA_BLOCK ) realloc( pPerfData, cbPerfData );
}
}
All this does is try to read the data using a gradually-increasing buffer size
until the read succeeds. The first problem is that the code in
RegQueryValueEx() which estimates the amount of memory required to return the
performance counter information isn't very accurate, since it always returns a
worst-case estimate which is usually nowhere near the actual amount required.
For example it may report that 128K of memory is required, but only return 64K
of data.
The next problem is that in some environments the call to RegQueryValueEx() can
produce an access violation at some random time in the future, adding a short
delay after the code block above makes the problem go away. This problem is
extremely difficult to reproduce, I haven't been able to get it to occur
despite running it on a number of machines.
The worst problem, which has now been reproduced on several machines, is that
RegQueryValueEx() may at times hang indefinitely. There's no pattern to this,
on some machines it never hangs, on some it hangs sometimes, and on others it
hangs all the time. It doesn't seem to chew up much memory as it's doing
whatever it's doing, but the longer you leave it, the longer an environment
like VC++ takes to recover when you kill the program.
A low-level memory checker indicated buffer overflows inside the NT kernel when
this function was called (for example ExpandEnvironmentStrings() in
KERNEL32.DLL, called an interminable number of calls down inside
RegQueryValueEx(), was overwriting memory (it wrote twice the allocated size of
a buffer to a buffer allocated by the NT kernel)).
My conclusion is that NT's RegQueryValueEx() function is too buggy and unstable
to be useful for gathering entropy on an NT machine, leaving NT without any
serious source of entropy for a CSPRNG. There's an alternative interface, the
Performance Data Helper (PDH) interface, but this is extremely clunky to use,
requires individual setup of counter reads via hardcoded registry paths and
other bletcherousness, and may not be available on all versions of NT (the docs
don't mention when PDH.DLL appeared, but I don't remember it in pre-4.0
versions).
Does anyone know of any alternative entropy sources under NT apart from the
relatively lightweight ones I already use (thread times, window positions, that
sort of thing)?
Peter.
The following archive was created by hippie-mail 7.98617-22 on Sat Apr 10 1999 - 01:18:05