| /* 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/. */ |
| |
| #define INCL_DOS |
| #define INCL_DOSERRORS |
| #include <os2.h> |
| #include "secrng.h" |
| #include "prerror.h" |
| #include <stdlib.h> |
| #include <time.h> |
| #include <stdio.h> |
| #include <sys/stat.h> |
| |
| static BOOL clockTickTime(unsigned long *phigh, unsigned long *plow) |
| { |
| APIRET rc = NO_ERROR; |
| QWORD qword = {0,0}; |
| |
| rc = DosTmrQueryTime(&qword); |
| if (rc != NO_ERROR) |
| return FALSE; |
| |
| *phigh = qword.ulHi; |
| *plow = qword.ulLo; |
| |
| return TRUE; |
| } |
| |
| size_t RNG_GetNoise(void *buf, size_t maxbuf) |
| { |
| unsigned long high = 0; |
| unsigned long low = 0; |
| clock_t val = 0; |
| int n = 0; |
| int nBytes = 0; |
| time_t sTime; |
| |
| if (maxbuf <= 0) |
| return 0; |
| |
| clockTickTime(&high, &low); |
| |
| /* get the maximally changing bits first */ |
| nBytes = sizeof(low) > maxbuf ? maxbuf : sizeof(low); |
| memcpy(buf, &low, nBytes); |
| n += nBytes; |
| maxbuf -= nBytes; |
| |
| if (maxbuf <= 0) |
| return n; |
| |
| nBytes = sizeof(high) > maxbuf ? maxbuf : sizeof(high); |
| memcpy(((char *)buf) + n, &high, nBytes); |
| n += nBytes; |
| maxbuf -= nBytes; |
| |
| if (maxbuf <= 0) |
| return n; |
| |
| /* get the number of milliseconds that have elapsed since application started */ |
| val = clock(); |
| |
| nBytes = sizeof(val) > maxbuf ? maxbuf : sizeof(val); |
| memcpy(((char *)buf) + n, &val, 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 *)) |
| { |
| APIRET rc; |
| ULONG sysInfo = 0; |
| char bootLetter[2]; |
| char sysDir[_MAX_PATH] = ""; |
| char filename[_MAX_PATH]; |
| HDIR hdir = HDIR_CREATE; |
| ULONG numFiles = 1; |
| FILEFINDBUF3 fileBuf = {0}; |
| ULONG buflen = sizeof(FILEFINDBUF3); |
| |
| if (DosQuerySysInfo(QSV_BOOT_DRIVE, QSV_BOOT_DRIVE, (PVOID)&sysInfo, |
| sizeof(ULONG)) == NO_ERROR) |
| { |
| bootLetter[0] = sysInfo + 'A' -1; |
| bootLetter[1] = '\0'; |
| strcpy(sysDir, bootLetter); |
| strcpy(sysDir+1, ":\\OS2\\"); |
| |
| strcpy( filename, sysDir ); |
| strcat( filename, "*.*" ); |
| } |
| |
| rc =DosFindFirst( filename, &hdir, FILE_NORMAL, &fileBuf, buflen, |
| &numFiles, FIL_STANDARD ); |
| if( rc == NO_ERROR ) |
| { |
| do { |
| // pass the full pathname to the callback |
| sprintf( filename, "%s%s", sysDir, fileBuf.achName ); |
| (*func)(filename); |
| |
| numFiles = 1; |
| rc = DosFindNext( hdir, &fileBuf, buflen, &numFiles ); |
| if( rc != NO_ERROR && rc != ERROR_NO_MORE_FILES ) |
| printf( "DosFindNext errod code = %d\n", rc ); |
| } while ( rc == NO_ERROR ); |
| |
| rc = DosFindClose(hdir); |
| if( rc != NO_ERROR ) |
| printf( "DosFindClose error code = %d", rc ); |
| } |
| else |
| printf( "DosFindFirst error code = %d", rc ); |
| |
| return TRUE; |
| } |
| |
| static int dwNumFiles, dwReadEvery, dwFileToRead=0; |
| |
| static void |
| CountFiles(const char *file) |
| { |
| dwNumFiles++; |
| } |
| |
| static void |
| ReadFiles(const char *file) |
| { |
| if ((dwNumFiles % dwReadEvery) == 0) |
| RNG_FileForRNG(file); |
| |
| dwNumFiles++; |
| } |
| |
| static void |
| ReadSingleFile(const char *filename) |
| { |
| unsigned char buffer[1024]; |
| FILE *file; |
| |
| file = fopen((char *)filename, "rb"); |
| if (file != NULL) { |
| while (fread(buffer, 1, sizeof(buffer), file) > 0) |
| ; |
| fclose(file); |
| } |
| } |
| |
| static void |
| ReadOneFile(const char *file) |
| { |
| if (dwNumFiles == dwFileToRead) { |
| ReadSingleFile(file); |
| } |
| |
| dwNumFiles++; |
| } |
| |
| static void |
| ReadSystemFiles(void) |
| { |
| // 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) |
| { |
| unsigned long *plong = 0; |
| PTIB ptib; |
| PPIB ppib; |
| APIRET rc = NO_ERROR; |
| DATETIME dt; |
| COUNTRYCODE cc = {0}; |
| COUNTRYINFO ci = {0}; |
| unsigned long actual = 0; |
| char path[_MAX_PATH]=""; |
| char fullpath[_MAX_PATH]=""; |
| unsigned long pathlength = sizeof(path); |
| FSALLOCATE fsallocate; |
| FILESTATUS3 fstatus; |
| unsigned long defaultdrive = 0; |
| unsigned long logicaldrives = 0; |
| unsigned long sysInfo[QSV_MAX] = {0}; |
| char buffer[20]; |
| int nBytes = 0; |
| |
| nBytes = RNG_GetNoise(buffer, sizeof(buffer)); |
| RNG_RandomUpdate(buffer, nBytes); |
| |
| /* allocate memory and use address and memory */ |
| plong = (unsigned long *)malloc(sizeof(*plong)); |
| RNG_RandomUpdate(&plong, sizeof(plong)); |
| RNG_RandomUpdate(plong, sizeof(*plong)); |
| free(plong); |
| |
| /* process info */ |
| rc = DosGetInfoBlocks(&ptib, &ppib); |
| if (rc == NO_ERROR) |
| { |
| RNG_RandomUpdate(ptib, sizeof(*ptib)); |
| RNG_RandomUpdate(ppib, sizeof(*ppib)); |
| } |
| |
| /* time */ |
| rc = DosGetDateTime(&dt); |
| if (rc == NO_ERROR) |
| { |
| RNG_RandomUpdate(&dt, sizeof(dt)); |
| } |
| |
| /* country */ |
| rc = DosQueryCtryInfo(sizeof(ci), &cc, &ci, &actual); |
| if (rc == NO_ERROR) |
| { |
| RNG_RandomUpdate(&cc, sizeof(cc)); |
| RNG_RandomUpdate(&ci, sizeof(ci)); |
| RNG_RandomUpdate(&actual, sizeof(actual)); |
| } |
| |
| /* current directory */ |
| rc = DosQueryCurrentDir(0, path, &pathlength); |
| strcat(fullpath, "\\"); |
| strcat(fullpath, path); |
| if (rc == NO_ERROR) |
| { |
| RNG_RandomUpdate(fullpath, strlen(fullpath)); |
| // path info |
| rc = DosQueryPathInfo(fullpath, FIL_STANDARD, &fstatus, sizeof(fstatus)); |
| if (rc == NO_ERROR) |
| { |
| RNG_RandomUpdate(&fstatus, sizeof(fstatus)); |
| } |
| } |
| |
| /* file system info */ |
| rc = DosQueryFSInfo(0, FSIL_ALLOC, &fsallocate, sizeof(fsallocate)); |
| if (rc == NO_ERROR) |
| { |
| RNG_RandomUpdate(&fsallocate, sizeof(fsallocate)); |
| } |
| |
| /* drive info */ |
| rc = DosQueryCurrentDisk(&defaultdrive, &logicaldrives); |
| if (rc == NO_ERROR) |
| { |
| RNG_RandomUpdate(&defaultdrive, sizeof(defaultdrive)); |
| RNG_RandomUpdate(&logicaldrives, sizeof(logicaldrives)); |
| } |
| |
| /* system info */ |
| rc = DosQuerySysInfo(1L, QSV_MAX, (PVOID)&sysInfo, sizeof(ULONG)*QSV_MAX); |
| if (rc == NO_ERROR) |
| { |
| RNG_RandomUpdate(&sysInfo, sizeof(sysInfo)); |
| } |
| |
| // now let's do some files |
| ReadSystemFiles(); |
| |
| /* more noise */ |
| nBytes = RNG_GetNoise(buffer, sizeof(buffer)); |
| RNG_RandomUpdate(buffer, nBytes); |
| } |
| |
| void RNG_FileForRNG(const char *filename) |
| { |
| struct stat stat_buf; |
| unsigned char buffer[1024]; |
| FILE *file = 0; |
| int nBytes = 0; |
| static int 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); |
| RNG_RandomUpdate(buffer, nBytes); |
| } |
| |
| static void rng_systemJitter(void) |
| { |
| dwNumFiles = 0; |
| EnumSystemFiles(ReadOneFile); |
| dwFileToRead++; |
| if (dwFileToRead >= dwNumFiles) { |
| dwFileToRead = 0; |
| } |
| } |
| |
| size_t RNG_SystemRNG(void *dest, size_t maxLen) |
| { |
| return rng_systemFromNoise(dest,maxLen); |
| } |