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 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
|
#if __STDC_VERSION__ >= 199901L
#define PERL_WANT_VARARGS
#endif
#define PERL_NO_GET_CONTEXT
#include "EXTERN.h"
#include "perl.h"
#define NO_XSLOCKS
#include "XSUB.h"
#include <sys/types.h>
#include <errno.h>
#if defined(HAVE_SYS_RANDOM_GETRANDOM) || defined(HAVE_SYS_RANDOM_ARC4RANDOM)
#include <sys/random.h>
#elif defined(HAVE_SYSCALL_GETRANDOM)
#include <sys/syscall.h>
#include <unistd.h>
#define getrandom(data, length, flags) syscall(SYS_getrandom, data, length, flags)
#elif defined(HAVE_UNISTD_ARC4RANDOM)
#include <unistd.h>
#elif defined(HAVE_STDLIB_ARC4RANDOM)
#include <stdlib.h>
#elif defined(HAVE_BCRYPT_GENRANDOM)
#define WIN32_NO_STATUS
#include <windows.h>
#undef WIN32_NO_STATUS
#include <winternl.h>
#include <ntstatus.h>
#include <bcrypt.h>
#elif defined(HAVE_RDRAND32) || defined(HAVE_RDRAND64)
#include <immintrin.h>
#else
#error "No suitable implementation found"
#endif
static const char error_string[] = "Could not read random bytes";
MODULE = Crypt::SysRandom::XS PACKAGE = Crypt::SysRandom::XS
PROTOTYPES: DISABLED
SV* random_bytes(size_t wanted)
CODE:
RETVAL = newSVpv("", 0);
SvGROW(RETVAL, wanted + 1);
SvCUR_set(RETVAL, wanted);
char* data = SvPVX(RETVAL);
#if defined(HAVE_BCRYPT_GENRANDOM)
NTSTATUS status = BCryptGenRandom(NULL, data, wanted, BCRYPT_USE_SYSTEM_PREFERRED_RNG);
if (!NT_SUCCESS(status)) {
SvREFCNT_dec(RETVAL);
croak(error_string);
}
#elif defined(HAVE_SYS_RANDOM_ARC4RANDOM) || defined(HAVE_UNISTD_ARC4RANDOM) || defined(HAVE_STDLIB_ARC4RANDOM)
arc4random_buf(data, wanted);
#elif defined(HAVE_RDRAND64)
if (wanted % 8)
SvGROW(RETVAL, wanted + (8 - (wanted % 8)) + 1);
int i;
for (i = 0; i < wanted; i += 8)
_rdrand64_step((unsigned long long*)(data + i));
if (wanted % 8)
data[wanted] = '\0';
#elif defined(HAVE_RDRAND32)
if (wanted % 4)
SvGROW(RETVAL, wanted + (4 - (wanted % 4)) + 1);
int i;
for (i = 0; i < wanted; i += 4)
_rdrand32_step((unsigned*)(data + i));
if (wanted % 4)
data[wanted] = '\0';
#else
size_t received = 0;
while (received < wanted) {
size_t length = wanted - received;
int result = getrandom(data, length, 0);
if (result == -1 && errno == EINTR) {
dXCPT;
XCPT_TRY_START {
PERL_ASYNC_CHECK();
} XCPT_TRY_END;
XCPT_CATCH {
SvREFCNT_dec(RETVAL);
XCPT_RETHROW;
}
} else if (result == -1 || result == 0) {
SvREFCNT_dec(RETVAL);
croak(error_string);
} else {
received += result;
data += result;
}
}
#endif
OUTPUT:
RETVAL
|