home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / crypl200.zip / LIB_RAND.C < prev    next >
Text File  |  1996-10-13  |  57KB  |  1,541 lines

  1. /****************************************************************************
  2. *                                                                            *
  3. *                          cryptlib Randomness Routines                        *
  4. *    Copyright Peter Gutmann, Matt Thomlinson, Blake Coverett, Paul Kendall,    *
  5. *                    Chris Wedgwood, and Brian Warner 1995-1996                *
  6. *                                                                            *
  7. ****************************************************************************/
  8.  
  9. /* This code probably needs more work - I'm not sure how thread-safe or
  10.    reentrant the whole thing is, especially under Unix, and the way the
  11.    weighting of the gathered randomness is handled under Unix probably needs
  12.    work as well - it's a bit pessimistic on some systems */
  13.  
  14. #include <ctype.h>
  15. #include <stdio.h>
  16. #include <stdlib.h>
  17. #include <string.h>
  18. #include <time.h>
  19. #include "crypt.h"
  20. #ifdef INC_ALL
  21.   #include "sha.h"
  22. #else
  23.   #include "hash/sha.h"
  24. #endif /* Compiler-specific includes */
  25.  
  26. /* The size of the random byte pool and the allocated size, which allows
  27.    for the overflow created by the fact that the SHA blocksize isn't any
  28.    useful multiple of a power of 2 */
  29.  
  30. #define RANDOMPOOL_SIZE            256
  31. #define RANDOMPOOL_ALLOCSIZE    ( ( RANDOMPOOL_SIZE + SHA_DIGESTSIZE - 1 ) / SHA_DIGESTSIZE ) * SHA_DIGESTSIZE
  32.  
  33. /* The buffer containing the random byte pool.  This isn't allocated until
  34.    needed because the allocation strategy may be changed through
  35.    cryptIoctl().
  36.  
  37.    Since the slow poll executes in the background, it can cause
  38.    synchronisation problems when a cryptAddRandom() or fast poll are
  39.    executed when a slow poll is in progress.   Under Win32 a critical section
  40.    is used to serialise access when adding data to the random pool.  The
  41.    synchronisation calls protect threadSafeAddRandomBuffer() and the
  42.    appropriate fastPoll() function.  For this reason fastPoll() must call
  43.    addRandmomBuffer (the low-level variant).
  44.  
  45.    Any functions added to lib_rand.c which call addRandomLong and
  46.    addRandomWord should enter the critical section as appropriate (as
  47.    fastPoll() does) */
  48.  
  49. #ifdef __WIN32__
  50.   #define THREADVAR volatile
  51. #else
  52.   #define THREADVAR
  53. #endif /* __WIN32__ */
  54.  
  55. static BYTE *randomPool;            /* Random byte pool */
  56. static THREADVAR int randomWritePos;/* Current write position in the pool */
  57. static THREADVAR int randomReadPos;    /* Current read position in the pool */
  58. static THREADVAR int randomStatus;    /* Wether there's any randomness in the pool */
  59.  
  60. #ifdef __WIN32__
  61.  
  62. static CRITICAL_SECTION randProt;
  63. volatile HANDLE threadID = NULL;    /* Thread ID, set by the thread */
  64. HANDLE threadEvent = NULL;            /* Thread event handle, used to signal
  65.                                        thread termination */
  66. #endif /* __WIN32__ */
  67.  
  68. /****************************************************************************
  69. *                                                                            *
  70. *                        Random Pool Management Routines                        *
  71. *                                                                            *
  72. ****************************************************************************/
  73.  
  74. /* The SHA transformation, taken from the MDC/SHS code.   */
  75.  
  76. void SHATransform( LONG *digest, LONG *data );
  77.  
  78. /* Stir up the data in the random buffer.  Given a circular buffer of length
  79.    n bytes, we use SHA to hash the 20 bytes at n with the 64 bytes at
  80.    n...n + 64 as the input data block.  Then move on to the next 20 bytes
  81.    until the entire buffer has been mixed.  This carries 512 bits of
  82.    randomness along with it, and wraps around the entire buffer.  We don't
  83.    bother with SHA data endianess-adjustment since we're not really
  84.    interested in the final output values, as long as they're well-mixed */
  85.  
  86. static void mixRandomPool( void )
  87.     {
  88.     int i;
  89.  
  90.     /* Stir up the entire pool */
  91. #ifdef _BIG_WORDS
  92.     for( i = 0; i < RANDOMPOOL_SIZE; i += SHA_DIGESTSIZE )
  93.         {
  94.         LONG digestLong[ SHA_DIGESTSIZE / 4 ];
  95.         LONG inputBuffer[ SHA_DATASIZE / 4 ];
  96.         BYTE *digestPtr;
  97.         int digestCount, j;
  98.  
  99.         /* Copy SHA_DATASIZE bytes from the circular buffer into the hash
  100.            data buffer, hash the data, and copy the result back into the
  101.            random pool */
  102.         for( j = 0; j < SHA_DATASIZE; j += 4 )
  103.             inputBuffer[ j / 4 ] = \
  104.                 ( ( LONG ) randomPool[ ( i + j ) % RANDOMPOOL_SIZE ] << 24 ) | \
  105.                 ( ( LONG ) randomPool[ ( i + j + 1 ) % RANDOMPOOL_SIZE ] << 16 ) | \
  106.                 ( ( LONG ) randomPool[ ( i + j + 2 ) % RANDOMPOOL_SIZE ] << 8 ) | \
  107.                 ( ( LONG ) randomPool[ ( i + j + 3 ) % RANDOMPOOL_SIZE ] );
  108.         digestPtr = randomPool + i;
  109.         for( j = 0; j < SHA_DIGESTSIZE / 4; j++ )
  110.             {
  111.             digestLong[ j ] = mgetBLong( digestPtr );
  112.             }
  113.         SHATransform( digestLong, inputBuffer );
  114.         digestPtr = randomPool + i;
  115.         for( j = 0; j < SHA_DIGESTSIZE / 4; j++ )
  116.             {
  117.             mputBLong( digestPtr, digestLong[ j ] );
  118.             }
  119.         zeroise( inputBuffer, SHA_DATASIZE );
  120.         }
  121. #else
  122.     for( i = 0; i < RANDOMPOOL_SIZE; i += SHA_DIGESTSIZE )
  123.         {
  124.         BYTE inputBuffer[ SHA_DATASIZE ];
  125.         int j;
  126.  
  127.         /* Copy SHA_DATASIZE bytes from the circular buffer into the hash
  128.            data buffer, hash the data, and copy the result back into the
  129.            random pool */
  130.         for( j = 0; j < SHA_DATASIZE; j++ )
  131.             inputBuffer[ j ] = randomPool[ ( i + j ) % RANDOMPOOL_SIZE ];
  132.         SHATransform( ( LONG * ) ( randomPool + i ), ( LONG * ) inputBuffer );
  133.         zeroise( inputBuffer, SHA_DATASIZE );
  134.         }
  135. #endif /* _BIG_WORDS */
  136.  
  137.     /* We're back to reading and writing from the start of the pool */
  138.     randomReadPos = randomWritePos = 0;
  139.     }
  140.  
  141. /* Add a random offset to the location where the next amount of data is to
  142.    be inserted */
  143.  
  144. #define randomizeAddPos()    randomWritePos += randomPool[ 0 ] & 0x0F
  145.  
  146. /* Add a byte to the random buffer.  This is implemented as a macro to avoid
  147.    leaving random data passed to a function on the stack.  These are low-
  148.    level routines which are not thread-safe */
  149.  
  150. #define addRandomByte( data ) \
  151.     { \
  152.     if( randomWritePos > RANDOMPOOL_SIZE - 1 ) \
  153.         mixRandomPool(); \
  154.     randomPool[ randomWritePos++ ] += data; \
  155.     }
  156.  
  157. #define addRandomWord( word ) \
  158.     addRandomByte( ( BYTE ) ( ( WORD ) word >> 8 ) ); \
  159.     addRandomByte( ( BYTE ) ( WORD ) word )
  160.  
  161. #define addRandomLong( word ) \
  162.     addRandomByte( ( BYTE ) ( ( LONG ) word >> 24 ) ); \
  163.     addRandomByte( ( BYTE ) ( ( LONG ) word >> 16 ) ); \
  164.     addRandomByte( ( BYTE ) ( ( LONG ) word >> 8 ) ); \
  165.     addRandomByte( ( BYTE ) ( LONG ) word )
  166.  
  167. /* Add a block of data to the random buffer */
  168.  
  169. static void addRandomBuffer( BYTE *buffer, int count )
  170.     {
  171.     while( count-- )
  172.         addRandomByte( *buffer++ );
  173.     }
  174.  
  175. #ifdef __WIN32__
  176.  
  177. /* Higher-level thread-safe version of addRandomBuffer */
  178.  
  179. static void threadSafeAddRandomBuffer( BYTE *buffer, int count )
  180.     {
  181.     EnterCriticalSection( &randProt );
  182.     addRandomBuffer( buffer, count );
  183.     LeaveCriticalSection( &randProt );
  184.     }
  185. #else
  186.   #define threadSafeAddRandomBuffer    addRandomBuffer
  187. #endif /* __WIN32__ */
  188.  
  189. /****************************************************************************
  190. *                                                                            *
  191. *                    OS-Specific Randomness-Gathering Functions                *
  192. *                                                                            *
  193. ****************************************************************************/
  194.  
  195. #if defined( __MSDOS__ )                                    /* DOS */
  196.  
  197. #include <fcntl.h>
  198. #include <io.h>
  199.  
  200. static void fastPoll( void )
  201.     {
  202.     /* There's not much we can do under DOS, we rely entirely on the
  203.        /dev/random read for information */
  204.     addRandomLong( time( NULL ) );
  205.     }
  206.  
  207. static void slowPoll( void )
  208.     {
  209.     BYTE buffer[ 128 ];
  210.     int fd, count;
  211.  
  212.     /* Read 128 bytes from /dev/random and add it to the buffer.  Since DOS
  213.        doesn't swap we don't need to be as careful about copying data to
  214.        temporary buffers as we usually are.  We also have to use unbuffered
  215.        I/O, since the high-level functions will read BUFSIZ bytes at once
  216.        from the input, comletely draining the driver of any randomness */
  217.     if( ( fd = open( "/dev/random", O_RDONLY ) ) == -1 )
  218.         return;
  219.     count = read( fd, buffer, 128 );
  220.     randomizeAddPos();
  221.     addRandomBuffer( buffer, count );
  222.     zeroise( buffer, 128 );
  223.     close( fd );
  224.  
  225.     /* Remember that we've got some randomness we can use */
  226.     randomStatus = CRYPT_OK;
  227.     }
  228.  
  229. #elif defined( __WIN16__ )                                    /* Win16 */
  230.  
  231. #include <stress.h>
  232. #include <toolhelp.h>
  233.  
  234. static void fastPoll( void )
  235.     {
  236.     static int noFastPolls = 0;
  237.     SYSHEAPINFO sysHeapInfo;
  238.     MEMMANINFO memManInfo;
  239.     TIMERINFO timerInfo;
  240.     POINT point;
  241.  
  242.     /* Get various basic pieces of system information */
  243.     addRandomWord( GetCapture() );    /* Handle of window with mouse capture */
  244.     addRandomWord( GetFocus() );    /* Handle of window with input focus */
  245.     addRandomLong( GetFreeSpace( 0 ) );    /* Amount of space in global heap */
  246.     addRandomWord( GetInputState() );    /* Whether system queue has any events */
  247.     addRandomLong( GetMessagePos() );    /* Cursor pos.for last message */
  248.     addRandomLong( GetMessageTime() );    /* 55 ms time for last message */
  249.     addRandomWord( GetNumTasks() );    /* Number of active tasks */
  250.     addRandomLong( GetTickCount() );/* 55 ms time since Windows started */
  251.     GetCursorPos( &point );            /* Current mouse cursor position */
  252.     addRandomBuffer( ( BYTE * ) &point, sizeof( POINT ) );
  253.     GetCaretPos( &point );            /* Current caret position */
  254.     addRandomBuffer( ( BYTE * ) &point, sizeof( POINT ) );
  255.  
  256.     /* Get the largest free memory block, number of lockable pages, number of
  257.        unlocked pages, number of free and used pages, and number of swapped
  258.        pages */
  259.     memManInfo.dwSize = sizeof( MEMMANINFO );
  260.     MemManInfo( &memManInfo );
  261.     addRandomBuffer( ( BYTE * ) &memManInfo, sizeof( MEMMANINFO ) );
  262.  
  263.     /* Get the execution times of the current task and VM to approximately
  264.        1ms resolution */
  265.     timerInfo.dwSize = sizeof( TIMERINFO );
  266.     TimerCount( &timerInfo );
  267.     addRandomBuffer( ( BYTE * ) &timerInfo, sizeof( TIMERINFO ) );
  268.  
  269.     /* Get the percentage free and segment of the user and GDI heap */
  270.     sysHeapInfo.dwSize = sizeof( SYSHEAPINFO );
  271.     SystemHeapInfo( &sysHeapInfo );
  272.     addRandomBuffer( ( BYTE * ) &sysHeapInfo, sizeof( SYSHEAPINFO ) );
  273.  
  274.     /* Since the Win16 fast poll gathers a reasonable amount of information,
  275.        we treat five of them as being equivalent to one slow poll */
  276.     if( ++noFastPolls >= 5 )
  277.         /* Remember that we've got some randomness we can use */
  278.         randomStatus = CRYPT_OK;
  279.     }
  280.  
  281. /* The slow poll can get *very* slow because of the overhead involved in
  282.    obtaining the necessary information.  On a moderately loaded system there
  283.    are often 500+ objects on the global heap and 50+ modules, so we limit
  284.    the number checked to a reasonable level to make sure we don't spend
  285.    forever polling.  We give the global heap walk the most leeway since this
  286.    provides the best source of randomness */
  287.  
  288. static void slowPoll( void )
  289.     {
  290.     MODULEENTRY moduleEntry;
  291.     GLOBALENTRY globalEntry;
  292.     TASKENTRY taskEntry;
  293.     int count;
  294.  
  295.     randomizeAddPos();
  296.  
  297.     /* Walk the global heap getting information on each entry in it.  This
  298.        retrieves the objects linear address, size, handle, lock count, owner,
  299.        object type, and segment type */
  300.     count = 0;
  301.     globalEntry.dwSize = sizeof( GLOBALENTRY );
  302.     if( GlobalFirst( &globalEntry, GLOBAL_ALL ) )
  303.         do
  304.             {
  305.             addRandomBuffer( ( BYTE * ) &globalEntry, sizeof( GLOBALENTRY ) );
  306.             count++;
  307.             }
  308.         while( count < 70 && GlobalNext( &globalEntry, GLOBAL_ALL ) );
  309.  
  310.     /* Walk the module list getting information on each entry in it.  This
  311.        retrieves the module name, handle, reference count, executable path,
  312.        and next module */
  313.     count = 0;
  314.     moduleEntry.dwSize = sizeof( MODULEENTRY );
  315.     if( ModuleFirst( &moduleEntry ) )
  316.         do
  317.             {
  318.             addRandomBuffer( ( BYTE * ) &moduleEntry, sizeof( MODULEENTRY ) );
  319.             count++;
  320.             }
  321.         while( count < 20 && ModuleNext( &moduleEntry ) );
  322.  
  323.     /* Walk the task list getting information on each entry in it.  This
  324.        retrieves the task handle, parent task handle, instance handle, stack
  325.        segment and offset, stack size, number of pending events, task queue,
  326.        and the name of module executing the task.  We also call TaskGetCSIP()
  327.        for the code segment and offset of each task if it's safe to do so */
  328.     count = 0;
  329.     taskEntry.dwSize = sizeof( TASKENTRY );
  330.     if( TaskFirst( &taskEntry ) )
  331.         do
  332.             {
  333.             addRandomBuffer( ( BYTE * ) &taskEntry, sizeof( TASKENTRY ) );
  334.             if( taskEntry.hTask != GetCurrentTask() )
  335.                 addRandomLong( TaskGetCSIP( taskEntry.hTask ) );
  336.             count++;
  337.             }
  338.         while( count < 100 && TaskNext( &taskEntry ) );
  339.  
  340.     /* Remember that we've got some randomness we can use */
  341.     randomStatus = CRYPT_OK;
  342.     }
  343.  
  344. #elif defined( __WIN32__ )                                    /* Win32 */
  345.  
  346. #include <tlhelp32.h>
  347. #include <winperf.h>
  348. #include <winioctl.h>
  349. #include <process.h>
  350.  
  351. #pragma comment( lib, "advapi32" )
  352.  
  353. #define    THREADSTACKSIZE        8192
  354.  
  355. static HANDLE hNetAPI32 = NULL;
  356.  
  357. static void fastPoll( void )
  358.     {
  359.     static BOOLEAN addedFixedItems = FALSE;
  360.     static int noFastPolls = 0;
  361.     FILETIME  creationTime, exitTime, kernelTime, userTime;
  362.     DWORD minimumWorkingSetSize, maximumWorkingSetSize;
  363.     LARGE_INTEGER performanceCount;
  364.     MEMORYSTATUS memoryStatus;
  365.     HANDLE handle;
  366.     POINT point;
  367.  
  368.     EnterCriticalSection( &randProt );
  369.  
  370.     /* Get various basic pieces of system information */
  371.     addRandomLong( GetActiveWindow() );    /* Handle of active window */
  372.     addRandomLong( GetCapture() );        /* Handle of window with mouse capture */
  373.     addRandomLong( GetClipboardOwner() );/* Handle of clipboard owner */
  374.     addRandomLong( GetClipboardViewer() );/* Handle of start of clpbd.viewer list */
  375.     addRandomLong( GetCurrentProcess() );/* Pseudohandle of current process */
  376.     addRandomLong( GetCurrentProcessId() );/* Current process ID */
  377.     addRandomLong( GetCurrentThread() );/* Pseudohandle of current thread */
  378.     addRandomLong( GetCurrentThreadId() );/* Current thread ID */
  379.     addRandomLong( GetCurrentTime() );    /* Milliseconds since Windows started */
  380.     addRandomLong( GetDesktopWindow() );/* Handle of desktop window */
  381.     addRandomLong( GetFocus() );        /* Handle of window with kb.focus */
  382.     addRandomWord( GetInputState() );    /* Whether sys.queue has any events */
  383.     addRandomLong( GetMessagePos() );    /* Cursor pos.for last message */
  384.     addRandomLong( GetMessageTime() );    /* 1 ms time for last message */
  385.     addRandomLong( GetOpenClipboardWindow() );    /* Handle of window with clpbd.open */
  386.     addRandomLong( GetProcessHeap() );    /* Handle of process heap */
  387.     addRandomLong( GetProcessWindowStation() );    /* Handle of procs window station */
  388.     addRandomLong( GetQueueStatus( QS_ALLEVENTS ) );/* Types of events in input queue */
  389.  
  390.     /* Get multiword system information */
  391.     GetCaretPos( &point );                /* Current caret position */
  392.     addRandomBuffer( ( BYTE * ) &point, sizeof( POINT ) );
  393.     GetCursorPos( &point );                /* Current mouse cursor position */
  394.     addRandomBuffer( ( BYTE * ) &point, sizeof( POINT ) );
  395.  
  396.     /* Get percent of memory in use, bytes of physical memory, bytes of free
  397.        physical memory, bytes in paging file, free bytes in paging file, user
  398.        bytes of address space, and free user bytes */
  399.     memoryStatus.dwLength = sizeof( MEMORYSTATUS );
  400.     GlobalMemoryStatus( &memoryStatus );
  401.     addRandomBuffer( ( BYTE * ) &memoryStatus, sizeof( MEMORYSTATUS ) );
  402.  
  403.     /* Get thread and process creation time, exit time, time in kernel mode,
  404.        and time in user mode in 100ns intervals */
  405.     handle = GetCurrentThread();
  406.     GetThreadTimes( handle, &creationTime, &exitTime, &kernelTime, &userTime );
  407.     addRandomBuffer( ( BYTE * ) &creationTime, sizeof( FILETIME ) );
  408.     addRandomBuffer( ( BYTE * ) &exitTime, sizeof( FILETIME ) );
  409.     addRandomBuffer( ( BYTE * ) &kernelTime, sizeof( FILETIME ) );
  410.     addRandomBuffer( ( BYTE * ) &userTime, sizeof( FILETIME ) );
  411.     handle = GetCurrentProcess();
  412.     GetProcessTimes( handle, &creationTime, &exitTime, &kernelTime, &userTime );
  413.     addRandomBuffer( ( BYTE * ) &creationTime, sizeof( FILETIME ) );
  414.     addRandomBuffer( ( BYTE * ) &exitTime, sizeof( FILETIME ) );
  415.     addRandomBuffer( ( BYTE * ) &kernelTime, sizeof( FILETIME ) );
  416.     addRandomBuffer( ( BYTE * ) &userTime, sizeof( FILETIME ) );
  417.  
  418.     /* Get the minimum and maximum working set size for the current process */
  419.     GetProcessWorkingSetSize( handle, &minimumWorkingSetSize,
  420.                               &maximumWorkingSetSize );
  421.     addRandomLong( minimumWorkingSetSize );
  422.     addRandomLong( maximumWorkingSetSize );
  423.  
  424.     /* The following are fixed for the lifetime of the process so we only
  425.        add them once */
  426.     if( !addedFixedItems )
  427.         {
  428.         STARTUPINFO startupInfo;
  429.  
  430.         /* Get name of desktop, console window title, new window position and
  431.            size, window flags, and handles for stdin, stdout, and stderr */
  432.         startupInfo.cb = sizeof( STARTUPINFO );
  433.         GetStartupInfo( &startupInfo );
  434.         addRandomBuffer( ( BYTE * ) &startupInfo, sizeof( STARTUPINFO ) );
  435.         addedFixedItems = TRUE;
  436.         }
  437.  
  438.     /* The docs say QPC can fail if appropriate hardware is not available.
  439.        It works on 486 & Pentium boxes, but hasn't been tested for 386 or
  440.        RISC boxes */
  441.     if( QueryPerformanceCounter( &performanceCount ) )
  442.         addRandomBuffer( ( BYTE * ) &performanceCount, sizeof( LARGE_INTEGER ) );
  443.     else
  444.         {
  445.         /* Millisecond accuracy at best... */
  446.         DWORD dwTicks = GetTickCount();
  447.         addRandomBuffer( ( BYTE * ) &dwTicks, sizeof( dwTicks ) );
  448.         }
  449.  
  450.     /* Since the Win32 fast poll gathers quite a bit of information, we treat
  451.        three of them as being equivalent to one slow poll */
  452.     if( ++noFastPolls >= 3 )
  453.         /* Remember that we've got some randomness we can use */
  454.         randomStatus = CRYPT_OK;
  455.  
  456.     LeaveCriticalSection( &randProt );
  457.     }
  458.  
  459. /* Type definitions for function pointers to call Toolhelp32 functions */
  460.  
  461. typedef BOOL ( WINAPI *MODULEWALK )( HANDLE hSnapshot, LPMODULEENTRY32 lpme );
  462. typedef BOOL ( WINAPI *THREADWALK )( HANDLE hSnapshot, LPTHREADENTRY32 lpte );
  463. typedef BOOL ( WINAPI *PROCESSWALK )( HANDLE hSnapshot, LPPROCESSENTRY32 lppe );
  464. typedef BOOL ( WINAPI *HEAPLISTWALK )( HANDLE hSnapshot, LPHEAPLIST32 lphl );
  465. typedef BOOL ( WINAPI *HEAPFIRST )( LPHEAPENTRY32 lphe, DWORD th32ProcessID, DWORD th32HeapID );
  466. typedef BOOL ( WINAPI *HEAPNEXT )( LPHEAPENTRY32 lphe );
  467. typedef HANDLE ( WINAPI *CREATESNAPSHOT )( DWORD dwFlags, DWORD th32ProcessID );
  468.  
  469. /* Global function pointers. These are necessary because the functions need
  470.    to be dynamically linked since only the Win95 kernel currently contains
  471.    them.  Explicitly linking to them will make the program unloadable under
  472.    NT */
  473.  
  474. static CREATESNAPSHOT pCreateToolhelp32Snapshot = NULL;
  475. static MODULEWALK pModule32First = NULL;
  476. static MODULEWALK pModule32Next = NULL;
  477. static PROCESSWALK pProcess32First = NULL;
  478. static PROCESSWALK pProcess32Next = NULL;
  479. static THREADWALK pThread32First = NULL;
  480. static THREADWALK pThread32Next = NULL;
  481. static HEAPLISTWALK pHeap32ListFirst = NULL;
  482. static HEAPLISTWALK pHeap32ListNext = NULL;
  483. static HEAPFIRST pHeap32First = NULL;
  484. static HEAPNEXT pHeap32Next = NULL;
  485.  
  486. static void slowPollWin95( void )
  487.     {
  488.     PROCESSENTRY32 pe32;
  489.     THREADENTRY32 te32;
  490.     MODULEENTRY32 me32;
  491.     HEAPLIST32 hl32;
  492.     HANDLE hSnapshot;
  493.  
  494.     /* Initialize the Toolhelp32 function pointers if necessary */
  495.     if( pCreateToolhelp32Snapshot == NULL )
  496.         {
  497.         HANDLE hKernel = NULL;
  498.  
  499.         /* Obtain the module handle of the kernel to retrieve the addresses
  500.            of the Toolhelp32 functions */
  501.         if( ( hKernel = GetModuleHandle( "KERNEL32.DLL" ) ) == NULL )
  502.             return;
  503.  
  504.         /* Now get pointers to the functions */
  505.         pCreateToolhelp32Snapshot = ( CREATESNAPSHOT ) GetProcAddress( hKernel,
  506.                                                     "CreateToolhelp32Snapshot" );
  507.         pModule32First = ( MODULEWALK ) GetProcAddress( hKernel,
  508.                                                     "Module32First" );
  509.         pModule32Next = ( MODULEWALK ) GetProcAddress( hKernel,
  510.                                                     "Module32Next" );
  511.         pProcess32First = ( PROCESSWALK ) GetProcAddress( hKernel,
  512.                                                     "Process32First" );
  513.         pProcess32Next = ( PROCESSWALK ) GetProcAddress( hKernel,
  514.                                                     "Process32Next" );
  515.         pThread32First = ( THREADWALK ) GetProcAddress( hKernel,
  516.                                                     "Thread32First" );
  517.         pThread32Next = ( THREADWALK ) GetProcAddress( hKernel,
  518.                                                     "Thread32Next" );
  519.         pHeap32ListFirst = ( HEAPLISTWALK ) GetProcAddress( hKernel,
  520.                                                     "Heap32ListFirst" );
  521.         pHeap32ListNext = ( HEAPLISTWALK ) GetProcAddress( hKernel,
  522.                                                     "Heap32ListNext" );
  523.         pHeap32First = ( HEAPFIRST ) GetProcAddress( hKernel,
  524.                                                     "Heap32First" );
  525.         pHeap32Next = ( HEAPNEXT ) GetProcAddress( hKernel,
  526.                                                     "Heap32Next" );
  527.  
  528.         /* Make sure we got valid pointers for every Toolhelp32 function */
  529.         if( pModule32First == NULL || pModule32Next == NULL || \
  530.             pProcess32First == NULL || pProcess32Next == NULL || \
  531.             pThread32First == NULL || pThread32Next == NULL || \
  532.             pHeap32ListFirst == NULL || pHeap32ListNext == NULL || \
  533.             pHeap32First == NULL || pHeap32Next == NULL || \
  534.             pCreateToolhelp32Snapshot == NULL )
  535.             {
  536.             /* Mark the main function as unavailable in case for future
  537.                reference */
  538.             pCreateToolhelp32Snapshot = NULL;
  539.             return;
  540.             }
  541.         }
  542.  
  543.     /* Take a snapshot of everything we can get to which is currently
  544.        in the system */
  545.     hSnapshot = pCreateToolhelp32Snapshot( TH32CS_SNAPALL, 0 );
  546.     if( !hSnapshot )
  547.         return;
  548.  
  549.     /* Walk through the local heap */
  550.     hl32.dwSize = sizeof( HEAPLIST32 );
  551.     if( pHeap32ListFirst( hSnapshot, &hl32 ) )
  552.         do
  553.             {
  554.             HEAPENTRY32 he32;
  555.  
  556.             /* First add the information from the basic Heaplist32
  557.                structure */
  558.             threadSafeAddRandomBuffer( ( BYTE * ) &hl32, sizeof( HEAPLIST32 ) );
  559.  
  560.             /* Now walk through the heap blocks getting information
  561.                on each of them */
  562.             he32.dwSize = sizeof( HEAPENTRY32 );
  563.             if( pHeap32First( &he32, hl32.th32ProcessID, hl32.th32HeapID ) )
  564.                 do
  565.                     threadSafeAddRandomBuffer( ( BYTE * ) &he32, sizeof( HEAPENTRY32 ) );
  566.                 while( pHeap32Next( &he32 ) );
  567.             }
  568.         while( pHeap32ListNext( hSnapshot, &hl32 ) );
  569.  
  570.     /* Walk through all processes */
  571.     pe32.dwSize = sizeof( PROCESSENTRY32 );
  572.     if( pProcess32First( hSnapshot, &pe32 ) )
  573.         do
  574.             threadSafeAddRandomBuffer( ( BYTE * ) &pe32, sizeof( PROCESSENTRY32 ) );
  575.         while( pProcess32Next( hSnapshot, &pe32 ) );
  576.  
  577.     /* Walk through all threads */
  578.     te32.dwSize = sizeof( THREADENTRY32 );
  579.     if( pThread32First( hSnapshot, &te32 ) )
  580.         do
  581.             threadSafeAddRandomBuffer( ( BYTE * ) &te32, sizeof( THREADENTRY32 ) );
  582.     while( pThread32Next( hSnapshot, &te32 ) );
  583.  
  584.     /* Walk through all modules associated with the process */
  585.     me32.dwSize = sizeof( MODULEENTRY32 );
  586.     if( pModule32First( hSnapshot, &me32 ) )
  587.         do
  588.             threadSafeAddRandomBuffer( ( BYTE * ) &me32, sizeof( MODULEENTRY32 ) );
  589.     while( pModule32Next( hSnapshot, &me32 ) );
  590.  
  591.     /* Clean up the snapshot */
  592.     CloseHandle( hSnapshot );
  593.  
  594.     /* Remember that we've got some randomness we can use */
  595.     randomStatus = CRYPT_OK;
  596.     }
  597.  
  598. /* Perform a thread-safe slow poll.  The following function *must* be started
  599.    as a thread */
  600.  
  601. static void threadSafeSlowPollWin95( void *dummy )
  602.     {
  603.     ResetEvent( threadEvent );
  604.     slowPollWin95();
  605.     SetEvent( threadEvent );
  606.     threadID = NULL;
  607.     _endthread();
  608.     }
  609.  
  610. /* Type definitions for function pointers to call NetAPI32 functions */
  611.  
  612. typedef DWORD ( WINAPI *NETSTATISTICSGET )( LPWSTR szServer, LPWSTR szService,
  613.                                             DWORD dwLevel, DWORD dwOptions,
  614.                                             LPBYTE *lpBuffer );
  615. typedef DWORD ( WINAPI *NETAPIBUFFERSIZE )( LPVOID lpBuffer, LPDWORD cbBuffer );
  616. typedef DWORD ( WINAPI *NETAPIBUFFERFREE )( LPVOID lpBuffer );
  617.  
  618. /* Global function pointers. These are necessary because the functions need
  619.    to be dynamically linked since only the WinNT kernel currently contains
  620.    them.  Explicitly linking to them will make the program unloadable under
  621.    Win95 */
  622.  
  623. static NETSTATISTICSGET pNetStatisticsGet = NULL;
  624. static NETAPIBUFFERSIZE pNetApiBufferSize = NULL;
  625. static NETAPIBUFFERFREE pNetApiBufferFree = NULL;
  626.  
  627. static void slowPollWinNT( void )
  628.     {
  629.     static int isWorkstation = CRYPT_ERROR;
  630.     PPERF_DATA_BLOCK pPerfData;
  631.     static int cbPerfData = 0x10000;
  632.     HANDLE hDevice;
  633.     LPBYTE lpBuffer;
  634.     DWORD dwSize, status;
  635.     int nDrive;
  636.  
  637.     /* Find out whether this is an NT server or workstation if necessary */
  638.     if( isWorkstation == CRYPT_ERROR )
  639.         {
  640.         HKEY hKey;
  641.  
  642.         if( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  643.                           "SYSTEM\\CurrentControlSet\\Control\\ProductOptions",
  644.                           0, KEY_READ, &hKey ) == ERROR_SUCCESS )
  645.             {
  646.             BYTE szValue[ 32 ];
  647.             dwSize = sizeof( szValue );
  648.  
  649.             isWorkstation = TRUE;
  650.             status = RegQueryValueEx( hKey, "ProductType", 0, NULL,
  651.                                       szValue, &dwSize );
  652.             if( status == ERROR_SUCCESS && stricmp( szValue, "WinNT" ) )
  653.                 /* Note: There are (at least) three cases for ProductType:
  654.                    WinNT = NT Workstation, ServerNT = NT Server, LanmanNT =
  655.                    NT Server acting as a Domain Controller */
  656.                 isWorkstation = FALSE;
  657.  
  658.             RegCloseKey( hKey );
  659.             }
  660.         }
  661.  
  662.     /* Initialize the NetAPI32 function pointers if necessary */
  663.     if( hNetAPI32 == NULL )
  664.         {
  665.         /* Obtain a handle to the module containing the Lan Manager functions */
  666.         if( hNetAPI32 = LoadLibrary( "NETAPI32.DLL" ) )
  667.             {
  668.             /* Now get pointers to the functions */
  669.             pNetStatisticsGet = ( NETSTATISTICSGET ) GetProcAddress( hNetAPI32,
  670.                                                         "NetStatisticsGet" );
  671.             pNetApiBufferSize = ( NETAPIBUFFERSIZE ) GetProcAddress( hNetAPI32,
  672.                                                         "NetApiBufferSize" );
  673.             pNetApiBufferFree = ( NETAPIBUFFERFREE ) GetProcAddress( hNetAPI32,
  674.                                                         "NetApiBufferFree" );
  675.  
  676.             /* Make sure we got valid pointers for every NetAPI32 function */
  677.             if( pNetStatisticsGet == NULL ||
  678.                 pNetApiBufferSize == NULL ||
  679.                 pNetApiBufferFree == NULL )
  680.                 {
  681.                 /* Free the library reference and reset the static handle */
  682.                 FreeLibrary( hNetAPI32 );
  683.                 hNetAPI32 = NULL;
  684.                 }
  685.             }
  686.         }
  687.  
  688.     /* Get network statistics.  Note: Both NT Workstation and NT Server by
  689.        default will be running both the workstation and server services.  The
  690.        heuristic below is probably useful though on the assumption that the
  691.        majority of the network traffic will be via the appropriate service */
  692.     if( hNetAPI32 &&
  693.         pNetStatisticsGet( NULL,
  694.                            isWorkstation ? L"LanmanWorkstation" : L"LanmanServer",
  695.                            0, 0, &lpBuffer ) == 0 )
  696.         {
  697.         pNetApiBufferSize( lpBuffer, &dwSize );
  698.         threadSafeAddRandomBuffer( ( BYTE * ) lpBuffer, dwSize );
  699.         pNetApiBufferFree( lpBuffer );
  700.         }
  701.  
  702.     /* Get disk I/O statistics for all the hard drives */
  703.     for( nDrive = 0;; nDrive++ )
  704.         {
  705.         DISK_PERFORMANCE diskPerformance;
  706.         char szDevice[ 24 ];
  707.  
  708.         /* Check whether we can access this device */
  709.         sprintf( szDevice, "\\\\.\\PhysicalDrive%d", nDrive );
  710.         hDevice = CreateFile( szDevice, 0, FILE_SHARE_READ | FILE_SHARE_WRITE,
  711.                               NULL, OPEN_EXISTING, 0, NULL );
  712.         if( hDevice == INVALID_HANDLE_VALUE )
  713.             break;
  714.  
  715.         /* Note: This only works if you have turned on the disk performance
  716.            counters with 'diskperf -y'.  These counters are off by default */
  717.         if( DeviceIoControl( hDevice, IOCTL_DISK_PERFORMANCE, NULL, 0,
  718.                              &diskPerformance, sizeof( DISK_PERFORMANCE ),
  719.                              &dwSize, NULL ) )
  720.             {
  721.             threadSafeAddRandomBuffer( ( BYTE * ) &diskPerformance, dwSize );
  722.             }
  723.         CloseHandle( hDevice );
  724.         }
  725.  
  726.     /* Get the performance counters */
  727.     pPerfData = ( PPERF_DATA_BLOCK ) malloc( cbPerfData );
  728.     while( pPerfData )
  729.         {
  730.         dwSize = cbPerfData;
  731.         status = RegQueryValueEx( HKEY_PERFORMANCE_DATA, "Global", NULL,
  732.                                   NULL, ( LPBYTE ) pPerfData, &dwSize );
  733.  
  734.         if( status == ERROR_SUCCESS )
  735.             {
  736.             if( !memcmp( pPerfData->Signature, L"PERF", 8 ) )
  737.                 threadSafeAddRandomBuffer( ( BYTE * ) pPerfData, dwSize );
  738.             free( pPerfData );
  739.             pPerfData = NULL;
  740.             }
  741.         else
  742.             if( status == ERROR_MORE_DATA )
  743.                 {
  744.                 cbPerfData += 4096;
  745.                 pPerfData == ( PPERF_DATA_BLOCK ) realloc( pPerfData, cbPerfData );
  746.                 }
  747.         }
  748.  
  749.     /* Remember that we've got some randomness we can use */
  750.     randomStatus = CRYPT_OK;
  751.     }
  752.  
  753. /* Perform a thread-safe slow poll.  The following function *must* be started
  754.    as a thread */
  755.  
  756. static void threadSafeSlowPollWinNT( void *dummy )
  757.     {
  758.     ResetEvent( threadEvent );
  759.     slowPollWinNT();
  760.     SetEvent(threadEvent);
  761.     threadID = NULL;
  762.     _endthread();
  763.     }
  764.  
  765. static void slowPoll( void )
  766.     {
  767.     static DWORD dwPlatform = ( DWORD ) CRYPT_ERROR;
  768.  
  769.     if( dwPlatform == CRYPT_ERROR )
  770.         {
  771.         OSVERSIONINFO osvi = { sizeof( osvi ) };
  772.         if( GetVersionEx( &osvi ) )
  773.             dwPlatform = osvi.dwPlatformId;
  774.         }
  775.  
  776.     /* Start a threaded slow poll.  If a slow poll is already running, we
  777.        just return since there isn't much point in running two of them at the
  778.        same time */
  779.     switch( dwPlatform )
  780.         {
  781.         case VER_PLATFORM_WIN32_NT:
  782.             if( !threadID )
  783.                 threadID = ( HANDLE ) _beginthread( threadSafeSlowPollWinNT,
  784.                                                     THREADSTACKSIZE, NULL );
  785.                break;
  786.  
  787.         case VER_PLATFORM_WIN32_WINDOWS:
  788.             if( !threadID )
  789.                 threadID = ( HANDLE ) _beginthread( threadSafeSlowPollWin95,
  790.                                                     THREADSTACKSIZE, NULL );
  791.             break;
  792.  
  793.         case VER_PLATFORM_WIN32s:
  794.             break;
  795.         }
  796.     }
  797.  
  798. /* Wait for the randomness gathering to finish.  Anything that requires the
  799.    gatherer process to have completed gathering entropy should call
  800.    randomFlush, which will block until the background process completes.  At
  801.    the moment this call is in the getRandomByte routine */
  802.  
  803. void randomFlush( void )
  804.     {
  805.     if( threadID != NULL )
  806.         WaitForSingleObject( threadEvent, INFINITE );
  807.     }
  808.  
  809. #elif defined( __UNIX__ )                                    /* Unix */
  810.  
  811. #ifdef __osf__
  812.   /* Somewhere in the morass of system-specific cruft which OSF/1 pulls in
  813.      via the following includes are various endianness defines, so we
  814.      undefine the cryptlib ones, which aren't really needed for this module
  815.      anyway */
  816.   #undef BIG_ENDIAN
  817.   #undef LITTLE_ENDIAN
  818. #endif /* __osf__ */
  819.  
  820. #include <unistd.h>
  821. #include <fcntl.h>
  822. #include <pwd.h>
  823. #include <sys/ipc.h>
  824. #include <sys/time.h>    /* SCO and SunOS need this before resource.h */
  825. #include <sys/resource.h>
  826. #ifdef _AIX
  827.   #include <sys/select.h>
  828. #endif /* _AIX */
  829. #include <sys/shm.h>
  830. #include <sys/signal.h>
  831. #include <sys/stat.h>
  832. #include <sys/types.h>    /* Verschiedene komische Typen */
  833. #include <sys/wait.h>
  834. /* #include <kitchensink.h> */
  835.  
  836. /* The structure containing information on random-data sources.  Each
  837.    record contains the source and a relative estimate of its usefulness
  838.    (weighting) which is used to scale the number of kB of output from the
  839.    source.  Usually the weighting is in the range 1-3 (or 0 for especially
  840.    useless sources).  If the source is constantly changing (certain types of
  841.    network statistics have this characteristic) but the amount of output is
  842.    small, the constant value 100 is added to the weighting to indicate that
  843.    the output should be treated as if a minimum of 1K of output had been
  844.    obtained.  If the source produces a lot of output then the scale factor is
  845.    fractional.  In order to provide enough randomness to satisfy the
  846.    requirements for a slow poll, we need to accumulate at least 25 points of
  847.    usefulness (a typical system should get about 30-35 points).
  848.  
  849.    Some potential options are missed out because of special considerations.
  850.    pstat -i and pstat -f can produce amazing amounts of output (the record
  851.    is 600K on an Oracle server) which floods the buffer and doesn't yield
  852.    anything useful (apart from perhaps increasing the entropy of the vmstat
  853.    output a bit), so we don't bother with this.  pstat in general produces
  854.    quite a bit of output, but it doesn't change much over time, so it gets
  855.    very low weightings.  netstat -s produces constantly-changing output but
  856.    also produces quite a bit of it, so it only gets a weighting of 2 rather
  857.    than 3.  The same holds for netstat -in, which gets 1 rather than 2.
  858.  
  859.    Some binaries are stored in different locations on different systems so
  860.    alternative paths are given for them.  The code sorts out which one to
  861.    run by itself, once it finds an exectable somewhere it moves on to the
  862.    next source.  The sources are arranged roughly in their order of
  863.    usefulness, occasionally sources which provide a tiny amount of
  864.    relatively useless data are placed ahead of ones which provide a large
  865.    amount of possibly useful data because another 100 bytes can't hurt, and
  866.    it means the buffer won't be swamped by one or two high-output sources.
  867.    All the high-output sources are clustered towards the end of the list
  868.    for this reason.  Some binaries checked for in a certain order, for
  869.    example under Slowaris /usr/ucb/ps understands aux as an arg, but the
  870.    others don't.  Some systems have conditional defines enabling alternatives
  871.    to commands which don't understand the usual options but will provide
  872.    enough output (in the form of error messages) to look like they're the
  873.    real thing, causing alternative options to be skipped (we can't check the
  874.    return either because some commands return peculiar, non-zero status even
  875.    when they're working correctly).
  876.  
  877.    In order to maximise use of the buffer, the code performs a form of run-
  878.    length compression on its input where a repeated sequence of bytes is
  879.    replaced by the occurrence count mod 256.  Some commands output an awful
  880.    lot of whitespace, this measure greatly increases the amount of data we
  881.    can fit in the buffer.
  882.  
  883.    Some broken preprocessors may give a division by zero warning on the
  884.    following macro */
  885.  
  886. #define SC( weight )    ( weight ? 1024 / weight : 0 )    /* Scale factor */
  887.  
  888. static struct RI {
  889.     const char *path;        /* Path to check for existence of source */
  890.     const char *arg;        /* Args for source */
  891.     const int usefulness;    /* Usefulness of source */
  892.     FILE *pipe;                /* Pipe to source as FILE * */
  893.     int pipeFD;                /* Pipe to source as FD */
  894.     pid_t pid;                /* pid of child for waitpid() */
  895.     int length;                /* Quantity of output produced */
  896.     const BOOLEAN hasAlternative;    /* Whether source has alt.location */
  897.     } dataSources[] = {
  898.     { "/bin/vmstat", "-s", SC( -3 ), NULL, 0, 0, 0, TRUE },
  899.     { "/usr/bin/vmstat", "-s", SC( -3 ), NULL, 0, 0, 0, FALSE },
  900.     { "/bin/vmstat", "-c", SC( -3 ), NULL, 0, 0, 0, TRUE },
  901.     { "/usr/bin/vmstat", "-c", SC( -3 ), NULL, 0, 0, 0, FALSE },
  902.     { "/usr/bin/pfstat", NULL, SC( -2 ), NULL, 0, 0, 0, FALSE },
  903.     { "/bin/vmstat", "-i", SC( -2 ), NULL, 0, 0, 0, TRUE },
  904.     { "/usr/bin/vmstat", "-i", SC( -2 ), NULL, 0, 0, 0, FALSE },
  905.     { "/usr/ucb/netstat", "-s", SC( 2 ), NULL, 0, 0, 0, TRUE },
  906.     { "/usr/bin/netstat", "-s", SC( 2 ), NULL, 0, 0, 0, TRUE },
  907.     { "/usr/sbin/netstat", "-s", SC( 2 ), NULL, 0, 0, 0, FALSE },
  908.     { "/usr/bin/nfsstat", NULL, SC( 2 ), NULL, 0, 0, 0, FALSE },
  909.     { "/usr/ucb/netstat", "-m", SC( -1 ), NULL, 0, 0, 0, TRUE },
  910.     { "/usr/bin/netstat", "-m", SC( -1 ), NULL, 0, 0, 0, TRUE },
  911.     { "/usr/sbin/netstat", "-m", SC( -1 ), NULL, 0, 0, 0, FALSE },
  912.     { "/usr/ucb/netstat", "-in", SC( -1 ), NULL, 0, 0, 0, TRUE },
  913.     { "/usr/bin/netstat", "-in", SC( -1 ), NULL, 0, 0, 0, TRUE },
  914.     { "/usr/sbin/netstat", "-in", SC( -1 ), NULL, 0, 0, 0, FALSE },
  915.     { "/usr/bin/mpstat", NULL, SC( 1 ), NULL, 0, 0, 0, FALSE },
  916.     { "/usr/bin/w", NULL, SC( 1 ), NULL, 0, 0, 0, FALSE },
  917.     { "/usr/bin/df", NULL, SC( 1 ), NULL, 0, 0, 0, TRUE },
  918.     { "/bin/df", NULL, SC( 1 ), NULL, 0, 0, 0, FALSE },
  919.     { "/usr/bin/iostat", NULL, SC( 0 ), NULL, 0, 0, 0, FALSE },
  920.     { "/usr/bin/uptime", NULL, SC( 0 ), NULL, 0, 0, 0, FALSE },
  921.     { "/bin/vmstat", "-f", SC( 0 ), NULL, 0, 0, 0, TRUE },
  922.     { "/usr/bin/vmstat", "-f", SC( 0 ), NULL, 0, 0, 0, FALSE },
  923.     { "/bin/vmstat", NULL, SC( 0 ), NULL, 0, 0, 0, TRUE },
  924.     { "/usr/bin/vmstat", NULL, SC( 0 ), NULL, 0, 0, 0, FALSE },
  925.     { "/usr/ucb/netstat", "-n", SC( 0.5 ), NULL, 0, 0, 0, TRUE },
  926.     { "/usr/bin/netstat", "-n", SC( 0.5 ), NULL, 0, 0, 0, TRUE },
  927.     { "/usr/sbin/netstat", "-n", SC( 0.5) , NULL, 0, 0, 0, FALSE },
  928. #ifdef __sgi
  929.     { "/bin/ps", "-el", SC( 0.3 ), NULL, 0, 0, 0, TRUE },
  930. #endif /* __sgi */
  931.     { "/usr/ucb/ps", "aux", SC( 0.3 ), NULL, 0, 0, 0, TRUE },
  932.     { "/usr/bin/ps", "aux", SC( 0.3 ), NULL, 0, 0, 0, TRUE },
  933.     { "/bin/ps", "aux", SC( 0.3 ), NULL, 0, 0, 0, FALSE },
  934.     { "/usr/bin/ipcs", "-a", SC( 0.5 ), NULL, 0, 0, 0, TRUE },
  935.     { "/bin/ipcs", "-a", SC( 0.5 ), NULL, 0, 0, 0, FALSE },
  936.                             /* Unreliable source, depends on system usage */
  937.     { "/etc/pstat", "-p", SC( 0.5 ), NULL, 0, 0, 0, TRUE },
  938.     { "/bin/pstat", "-p", SC( 0.5 ), NULL, 0, 0, 0, FALSE },
  939.     { "/etc/pstat", "-S", SC( 0.2 ), NULL, 0, 0, 0, TRUE },
  940.     { "/bin/pstat", "-S", SC( 0.2 ), NULL, 0, 0, 0, FALSE },
  941.     { "/etc/pstat", "-v", SC( 0.2 ), NULL, 0, 0, 0, TRUE },
  942.     { "/bin/pstat", "-v", SC( 0.2 ), NULL, 0, 0, 0, FALSE },
  943.     { "/etc/pstat", "-x", SC( 0.2 ), NULL, 0, 0, 0, TRUE },
  944.     { "/bin/pstat", "-x", SC( 0.2 ), NULL, 0, 0, 0, FALSE },
  945.     { "/etc/pstat", "-t", SC( 0.1 ), NULL, 0, 0, 0, TRUE },
  946.     { "/bin/pstat", "-t", SC( 0.1 ), NULL, 0, 0, 0, FALSE },
  947.                             /* pstat is your friend (usually) */
  948.     { "/usr/sbin/advfsstat", "-b usr_domain", SC( 0 ), NULL, 0, 0, 0, FALSE },
  949.     { "/usr/sbin/advfsstat", "-l 2 usr_domain", SC( 0.5 ), NULL, 0, 0, 0, FALSE },
  950.     { "/usr/sbin/advfsstat", "-p usr_domain", SC( 0 ), NULL, 0, 0, 0, FALSE },
  951.                             /* This is a complex and screwball program.  Some
  952.                                systems have things like rX_dmn, x = integer,
  953.                                for RAID systems, but the statistics are
  954.                                pretty dodgy */
  955.     { NULL, NULL, 0, NULL, 0, 0, 0, FALSE } };
  956.  
  957. /* Variables to manage the child process which fills the buffer */
  958.  
  959. static pid_t gathererProcess = 0;/* The child process which fills the buffer */
  960. static BYTE *gathererBuffer;    /* Shared buffer for gathering random noise */
  961. static int gathererMemID;        /* ID for shared memory */
  962. static int gathererBufSize;        /* Size of the shared memory buffer */
  963. static uid_t gathererID = -1;    /* Gatherers user ID */
  964.  
  965. /* The struct at the start of the shared memory buffer used to communicate
  966.    information from the child to the parent */
  967.  
  968. typedef struct {
  969.     int usefulness;                /* Usefulness of data in buffer */
  970.     int noBytes;                /* No.of bytes in buffer */
  971.     } GATHERER_INFO;
  972.  
  973. /* Under SunOS popen() doesn't record the pid of the child process.  When
  974.    pclose() is called, instead of calling waitpid() for the correct child, it
  975.    calls wait() repeatedly until the right child is reaped.  The problem is
  976.    that this reaps any other children that happen to have died at that
  977.    moment, and when their pclose() comes along, the process hangs forever.
  978.    The fix is to use a wrapper for popen()/pclose() which saves the pid in
  979.    the dataSources structure (code adapted from GNU-libc's popen() call) */
  980.  
  981. #include <sys/errno.h>
  982.  
  983. extern int errno;
  984.  
  985. static FILE *my_popen( struct RI *entry )
  986.     {
  987.     int pipedes[ 2 ];
  988.     FILE *stream;
  989.  
  990.     /* Create the pipe */
  991.     if( pipe( pipedes ) < 0 )
  992.         return( NULL );
  993.  
  994.     /* Fork off the child ("vfork() is like an OS orgasm.  All OS's want to
  995.        do it, but most just end up faking it" - Chris Wedgwood).  If your OS
  996.        supports it, you should try to use vfork() here because it's somewhat
  997.        more efficient */
  998. #if defined( sun ) || defined( __ultrix__ ) || defined( __osf__ )
  999.     entry->pid = vfork();
  1000. #else
  1001.     entry->pid = fork();
  1002. #endif /* Unixen which have vfork() */
  1003.     if( entry->pid == ( pid_t ) -1 )
  1004.         {
  1005.         /* The fork failed */
  1006.         close( pipedes[ 0 ] );
  1007.         close( pipedes[ 1 ] );
  1008.         return( NULL );
  1009.         }
  1010.     else
  1011.         if( entry->pid == ( pid_t ) 0 )
  1012.             {
  1013.             /* We are the child.  Make the read side of the pipe be stdout */
  1014.             if( dup2( pipedes[ STDOUT_FILENO ], STDOUT_FILENO ) < 0 )
  1015.                 exit( 127 );
  1016.  
  1017.             /* Close the pipe descriptors */
  1018.             close( pipedes[ STDIN_FILENO ] );
  1019.             close( pipedes[ STDOUT_FILENO ] );
  1020.  
  1021.             /* Try and exec the program */
  1022.             execl( entry->path, entry->path, entry->arg, NULL );
  1023.  
  1024.             /* Die if the exec failed */
  1025.             exit( 127 );
  1026.             }
  1027.  
  1028.     /* We are the parent.  Close the irrelevant side of the pipe and open the
  1029.        relevant side as a new stream.  Mark our side of the pipe to close on
  1030.        exec, so new children won't see it */
  1031.     close( pipedes[ STDOUT_FILENO ] );
  1032.     fcntl( pipedes[ STDIN_FILENO ], F_SETFD, FD_CLOEXEC );
  1033.     stream = fdopen( pipedes[ STDIN_FILENO ], "r" );
  1034.     if( stream == NULL )
  1035.         {
  1036.         int savedErrno = errno;
  1037.  
  1038.         /* The stream couldn't be opened or the child structure couldn't be
  1039.            allocated.  Kill the child and close the other side of the pipe */
  1040.         kill( entry->pid, SIGKILL );
  1041.         if( stream == NULL )
  1042.             close( pipedes[ STDOUT_FILENO ] );
  1043.         else
  1044.             fclose( stream );
  1045.         waitpid( entry->pid, NULL, 0 );
  1046.         entry->pid = 0;
  1047.         errno = savedErrno;
  1048.         return( NULL );
  1049.         }
  1050.  
  1051.     return( stream );
  1052.     }
  1053.  
  1054. static int my_pclose( struct RI *entry )
  1055.     {
  1056.     int status = 0;
  1057.  
  1058.     if( fclose( entry->pipe ) )
  1059.         return( -1 );
  1060.  
  1061.     /* We ignore the return value from the process because some programs
  1062.        return funny values which would result in the input being discarded
  1063.        even if they executed successfully.  This isn't a problem because
  1064.        the 1K size threshold will filter out any programs which exit with
  1065.        a usage message without producing useful output */
  1066.     if( waitpid( entry->pid, NULL, 0 ) != entry->pid )
  1067.         status = -1;
  1068.  
  1069.     entry->pipe = NULL;
  1070.     entry->pid = 0;
  1071.     return( status );
  1072.     }
  1073.  
  1074. /* Unix fast poll - not terribly useful */
  1075.  
  1076. static void fastPoll( void )
  1077.     {
  1078. #ifndef _M_XENIX    /* SCO has a gettimeofday() prototype, but no sys.call */
  1079.     struct timeval tv;
  1080. #ifndef __hpux        /* PHUX has the fn.prototypes, but not the system call */
  1081.     struct rusage rusage;
  1082. #endif /* __hpux */
  1083.  
  1084.     gettimeofday( &tv, NULL );
  1085.     addRandomLong( tv.tv_sec );
  1086.     addRandomLong( tv.tv_usec );
  1087.  
  1088. #ifndef __hpux
  1089.     getrusage( RUSAGE_SELF, &rusage );
  1090.     addRandomBuffer( ( BYTE * ) &rusage, sizeof( struct rusage ) );
  1091. #endif /* __hpux */
  1092. #endif /* _M_XENIX */
  1093.     }
  1094.  
  1095. /* Unix slow poll with special support for Linux.  Really for Linux >=1.3.43
  1096.    (>=2.0.12 recommended), "mknod /dev/urandom c 1 9" if you don't have this
  1097.    device, and also "mknod /dev/random c 1 8" (this assumes you're root -
  1098.    "Use Linux, be your own luser").
  1099.  
  1100.    If a few of the randomness sources create a large amount of output then
  1101.    the slowPoll() stops once the buffer has been filled (but before all the
  1102.    randomness sources have been sucked dry) so that the 'usefulness' factor
  1103.    remains below the threshold.  For this reason the gatherer buffer has to
  1104.    be fairly sizeable on moderately loaded systems.  This is something of a
  1105.    bug since the usefulness should be influenced by the amount of output as
  1106.    well as the source type */
  1107.  
  1108. #define DEVRANDOM_BITS        1024
  1109. #define SHARED_BUFSIZE         49152    /* Usually about 25K are filled */
  1110.  
  1111. static void slowPoll( void )
  1112.     {
  1113.     int    fd;
  1114.  
  1115.     if( ( fd = open( "/dev/urandom", O_RDONLY ) ) >= 0 )
  1116.         {
  1117.         BYTE buffer[ DEVRANDOM_BITS / 8 ];
  1118.  
  1119.         /* Read data from /dev/urandom, which won't block (although the
  1120.            quality of the noise is lesser).  This is Linux-specific, but we
  1121.            may as well leave it in for other systems in case it's present
  1122.            there */
  1123.         read( fd, buffer, DEVRANDOM_BITS / 8 );
  1124.         randomizeAddPos();
  1125.         addRandomBuffer( buffer, DEVRANDOM_BITS / 8 );
  1126.         zeroise( buffer, DEVRANDOM_BITS / 8 );
  1127.         close( fd );
  1128.         gathererProcess = 0; /* We never forked off a child */
  1129.  
  1130.         /* Remember that we've got some randomness we can use */
  1131.         randomStatus = CRYPT_OK;
  1132.         }
  1133.     else
  1134.         {
  1135.         GATHERER_INFO *gathererInfo;
  1136.         BOOLEAN moreSources;
  1137.         struct timeval tv;
  1138.         struct passwd *passwd;
  1139.         fd_set fds;
  1140. #if defined( __hpux )
  1141.         size_t maxFD = 0;
  1142.         int pageSize = 4096;            /* PHUX doesn't have getpagesize() */
  1143. #elif defined( _M_XENIX )
  1144.         int maxFD = 0, pageSize = 4096;    /* Nor does SCO, but it gets fd right */
  1145. #else
  1146.         int maxFD = 0, pageSize = getpagesize();
  1147. #endif /* OS-specific brokenness */
  1148.         int bufPos, i, usefulness = 0;
  1149.  
  1150.         /* Set up the shared memory */
  1151.         gathererBufSize = ( SHARED_BUFSIZE / pageSize ) * ( pageSize + 1 );
  1152.         if( ( gathererMemID = shmget( IPC_PRIVATE, gathererBufSize,
  1153.                                       IPC_CREAT | 0600 ) ) == -1 )
  1154.             return;    /* Something broke */
  1155.         if( ( gathererBuffer = ( BYTE * ) shmat( gathererMemID, NULL, 0 ) ) == ( BYTE * ) -1 )
  1156.             return; /* Something broke */
  1157.  
  1158.         /* Fork off the gatherer, the parent process returns to the caller */
  1159.         if( ( gathererProcess = fork() ) || ( gathererProcess == -1 ) )
  1160.             return;    /* Error/parent process returns */
  1161.  
  1162.         fclose( stderr );    /* Arrghh!!  It's Stuart code!! */
  1163.  
  1164.         /* Make sure we don't call popen() as root */
  1165.         if( gathererID == -1 && \
  1166.             ( passwd = getpwnam( "nobody" ) ) != NULL )
  1167.             gathererID = passwd->pw_uid;
  1168.         setuid( gathererID );
  1169.  
  1170.         /* Fire up each randomness source */
  1171.         FD_ZERO( &fds );
  1172.         for( i = 0; dataSources[ i ].path != NULL; i++ )
  1173.             {
  1174.             /* Since popen() is a fairly heavy function, we check to see
  1175.                whether the executable exists before we try to run it */
  1176.             if( access( dataSources[ i ].path, X_OK ) )
  1177.                 {
  1178. #ifdef DEBUG_RANDOM
  1179.                 printf( "%s not present%s\n", dataSources[ i ].path,
  1180.                         dataSources[ i ].hasAlternative ? ", has alternatives" : "" );
  1181. #endif /* DEBUG_RANDOM */
  1182.                 dataSources[ i ].pipe = NULL;
  1183.                 }
  1184.             else
  1185.                 dataSources[ i ].pipe = my_popen( &dataSources[ i ] );
  1186.             if( dataSources[ i ].pipe != NULL )
  1187.                 {
  1188.                 dataSources[ i ].pipeFD = fileno( dataSources[ i ].pipe );
  1189.                 if( dataSources[ i ].pipeFD > maxFD )
  1190.                     maxFD = dataSources[ i ].pipeFD;
  1191.                 fcntl( dataSources[ i ].pipeFD, F_SETFL, O_NONBLOCK );
  1192.                 FD_SET( dataSources[ i ].pipeFD, &fds );
  1193.                 dataSources[ i ].length = 0;
  1194.  
  1195.                 /* If there are alternatives for this command, don't try and
  1196.                    execute them */
  1197.                 while( dataSources[ i ].hasAlternative )
  1198.                     {
  1199. #ifdef DEBUG_RANDOM
  1200.                     printf( "Skipping %s\n", dataSources[ i + 1 ].path );
  1201. #endif /* DEBUG_RANDOM */
  1202.                     i++;
  1203.                     }
  1204.                 }
  1205.             }
  1206.         gathererInfo = ( GATHERER_INFO * ) gathererBuffer;
  1207.         bufPos = sizeof( GATHERER_INFO );    /* Start of buf.has status info */
  1208.  
  1209.         /* Suck all the data we can get from each of the sources */
  1210.         moreSources = TRUE;
  1211.         while( moreSources && bufPos <= gathererBufSize )
  1212.             {
  1213.             /* Wait for data to become available from any of the sources,
  1214.                with a timeout of 10 seconds.  This adds even more randomness
  1215.                since data becomes available in a nondeterministic fashion.
  1216.                Kudos to HP's QA department for managing to ship a select()
  1217.                which breaks its own prototype */
  1218.             tv.tv_sec = 10;
  1219.             tv.tv_usec = 0;
  1220. #ifdef __hpux
  1221.             if( select( maxFD + 1, ( int * ) &fds, NULL, NULL, &tv ) == -1 )
  1222. #else
  1223.             if( select( maxFD + 1, &fds, NULL, NULL, &tv ) == -1 )
  1224. #endif /* __hpux */
  1225.                 break;
  1226.  
  1227.             /* One of the sources has data available, read it into the
  1228.                buffer */
  1229.             for( i = 0; dataSources[ i ].path != NULL; i++ )
  1230.                 if( dataSources[ i ].pipe != NULL && \
  1231.                     FD_ISSET( dataSources[ i ].pipeFD, &fds ) )
  1232.                     {
  1233.                     size_t noBytes;
  1234.  
  1235.                     if( ( noBytes = fread( gathererBuffer + bufPos, 1,
  1236.                                            gathererBufSize - bufPos,
  1237.                                            dataSources[ i ].pipe ) ) == 0 )
  1238.                         {
  1239.                         if( my_pclose( &dataSources[ i ] ) == 0 )
  1240.                             {
  1241.                             int total = 0;
  1242.  
  1243.                             /* Try and estimate how much entropy we're
  1244.                                getting from a data source */
  1245.                             if( dataSources[ i ].usefulness )
  1246.                                 if( dataSources[ i ].usefulness < 0 )
  1247.                                     total = ( dataSources[ i ].length + 999 ) / \
  1248.                                             -dataSources[ i ].usefulness;
  1249.                                 else
  1250.                                     total = dataSources[ i ].length / \
  1251.                                             dataSources[ i ].usefulness;
  1252. #ifdef DEBUG_RANDOM
  1253.                             printf( "%s %s contributed %d bytes "
  1254.                                     "(compressed), usefulness = %d\n",
  1255.                                     dataSources[ i ].path,
  1256.                                     ( dataSources[ i ].arg != NULL ) ? \
  1257.                                     dataSources[ i ].arg : "",
  1258.                                     dataSources[ i ].length, total );
  1259. #endif /* DEBUG_RANDOM */
  1260.                             usefulness += total;
  1261.                             }
  1262.                         dataSources[ i ].pipe = NULL;
  1263.                         }
  1264.                     else
  1265.                         {
  1266.                         int currPos = bufPos;
  1267.                         int endPos = bufPos + noBytes;
  1268.  
  1269.                         /* Run-length compress the input byte sequence */
  1270.                         while( currPos < endPos )
  1271.                             {
  1272.                             int ch = gathererBuffer[ currPos ];
  1273.  
  1274.                             /* If it's a single byte, just copy it over */
  1275.                             if( ch != gathererBuffer[ currPos + 1 ] )
  1276.                                 {
  1277.                                 gathererBuffer[ bufPos++ ] = ch;
  1278.                                 currPos++;
  1279.                                 }
  1280.                             else
  1281.                                 {
  1282.                                 int count = 0;
  1283.  
  1284.                                 /* It's a run of repeated bytes, replace
  1285.                                    them with the byte count mod 256 */
  1286.                                 while( ( ch == gathererBuffer[ currPos ] ) && \
  1287.                                        currPos < endPos )
  1288.                                     {
  1289.                                     count++;
  1290.                                     currPos++;
  1291.                                     }
  1292.                                 gathererBuffer[ bufPos++ ] = count;
  1293.                                 noBytes -= count - 1;
  1294.                                 }
  1295.                             }
  1296.  
  1297.                         /* Remember the number of (compressed) bytes of input
  1298.                            we obtained */
  1299.                         dataSources[ i ].length += noBytes;
  1300.                         }
  1301.                     }
  1302.  
  1303.             /* Check if there is more input available on any of the sources */
  1304.             moreSources = FALSE;
  1305.             FD_ZERO( &fds );
  1306.             for( i = 0; dataSources[ i ].path != NULL; i++ )
  1307.                 if( dataSources[ i ].pipe != NULL )
  1308.                     {
  1309.                     FD_SET( dataSources[ i ].pipeFD, &fds );
  1310.                     moreSources = TRUE;
  1311.                     }
  1312.             }
  1313.         gathererInfo->usefulness = usefulness;
  1314.         gathererInfo->noBytes = bufPos;
  1315. #ifdef DEBUG_RANDOM
  1316.         printf( "Got %d bytes, usefulness = %d\n", bufPos, usefulness );
  1317. #endif /* DEBUG_RANDOM */
  1318.  
  1319.         /* Child MUST exit here */
  1320.         exit( 0 );
  1321.         }
  1322.     }
  1323.  
  1324. /* Wait for the randomness gathering to finish.  Anything that requires the
  1325.    gatherer process to have completed gathering entropy should call
  1326.    randomFlush(), which will block until the background process completes.
  1327.    At the moment this call is in the getRandomByte() routine */
  1328.  
  1329. static void randomFlush()
  1330.     {
  1331.     if( gathererProcess    )
  1332.         {
  1333.         GATHERER_INFO *gathererInfo = ( GATHERER_INFO * ) gathererBuffer;
  1334.         int    status;
  1335.  
  1336.         /* Wait for the gathering process to finish, add the randomness it's
  1337.            gathered, and detach the shared memory */
  1338.         waitpid( gathererProcess, &status, 0 ); /* Should prob.check status */
  1339.         addRandomBuffer( gathererBuffer, gathererInfo->noBytes );
  1340.         if( gathererInfo->usefulness >= 25 )
  1341.             randomStatus = CRYPT_OK;
  1342.         zeroise( gathererBuffer, gathererBufSize );
  1343.         shmdt( gathererBuffer );
  1344.         shmctl( gathererMemID, IPC_RMID, NULL );
  1345.         gathererProcess = 0;
  1346.         }
  1347.     }
  1348. #else
  1349.   #error You need to create the OS-specific randomness-gathering functions for lib_rand.c
  1350. #endif /* Various OS-specific defines */
  1351.  
  1352. /****************************************************************************
  1353. *                                                                            *
  1354. *                            Random Pool External Interface                    *
  1355. *                                                                            *
  1356. ****************************************************************************/
  1357.  
  1358. /* Add random data to the random pool.  We don't try to estimate the amount
  1359.    of entroy which we're adding due to the difficulty in doing this - if this
  1360.    sort of thing is required it's up to the user to look after it */
  1361.  
  1362. CRET cryptAddRandom( void CPTR randomData, int randomDataLength )
  1363.     {
  1364.     BYTE *randomDataPtr = ( BYTE * ) randomData;
  1365.  
  1366.     /* Perform basic error checking */
  1367.     if( randomData == NULL )
  1368.         {
  1369.         if( randomDataLength != CRYPT_RANDOM_FASTPOLL && \
  1370.             randomDataLength != CRYPT_RANDOM_SLOWPOLL )
  1371.             return( CRYPT_BADPARM1 );
  1372.         }
  1373.     else
  1374.         if( randomDataLength <= 0 )
  1375.             return( CRYPT_BADPARM2 );
  1376.  
  1377.     /* If the random data pool doesn't exist yet, create it now */
  1378.     if( randomPool == NULL )
  1379.         {
  1380.         int status;
  1381.  
  1382. #ifdef __WIN32__
  1383.         InitializeCriticalSection( &randProt );
  1384.         if( ( threadEvent = CreateEvent( NULL, FALSE, FALSE, NULL ) ) == NULL )
  1385.             return( CRYPT_NOMEM );    /* Anon.event, auto reset, not signalled */
  1386. #endif /* __WIN32__ */
  1387.  
  1388.         if( ( status = secureMalloc( ( void ** ) &randomPool,
  1389.                                      RANDOMPOOL_ALLOCSIZE ) ) != CRYPT_OK )
  1390.             return( status );
  1391.         randomWritePos = randomReadPos = 0;
  1392.         randomStatus = CRYPT_NORANDOM;
  1393.         }
  1394.  
  1395.     /* If we're adding data to the pool, add it now and exit */
  1396.     if( randomData != NULL )
  1397.         {
  1398.         threadSafeAddRandomBuffer( randomDataPtr, randomDataLength );
  1399.  
  1400.         /* We assume that the externally-added randomness is strong enough to
  1401.            satisfy the requirements for good random data.  Presumably anyone
  1402.            who bothers to use this call will ensure that they're using
  1403.            appropriate data such as the output of a hardware source and not
  1404.            just a call to time() */
  1405.         randomStatus = CRYPT_OK;
  1406.  
  1407.         return( CRYPT_OK );
  1408.         }
  1409.  
  1410.     /* Perform either a fast or slow poll for random system data */
  1411.     if( randomDataLength == CRYPT_RANDOM_FASTPOLL )
  1412.         fastPoll();
  1413.     else
  1414.         slowPoll();
  1415.  
  1416.     return( CRYPT_OK );
  1417.     }
  1418.  
  1419. /* Generate a session key in an encryption context from data in the random
  1420.    pool */
  1421.  
  1422. CRET cryptGenerateContextEx( CRYPT_CONTEXT cryptContext, const int userKeyLength )
  1423.     {
  1424.     CRYPT_INFO *cryptInfoPtr = CONTEXT_TO_INFO( cryptContext );
  1425.     CAPABILITY_INFO *capabilityInfoPtr;
  1426.     int keyLength;
  1427.  
  1428.     /* Perform basic error checking */
  1429.     if( isBadCookie( cryptContext ) )
  1430.         return( CRYPT_BADPARM1 );
  1431.     if( cryptInfoPtr->checkValue != CRYPT_MAGIC )
  1432.         return( CRYPT_NOTINITED );
  1433.     capabilityInfoPtr = cryptInfoPtr->capabilityInfo;
  1434.  
  1435.     /* If it's a hash function or PKC, the session key generate operation is
  1436.        meaningless */
  1437.     if( cryptInfoPtr->capabilityInfo->cryptMode == CRYPT_MODE_NONE || \
  1438.         cryptInfoPtr->isPKCcontext )
  1439.         return( CRYPT_NOTAVAIL );
  1440.  
  1441.     /* Determine the number of random bytes we'll need.  In order to avoid
  1442.        problems with space inside shorter RSA-encrypted blocks, we limit the
  1443.        total keysize to 448 bits, which is adequate for all purposes - the
  1444.        limiting factor is three-key triple DESX, which requires ( 3 * 64 ) +
  1445.        ( 4 * 64 ) bits of key, and absolutely must have that many bits or it
  1446.        just reduces to triple-DES with a bit of DESX.  Unfortunately we can't
  1447.        tell what the user is going to do with the generated key so we have to
  1448.        take the approach of using the shortest possible length.  This means
  1449.        that the default keys generated for Blowfish, MDC/SHS, and triple DESX
  1450.        can't be exported when very short RSA keys are used */
  1451.     if( ( keyLength = userKeyLength ) == CRYPT_USE_DEFAULT )
  1452.         if( capabilityInfoPtr->getKeysizeFunction != NULL )
  1453.             keyLength = capabilityInfoPtr->getKeysizeFunction( cryptInfoPtr );
  1454.         else
  1455.             keyLength = capabilityInfoPtr->maxKeySize;
  1456.     if( keyLength > bitsToBytes( 448 ) )
  1457.         keyLength = bitsToBytes( 448 );
  1458.     if( keyLength > RANDOMPOOL_SIZE )
  1459.         return( CRYPT_BADPARM3 );
  1460.  
  1461.     /* Perform a failsafe check - this should only ever be called once per
  1462.         app, because after the first blocking poll the programmer of the
  1463.         calling app will make sure there's a slow poll done earlier on */
  1464.     if( randomPool == NULL )
  1465.         cryptAddRandom( NULL, CRYPT_RANDOM_SLOWPOLL );
  1466. #if defined( __UNIX__ ) || defined( __WIN32__ )
  1467.     randomFlush();    /* Make sure any gatherer thread/process has completed */
  1468. #endif /* __UNIX__ || __WIN32__ */
  1469.  
  1470.     /* If we still can't get any random information, let the user know */
  1471.     if( cryptStatusError( randomStatus ) )
  1472.         return( randomStatus );
  1473.  
  1474.     /* Load a session key into the encryption context.  Before we use the
  1475.        information from the random pool, we perform a final quick poll of
  1476.        the system to get any last bit of entropy.  We then pass the
  1477.        (probably pagelocked) random pool directly to cryptLoadContext() to
  1478.        avoid copying it to a pageable temporary buffer.
  1479.        Note that we don't want to set the clearBuffer flag in the encryption
  1480.        context here because (a) the entropy pool is probably pagelocked
  1481.        anyway and (b) we don't want to lose the contents of the pool */
  1482.     fastPoll();
  1483. #ifdef __WIN32__
  1484.     EnterCriticalSection( &randProt );
  1485. #endif /* __WIN32__ */
  1486.     mixRandomPool();
  1487. #ifdef __WIN32__
  1488.     LeaveCriticalSection( &randProt );
  1489. #endif /* __WIN32__ */
  1490.     return( cryptLoadContext( cryptContext, randomPool, keyLength ) );
  1491.     }
  1492.  
  1493. /* Retrieve data from the random pool */
  1494.  
  1495. int getRandomByte( void )
  1496.     {
  1497. #if defined( __UNIX__ ) || defined( __WIN32__ )
  1498.     randomFlush();    /* Make sure any gatherer thread/process has completed */
  1499. #endif /* __UNIX__ || __WIN32__ */
  1500.  
  1501.     /* Perform a failsafe check - this should only ever be called once per
  1502.        app, because after the first blocking poll the programmer of the
  1503.        calling app will make sure there's a slow poll done earlier on */
  1504.     if( randomPool == NULL )
  1505.         cryptAddRandom( NULL, CRYPT_RANDOM_SLOWPOLL );
  1506.  
  1507.     /* If we still can't get any random information, let the user know */
  1508.     if( cryptStatusError( randomStatus ) )
  1509.         return( randomStatus );
  1510.  
  1511.     /* If there's newly-written (and currently unmixed) data in the pool or
  1512.        we've reached the end of the pool, mix it up, then return the next
  1513.        byte in the pool */
  1514.     if( randomWritePos || randomReadPos > RANDOMPOOL_SIZE )
  1515.         mixRandomPool();
  1516.     return( randomPool[ randomReadPos++ ] );
  1517.     }
  1518.  
  1519. /* Shut down the random data pool */
  1520.  
  1521. void endRandom( void )
  1522.     {
  1523. #if defined( __WIN32__ )
  1524.     if( threadID != NULL )
  1525.         CloseHandle( threadID );
  1526.     if( threadEvent != NULL )
  1527.         CloseHandle( threadEvent );
  1528.     DeleteCriticalSection( &randProt );
  1529.     if( hNetAPI32 )
  1530.         {
  1531.         FreeLibrary( hNetAPI32 );
  1532.         hNetAPI32 = NULL;
  1533.         }
  1534. #endif /* __WIN32__ */
  1535.     if( randomPool != NULL )
  1536.         {
  1537.         secureFree( ( void ** ) &randomPool );
  1538.         randomWritePos = randomReadPos = 0;
  1539.         }
  1540.     }
  1541.