mte/unikernel/duniverse/mirage-crypto/rng/unix/mc_getrandom_stubs.c

88 lines
2.7 KiB
C
Raw Normal View History

2025-11-11 02:07:51 +01:00
#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(__ANDROID_API__) && __ANDROID_API__ < 28
// on Android 27 and earlier, we use Google's <sys/random.h> recommended arc4random_buf
# include <stdlib.h>
void raw_getrandom (uint8_t *data, size_t len) {
arc4random_buf(data, len);
}
#elif 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, size_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, size_t len) {
size_t rlen = 0;
for (size_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, size_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), Long_val(len));
return Val_unit;
}