diff options
Diffstat (limited to 'security/nss/lib/freebl/win_rand.c')
-rw-r--r-- | security/nss/lib/freebl/win_rand.c | 415 |
1 files changed, 415 insertions, 0 deletions
diff --git a/security/nss/lib/freebl/win_rand.c b/security/nss/lib/freebl/win_rand.c new file mode 100644 index 000000000..dc16b19b7 --- /dev/null +++ b/security/nss/lib/freebl/win_rand.c @@ -0,0 +1,415 @@ +/* + * 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> +#endif + +static BOOL +CurrentClockTickTime(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 BOOL +EnumSystemFiles(void (*func)(const 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 void +CountFiles(const char *file) +{ + dwNumFiles++; +} + +static void +ReadFiles(const char *file) +{ + if ((dwNumFiles % dwReadEvery) == 0) + RNG_FileForRNG(file); + + dwNumFiles++; +} + +static void +ReadSystemFiles() +{ + // 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(const 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 */ |