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