1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4 
5 #define INCL_DOS
6 #define INCL_DOSERRORS
7 #include <os2.h>
8 #include "secrng.h"
9 #include "prerror.h"
10 #include <stdlib.h>
11 #include <time.h>
12 #include <stdio.h>
13 #include <sys/stat.h>
14 
15 static BOOL
clockTickTime(unsigned long * phigh,unsigned long * plow)16 clockTickTime(unsigned long *phigh, unsigned long *plow)
17 {
18     APIRET rc = NO_ERROR;
19     QWORD qword = { 0, 0 };
20 
21     rc = DosTmrQueryTime(&qword);
22     if (rc != NO_ERROR)
23         return FALSE;
24 
25     *phigh = qword.ulHi;
26     *plow = qword.ulLo;
27 
28     return TRUE;
29 }
30 
31 size_t
RNG_GetNoise(void * buf,size_t maxbuf)32 RNG_GetNoise(void *buf, size_t maxbuf)
33 {
34     unsigned long high = 0;
35     unsigned long low = 0;
36     clock_t val = 0;
37     int n = 0;
38     int nBytes = 0;
39     time_t sTime;
40 
41     if (maxbuf <= 0)
42         return 0;
43 
44     clockTickTime(&high, &low);
45 
46     /* get the maximally changing bits first */
47     nBytes = sizeof(low) > maxbuf ? maxbuf : sizeof(low);
48     memcpy(buf, &low, nBytes);
49     n += nBytes;
50     maxbuf -= nBytes;
51 
52     if (maxbuf <= 0)
53         return n;
54 
55     nBytes = sizeof(high) > maxbuf ? maxbuf : sizeof(high);
56     memcpy(((char *)buf) + n, &high, nBytes);
57     n += nBytes;
58     maxbuf -= nBytes;
59 
60     if (maxbuf <= 0)
61         return n;
62 
63     /* get the number of milliseconds that have elapsed since application started */
64     val = clock();
65 
66     nBytes = sizeof(val) > maxbuf ? maxbuf : sizeof(val);
67     memcpy(((char *)buf) + n, &val, nBytes);
68     n += nBytes;
69     maxbuf -= nBytes;
70 
71     if (maxbuf <= 0)
72         return n;
73 
74     /* get the time in seconds since midnight Jan 1, 1970 */
75     time(&sTime);
76     nBytes = sizeof(sTime) > maxbuf ? maxbuf : sizeof(sTime);
77     memcpy(((char *)buf) + n, &sTime, nBytes);
78     n += nBytes;
79 
80     return n;
81 }
82 
83 static BOOL
EnumSystemFiles(void (* func)(const char *))84 EnumSystemFiles(void (*func)(const char *))
85 {
86     APIRET rc;
87     ULONG sysInfo = 0;
88     char bootLetter[2];
89     char sysDir[_MAX_PATH] = "";
90     char filename[_MAX_PATH];
91     HDIR hdir = HDIR_CREATE;
92     ULONG numFiles = 1;
93     FILEFINDBUF3 fileBuf = { 0 };
94     ULONG buflen = sizeof(FILEFINDBUF3);
95 
96     if (DosQuerySysInfo(QSV_BOOT_DRIVE, QSV_BOOT_DRIVE, (PVOID)&sysInfo,
97                         sizeof(ULONG)) == NO_ERROR) {
98         bootLetter[0] = sysInfo + 'A' - 1;
99         bootLetter[1] = '\0';
100         strcpy(sysDir, bootLetter);
101         strcpy(sysDir + 1, ":\\OS2\\");
102 
103         strcpy(filename, sysDir);
104         strcat(filename, "*.*");
105     }
106 
107     rc = DosFindFirst(filename, &hdir, FILE_NORMAL, &fileBuf, buflen,
108                       &numFiles, FIL_STANDARD);
109     if (rc == NO_ERROR) {
110         do {
111             // pass the full pathname to the callback
112             sprintf(filename, "%s%s", sysDir, fileBuf.achName);
113             (*func)(filename);
114 
115             numFiles = 1;
116             rc = DosFindNext(hdir, &fileBuf, buflen, &numFiles);
117             if (rc != NO_ERROR && rc != ERROR_NO_MORE_FILES)
118                 printf("DosFindNext errod code = %d\n", rc);
119         } while (rc == NO_ERROR);
120 
121         rc = DosFindClose(hdir);
122         if (rc != NO_ERROR)
123             printf("DosFindClose error code = %d", rc);
124     } else
125         printf("DosFindFirst error code = %d", rc);
126 
127     return TRUE;
128 }
129 
130 static int dwNumFiles, dwReadEvery, dwFileToRead = 0;
131 
132 static void
CountFiles(const char * file)133 CountFiles(const char *file)
134 {
135     dwNumFiles++;
136 }
137 
138 static void
ReadFiles(const char * file)139 ReadFiles(const char *file)
140 {
141     if ((dwNumFiles % dwReadEvery) == 0)
142         RNG_FileForRNG(file);
143 
144     dwNumFiles++;
145 }
146 
147 static void
ReadSingleFile(const char * filename)148 ReadSingleFile(const char *filename)
149 {
150     unsigned char buffer[1024];
151     FILE *file;
152 
153     file = fopen((char *)filename, "rb");
154     if (file != NULL) {
155         while (fread(buffer, 1, sizeof(buffer), file) > 0)
156             ;
157         fclose(file);
158     }
159 }
160 
161 static void
ReadOneFile(const char * file)162 ReadOneFile(const char *file)
163 {
164     if (dwNumFiles == dwFileToRead) {
165         ReadSingleFile(file);
166     }
167 
168     dwNumFiles++;
169 }
170 
171 static void
ReadSystemFiles(void)172 ReadSystemFiles(void)
173 {
174     // first count the number of files
175     dwNumFiles = 0;
176     if (!EnumSystemFiles(CountFiles))
177         return;
178 
179     RNG_RandomUpdate(&dwNumFiles, sizeof(dwNumFiles));
180 
181     // now read 10 files
182     if (dwNumFiles == 0)
183         return;
184 
185     dwReadEvery = dwNumFiles / 10;
186     if (dwReadEvery == 0)
187         dwReadEvery = 1; // less than 10 files
188 
189     dwNumFiles = 0;
190     EnumSystemFiles(ReadFiles);
191 }
192 
193 void
RNG_SystemInfoForRNG(void)194 RNG_SystemInfoForRNG(void)
195 {
196     unsigned long *plong = 0;
197     PTIB ptib;
198     PPIB ppib;
199     APIRET rc = NO_ERROR;
200     DATETIME dt;
201     COUNTRYCODE cc = { 0 };
202     COUNTRYINFO ci = { 0 };
203     unsigned long actual = 0;
204     char path[_MAX_PATH] = "";
205     char fullpath[_MAX_PATH] = "";
206     unsigned long pathlength = sizeof(path);
207     FSALLOCATE fsallocate;
208     FILESTATUS3 fstatus;
209     unsigned long defaultdrive = 0;
210     unsigned long logicaldrives = 0;
211     unsigned long sysInfo[QSV_MAX] = { 0 };
212     char buffer[20];
213     int nBytes = 0;
214 
215     nBytes = RNG_GetNoise(buffer, sizeof(buffer));
216     RNG_RandomUpdate(buffer, nBytes);
217 
218     /* allocate memory and use address and memory */
219     plong = (unsigned long *)malloc(sizeof(*plong));
220     RNG_RandomUpdate(&plong, sizeof(plong));
221     RNG_RandomUpdate(plong, sizeof(*plong));
222     free(plong);
223 
224     /* process info */
225     rc = DosGetInfoBlocks(&ptib, &ppib);
226     if (rc == NO_ERROR) {
227         RNG_RandomUpdate(ptib, sizeof(*ptib));
228         RNG_RandomUpdate(ppib, sizeof(*ppib));
229     }
230 
231     /* time */
232     rc = DosGetDateTime(&dt);
233     if (rc == NO_ERROR) {
234         RNG_RandomUpdate(&dt, sizeof(dt));
235     }
236 
237     /* country */
238     rc = DosQueryCtryInfo(sizeof(ci), &cc, &ci, &actual);
239     if (rc == NO_ERROR) {
240         RNG_RandomUpdate(&cc, sizeof(cc));
241         RNG_RandomUpdate(&ci, sizeof(ci));
242         RNG_RandomUpdate(&actual, sizeof(actual));
243     }
244 
245     /* current directory */
246     rc = DosQueryCurrentDir(0, path, &pathlength);
247     strcat(fullpath, "\\");
248     strcat(fullpath, path);
249     if (rc == NO_ERROR) {
250         RNG_RandomUpdate(fullpath, strlen(fullpath));
251         // path info
252         rc = DosQueryPathInfo(fullpath, FIL_STANDARD, &fstatus, sizeof(fstatus));
253         if (rc == NO_ERROR) {
254             RNG_RandomUpdate(&fstatus, sizeof(fstatus));
255         }
256     }
257 
258     /* file system info */
259     rc = DosQueryFSInfo(0, FSIL_ALLOC, &fsallocate, sizeof(fsallocate));
260     if (rc == NO_ERROR) {
261         RNG_RandomUpdate(&fsallocate, sizeof(fsallocate));
262     }
263 
264     /* drive info */
265     rc = DosQueryCurrentDisk(&defaultdrive, &logicaldrives);
266     if (rc == NO_ERROR) {
267         RNG_RandomUpdate(&defaultdrive, sizeof(defaultdrive));
268         RNG_RandomUpdate(&logicaldrives, sizeof(logicaldrives));
269     }
270 
271     /* system info */
272     rc = DosQuerySysInfo(1L, QSV_MAX, (PVOID)&sysInfo, sizeof(ULONG) * QSV_MAX);
273     if (rc == NO_ERROR) {
274         RNG_RandomUpdate(&sysInfo, sizeof(sysInfo));
275     }
276 
277     // now let's do some files
278     ReadSystemFiles();
279 
280     /* more noise */
281     nBytes = RNG_GetNoise(buffer, sizeof(buffer));
282     RNG_RandomUpdate(buffer, nBytes);
283 }
284 
285 void
RNG_FileForRNG(const char * filename)286 RNG_FileForRNG(const char *filename)
287 {
288     struct stat stat_buf;
289     unsigned char buffer[1024];
290     FILE *file = 0;
291     int nBytes = 0;
292     static int totalFileBytes = 0;
293 
294     if (stat((char *)filename, &stat_buf) < 0)
295         return;
296 
297     RNG_RandomUpdate((unsigned char *)&stat_buf, sizeof(stat_buf));
298 
299     file = fopen((char *)filename, "r");
300     if (file != NULL) {
301         for (;;) {
302             size_t bytes = fread(buffer, 1, sizeof(buffer), file);
303 
304             if (bytes == 0)
305                 break;
306 
307             RNG_RandomUpdate(buffer, bytes);
308             totalFileBytes += bytes;
309             if (totalFileBytes > 250000)
310                 break;
311         }
312         fclose(file);
313     }
314 
315     nBytes = RNG_GetNoise(buffer, 20);
316     RNG_RandomUpdate(buffer, nBytes);
317 }
318 
319 static void
rng_systemJitter(void)320 rng_systemJitter(void)
321 {
322     dwNumFiles = 0;
323     EnumSystemFiles(ReadOneFile);
324     dwFileToRead++;
325     if (dwFileToRead >= dwNumFiles) {
326         dwFileToRead = 0;
327     }
328 }
329 
330 size_t
RNG_SystemRNG(void * dest,size_t maxLen)331 RNG_SystemRNG(void *dest, size_t maxLen)
332 {
333     return rng_systemFromNoise(dest, maxLen);
334 }
335