GCC Code Coverage Report


Directory: src/gate/
File: src/gate/randomgen.c
Date: 2025-09-14 13:10:38
Exec Total Coverage
Lines: 28 32 87.5%
Functions: 4 4 100.0%
Branches: 8 12 66.7%

Line Branch Exec Source
1 /* GATE PROJECT LICENSE:
2 +----------------------------------------------------------------------------+
3 | Copyright(c) 2018-2025, Stefan Meislinger <sm@opengate.at> |
4 | All rights reserved. |
5 | |
6 | Redistribution and use in source and binary forms, with or without |
7 | modification, are permitted provided that the following conditions are met:|
8 | |
9 | 1. Redistributions of source code must retain the above copyright notice, |
10 | this list of conditions and the following disclaimer. |
11 | 2. Redistributions in binary form must reproduce the above copyright |
12 | notice, this list of conditions and the following disclaimer in the |
13 | documentation and/or other materials provided with the distribution. |
14 | |
15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"|
16 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
17 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
18 | ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
19 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
20 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
21 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
22 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
23 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
24 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
25 | THE POSSIBILITY OF SUCH DAMAGE. |
26 +----------------------------------------------------------------------------+
27 */
28
29 #include "gate/randomgen.h"
30 #include "gate/results.h"
31
32 #if defined(GATE_SYS_WIN16)
33 # define GATE_CORE_RANDOM_GATE_IMPL 1
34 #elif defined(GATE_SYS_WIN)
35 # define GATE_CORE_RANDOM_WINAPI_IMPL 1
36 #elif defined(GATE_SYS_POSIX)
37 # define GATE_CORE_RANDOM_POSIX_IMPL 1
38 #else
39 # define GATE_CORE_RANDOM_GATE_IMPL 1
40 #endif
41
42
43
44 #if defined(GATE_CORE_RANDOM_WINAPI_IMPL)
45
46 #ifndef _WIN32_WINNT
47 #define _WIN32_WINNT 0x0400
48 #endif
49
50 #include "gate/platforms.h"
51 #include "gate/debugging.h"
52
53 #include <wincrypt.h>
54 #if defined(GATE_SYS_WINSTORE)
55 # include <bcrypt.h>
56 # pragma comment(lib, "bcrypt.lib")
57 #endif
58
59 #if defined(GATE_WIN32_ANSI)
60 # include <stdlib.h>
61 #endif
62
63 typedef LONG(WINAPI* BCryptGenRandomProc)(PVOID hAlgorithm, PUCHAR pbBuffer, ULONG cbBuffer, ULONG dwFlags);
64
65 static BCryptGenRandomProc BCryptGenRandomImpl = NULL;
66
67 #ifndef STATUS_SUCCESS
68 # define STATUS_SUCCESS ((LONG)0x00000000L)
69 #endif
70
71 #ifndef BCRYPT_RNG_USE_ENTROPY_IN_BUFFER
72 # define BCRYPT_RNG_USE_ENTROPY_IN_BUFFER 0x00000001
73 #endif
74
75 #ifndef BCRYPT_USE_SYSTEM_PREFERRED_RNG
76 # define BCRYPT_USE_SYSTEM_PREFERRED_RNG 0x00000002
77 #endif
78
79 static gate_bool_t load_bcrypt()
80 {
81 static HMODULE hmod = NULL;
82 LONG ntstatus;
83 UCHAR test_buffer[sizeof(gate_uint32_t)];
84
85 if (!BCryptGenRandomImpl)
86 {
87 #if defined(GATE_SYS_WINSTORE)
88 BCryptGenRandomImpl = &BCryptGenRandom;
89 #else
90 if (!hmod)
91 {
92 hmod = gate_win32_load_library(_T("bcrypt.dll"), 0);
93 }
94 if (!hmod)
95 {
96 return false;
97 }
98 if (!gate_win32_get_proc_address(hmod, "BCryptGenRandom", &BCryptGenRandomImpl))
99 {
100 return false;
101 }
102 #endif
103 }
104
105 ntstatus = BCryptGenRandomImpl(NULL, test_buffer, sizeof(test_buffer), BCRYPT_USE_SYSTEM_PREFERRED_RNG);
106 if (ntstatus != STATUS_SUCCESS)
107 {
108 return false;
109 }
110
111 return true;
112 }
113
114 #ifndef CRYPT_SILENT
115 #define CRYPT_SILENT 0x0040
116 #endif
117
118 gate_result_t gate_randomgenerator_create(gate_randomsession_t* session)
119 {
120 gate_result_t ret = GATE_RESULT_FAILED;
121 HCRYPTPROV provider = 0;
122 DWORD error_code;
123 do
124 {
125 if (load_bcrypt())
126 {
127 *session = &BCryptGenRandomImpl;
128 ret = GATE_RESULT_OK;
129 break;
130 }
131
132 #if defined(GATE_SYS_WINCE)
133 if (!CryptAcquireContext(&provider, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
134 {
135 error_code = GetLastError();
136 GATE_DEBUG_TRACE_MSG_VALUE("CryptAcquireContext() failed", error_code);
137 ret = GATE_RESULT_FAILED;
138 break;
139 }
140 #else
141 if (!gate_platform.AdvCryptAcquireContext)
142 {
143 ret = GATE_RESULT_NOTSUPPORTED;
144 # if defined(GATE_WIN32_ANSI)
145 /* WinNT 3 does not support Crypt API
146 use CRT fallback */
147 srand(GetTickCount());
148 *session = NULL;
149 ret = GATE_RESULT_OK;
150 # endif
151 break;
152 }
153 if (!gate_platform.AdvCryptAcquireContext(&provider, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
154 {
155 /* Win9x has no SILENT flag */
156 if (!gate_platform.AdvCryptAcquireContext(&provider, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
157 {
158 error_code = GetLastError();
159 GATE_DEBUG_TRACE_MSG_VALUE("CryptAcquireContext() failed", error_code);
160 ret = GATE_RESULT_FAILED;
161 break;
162 }
163 }
164 #endif
165 * session = (gate_randomsession_t)(gate_uintptr_t)provider;
166 ret = GATE_RESULT_OK;
167 } while (0);
168 return ret;
169 }
170
171 union gate_randomgen_number
172 {
173 gate_uint64_t num;
174 BYTE buffer[sizeof(gate_uint64_t)];
175 BYTE dummy[32];
176 };
177
178 gate_result_t gate_randomgenerator_get_num(gate_randomsession_t* session, gate_uint64_t* number)
179 {
180 gate_result_t ret = GATE_RESULT_FAILED;
181 union gate_randomgen_number tmp;
182
183 ret = gate_randomgenerator_get_buffer(session, &tmp.buffer[0], sizeof(tmp.buffer));
184 if (GATE_SUCCEEDED(ret))
185 {
186 *number = tmp.num;
187 }
188 return ret;
189 }
190 gate_result_t gate_randomgenerator_get_buffer(gate_randomsession_t* session, void* buffer, gate_size_t bufferlen)
191 {
192 gate_result_t ret = GATE_RESULT_FAILED;
193 HCRYPTPROV hProv = (HCRYPTPROV)(gate_uintptr_t)*session;
194 LONG ntstatus;
195 BYTE* byte_buffer = (BYTE*)buffer;
196
197 do
198 {
199 if (!session)
200 {
201 ret = GATE_RESULT_INVALIDARG;
202 break;
203 }
204 if ((*session == &BCryptGenRandomImpl) && (BCryptGenRandomImpl != NULL))
205 {
206 ntstatus = BCryptGenRandomImpl(NULL, byte_buffer, (ULONG)bufferlen, BCRYPT_USE_SYSTEM_PREFERRED_RNG);
207 if (STATUS_SUCCESS == ntstatus)
208 {
209 ret = GATE_RESULT_OK;
210 }
211 else
212 {
213 ret = GATE_RESULT_FAILED;
214 }
215 break;
216 }
217
218 #if defined(GATE_SYS_WINCE)
219 if (!CryptGenRandom(hProv, (DWORD)bufferlen, byte_buffer))
220 {
221 ret = GATE_RESULT_FAILED;
222 break;
223 }
224 #else
225 if (!gate_platform.AdvCryptGenRandom)
226 {
227 ret = GATE_RESULT_NOTSUPPORTED;
228 # if defined(GATE_WIN32_ANSI)
229 /* CRT fallback: */
230 while (bufferlen-- > 0)
231 {
232 *byte_buffer = (BYTE)(rand() % 256);
233 ++byte_buffer;
234 }
235 ret = GATE_RESULT_OK;
236 # endif
237 break;
238 }
239 if (!gate_platform.AdvCryptGenRandom(hProv, (DWORD)bufferlen, byte_buffer))
240 {
241 ret = GATE_RESULT_FAILED;
242 break;
243 }
244 #endif
245 ret = GATE_RESULT_OK;
246 } while (0);
247 return ret;
248 }
249
250 gate_result_t gate_randomgenerator_destroy(gate_randomsession_t* session)
251 {
252 gate_result_t ret = GATE_RESULT_FAILED;
253 HCRYPTPROV hProv;
254
255 do
256 {
257 if (!session)
258 {
259 ret = GATE_RESULT_INVALIDARG;
260 break;
261 }
262 if (*session == &BCryptGenRandomImpl)
263 {
264 /* nothing to release */
265 ret = GATE_RESULT_OK;
266 break;
267 }
268
269 hProv = (HCRYPTPROV)(gate_uintptr_t)*session;
270 if (hProv)
271 {
272 #if defined(GATE_SYS_WINCE)
273 if (!CryptReleaseContext(hProv, 0))
274 {
275 ret = GATE_RESULT_FAILED;
276 }
277 #else
278 if (!gate_platform.AdvCryptReleaseContext)
279 {
280 ret = GATE_RESULT_NOTSUPPORTED;
281 break;
282 }
283 if (!gate_platform.AdvCryptReleaseContext(hProv, 0))
284 {
285 ret = GATE_RESULT_FAILED;
286 }
287 #endif
288 }
289 *session = NULL;
290 ret = GATE_RESULT_OK;
291 } while (0);
292
293 return ret;
294 }
295
296
297 #endif /* GATE_CORE_RANDOM_WINAPI_IMPL */
298
299
300
301 #if defined(GATE_CORE_RANDOM_POSIX_IMPL)
302
303 #include "gate/platforms.h"
304 #include <fcntl.h>
305
306 6 gate_result_t gate_randomgenerator_create(gate_randomsession_t* session)
307 {
308 6 int file = open("/dev/random", O_RDONLY, 0);
309
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (file == -1)
310 {
311 return GATE_RESULT_FAILED;
312 }
313 else
314 {
315 6 *session = (gate_randomsession_t)(gate_intptr_t)file;
316 6 return GATE_RESULT_OK;
317 }
318 }
319
320 union gate_randomgen_number
321 {
322 gate_uint64_t num;
323 char buffer[sizeof(gate_uint64_t)];
324 };
325
326 251002 gate_result_t gate_randomgenerator_get_num(gate_randomsession_t* session, gate_uint64_t* number)
327 {
328 251002 int file = (int)(gate_intptr_t)*session;
329 union gate_randomgen_number tmp;
330 251002 gate_size_t count = 0;
331 ssize_t readresult;
332
2/2
✓ Branch 0 taken 251002 times.
✓ Branch 1 taken 251002 times.
502004 while (count < sizeof(tmp.buffer))
333 {
334 251002 readresult = read(file, &tmp.buffer[count], sizeof(tmp.buffer) - count);
335
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 251002 times.
251002 if (readresult == -1)
336 {
337 return GATE_RESULT_FAILED;
338 }
339 251002 count += (gate_size_t)readresult;
340 }
341
342 251002 *number = tmp.num;
343 251002 return GATE_RESULT_OK;
344 }
345 1003 gate_result_t gate_randomgenerator_get_buffer(gate_randomsession_t* session, void* buffer, gate_size_t bufferlen)
346 {
347 1003 int file = (int)(gate_intptr_t)*session;
348 1003 char* ptr = (char*)buffer;
349 1003 gate_size_t count = 0;
350 ssize_t readresult;
351
2/2
✓ Branch 0 taken 1003 times.
✓ Branch 1 taken 1003 times.
2006 while (count < bufferlen)
352 {
353 1003 readresult = read(file, &ptr[count], bufferlen - count);
354
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1003 times.
1003 if (readresult == -1)
355 {
356 return GATE_RESULT_FAILED;
357 }
358 1003 count += (gate_size_t)readresult;
359 }
360 1003 return GATE_RESULT_OK;
361 }
362
363 6 gate_result_t gate_randomgenerator_destroy(gate_randomsession_t* session)
364 {
365 6 int file = (int)(gate_intptr_t)*session;
366
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
6 if (-1 == close(file))
367 {
368 return GATE_RESULT_FAILED;
369 }
370 6 *session = NULL;
371 6 return GATE_RESULT_OK;
372 }
373
374 #endif /* GATE_CORE_RANDOM_POSIX_IMPL */
375
376
377 #if defined(GATE_CORE_RANDOM_GATE_IMPL)
378
379 #include "gate/memalloc.h"
380 #include "gate/times.h"
381
382 /* GATE uses KISS from George Marsaglia's implementation */
383 /* http://www.cse.yorku.ca/~oz/marsaglia-rng.html */
384
385 typedef unsigned long rnd_num_t;
386
387 typedef struct
388 {
389 rnd_num_t z;
390 rnd_num_t w;
391 rnd_num_t jsr;
392 rnd_num_t jcong;
393 rnd_num_t a;
394 rnd_num_t b;
395 rnd_num_t t[256];
396
397 rnd_num_t x;
398 rnd_num_t y;
399 rnd_num_t bro;
400
401 unsigned char c;
402
403 } gate_randomgen_impl_t;
404
405
406 static gate_randomgen_impl_t* get_global_random_impl()
407 {
408 #if defined(GATE_SYS_DOS)
409 static gate_randomgen_impl_t near global_random_impl;
410 #else
411 static gate_randomgen_impl_t global_random_impl;
412 #endif
413 return &global_random_impl;
414 }
415
416
417
418 static rnd_num_t random_znew(gate_randomgen_impl_t* impl)
419 {
420 return (impl->z = 36969 * (impl->z & 65535) + (impl->z >> 16));
421 }
422 static rnd_num_t random_wnew(gate_randomgen_impl_t* impl)
423 {
424 return (impl->w = 18000 * (impl->w & 65535) + (impl->w >> 16));
425 }
426 static rnd_num_t random_MWC(gate_randomgen_impl_t* impl)
427 {
428 return ((random_znew(impl) << 16) + random_wnew(impl));
429 }
430 static rnd_num_t random_CONG(gate_randomgen_impl_t* impl)
431 {
432 return (impl->jcong = 69069 * impl->jcong + 1234567);
433 }
434 static rnd_num_t random_SHR3(gate_randomgen_impl_t* impl)
435 {
436 return (impl->jsr ^= (impl->jsr << 17), impl->jsr ^= (impl->jsr >> 13), impl->jsr ^= (impl->jsr << 5));
437 }
438 static rnd_num_t random_KISS(gate_randomgen_impl_t* impl)
439 {
440 return ((random_MWC(impl) ^ random_CONG(impl)) + random_SHR3(impl));
441 }
442 static rnd_num_t random_LFIB4(gate_randomgen_impl_t* impl)
443 {
444 return (impl->c++,
445 impl->t[impl->c] = impl->t[impl->c]
446 + impl->t[(unsigned char)(impl->c + 58)]
447 + impl->t[(unsigned char)(impl->c + 119)]
448 + impl->t[(unsigned char)(impl->c + 178)]
449 );
450 }
451
452 static void random_init(gate_randomgen_impl_t* impl, unsigned long seed)
453 {
454 unsigned int i;
455 impl->z = 12345 + ((seed) | 0xff);
456 impl->w = 65435 + ((seed >> 4) | 0xff);
457 impl->jsr = 34221 + ((seed >> 8) | 0xff);
458 impl->jcong = 12345 + ((seed >> 12) | 0xff);
459 impl->a = 9983651 + ((seed >> 16) | 0xff);
460 impl->b = 95746118 + ((seed >> 20) | 0xff);
461 impl->x = 0;
462 impl->y = 0;
463 impl->bro = 0;
464 impl->c = 0;
465
466 for (i = 0; i != sizeof(impl->t) / sizeof(impl->t[0]); ++i)
467 {
468 impl->t[i] = random_KISS(impl);
469 }
470 }
471
472 gate_result_t gate_randomgenerator_create(gate_randomsession_t* session)
473 {
474 gate_result_t ret = GATE_RESULT_OK;
475 gate_randomgen_impl_t* ptr_impl;
476 gate_time_t tm = GATE_INIT_EMPTY;
477 if (session)
478 {
479 ptr_impl = (gate_randomgen_impl_t*)gate_mem_alloc(sizeof(gate_randomgen_impl_t));
480 if (ptr_impl == NULL)
481 {
482 ptr_impl = get_global_random_impl();
483 }
484 *session = (void*)ptr_impl;
485 }
486 else
487 {
488 ptr_impl = get_global_random_impl();
489 }
490
491 gate_time_now(&tm);
492 random_init(ptr_impl, (unsigned long)(tm.timestamp & 0xffffffff));
493
494 return ret;
495 }
496
497 gate_result_t gate_randomgenerator_get_num(gate_randomsession_t* session, gate_uint64_t* number)
498 {
499 gate_result_t ret = GATE_RESULT_OK;
500 gate_randomgen_impl_t* ptr_impl;
501 gate_uint64_t num[4];
502 if (session)
503 {
504 ptr_impl = (gate_randomgen_impl_t*)*session;
505 }
506 else
507 {
508 ptr_impl = get_global_random_impl();
509 }
510 num[0] = random_LFIB4(ptr_impl);
511 num[1] = random_LFIB4(ptr_impl);
512 num[2] = random_LFIB4(ptr_impl);
513 num[3] = random_LFIB4(ptr_impl);
514
515 if (number)
516 {
517 *number = (num[0] & 0xffff)
518 | ((num[1] & 0xffff) << 16)
519 | ((num[2] & 0xffff) << 32)
520 | ((num[3] & 0xffff) << 48)
521 ;
522 }
523 return ret;
524 }
525
526 gate_result_t gate_randomgenerator_get_buffer(gate_randomsession_t* session, void* buffer, gate_size_t bufferlen)
527 {
528 gate_result_t ret = GATE_RESULT_OK;
529 gate_randomgen_impl_t* ptr_impl;
530 unsigned char* ptr_buffer = (unsigned char*)buffer;
531 if (session)
532 {
533 ptr_impl = (gate_randomgen_impl_t*)*session;
534 }
535 else
536 {
537 ptr_impl = get_global_random_impl();
538 }
539 while (bufferlen-- != 0)
540 {
541 *ptr_buffer = (unsigned char)((random_LFIB4(ptr_impl) >> 4) & 0xff);
542 ++ptr_buffer;
543 }
544 return ret;
545 }
546
547 gate_result_t gate_randomgenerator_destroy(gate_randomsession_t* session)
548 {
549 gate_randomgen_impl_t* ptr_impl;
550 if (session)
551 {
552 ptr_impl = (gate_randomgen_impl_t*)*session;
553 if (ptr_impl && (ptr_impl != get_global_random_impl()))
554 {
555 gate_mem_dealloc(ptr_impl);
556 }
557 }
558 return GATE_RESULT_OK;
559 }
560
561 #endif /* GATE_CORE_RANDOM_GATE_IMPL */
562
563