diff options
Diffstat (limited to 'util-src/crand.c')
-rw-r--r-- | util-src/crand.c | 156 |
1 files changed, 156 insertions, 0 deletions
diff --git a/util-src/crand.c b/util-src/crand.c new file mode 100644 index 00000000..9a45f10f --- /dev/null +++ b/util-src/crand.c @@ -0,0 +1,156 @@ +/* Prosody IM +-- Copyright (C) 2008-2016 Matthew Wild +-- Copyright (C) 2008-2016 Waqas Hussain +-- Copyright (C) 2016 Kim Alvefur +-- +-- This project is MIT/X11 licensed. Please see the +-- COPYING file in the source package for more information. +-- +*/ + +/* +* crand.c +* C PRNG interface +*/ + +#include "lualib.h" +#include "lauxlib.h" + +#include <string.h> +#include <errno.h> + +/* + * TODO: Decide on fixed size or dynamically allocated buffer + */ +#if 1 +#include <malloc.h> +#else +#define BUFLEN 256 +#endif + +#if defined(WITH_GETRANDOM) +#include <unistd.h> +#include <sys/syscall.h> +#include <linux/random.h> + +#ifndef SYS_getrandom +#error getrandom() requires Linux 3.17 or later +#endif + +/* Was this not supposed to be a function? */ +int getrandom(char *buf, size_t len, int flags) { + return syscall(SYS_getrandom, buf, len, flags); +} + +#elif defined(WITH_ARC4RANDOM) +#include <stdlib.h> +#elif defined(WITH_OPENSSL) +#include <openssl/rand.h> +#else +#error util.crand compiled without a random source +#endif + +int Lrandom(lua_State *L) { +#ifdef BUFLEN + unsigned char buf[BUFLEN]; +#else + unsigned char *buf; +#endif + int ret = 0; + size_t len = (size_t)luaL_checkint(L, 1); +#ifdef BUFLEN + len = len > BUFLEN ? BUFLEN : len; +#else + buf = malloc(len); + + if(buf == NULL) { + lua_pushnil(L); + lua_pushstring(L, "out of memory"); + /* or it migth be better to + * return lua_error(L); + */ + return 2; + } +#endif + +#if defined(WITH_GETRANDOM) + ret = getrandom(buf, len, 0); + + if(ret < 0) { +#ifndef BUFLEN + free(buf); +#endif + lua_pushnil(L); + lua_pushstring(L, strerror(errno)); + lua_pushinteger(L, errno); + return 3; + } + +#elif defined(WITH_ARC4RANDOM) + arc4random_buf(buf, len); + ret = len; +#elif defined(WITH_OPENSSL) + ret = RAND_bytes(buf, len); + + if(ret == 1) { + ret = len; + } else { +#ifndef BUFLEN + free(buf); +#endif + lua_pushnil(L); + lua_pushstring(L, "failed"); + /* lua_pushinteger(L, ERR_get_error()); */ + return 2; + } + +#endif + + lua_pushlstring(L, buf, ret); +#ifndef BUFLEN + free(buf); +#endif + return 1; +} + +#ifdef ENABLE_SEEDING +int Lseed(lua_State *L) { + size_t len; + const char *seed = lua_tolstring(L, 1, &len); + +#if defined(WITH_OPENSSL) + RAND_add(seed, len, len); + return 0; +#else + lua_pushnil(L); + lua_pushliteral(L, "not-supported"); + return 2; +#endif +} +#endif + +int luaopen_util_crand(lua_State *L) { + lua_newtable(L); + lua_pushcfunction(L, Lrandom); + lua_setfield(L, -2, "bytes"); +#ifdef ENABLE_SEEDING + lua_pushcfunction(L, Lseed); + lua_setfield(L, -2, "seed"); +#endif + +#if defined(WITH_GETRANDOM) + lua_pushstring(L, "Linux"); +#elif defined(WITH_ARC4RANDOM) + lua_pushstring(L, "arc4random()"); +#elif defined(WITH_OPENSSL) + lua_pushstring(L, "OpenSSL"); +#endif + lua_setfield(L, -2, "_source"); + +#if defined(WITH_OPENSSL) && defined(_WIN32) + /* Do we need to seed this on Windows? */ +#endif + + return 1; +} + |