win_rand.c

来自「支持SSL v2/v3, TLS, PKCS #5, PKCS #7, PKCS」· C语言 代码 · 共 416 行

C
416
字号
/* * The contents of this file are subject to the Mozilla Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/MPL/ *  * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. *  * The Original Code is the Netscape security libraries. *  * The Initial Developer of the Original Code is Netscape * Communications Corporation.  Portions created by Netscape are  * Copyright (C) 1994-2000 Netscape Communications Corporation.  All * Rights Reserved. *  * Contributor(s): *  * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License Version 2 or later (the * "GPL"), in which case the provisions of the GPL are applicable  * instead of those above.  If you wish to allow use of your  * version of this file only under the terms of the GPL and not to * allow others to use your version of this file under the MPL, * indicate your decision by deleting the provisions above and * replace them with the notice and other provisions required by * the GPL.  If you do not delete the provisions above, a recipient * may use your version of this file under either the MPL or the * GPL. */#include "secrng.h"#ifdef XP_WIN#include <windows.h>#include <time.h>#include <io.h>#include <sys/types.h>#include <sys/stat.h>#include <stdio.h>#ifndef _WIN32#define VTD_Device_ID   5#define OP_OVERRIDE     _asm _emit 0x66#include <dos.h>#endifstatic BOOLCurrentClockTickTime(LPDWORD lpdwHigh, LPDWORD lpdwLow){#ifdef _WIN32    LARGE_INTEGER   liCount;    if (!QueryPerformanceCounter(&liCount))        return FALSE;    *lpdwHigh = liCount.u.HighPart;    *lpdwLow = liCount.u.LowPart;    return TRUE;#else   /* is WIN16 */    BOOL    bRetVal;    FARPROC lpAPI;    WORD    w1, w2, w3, w4;    // Get direct access to the VTD and query the current clock tick time    _asm {        xor   di, di        mov   es, di        mov   ax, 1684h        mov   bx, VTD_Device_ID        int   2fh        mov   ax, es        or    ax, di        jz    EnumerateFailed        ; VTD API is available. First store the API address (the address actually        ; contains an instruction that causes a fault, the fault handler then        ; makes the ring transition and calls the API in the VxD)        mov   word ptr lpAPI, di        mov   word ptr lpAPI+2, es        mov   ax, 100h      ; API function to VTD_Get_Real_Time;       call  dword ptr [lpAPI]        call  [lpAPI]        ; Result is in EDX:EAX which we will get 16-bits at a time        mov   w2, dx        OP_OVERRIDE        shr   dx,10h        ; really "shr edx, 16"        mov   w1, dx        mov   w4, ax        OP_OVERRIDE        shr   ax,10h        ; really "shr eax, 16"        mov   w3, ax        mov   bRetVal, 1    ; return TRUE        jmp   EnumerateExit      EnumerateFailed:        mov   bRetVal, 0    ; return FALSE      EnumerateExit:    }    *lpdwHigh = MAKELONG(w2, w1);    *lpdwLow = MAKELONG(w4, w3);    return bRetVal;#endif  /* is WIN16 */}size_t RNG_GetNoise(void *buf, size_t maxbuf){    DWORD   dwHigh, dwLow, dwVal;    int     n = 0;    int     nBytes;    time_t  sTime;    if (maxbuf <= 0)        return 0;    CurrentClockTickTime(&dwHigh, &dwLow);    // get the maximally changing bits first    nBytes = sizeof(dwLow) > maxbuf ? maxbuf : sizeof(dwLow);    memcpy((char *)buf, &dwLow, nBytes);    n += nBytes;    maxbuf -= nBytes;    if (maxbuf <= 0)        return n;    nBytes = sizeof(dwHigh) > maxbuf ? maxbuf : sizeof(dwHigh);    memcpy(((char *)buf) + n, &dwHigh, nBytes);    n += nBytes;    maxbuf -= nBytes;    if (maxbuf <= 0)        return n;    // get the number of milliseconds that have elapsed since Windows started    dwVal = GetTickCount();    nBytes = sizeof(dwVal) > maxbuf ? maxbuf : sizeof(dwVal);    memcpy(((char *)buf) + n, &dwVal, nBytes);    n += nBytes;    maxbuf -= nBytes;    if (maxbuf <= 0)        return n;    // get the time in seconds since midnight Jan 1, 1970    time(&sTime);    nBytes = sizeof(sTime) > maxbuf ? maxbuf : sizeof(sTime);    memcpy(((char *)buf) + n, &sTime, nBytes);    n += nBytes;    return n;}static BOOLEnumSystemFiles(void (*func)(char *)){    int                 iStatus;    char                szSysDir[_MAX_PATH];    char                szFileName[_MAX_PATH];#ifdef _WIN32    struct _finddata_t  fdData;    long                lFindHandle;#else    struct _find_t  fdData;#endif    if (!GetSystemDirectory(szSysDir, sizeof(szSysDir)))        return FALSE;    // tack *.* on the end so we actually look for files. this will    // not overflow    strcpy(szFileName, szSysDir);    strcat(szFileName, "\\*.*");#ifdef _WIN32    lFindHandle = _findfirst(szFileName, &fdData);    if (lFindHandle == -1)        return FALSE;#else    if (_dos_findfirst(szFileName, _A_NORMAL | _A_RDONLY | _A_ARCH | _A_SUBDIR, &fdData) != 0)        return FALSE;#endif    do {        // pass the full pathname to the callback        sprintf(szFileName, "%s\\%s", szSysDir, fdData.name);        (*func)(szFileName);#ifdef _WIN32        iStatus = _findnext(lFindHandle, &fdData);#else        iStatus = _dos_findnext(&fdData);#endif    } while (iStatus == 0);#ifdef _WIN32    _findclose(lFindHandle);#endif    return TRUE;}static DWORD    dwNumFiles, dwReadEvery;static voidCountFiles(char *file){    dwNumFiles++;}static voidReadFiles(char *file){    if ((dwNumFiles % dwReadEvery) == 0)        RNG_FileForRNG(file);    dwNumFiles++;}static voidReadSystemFiles(){    // first count the number of files    dwNumFiles = 0;    if (!EnumSystemFiles(CountFiles))        return;    RNG_RandomUpdate(&dwNumFiles, sizeof(dwNumFiles));    // now read 10 files    if (dwNumFiles == 0)        return;    dwReadEvery = dwNumFiles / 10;    if (dwReadEvery == 0)        dwReadEvery = 1;  // less than 10 files    dwNumFiles = 0;    EnumSystemFiles(ReadFiles);}void RNG_SystemInfoForRNG(void){    DWORD           dwVal;    char            buffer[256];    int             nBytes;#ifdef _WIN32    MEMORYSTATUS    sMem;    DWORD           dwSerialNum;    DWORD           dwComponentLen;    DWORD           dwSysFlags;    char            volName[128];    DWORD           dwSectors, dwBytes, dwFreeClusters, dwNumClusters;    HANDLE          hVal;#else    int             iVal;    HTASK           hTask;    WORD            wDS, wCS;    LPSTR           lpszEnv;#endif    nBytes = RNG_GetNoise(buffer, 20);  // get up to 20 bytes    RNG_RandomUpdate(buffer, nBytes);#ifdef _WIN32    sMem.dwLength = sizeof(sMem);    GlobalMemoryStatus(&sMem);                // assorted memory stats    RNG_RandomUpdate(&sMem, sizeof(sMem));    dwVal = GetLogicalDrives();    RNG_RandomUpdate(&dwVal, sizeof(dwVal));  // bitfields in bits 0-25#else    dwVal = GetFreeSpace(0);    RNG_RandomUpdate(&dwVal, sizeof(dwVal));    _asm    mov wDS, ds;    _asm    mov wCS, cs;    RNG_RandomUpdate(&wDS, sizeof(wDS));    RNG_RandomUpdate(&wCS, sizeof(wCS));#endif#ifdef _WIN32    dwVal = sizeof(buffer);    if (GetComputerName(buffer, &dwVal))        RNG_RandomUpdate(buffer, dwVal);/* XXX This is code that got yanked because of NSPR20.  We should put it * back someday. */#ifdef notdef    {    POINT ptVal;    GetCursorPos(&ptVal);    RNG_RandomUpdate(&ptVal, sizeof(ptVal));    }    dwVal = GetQueueStatus(QS_ALLINPUT);      // high and low significant    RNG_RandomUpdate(&dwVal, sizeof(dwVal));    {    HWND hWnd;    hWnd = GetClipboardOwner();               // 2 or 4 bytes    RNG_RandomUpdate((void *)&hWnd, sizeof(hWnd));    }    {    UUID sUuid;    UuidCreate(&sUuid);                       // this will fail on machines with no ethernet    RNG_RandomUpdate(&sUuid, sizeof(sUuid));  // boards. shove the bits in regardless    }#endif    hVal = GetCurrentProcess();               // 4 byte handle of current task    RNG_RandomUpdate(&hVal, sizeof(hVal));    dwVal = GetCurrentProcessId();            // process ID (4 bytes)    RNG_RandomUpdate(&dwVal, sizeof(dwVal));    volName[0] = '\0';    buffer[0] = '\0';    GetVolumeInformation(NULL,                         volName,                         sizeof(volName),                         &dwSerialNum,                         &dwComponentLen,                         &dwSysFlags,                         buffer,                         sizeof(buffer));    RNG_RandomUpdate(volName,         strlen(volName));    RNG_RandomUpdate(&dwSerialNum,    sizeof(dwSerialNum));    RNG_RandomUpdate(&dwComponentLen, sizeof(dwComponentLen));    RNG_RandomUpdate(&dwSysFlags,     sizeof(dwSysFlags));    RNG_RandomUpdate(buffer,          strlen(buffer));    if (GetDiskFreeSpace(NULL, &dwSectors, &dwBytes, &dwFreeClusters, &dwNumClusters)) {        RNG_RandomUpdate(&dwSectors,      sizeof(dwSectors));        RNG_RandomUpdate(&dwBytes,        sizeof(dwBytes));        RNG_RandomUpdate(&dwFreeClusters, sizeof(dwFreeClusters));        RNG_RandomUpdate(&dwNumClusters,  sizeof(dwNumClusters));    }#else   /* is WIN16 */    hTask = GetCurrentTask();    RNG_RandomUpdate((void *)&hTask, sizeof(hTask));    iVal = GetNumTasks();    RNG_RandomUpdate(&iVal, sizeof(iVal));      // number of running tasks    lpszEnv = GetDOSEnvironment();    while (*lpszEnv != '\0') {        RNG_RandomUpdate(lpszEnv, strlen(lpszEnv));        lpszEnv += strlen(lpszEnv) + 1;    }#endif  /* is WIN16 */    // now let's do some files    ReadSystemFiles();    nBytes = RNG_GetNoise(buffer, 20);  // get up to 20 bytes    RNG_RandomUpdate(buffer, nBytes);}void RNG_FileForRNG(char *filename){    FILE*           file;    int             nBytes;    struct stat     stat_buf;    unsigned char   buffer[1024];    static DWORD    totalFileBytes = 0;    /* windows doesn't initialize all the bytes in the stat buf,     * so initialize them all here to avoid UMRs.     */    memset(&stat_buf, 0, sizeof stat_buf);    if (stat((char *)filename, &stat_buf) < 0)        return;    RNG_RandomUpdate((unsigned char*)&stat_buf, sizeof(stat_buf));    file = fopen((char *)filename, "r");    if (file != NULL) {        for (;;) {            size_t  bytes = fread(buffer, 1, sizeof(buffer), file);            if (bytes == 0)                break;            RNG_RandomUpdate(buffer, bytes);            totalFileBytes += bytes;            if (totalFileBytes > 250000)                break;        }        fclose(file);    }    nBytes = RNG_GetNoise(buffer, 20);  // get up to 20 bytes    RNG_RandomUpdate(buffer, nBytes);}#endif  /* is XP_WIN */

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?