win_rand.c
上传用户:lyxiangda
上传日期:2007-01-12
资源大小:3042k
文件大小:11k
源码类别:

CA认证

开发平台:

WINDOWS

  1. /*
  2.  * The contents of this file are subject to the Mozilla Public
  3.  * License Version 1.1 (the "License"); you may not use this file
  4.  * except in compliance with the License. You may obtain a copy of
  5.  * the License at http://www.mozilla.org/MPL/
  6.  * 
  7.  * Software distributed under the License is distributed on an "AS
  8.  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  9.  * implied. See the License for the specific language governing
  10.  * rights and limitations under the License.
  11.  * 
  12.  * The Original Code is the Netscape security libraries.
  13.  * 
  14.  * The Initial Developer of the Original Code is Netscape
  15.  * Communications Corporation.  Portions created by Netscape are 
  16.  * Copyright (C) 1994-2000 Netscape Communications Corporation.  All
  17.  * Rights Reserved.
  18.  * 
  19.  * Contributor(s):
  20.  * 
  21.  * Alternatively, the contents of this file may be used under the
  22.  * terms of the GNU General Public License Version 2 or later (the
  23.  * "GPL"), in which case the provisions of the GPL are applicable 
  24.  * instead of those above.  If you wish to allow use of your 
  25.  * version of this file only under the terms of the GPL and not to
  26.  * allow others to use your version of this file under the MPL,
  27.  * indicate your decision by deleting the provisions above and
  28.  * replace them with the notice and other provisions required by
  29.  * the GPL.  If you do not delete the provisions above, a recipient
  30.  * may use your version of this file under either the MPL or the
  31.  * GPL.
  32.  */
  33. #include "secrng.h"
  34. #ifdef XP_WIN
  35. #include <windows.h>
  36. #include <time.h>
  37. #include <io.h>
  38. #include <sys/types.h>
  39. #include <sys/stat.h>
  40. #include <stdio.h>
  41. #ifndef _WIN32
  42. #define VTD_Device_ID   5
  43. #define OP_OVERRIDE     _asm _emit 0x66
  44. #include <dos.h>
  45. #endif
  46. static BOOL
  47. CurrentClockTickTime(LPDWORD lpdwHigh, LPDWORD lpdwLow)
  48. {
  49. #ifdef _WIN32
  50.     LARGE_INTEGER   liCount;
  51.     if (!QueryPerformanceCounter(&liCount))
  52.         return FALSE;
  53.     *lpdwHigh = liCount.u.HighPart;
  54.     *lpdwLow = liCount.u.LowPart;
  55.     return TRUE;
  56. #else   /* is WIN16 */
  57.     BOOL    bRetVal;
  58.     FARPROC lpAPI;
  59.     WORD    w1, w2, w3, w4;
  60.     // Get direct access to the VTD and query the current clock tick time
  61.     _asm {
  62.         xor   di, di
  63.         mov   es, di
  64.         mov   ax, 1684h
  65.         mov   bx, VTD_Device_ID
  66.         int   2fh
  67.         mov   ax, es
  68.         or    ax, di
  69.         jz    EnumerateFailed
  70.         ; VTD API is available. First store the API address (the address actually
  71.         ; contains an instruction that causes a fault, the fault handler then
  72.         ; makes the ring transition and calls the API in the VxD)
  73.         mov   word ptr lpAPI, di
  74.         mov   word ptr lpAPI+2, es
  75.         mov   ax, 100h      ; API function to VTD_Get_Real_Time
  76. ;       call  dword ptr [lpAPI]
  77.         call  [lpAPI]
  78.         ; Result is in EDX:EAX which we will get 16-bits at a time
  79.         mov   w2, dx
  80.         OP_OVERRIDE
  81.         shr   dx,10h        ; really "shr edx, 16"
  82.         mov   w1, dx
  83.         mov   w4, ax
  84.         OP_OVERRIDE
  85.         shr   ax,10h        ; really "shr eax, 16"
  86.         mov   w3, ax
  87.         mov   bRetVal, 1    ; return TRUE
  88.         jmp   EnumerateExit
  89.       EnumerateFailed:
  90.         mov   bRetVal, 0    ; return FALSE
  91.       EnumerateExit:
  92.     }
  93.     *lpdwHigh = MAKELONG(w2, w1);
  94.     *lpdwLow = MAKELONG(w4, w3);
  95.     return bRetVal;
  96. #endif  /* is WIN16 */
  97. }
  98. size_t RNG_GetNoise(void *buf, size_t maxbuf)
  99. {
  100.     DWORD   dwHigh, dwLow, dwVal;
  101.     int     n = 0;
  102.     int     nBytes;
  103.     time_t  sTime;
  104.     if (maxbuf <= 0)
  105.         return 0;
  106.     CurrentClockTickTime(&dwHigh, &dwLow);
  107.     // get the maximally changing bits first
  108.     nBytes = sizeof(dwLow) > maxbuf ? maxbuf : sizeof(dwLow);
  109.     memcpy((char *)buf, &dwLow, nBytes);
  110.     n += nBytes;
  111.     maxbuf -= nBytes;
  112.     if (maxbuf <= 0)
  113.         return n;
  114.     nBytes = sizeof(dwHigh) > maxbuf ? maxbuf : sizeof(dwHigh);
  115.     memcpy(((char *)buf) + n, &dwHigh, nBytes);
  116.     n += nBytes;
  117.     maxbuf -= nBytes;
  118.     if (maxbuf <= 0)
  119.         return n;
  120.     // get the number of milliseconds that have elapsed since Windows started
  121.     dwVal = GetTickCount();
  122.     nBytes = sizeof(dwVal) > maxbuf ? maxbuf : sizeof(dwVal);
  123.     memcpy(((char *)buf) + n, &dwVal, nBytes);
  124.     n += nBytes;
  125.     maxbuf -= nBytes;
  126.     if (maxbuf <= 0)
  127.         return n;
  128.     // get the time in seconds since midnight Jan 1, 1970
  129.     time(&sTime);
  130.     nBytes = sizeof(sTime) > maxbuf ? maxbuf : sizeof(sTime);
  131.     memcpy(((char *)buf) + n, &sTime, nBytes);
  132.     n += nBytes;
  133.     return n;
  134. }
  135. static BOOL
  136. EnumSystemFiles(void (*func)(char *))
  137. {
  138.     int                 iStatus;
  139.     char                szSysDir[_MAX_PATH];
  140.     char                szFileName[_MAX_PATH];
  141. #ifdef _WIN32
  142.     struct _finddata_t  fdData;
  143.     long                lFindHandle;
  144. #else
  145.     struct _find_t  fdData;
  146. #endif
  147.     if (!GetSystemDirectory(szSysDir, sizeof(szSysDir)))
  148.         return FALSE;
  149.     // tack *.* on the end so we actually look for files. this will
  150.     // not overflow
  151.     strcpy(szFileName, szSysDir);
  152.     strcat(szFileName, "\*.*");
  153. #ifdef _WIN32
  154.     lFindHandle = _findfirst(szFileName, &fdData);
  155.     if (lFindHandle == -1)
  156.         return FALSE;
  157. #else
  158.     if (_dos_findfirst(szFileName, _A_NORMAL | _A_RDONLY | _A_ARCH | _A_SUBDIR, &fdData) != 0)
  159.         return FALSE;
  160. #endif
  161.     do {
  162.         // pass the full pathname to the callback
  163.         sprintf(szFileName, "%s\%s", szSysDir, fdData.name);
  164.         (*func)(szFileName);
  165. #ifdef _WIN32
  166.         iStatus = _findnext(lFindHandle, &fdData);
  167. #else
  168.         iStatus = _dos_findnext(&fdData);
  169. #endif
  170.     } while (iStatus == 0);
  171. #ifdef _WIN32
  172.     _findclose(lFindHandle);
  173. #endif
  174.     return TRUE;
  175. }
  176. static DWORD    dwNumFiles, dwReadEvery;
  177. static void
  178. CountFiles(char *file)
  179. {
  180.     dwNumFiles++;
  181. }
  182. static void
  183. ReadFiles(char *file)
  184. {
  185.     if ((dwNumFiles % dwReadEvery) == 0)
  186.         RNG_FileForRNG(file);
  187.     dwNumFiles++;
  188. }
  189. static void
  190. ReadSystemFiles()
  191. {
  192.     // first count the number of files
  193.     dwNumFiles = 0;
  194.     if (!EnumSystemFiles(CountFiles))
  195.         return;
  196.     RNG_RandomUpdate(&dwNumFiles, sizeof(dwNumFiles));
  197.     // now read 10 files
  198.     if (dwNumFiles == 0)
  199.         return;
  200.     dwReadEvery = dwNumFiles / 10;
  201.     if (dwReadEvery == 0)
  202.         dwReadEvery = 1;  // less than 10 files
  203.     dwNumFiles = 0;
  204.     EnumSystemFiles(ReadFiles);
  205. }
  206. void RNG_SystemInfoForRNG(void)
  207. {
  208.     DWORD           dwVal;
  209.     char            buffer[256];
  210.     int             nBytes;
  211. #ifdef _WIN32
  212.     MEMORYSTATUS    sMem;
  213.     DWORD           dwSerialNum;
  214.     DWORD           dwComponentLen;
  215.     DWORD           dwSysFlags;
  216.     char            volName[128];
  217.     DWORD           dwSectors, dwBytes, dwFreeClusters, dwNumClusters;
  218.     HANDLE          hVal;
  219. #else
  220.     int             iVal;
  221.     HTASK           hTask;
  222.     WORD            wDS, wCS;
  223.     LPSTR           lpszEnv;
  224. #endif
  225.     nBytes = RNG_GetNoise(buffer, 20);  // get up to 20 bytes
  226.     RNG_RandomUpdate(buffer, nBytes);
  227. #ifdef _WIN32
  228.     sMem.dwLength = sizeof(sMem);
  229.     GlobalMemoryStatus(&sMem);                // assorted memory stats
  230.     RNG_RandomUpdate(&sMem, sizeof(sMem));
  231.     dwVal = GetLogicalDrives();
  232.     RNG_RandomUpdate(&dwVal, sizeof(dwVal));  // bitfields in bits 0-25
  233. #else
  234.     dwVal = GetFreeSpace(0);
  235.     RNG_RandomUpdate(&dwVal, sizeof(dwVal));
  236.     _asm    mov wDS, ds;
  237.     _asm    mov wCS, cs;
  238.     RNG_RandomUpdate(&wDS, sizeof(wDS));
  239.     RNG_RandomUpdate(&wCS, sizeof(wCS));
  240. #endif
  241. #ifdef _WIN32
  242.     dwVal = sizeof(buffer);
  243.     if (GetComputerName(buffer, &dwVal))
  244.         RNG_RandomUpdate(buffer, dwVal);
  245. /* XXX This is code that got yanked because of NSPR20.  We should put it
  246.  * back someday.
  247.  */
  248. #ifdef notdef
  249.     {
  250.     POINT ptVal;
  251.     GetCursorPos(&ptVal);
  252.     RNG_RandomUpdate(&ptVal, sizeof(ptVal));
  253.     }
  254.     dwVal = GetQueueStatus(QS_ALLINPUT);      // high and low significant
  255.     RNG_RandomUpdate(&dwVal, sizeof(dwVal));
  256.     {
  257.     HWND hWnd;
  258.     hWnd = GetClipboardOwner();               // 2 or 4 bytes
  259.     RNG_RandomUpdate((void *)&hWnd, sizeof(hWnd));
  260.     }
  261.     {
  262.     UUID sUuid;
  263.     UuidCreate(&sUuid);                       // this will fail on machines with no ethernet
  264.     RNG_RandomUpdate(&sUuid, sizeof(sUuid));  // boards. shove the bits in regardless
  265.     }
  266. #endif
  267.     hVal = GetCurrentProcess();               // 4 byte handle of current task
  268.     RNG_RandomUpdate(&hVal, sizeof(hVal));
  269.     dwVal = GetCurrentProcessId();            // process ID (4 bytes)
  270.     RNG_RandomUpdate(&dwVal, sizeof(dwVal));
  271.     volName[0] = '';
  272.     buffer[0] = '';
  273.     GetVolumeInformation(NULL,
  274.                          volName,
  275.                          sizeof(volName),
  276.                          &dwSerialNum,
  277.                          &dwComponentLen,
  278.                          &dwSysFlags,
  279.                          buffer,
  280.                          sizeof(buffer));
  281.     RNG_RandomUpdate(volName,         strlen(volName));
  282.     RNG_RandomUpdate(&dwSerialNum,    sizeof(dwSerialNum));
  283.     RNG_RandomUpdate(&dwComponentLen, sizeof(dwComponentLen));
  284.     RNG_RandomUpdate(&dwSysFlags,     sizeof(dwSysFlags));
  285.     RNG_RandomUpdate(buffer,          strlen(buffer));
  286.     if (GetDiskFreeSpace(NULL, &dwSectors, &dwBytes, &dwFreeClusters, &dwNumClusters)) {
  287.         RNG_RandomUpdate(&dwSectors,      sizeof(dwSectors));
  288.         RNG_RandomUpdate(&dwBytes,        sizeof(dwBytes));
  289.         RNG_RandomUpdate(&dwFreeClusters, sizeof(dwFreeClusters));
  290.         RNG_RandomUpdate(&dwNumClusters,  sizeof(dwNumClusters));
  291.     }
  292. #else   /* is WIN16 */
  293.     hTask = GetCurrentTask();
  294.     RNG_RandomUpdate((void *)&hTask, sizeof(hTask));
  295.     iVal = GetNumTasks();
  296.     RNG_RandomUpdate(&iVal, sizeof(iVal));      // number of running tasks
  297.     lpszEnv = GetDOSEnvironment();
  298.     while (*lpszEnv != '') {
  299.         RNG_RandomUpdate(lpszEnv, strlen(lpszEnv));
  300.         lpszEnv += strlen(lpszEnv) + 1;
  301.     }
  302. #endif  /* is WIN16 */
  303.     // now let's do some files
  304.     ReadSystemFiles();
  305.     nBytes = RNG_GetNoise(buffer, 20);  // get up to 20 bytes
  306.     RNG_RandomUpdate(buffer, nBytes);
  307. }
  308. void RNG_FileForRNG(char *filename)
  309. {
  310.     FILE*           file;
  311.     int             nBytes;
  312.     struct stat     stat_buf;
  313.     unsigned char   buffer[1024];
  314.     static DWORD    totalFileBytes = 0;
  315.     /* windows doesn't initialize all the bytes in the stat buf,
  316.      * so initialize them all here to avoid UMRs.
  317.      */
  318.     memset(&stat_buf, 0, sizeof stat_buf);
  319.     if (stat((char *)filename, &stat_buf) < 0)
  320.         return;
  321.     RNG_RandomUpdate((unsigned char*)&stat_buf, sizeof(stat_buf));
  322.     file = fopen((char *)filename, "r");
  323.     if (file != NULL) {
  324.         for (;;) {
  325.             size_t  bytes = fread(buffer, 1, sizeof(buffer), file);
  326.             if (bytes == 0)
  327.                 break;
  328.             RNG_RandomUpdate(buffer, bytes);
  329.             totalFileBytes += bytes;
  330.             if (totalFileBytes > 250000)
  331.                 break;
  332.         }
  333.         fclose(file);
  334.     }
  335.     nBytes = RNG_GetNoise(buffer, 20);  // get up to 20 bytes
  336.     RNG_RandomUpdate(buffer, nBytes);
  337. }
  338. #endif  /* is XP_WIN */