/**************************************************************************** * * * Tandem Randomness-Gathering Code * * Copyright Peter Gutmann 2002-2004 * * * ****************************************************************************/ /* This module is part of the cryptlib continuously seeded pseudorandom number generator. For usage conditions, see random.c */ /* Define the following to print diagnostic information on where randomness is coming from */ /* #define DEBUG_RANDOM */ /* General includes */ #include "crypt.h" /* OS-specific includes */ #include #include /* The size of the intermediate buffer used to accumulate polled data */ #define RANDOM_BUFSIZE 4096 /* The number of processes per CPU that we fetch attributes for. We set an upper limit on this to make sure that we don't take too much time doing it */ #define NO_PROCESSES 50 /* The CPU attributes that we fetch. This typically yields 150 words of attribute data */ static const short int cpuAttrList[] = { 2, /* INT: Processor type */ 7, /* INT_32: Swappable pages */ 8, /* INT_32: Free pages */ 9, /* INT_32: Current locked pages */ 11, /* INT_32: Max.locked memory pages */ 12, /* INT_32: No.page faults */ 13, /* INT_32: Scans per memory manager call */ 14, /* INT_32: No.mem manager scans */ 15, /* INT_32: Page fault frequency indicator */ 16, /* INT_32: Paging queue length */ 18, /* FIXED: Wall clock time */ 19, /* FIXED: CPU time */ 20, /* FIXED: Idle time */ 21, /* FIXED: Interrupt time */ 22, /* INT: Process queue length */ 23, /* INT_32: No.dispatch interrupts */ 24, /* INT[]: Process Control Blocks (PCBs) in low PINs */ 25, /* INT[]: Process Control Blocks (PCBs) in high PINs */ 26, /* INT_32[]: Time List Elements (TLEs) */ 27, /* INT_32[]: Process Time List Elements (TLEs) */ 28, /* INT: No.breakpoints currently set */ 29, /* FIXED: Time spent in message sends */ 35, /* INT_32[24]: Interrupt count */ 36, /* FIXED: Disk cache hits */ 37, /* FIXED: Disk I/Os */ 38, /* INT,INT,/* FIXED: Processor queue state */ 39, /* INT,INT,/* FIXED: Memory queue state */ 40, /* INT_32: IPC sequenced messages */ 41, /* INT_32: IPC unsequenced messages */ 42, /* INT_32: Correctable memory errors */ 43, /* INT_32: VM pages created */ 44, /* FIXED: Time spent in interpreter (for NSR-L CPUs) */ 45, /* INT_32: Interpreter transitions (for NSR-L CPUs) */ 46, /* INT_32: Transactions since Measure product started */ 50, /* FIXED: Time in accelerated mode (for TNS/R CPUs) */ 58, /* INT_32: Kernel segments in use */ 59 /* INT_32: Maximum segments used */ }; #define NO_CPU_ATTRS ( sizeof( cpuAttrList ) / sizeof( short int ) ) /* The process attributes that we fetch. This typically yields 80 words of attribute data */ static const short int procAttrList[] = { 1, /* INT: Creator access ID */ 2, /* INT: Process access ID */ 6, /* INT[10]: gmom process handle */ 7, /* INT: Job ID */ 8, /* INT: Process subtype */ 10, /* INT: Process state */ 11, /* INT[2]: System process type */ 15, /* INT: Process list */ 28, /* INT: Process type */ 30, /* FIXED: Process time */ 31, /* INT: Wait state */ 32, /* INT: Process state */ 35, /* INT: Context switches */ 41, /* INT: Process file security */ 42, /* INT: Current priority */ 43, /* INT: Initial priority */ 44, /* INT: Remote creator */ 45, /* INT: Logged-on state */ 47, /* INT: Prim. or sec.in process pair */ 48, /* INT: Process handle */ 53, /* FIXED: Creation timestamp */ 54, /* INT: No resident pages */ 55, /* INT_32: Messages sent */ 56, /* INT_32: Messages received */ 57, /* INT: Receive queue length */ 58, /* INT: Receive queue max.length */ 59, /* INT_32: Page faults */ 63, /* INT: Stop mode */ 64, /* INT: Stop request queue */ 72, /* INT: Logon flags and states */ 73, /* INT: Applicable attributes */ 76, /* INT_32: Curr.process file segment (PFS) size */ 77, /* INT_32: Max.process file segment (PFS) extent */ 102, /* INT_32: Base addr.of main stack */ 103, /* INT_32: Current main stack size */ 104, /* INT_32: Max.main stack extent */ 105, /* INT_32: Base addr.of privileged stack */ 106, /* INT_32: Current privileged stack size */ 107, /* INT_32: Max.privileged stack extent */ 108, /* INT_32: Base addr. of global data */ 109, /* INT_32: Size of global data */ 110, /* INT_32: Base addr.of native heap */ 111, /* INT_32: Current native heap size */ 112 /* INT_32: Max.native heap extent */ }; #define NO_PROC_ATTRS ( sizeof( procAttrList ) / sizeof( short int ) ) /* Get a list of process IDs of all running processes */ static int getProcessList( const short int cpuNo, short int *pidBuffer, const short int pidBufSize ) { const static short int retAttrList[] = { 38 }; /* Process ID */ const static short int srchAttrList[] = { 9 }; /* Minimum priority */ const static short int srchValList[] = { 0 }; /* Priority >= 0 */ short int error, pin = 0, noAttrs; /* Get a list of active processes by searching for all processes with a minimum priority (attribute 9) >= 0, returning a list of all process IDs. The search can return error code 7 (no more matches) if we run out of processes before we run out of buffer space, this isn't an error since we still got some matches */ error = PROCESS_GETINFOLIST_( cpuNo /* CPU no.*/ ,&pin /* Process ID */ , /* Node name */ , /* Node name length */ , /* Process handle */ ,( short int * ) retAttrList /* Attrs.to read */ ,1 /* No.attrs.to read */ ,pidBuffer /* Returned attrs.*/ ,pidBufSize /* Ret.attrs.buffer size */ ,&noAttrs /* No.returned attrs.*/ , /* Error info */ ,2 /* Find as many as will fit */ ,( short int * ) srchAttrList /* Attrs.to search for */ ,1 /* No.attrs.to search for */ ,( short int * ) srchValList /* Attr.value to search for */ ,1 /* No.attr.values */ ); return( ( error == 0 || error == 7 ) ? noAttrs : 0 ); } /* Get various quick pieces of info */ void fastPoll( void ) { RANDOM_STATE randomState; BYTE buffer[ RANDOM_BUFSIZE + 8 ]; long long totalTime, busyTime, intTime, idleTime; _cc_status cc; short int value, error; int quality = 0; initRandomData( randomState, buffer, RANDOM_BUFSIZE ); /* CPU usage info */ cc = CPUTIMES( /* Local CPU */ , /* Local system */ ,&totalTime /* Wall clock time */ ,&busyTime /* CPU time */ ,&intTime /* Interrupt time */ ,&idleTime /* Idle time */ ); if( _status_eq( cc ) ) { addRandomData( randomState, &totalTime, sizeof( long long ) ); addRandomData( randomState, &busyTime, sizeof( long long ) ); addRandomData( randomState, &intTime, sizeof( long long ) ); addRandomData( randomState, &idleTime, sizeof( long long ) ); quality = 2; } /* Message queue info */ error = MESSAGESYSTEMINFO( 4 /* Messages in rcv.queue */ ,&value /* No.messages */ ); if( error == 0 ) { addRandomValue( randomState, value ); quality++; } error = MESSAGESYSTEMINFO( 5 /* Messages in send.queue */ ,&value /* No.messages */ ); if( error == 0 ) { addRandomValue( randomState, value ); quality++; } /* Runtime of current process in microseconds */ totalTime = MYPROCESSTIME(); addRandomData( randomState, &totalTime, sizeof( long long ) ); /* Flush any remaining data through */ #ifdef DEBUG_RANDOM printf( "fastPoll: quality = %d.\n", quality ); #endif /* DEBUG_RANDOM */ endRandomData( randomState, quality ); } /* Enumerate all processes running on all CPUs and fetch the statistics that are likely to be high-entropy */ void slowPoll( void ) { RANDOM_STATE randomState; BYTE buffer[ RANDOM_BUFSIZE + 8 ]; const long cpuStatus = PROCESSORSTATUS() & 0xFFFFUL; long cpuStatusMask; short int cpuNo; int attrCount = 0; initRandomData( randomState, buffer, RANDOM_BUFSIZE ); /* Enumerate all available CPUs. Although the docs indicate that PROCESSORSTATUS() starts numbering CPUs from bit 0, it actually appears to number them from bit 15 */ for( cpuStatusMask = 0x8000, cpuNo = 0; \ cpuStatusMask > 0; \ cpuStatusMask >>= 1, cpuNo++ ) { short int pidBuffer[ NO_PROCESSES + 8 ]; short int noAttrs, error; int i, noProcesses; /* If this CPU isn't available, continue */ if( !( cpuStatusMask & cpuStatus ) ) continue; #ifdef DEBUG_RANDOM printf( "Getting info for CPU #%d.\n", cpuNo ); #endif /* DEBUG_RANDOM */ /* Get status info for this CPU */ error = PROCESSOR_GETINFOLIST_( /* Node name */ , /* Node name length */ ,cpuNo /* CPU no.*/ ,( short int * ) cpuAttrList /* Attrs.to read */ ,NO_CPU_ATTRS /* No.attrs.to read */ ,( short int * ) buffer /* Returned attrs.*/ ,RANDOM_BUFSIZE / sizeof( short int ) /* Ret.attrs.buffer size */ ,&noAttrs /* No.returned attrs.*/ ); if( error == 0 ) { #ifdef DEBUG_RANDOM printf( "PROCESSOR_GETINFOLIST returned %d attributes.\n", noAttrs ); #endif /* DEBUG_RANDOM */ addRandomData( randomState, buffer, noAttrs * sizeof( short int ) ); attrCount += noAttrs / 2; } /* Get status info for the first NO_PROCESSES processes on this CPU */ noProcesses = getProcessList( cpuNo, pidBuffer, NO_PROCESSES ); if( noProcesses <= 0 ) { /* If the process-list read fails for some reason, we can still get info for at least the first two processes, which are always present */ noProcesses = 2; pidBuffer[ 0 ] = 0; pidBuffer[ 1 ] = 1; } for( i = 0; i < noProcesses; i++ ) { short int pin = pidBuffer[ i ]; error = PROCESS_GETINFOLIST_( cpuNo /* CPU no.*/ ,&pin /* Process ID */ , /* Node name */ , /* Node name length */ , /* Process handle */ ,( short int * ) procAttrList /* Attrs.to read */ ,NO_PROC_ATTRS/* No.attrs.to read */ ,( short int * ) buffer /* Returned attrs.*/ ,RANDOM_BUFSIZE / sizeof( short int ) /* Ret.attrs.buffer size */ ,&noAttrs /* No.returned attrs.*/ ); if( error == 0 ) { #ifdef DEBUG_RANDOM printf( "PROCESS_GETINFOLIST returned %d attributes for " "process %d.\n", noAttrs, pin ); #endif /* DEBUG_RANDOM */ addRandomData( randomState, buffer, noAttrs * sizeof( short int ) ); attrCount += max( noAttrs / 5, 10 ); } } } /* Flush any remaining data through. Quality = attrCount */ endRandomData( randomState, min( attrCount, 100 ) ); }