Index: mozilla/security/nss/lib/freebl/win_rand.c |
=================================================================== |
--- mozilla/security/nss/lib/freebl/win_rand.c (revision 191424) |
+++ mozilla/security/nss/lib/freebl/win_rand.c (working copy) |
@@ -1,463 +0,0 @@ |
-/* This Source Code Form is subject to the terms of the Mozilla Public |
- * License, v. 2.0. If a copy of the MPL was not distributed with this |
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
- |
-#include "secrng.h" |
-#include "secerr.h" |
- |
-#ifdef XP_WIN |
-#include <windows.h> |
-#include <shlobj.h> /* for CSIDL constants */ |
-#include <time.h> |
-#include <io.h> |
-#include <sys/types.h> |
-#include <sys/stat.h> |
-#include <stdio.h> |
-#include "prio.h" |
-#include "prerror.h" |
- |
-static PRInt32 filesToRead; |
-static DWORD totalFileBytes; |
-static DWORD maxFileBytes = 250000; /* 250 thousand */ |
-static DWORD dwNumFiles, dwReadEvery, dwFileToRead; |
-static PRBool usedWindowsPRNG; |
- |
-static BOOL |
-CurrentClockTickTime(LPDWORD lpdwHigh, LPDWORD lpdwLow) |
-{ |
- LARGE_INTEGER liCount; |
- |
- if (!QueryPerformanceCounter(&liCount)) |
- return FALSE; |
- |
- *lpdwHigh = liCount.u.HighPart; |
- *lpdwLow = liCount.u.LowPart; |
- return TRUE; |
-} |
- |
-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; |
-} |
- |
-typedef PRInt32 (* Handler)(const PRUnichar *); |
-#define MAX_DEPTH 2 |
-#define MAX_FOLDERS 4 |
-#define MAX_FILES 1024 |
- |
-static void |
-EnumSystemFilesInFolder(Handler func, PRUnichar* szSysDir, int maxDepth) |
-{ |
- int iContinue; |
- unsigned int uFolders = 0; |
- unsigned int uFiles = 0; |
- HANDLE lFindHandle; |
- WIN32_FIND_DATAW fdData; |
- PRUnichar szFileName[_MAX_PATH]; |
- |
- if (maxDepth < 0) |
- return; |
- // append *.* so we actually look for files. |
- _snwprintf(szFileName, _MAX_PATH, L"%s\\*.*", szSysDir); |
- szFileName[_MAX_PATH - 1] = L'\0'; |
- |
- lFindHandle = FindFirstFileW(szFileName, &fdData); |
- if (lFindHandle == INVALID_HANDLE_VALUE) |
- return; |
- do { |
- iContinue = 1; |
- if (wcscmp(fdData.cFileName, L".") == 0 || |
- wcscmp(fdData.cFileName, L"..") == 0) { |
- // skip "." and ".." |
- } else { |
- // pass the full pathname to the callback |
- _snwprintf(szFileName, _MAX_PATH, L"%s\\%s", szSysDir, |
- fdData.cFileName); |
- szFileName[_MAX_PATH - 1] = L'\0'; |
- if (fdData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { |
- if (++uFolders <= MAX_FOLDERS) |
- EnumSystemFilesInFolder(func, szFileName, maxDepth - 1); |
- } else { |
- iContinue = (++uFiles <= MAX_FILES) && !(*func)(szFileName); |
- } |
- } |
- if (iContinue) |
- iContinue = FindNextFileW(lFindHandle, &fdData); |
- } while (iContinue); |
- FindClose(lFindHandle); |
-} |
- |
-static BOOL |
-EnumSystemFiles(Handler func) |
-{ |
- PRUnichar szSysDir[_MAX_PATH]; |
- static const int folders[] = { |
- CSIDL_BITBUCKET, |
- CSIDL_RECENT, |
- CSIDL_INTERNET_CACHE, |
- CSIDL_HISTORY, |
- 0 |
- }; |
- int i = 0; |
- if (_MAX_PATH > (i = GetTempPathW(_MAX_PATH, szSysDir))) { |
- if (i > 0 && szSysDir[i-1] == L'\\') |
- szSysDir[i-1] = L'\0'; // we need to lop off the trailing slash |
- EnumSystemFilesInFolder(func, szSysDir, MAX_DEPTH); |
- } |
- for(i = 0; folders[i]; i++) { |
- DWORD rv = SHGetSpecialFolderPathW(NULL, szSysDir, folders[i], 0); |
- if (szSysDir[0]) |
- EnumSystemFilesInFolder(func, szSysDir, MAX_DEPTH); |
- szSysDir[0] = L'\0'; |
- } |
- return PR_TRUE; |
-} |
- |
-static PRInt32 |
-CountFiles(const PRUnichar *file) |
-{ |
- dwNumFiles++; |
- return 0; |
-} |
- |
-static int |
-ReadSingleFile(const char *filename) |
-{ |
- PRFileDesc * file; |
- unsigned char buffer[1024]; |
- |
- file = PR_Open(filename, PR_RDONLY, 0); |
- if (file != NULL) { |
- while (PR_Read(file, buffer, sizeof buffer) > 0) |
- ; |
- PR_Close(file); |
- } |
- return (file != NULL); |
-} |
- |
-static PRInt32 |
-ReadOneFile(const PRUnichar *szFileName) |
-{ |
- char narrowFileName[_MAX_PATH]; |
- |
- if (dwNumFiles == dwFileToRead) { |
- int success = WideCharToMultiByte(CP_ACP, 0, szFileName, -1, |
- narrowFileName, _MAX_PATH, |
- NULL, NULL); |
- if (success) |
- success = ReadSingleFile(narrowFileName); |
- if (!success) |
- dwFileToRead++; /* couldn't read this one, read the next one. */ |
- } |
- dwNumFiles++; |
- return dwNumFiles > dwFileToRead; |
-} |
- |
-static PRInt32 |
-ReadFiles(const PRUnichar *szFileName) |
-{ |
- char narrowFileName[_MAX_PATH]; |
- |
- if ((dwNumFiles % dwReadEvery) == 0) { |
- ++filesToRead; |
- } |
- if (filesToRead) { |
- DWORD prevFileBytes = totalFileBytes; |
- int iContinue = WideCharToMultiByte(CP_ACP, 0, szFileName, -1, |
- narrowFileName, _MAX_PATH, |
- NULL, NULL); |
- if (iContinue) { |
- RNG_FileForRNG(narrowFileName); |
- } |
- if (prevFileBytes < totalFileBytes) { |
- --filesToRead; |
- } |
- } |
- dwNumFiles++; |
- return (totalFileBytes >= maxFileBytes); |
-} |
- |
-static void |
-ReadSystemFiles(void) |
-{ |
- // first count the number of files |
- dwNumFiles = 0; |
- if (!EnumSystemFiles(CountFiles)) |
- return; |
- |
- RNG_RandomUpdate(&dwNumFiles, sizeof(dwNumFiles)); |
- |
- // now read the first 10 readable files, then 10 or 11 files |
- // spread throughout the system directory |
- filesToRead = 10; |
- if (dwNumFiles == 0) |
- return; |
- |
- dwReadEvery = dwNumFiles / 10; |
- if (dwReadEvery == 0) |
- dwReadEvery = 1; // less than 10 files |
- |
- dwNumFiles = 0; |
- totalFileBytes = 0; |
- EnumSystemFiles(ReadFiles); |
-} |
- |
-void RNG_SystemInfoForRNG(void) |
-{ |
- DWORD dwVal; |
- char buffer[256]; |
- int nBytes; |
- MEMORYSTATUS sMem; |
- HANDLE hVal; |
- DWORD dwSerialNum; |
- DWORD dwComponentLen; |
- DWORD dwSysFlags; |
- char volName[128]; |
- DWORD dwSectors, dwBytes, dwFreeClusters, dwNumClusters; |
- |
- nBytes = RNG_GetNoise(buffer, 20); // get up to 20 bytes |
- RNG_RandomUpdate(buffer, nBytes); |
- |
- 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 |
- |
- dwVal = sizeof(buffer); |
- if (GetComputerName(buffer, &dwVal)) |
- RNG_RandomUpdate(buffer, dwVal); |
- |
- hVal = GetCurrentProcess(); // 4 or 8 byte pseudo handle (a |
- // constant!) of current process |
- RNG_RandomUpdate(&hVal, sizeof(hVal)); |
- |
- dwVal = GetCurrentProcessId(); // process ID (4 bytes) |
- RNG_RandomUpdate(&dwVal, sizeof(dwVal)); |
- |
- dwVal = GetCurrentThreadId(); // thread 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)); |
- } |
- |
- // Skip the potentially slow file scanning if the OS's PRNG worked. |
- if (!usedWindowsPRNG) |
- ReadSystemFiles(); |
- |
- nBytes = RNG_GetNoise(buffer, 20); // get up to 20 bytes |
- RNG_RandomUpdate(buffer, nBytes); |
-} |
- |
-static void rng_systemJitter(void) |
-{ |
- dwNumFiles = 0; |
- EnumSystemFiles(ReadOneFile); |
- dwFileToRead++; |
- if (dwFileToRead >= dwNumFiles) { |
- dwFileToRead = 0; |
- } |
-} |
- |
- |
-void RNG_FileForRNG(const char *filename) |
-{ |
- FILE* file; |
- int nBytes; |
- struct stat stat_buf; |
- unsigned char buffer[1024]; |
- |
- /* 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 > maxFileBytes) |
- break; |
- } |
- |
- fclose(file); |
- } |
- |
- nBytes = RNG_GetNoise(buffer, 20); // get up to 20 bytes |
- RNG_RandomUpdate(buffer, nBytes); |
-} |
- |
- |
-/* |
- * CryptoAPI requires Windows NT 4.0 or Windows 95 OSR2 and later. |
- * Until we drop support for Windows 95, we need to emulate some |
- * definitions and declarations in <wincrypt.h> and look up the |
- * functions in advapi32.dll at run time. |
- */ |
- |
-#ifndef WIN64 |
-typedef unsigned long HCRYPTPROV; |
-#endif |
- |
-#define CRYPT_VERIFYCONTEXT 0xF0000000 |
- |
-#define PROV_RSA_FULL 1 |
- |
-typedef BOOL |
-(WINAPI *CryptAcquireContextAFn)( |
- HCRYPTPROV *phProv, |
- LPCSTR pszContainer, |
- LPCSTR pszProvider, |
- DWORD dwProvType, |
- DWORD dwFlags); |
- |
-typedef BOOL |
-(WINAPI *CryptReleaseContextFn)( |
- HCRYPTPROV hProv, |
- DWORD dwFlags); |
- |
-typedef BOOL |
-(WINAPI *CryptGenRandomFn)( |
- HCRYPTPROV hProv, |
- DWORD dwLen, |
- BYTE *pbBuffer); |
- |
-/* |
- * Windows XP and Windows Server 2003 and later have RtlGenRandom, |
- * which must be looked up by the name SystemFunction036. |
- */ |
-typedef BOOLEAN |
-(APIENTRY *RtlGenRandomFn)( |
- PVOID RandomBuffer, |
- ULONG RandomBufferLength); |
- |
-size_t RNG_SystemRNG(void *dest, size_t maxLen) |
-{ |
- HMODULE hModule; |
- RtlGenRandomFn pRtlGenRandom; |
- CryptAcquireContextAFn pCryptAcquireContextA; |
- CryptReleaseContextFn pCryptReleaseContext; |
- CryptGenRandomFn pCryptGenRandom; |
- HCRYPTPROV hCryptProv; |
- size_t bytes = 0; |
- |
- usedWindowsPRNG = PR_FALSE; |
- hModule = LoadLibrary("advapi32.dll"); |
- if (hModule == NULL) { |
- return rng_systemFromNoise(dest,maxLen); |
- } |
- pRtlGenRandom = (RtlGenRandomFn) |
- GetProcAddress(hModule, "SystemFunction036"); |
- if (pRtlGenRandom) { |
- if (pRtlGenRandom(dest, maxLen)) { |
- bytes = maxLen; |
- usedWindowsPRNG = PR_TRUE; |
- } else { |
- bytes = rng_systemFromNoise(dest,maxLen); |
- } |
- goto done; |
- } |
- pCryptAcquireContextA = (CryptAcquireContextAFn) |
- GetProcAddress(hModule, "CryptAcquireContextA"); |
- pCryptReleaseContext = (CryptReleaseContextFn) |
- GetProcAddress(hModule, "CryptReleaseContext"); |
- pCryptGenRandom = (CryptGenRandomFn) |
- GetProcAddress(hModule, "CryptGenRandom"); |
- if (!pCryptAcquireContextA || !pCryptReleaseContext || !pCryptGenRandom) { |
- bytes = rng_systemFromNoise(dest,maxLen); |
- goto done; |
- } |
- if (pCryptAcquireContextA(&hCryptProv, NULL, NULL, |
- PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) { |
- if (pCryptGenRandom(hCryptProv, maxLen, dest)) { |
- bytes = maxLen; |
- usedWindowsPRNG = PR_TRUE; |
- } |
- pCryptReleaseContext(hCryptProv, 0); |
- } |
- if (bytes == 0) { |
- bytes = rng_systemFromNoise(dest,maxLen); |
- } |
-done: |
- FreeLibrary(hModule); |
- return bytes; |
-} |
-#endif /* is XP_WIN */ |