forked from mirage/mirage-crypto
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathmc_getrandom_stubs.c
80 lines (71 loc) · 2.43 KB
/
mc_getrandom_stubs.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
#ifndef _MSC_VER
# include <unistd.h>
#endif
#include "mirage_crypto.h"
#include <caml/mlvalues.h>
#include <caml/memory.h>
#include <caml/unixsupport.h>
#include <caml/bigarray.h>
#if defined(__linux) || defined(__GNU__)
# include <errno.h>
// on Linux and GNU/Hurd, we use getrandom and loop
# if __GLIBC__ && __GLIBC__ <= 2 && __GLIBC_MINOR__ < 25
# include <sys/syscall.h>
# define getrandom(buf, len, flags) syscall(SYS_getrandom, (buf), (len), (flags))
# else
# include <sys/random.h>
# define getrandom(buf, len, flags) getrandom((buf), (len), (flags))
# endif
void raw_getrandom (uint8_t *data, uint32_t len) {
size_t off = 0;
ssize_t r = 0;
while (off < len) {
r = getrandom(data + off, len - off, 0);
if (r == -1) {
if (errno == EINTR) continue;
else uerror("getrandom", Nothing);
}
off += (size_t)r;
}
}
#elif (defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__) || defined(__OpenBSD__) || defined(__APPLE__)) || defined(__NetBSD__)
// on BSD and macOS, loop (in pieces of 256) getentropy
#if defined(__APPLE__)
// on macOS, getentropy is defined in sys/random.h (on BSD in unistd.h)
#include <sys/random.h>
#endif
#include <sys/param.h>
void raw_getrandom (uint8_t *data, uint32_t len) {
size_t rlen = 0;
for (uint32_t i = 0; i <= len; i += 256) {
rlen = MIN(256, len - i);
if (getentropy(data + i, rlen) == -1) uerror("getentropy", Nothing);
}
}
#elif (defined(_WIN32))
/* There is a choice between using RtlGenRandom and BCryptGenRandom
* here, and Microsoft does not make the choice obvious. It appears
* that RtlGenRandom is best used when older Windows compatibility
* is of concern, but requires some gymnastics around binding it
* with the right calling convention.
*
* Therefore (https://github.com/mirage/mirage-crypto/pull/39) we
* have decided to go with the more modern Windows API with bcrypt,
* and make Windows 10 our minimum supported version of mirage-crypto.
*/
#include <Windows.h>
#include <ntstatus.h>
#include <bcrypt.h>
void raw_getrandom(uint8_t *data, uint32_t len) {
NTSTATUS Status;
Status = BCryptGenRandom(NULL, data, len, BCRYPT_USE_SYSTEM_PREFERRED_RNG);
if (Status != STATUS_SUCCESS)
uerror("BCryptGenRandom", Nothing);
}
#else
#error "Retrieving random data not supported on this platform"
#endif
CAMLprim value mc_getrandom (value buf, value off, value len) {
raw_getrandom(_bp_uint8_off(buf, off), Int_val(len));
return Val_unit;
}