2 -- Copyright (C) 2008-2017 Matthew Wild
3 -- Copyright (C) 2008-2017 Waqas Hussain
4 -- Copyright (C) 2016-2017 Kim Alvefur
6 -- This project is MIT/X11 licensed. Please see the
7 -- COPYING file in the source package for more information.
15 * The purpose of this module is to provide access to a PRNG in
16 * environments without /dev/urandom
18 * Caution! This has not been extensively tested.
22 #define _DEFAULT_SOURCE
31 #if defined(WITH_GETRANDOM)
33 #ifndef __GLIBC_PREREQ
34 /* Not compiled with glibc at all */
35 #define __GLIBC_PREREQ(a,b) 0
38 #if ! __GLIBC_PREREQ(2,25)
39 /* Not compiled with a glibc that provides getrandom() */
41 #include <sys/syscall.h>
44 #error getrandom() requires Linux 3.17 or later
47 /* This wasn't present before glibc 2.25 */
48 int getrandom(void *buf
, size_t buflen
, unsigned int flags
) {
49 return syscall(SYS_getrandom
, buf
, buflen
, flags
);
52 #include <sys/random.h>
55 #elif defined(WITH_OPENSSL)
56 #include <openssl/rand.h>
57 #elif defined(WITH_ARC4RANDOM)
59 #include <bsd/stdlib.h>
62 #error util.crand compiled without a random source
66 #define SMALLBUFSIZ 32
69 int Lrandom(lua_State
*L
) {
70 char smallbuf
[SMALLBUFSIZ
];
71 char *buf
= &smallbuf
[0];
72 const lua_Integer l
= luaL_checkinteger(L
, 1);
74 luaL_argcheck(L
, l
>= 0, 1, "must be > 0");
77 lua_pushliteral(L
, "");
81 if(len
> SMALLBUFSIZ
) {
82 buf
= lua_newuserdata(L
, len
);
85 #if defined(WITH_GETRANDOM)
87 * This acts like a read from /dev/urandom with the exception that it
88 * *does* block if the entropy pool is not yet initialized.
94 int ret
= getrandom(p
, left
, 0);
97 lua_pushstring(L
, strerror(errno
));
105 #elif defined(WITH_ARC4RANDOM)
106 arc4random_buf(buf
, len
);
107 #elif defined(WITH_OPENSSL)
110 lua_pushliteral(L
, "OpenSSL PRNG not seeded");
114 if(RAND_bytes((unsigned char *)buf
, len
) != 1) {
115 /* TODO ERR_get_error() */
116 lua_pushstring(L
, "RAND_bytes() failed");
122 lua_pushlstring(L
, buf
, len
);
126 int luaopen_util_crand(lua_State
*L
) {
127 #if (LUA_VERSION_NUM > 501)
128 luaL_checkversion(L
);
131 lua_createtable(L
, 0, 2);
132 lua_pushcfunction(L
, Lrandom
);
133 lua_setfield(L
, -2, "bytes");
135 #if defined(WITH_GETRANDOM)
136 lua_pushstring(L
, "Linux");
137 #elif defined(WITH_ARC4RANDOM)
138 lua_pushstring(L
, "arc4random()");
139 #elif defined(WITH_OPENSSL)
140 lua_pushstring(L
, "OpenSSL");
142 lua_setfield(L
, -2, "_source");