/*
*
* LICENSE AGREEMENT NON-COMMERCIAL USE (Random Seed Generation)
*
* Netscape Communications Corporation ("Netscape") hereby grants you a
* non-exclusive, non-transferable license to use the source code version
* of the accompanying random seed generation software (the "Software")
* subject to the following terms:
*
* 1. You may use, modify and/or incorporate the Software, in whole or in
* part, into other software programs (a "Derivative Work") solely in
* order to evaluate the Software's features, functions and capabilities.
*
* 2. You may not use the Software or Derivative Works for
* revenue-generating purposes. You may not:
*
* (a) license or distribute the Software or any Derivative Work
* in any manner that generates license fees, royalties,
* maintenance fees, upgrade fees or any other form of income.
*
* (b) use the Software or a Derivative Work to provide services
* to others for which you are compensated in any manner.
*
* (c) distribute the Software or a Derivative Work without
* written agreement from the end user to abide by the terms of
* Sections 1 and 2 of this Agreement.
*
* 3. This license is granted free of charge.
*
* 4. Any modification of the Software or Derivative Work must
* prominently state in the code and associated documentation that it has
* been modified, the date modified and the identity of the person(s) who
* made the modifications.
*
* 5. Licensee will promptly notify Netscape of any proposed or
* implemented improvement in the Software and grants Netscape the
* perpetual right to incorporate any such improvements into the Software
* and into Netscape's products which incorporate the Software (which may
* be distributed to third parties). Licensee will also promptly notify
* Netscape of any alleged deficiency in the Software. If Netscape
* requests, Licensee will provide Netscape with a copy of each Derivative
* Work Licensee creates.
*
* 6. Any copy of the Software or Derivative Work shall include a copy of
* this Agreement, Netscape's copyright notices and the disclaimer of
* warranty and limitation of liability.
*
* 7. Title, ownership rights, and intellectual property rights in and to
* the Software shall remain in Netscape and/or its suppliers. You may
* use the Software only as provided in this Agreement. Netscape shall
* have no obligation to provide maintenance, support, upgrades or new
* releases to you or any person to whom you distribute the Software or a
* Derivative Work.
*
* 8. Netscape may use Licensee's name in publicity materials as a
* licensee of the Software.
*
* 9. Disclaimer of Warranty. THE SOFTWARE IS LICENSED "AS IS" WITHOUT
* WARRANTY OF ANY KIND, INCLUDING WITHOUT LIMITATION, PERFORMANCE,
* MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE. THE ENTIRE RISK
* AS TO THE RESULTS AND PERFORMANCE OF THE SOFTWARE IS ASSUMED BY YOU.
*
* 10. Limitation of Liability. UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL
* THEORY SHALL NETSCAPE OR ITS SUPPLIERS BE LIABLE TO YOU OR ANY OTHER
* PERSON FOR ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* OF ANY CHARACTER INCLUDING WITHOUT LIMITATION ANY COMMERCIAL DAMAGES OR
* LOSSES , EVEN IF NETSCAPE HAS BEEN INFORMED OF THE POSSIBILITY OF SUCH
* DAMAGES.
*
* 11. You may not download or otherwise export or reexport the Software
* or any underlying information or technology except in full compliance
* with all United States and other applicable laws and regulations.
*
* 10. Either party may terminate this Agreement immediately in the event
* of default by the other party. You may also terminate this Agreement
* at any time by destroying the Software and all copies thereof.
*
* 11. Use, duplication or disclosure by the United States Government is
* subject to restrictions set forth in subparagraphs (a) through (d) of
* the Commercial Computer-Restricted Rights clause at FAR 52.227-19 when
* applicable, or in subparagraph (c)(1)(ii) of the Rights in Technical
* Data and Computer Program clause at DFARS 252.227-7013, and in similar
* clauses in the NASA FAR Supplement. Contractor/manufacturer is Netscape
* Communications Corporation, 501 East Middlefield Road, Mountain View,
* CA 94043.
*
* 12. This Agreement shall be governed by and construed under California
* law as such law applies to agreements between California residents
* entered into and to be performed entirely within California, except as
* governed by Federal law.
*
*/
#include "secrng.h"
#include "xp_core.h"
#ifdef XP_WIN
#include <windows.h>
#include <time.h>
#include <io.h>
#include <sys/types.h>
#include <sys/stat.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
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
; 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
}
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)(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(char *file)
{
dwNumFiles++;
}
static void
ReadFiles(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;
POINT ptVal;
HWND hWnd;
char buffer[256];
int nBytes;
#ifdef _WIN32
MEMORYSTATUS sMem;
UUID sUuid;
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);
GetCursorPos(&ptVal);
RNG_RandomUpdate(&ptVal, sizeof(ptVal));
#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
dwVal = GetQueueStatus(QS_ALLINPUT); // high and low significant
RNG_RandomUpdate(&dwVal, sizeof(dwVal));
hWnd = GetClipboardOwner(); // 2 or 4 bytes
RNG_RandomUpdate((void *)&hWnd, sizeof(hWnd));
#ifdef _WIN32
dwVal = sizeof(buffer);
if (GetComputerName(buffer, &dwVal))
RNG_RandomUpdate(buffer, dwVal);
UuidCreate(&sUuid); // this will fail on machines with no ethernet
RNG_RandomUpdate(&sUuid, sizeof(sUuid)); // boards. shove the bits in regardless
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
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
// 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)
{
struct stat stat_buf;
unsigned char buffer[1024];
FILE* file;
int nBytes;
static DWORD totalFileBytes = 0;
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