Mercurial > librandom
comparison 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 |
comparison
equal
deleted
inserted
replaced
| -1:000000000000 | 0:9ee92e7a1cb5 |
|---|---|
| 1 #include <stdio.h> | |
| 2 #include <stdlib.h> | |
| 3 #include <stdint.h> | |
| 4 | |
| 5 #include "librandom.h" | |
| 6 | |
| 7 #ifdef _WIN32 | |
| 8 # define RANDOM_WIN32 | |
| 9 #elif defined(__MACH__) && defined(__APPLE__) | |
| 10 # define RANDOM_ARC4RANDOM | |
| 11 #else | |
| 12 # define RANDOM_UNIX | |
| 13 #endif | |
| 14 | |
| 15 #ifdef RANDOM_WIN32 | |
| 16 # include <windows.h> | |
| 17 # include <wincrypt.h> | |
| 18 #endif | |
| 19 | |
| 20 #define ARRAY_SIZE(x) (sizeof(x)/sizeof(*(x))) | |
| 21 | |
| 22 /* NOTE: I am not sure if other platforms provide real APIs for good | |
| 23 * randomness. Macintosh provides SetRandomSeed and RandomBits, but I | |
| 24 * am skeptical of its use as a good random number generator. */ | |
| 25 | |
| 26 #ifdef RANDOM_UNIX | |
| 27 | |
| 28 struct random_unix { | |
| 29 FILE *f; | |
| 30 }; | |
| 31 | |
| 32 static void random_unix_close(struct random *r) | |
| 33 { | |
| 34 struct random_unix *ru = r->userdata; | |
| 35 | |
| 36 if (ru->f) | |
| 37 fclose(ru->f); | |
| 38 | |
| 39 free(ru); | |
| 40 } | |
| 41 | |
| 42 static size_t random_unix_read(struct random *r, void *ptr, size_t s) | |
| 43 { | |
| 44 struct random_unix *ru = r->userdata; | |
| 45 | |
| 46 return fread(ptr, s, 1, ru->f); | |
| 47 } | |
| 48 | |
| 49 static int random_unix_init(struct random *r) | |
| 50 { | |
| 51 /* hmmm. */ | |
| 52 static const char *names[] = { | |
| 53 "/dev/random", | |
| 54 "/dev/urandom", | |
| 55 }; | |
| 56 struct random_unix *ru = malloc(sizeof(*ru)); | |
| 57 size_t i; | |
| 58 | |
| 59 for (i = 0; i < ARRAY_SIZE(names); i++) { | |
| 60 ru->f = fopen(names[i], "rb"); | |
| 61 if (ru->f) | |
| 62 goto gotdevice; | |
| 63 } | |
| 64 | |
| 65 free(ru); | |
| 66 return -1; | |
| 67 | |
| 68 gotdevice: | |
| 69 | |
| 70 r->userdata = ru; | |
| 71 r->close = random_unix_close; | |
| 72 r->read = random_unix_read; | |
| 73 | |
| 74 return 0; | |
| 75 } | |
| 76 | |
| 77 #endif | |
| 78 | |
| 79 /* ------------------------------------------------------------------------ */ | |
| 80 | |
| 81 #ifdef RANDOM_ARC4RANDOM | |
| 82 | |
| 83 static size_t random_arc4random_read(struct random *r, void *ptr, size_t s) | |
| 84 { | |
| 85 size_t l = s; | |
| 86 | |
| 87 while (l > 0) { | |
| 88 size_t amt; | |
| 89 uint32_t x; | |
| 90 | |
| 91 amt = MIN(sizeof(x), l); | |
| 92 x = arc4random(); | |
| 93 | |
| 94 memcpy(ptr, &x, amt); | |
| 95 | |
| 96 ptr += amt; | |
| 97 l -= amt; | |
| 98 } | |
| 99 | |
| 100 return s; | |
| 101 } | |
| 102 | |
| 103 static void random_arc4random_close(struct random *r) | |
| 104 { | |
| 105 /* nothing */ | |
| 106 } | |
| 107 | |
| 108 static int random_arc4random_init(struct random *r) | |
| 109 { | |
| 110 /* always successful */ | |
| 111 r->read = random_arc4random_read; | |
| 112 r->close = random_arc4random_close; | |
| 113 return 0; | |
| 114 } | |
| 115 | |
| 116 #endif | |
| 117 | |
| 118 /* ------------------------------------------------------------------------ */ | |
| 119 | |
| 120 #ifdef RANDOM_WIN32 | |
| 121 | |
| 122 typedef BOOL (*pADVAPI32_CryptReleaseContext)(HCRYPTPROV hProv, DWORD dwFlags); | |
| 123 typedef BOOL (*pADVAPI32_CryptGenRandom)(HCRYPTPROV hProv, DWORD dwLen, BYTE *pbBuffer); | |
| 124 typedef BOOL (*pADVAPI32_CryptAcquireContextA)(HCRYPTPROV *phProv, LPCSTR szContainer, LPCSTR szProvider, DWORD dwProvType,DWORD dwFlags); | |
| 125 | |
| 126 struct random_win32 { | |
| 127 HCRYPTPROV c; | |
| 128 | |
| 129 HMODULE advapi32; | |
| 130 pADVAPI32_CryptReleaseContext ADVAPI32_CryptReleaseContext; | |
| 131 pADVAPI32_CryptGenRandom ADVAPI32_CryptGenRandom; | |
| 132 pADVAPI32_CryptAcquireContextA ADVAPI32_CryptAcquireContextA; | |
| 133 }; | |
| 134 | |
| 135 static void random_win32_close(struct random *r) | |
| 136 { | |
| 137 struct random_win32 *rw = r->userdata; | |
| 138 | |
| 139 rw->ADVAPI32_CryptReleaseContext(rw->c, 0); | |
| 140 FreeLibrary(rw->advapi32); | |
| 141 | |
| 142 free(rw); | |
| 143 } | |
| 144 | |
| 145 static size_t random_win32_read(struct random *r, void *ptr, size_t s) | |
| 146 { | |
| 147 struct random_win32 *rw = r->userdata; | |
| 148 | |
| 149 if (!rw->ADVAPI32_CryptGenRandom(rw->c, s, ptr)) | |
| 150 return 0; | |
| 151 | |
| 152 return s; | |
| 153 } | |
| 154 | |
| 155 static int random_win32_init(struct random *r) | |
| 156 { | |
| 157 HCRYPTPROV c; | |
| 158 struct random_win32 *rw; | |
| 159 | |
| 160 rw = malloc(sizeof(*rw)); | |
| 161 if (!rw) | |
| 162 return -2; | |
| 163 | |
| 164 rw->advapi32 = LoadLibraryA("ADVAPI32.DLL"); | |
| 165 if (!rw->advapi32) | |
| 166 return -3; | |
| 167 | |
| 168 #define LOADFUNC(x) \ | |
| 169 rw->ADVAPI32_##x = (pADVAPI32_##x)GetProcAddress(rw->advapi32, #x); \ | |
| 170 if (!rw->ADVAPI32_##x) \ | |
| 171 return -4 | |
| 172 | |
| 173 LOADFUNC(CryptAcquireContextA); | |
| 174 LOADFUNC(CryptGenRandom); | |
| 175 LOADFUNC(CryptReleaseContext); | |
| 176 | |
| 177 if (!rw->ADVAPI32_CryptAcquireContextA(&c, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) | |
| 178 return -1; | |
| 179 | |
| 180 | |
| 181 rw->c = c; | |
| 182 | |
| 183 r->userdata = rw; | |
| 184 r->close = random_win32_close; | |
| 185 r->read = random_win32_read; | |
| 186 return 0; | |
| 187 } | |
| 188 | |
| 189 #endif | |
| 190 | |
| 191 /* ------------------------------------------------------------------------ */ | |
| 192 /* platform-independent routines */ | |
| 193 | |
| 194 int random_init(struct random *r) | |
| 195 { | |
| 196 int i; | |
| 197 | |
| 198 int (*funcs[])(struct random *r) = { | |
| 199 #ifdef RANDOM_ARC4RANDOM | |
| 200 random_arc4random_init, | |
| 201 #endif | |
| 202 #ifdef RANDOM_UNIX | |
| 203 random_unix_init, | |
| 204 #endif | |
| 205 #ifdef RANDOM_WIN32 | |
| 206 random_win32_init, | |
| 207 #endif | |
| 208 NULL, | |
| 209 }; | |
| 210 | |
| 211 for (i = 0; funcs[i]; i++) | |
| 212 if (!funcs[i](r)) | |
| 213 return 0; | |
| 214 | |
| 215 return -1; | |
| 216 } | |
| 217 | |
| 218 void random_close(struct random *r) | |
| 219 { | |
| 220 r->close(r); | |
| 221 } | |
| 222 | |
| 223 size_t random_read(struct random *r, void *ptr, size_t s) | |
| 224 { | |
| 225 return r->read(r, ptr, s); | |
| 226 } |
