Mercurial > librandom
view librandom.c @ 0:9ee92e7a1cb5 default tip
*: initial commit
this is a very simple, bare-bones randomness API. if the system can't provide
it, so be it -- init will fail.
author | Paper <paper@tflc.us> |
---|---|
date | Tue, 10 Jun 2025 16:18:50 -0400 |
parents | |
children |
line wrap: on
line source
#include <stdio.h> #include <stdlib.h> #include <stdint.h> #include "librandom.h" #ifdef _WIN32 # define RANDOM_WIN32 #elif defined(__MACH__) && defined(__APPLE__) # define RANDOM_ARC4RANDOM #else # define RANDOM_UNIX #endif #ifdef RANDOM_WIN32 # include <windows.h> # include <wincrypt.h> #endif #define ARRAY_SIZE(x) (sizeof(x)/sizeof(*(x))) /* NOTE: I am not sure if other platforms provide real APIs for good * randomness. Macintosh provides SetRandomSeed and RandomBits, but I * am skeptical of its use as a good random number generator. */ #ifdef RANDOM_UNIX struct random_unix { FILE *f; }; static void random_unix_close(struct random *r) { struct random_unix *ru = r->userdata; if (ru->f) fclose(ru->f); free(ru); } static size_t random_unix_read(struct random *r, void *ptr, size_t s) { struct random_unix *ru = r->userdata; return fread(ptr, s, 1, ru->f); } static int random_unix_init(struct random *r) { /* hmmm. */ static const char *names[] = { "/dev/random", "/dev/urandom", }; struct random_unix *ru = malloc(sizeof(*ru)); size_t i; for (i = 0; i < ARRAY_SIZE(names); i++) { ru->f = fopen(names[i], "rb"); if (ru->f) goto gotdevice; } free(ru); return -1; gotdevice: r->userdata = ru; r->close = random_unix_close; r->read = random_unix_read; return 0; } #endif /* ------------------------------------------------------------------------ */ #ifdef RANDOM_ARC4RANDOM static size_t random_arc4random_read(struct random *r, void *ptr, size_t s) { size_t l = s; while (l > 0) { size_t amt; uint32_t x; amt = MIN(sizeof(x), l); x = arc4random(); memcpy(ptr, &x, amt); ptr += amt; l -= amt; } return s; } static void random_arc4random_close(struct random *r) { /* nothing */ } static int random_arc4random_init(struct random *r) { /* always successful */ r->read = random_arc4random_read; r->close = random_arc4random_close; return 0; } #endif /* ------------------------------------------------------------------------ */ #ifdef RANDOM_WIN32 typedef BOOL (*pADVAPI32_CryptReleaseContext)(HCRYPTPROV hProv, DWORD dwFlags); typedef BOOL (*pADVAPI32_CryptGenRandom)(HCRYPTPROV hProv, DWORD dwLen, BYTE *pbBuffer); typedef BOOL (*pADVAPI32_CryptAcquireContextA)(HCRYPTPROV *phProv, LPCSTR szContainer, LPCSTR szProvider, DWORD dwProvType,DWORD dwFlags); struct random_win32 { HCRYPTPROV c; HMODULE advapi32; pADVAPI32_CryptReleaseContext ADVAPI32_CryptReleaseContext; pADVAPI32_CryptGenRandom ADVAPI32_CryptGenRandom; pADVAPI32_CryptAcquireContextA ADVAPI32_CryptAcquireContextA; }; static void random_win32_close(struct random *r) { struct random_win32 *rw = r->userdata; rw->ADVAPI32_CryptReleaseContext(rw->c, 0); FreeLibrary(rw->advapi32); free(rw); } static size_t random_win32_read(struct random *r, void *ptr, size_t s) { struct random_win32 *rw = r->userdata; if (!rw->ADVAPI32_CryptGenRandom(rw->c, s, ptr)) return 0; return s; } static int random_win32_init(struct random *r) { HCRYPTPROV c; struct random_win32 *rw; rw = malloc(sizeof(*rw)); if (!rw) return -2; rw->advapi32 = LoadLibraryA("ADVAPI32.DLL"); if (!rw->advapi32) return -3; #define LOADFUNC(x) \ rw->ADVAPI32_##x = (pADVAPI32_##x)GetProcAddress(rw->advapi32, #x); \ if (!rw->ADVAPI32_##x) \ return -4 LOADFUNC(CryptAcquireContextA); LOADFUNC(CryptGenRandom); LOADFUNC(CryptReleaseContext); if (!rw->ADVAPI32_CryptAcquireContextA(&c, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) return -1; rw->c = c; r->userdata = rw; r->close = random_win32_close; r->read = random_win32_read; return 0; } #endif /* ------------------------------------------------------------------------ */ /* platform-independent routines */ int random_init(struct random *r) { int i; int (*funcs[])(struct random *r) = { #ifdef RANDOM_ARC4RANDOM random_arc4random_init, #endif #ifdef RANDOM_UNIX random_unix_init, #endif #ifdef RANDOM_WIN32 random_win32_init, #endif NULL, }; for (i = 0; funcs[i]; i++) if (!funcs[i](r)) return 0; return -1; } void random_close(struct random *r) { r->close(r); } size_t random_read(struct random *r, void *ptr, size_t s) { return r->read(r, ptr, s); }