diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d3d95cb..9845137 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,7 +11,7 @@ on: - "docs/**" env: - ROCKSPEC_VERSION: 0.0.1 + ROCKSPEC_VERSION: 0.0.2 DEV_ROCKSPEC: lua-cryptorandom-dev-1.rockspec jobs: diff --git a/Makefile.macosx b/Makefile.macosx index 414d91a..38b4373 100644 --- a/Makefile.macosx +++ b/Makefile.macosx @@ -2,6 +2,7 @@ OBJ_EXTENSION = o LIB_EXTENSION = so CFLAGS_EXTRA = -DLUA_CRYPTORANDOM_BUILD_SHARED -DLUA_CRYPTORANDOM_USE_APPLE LIBFLAG_EXTRA = -framework Security +LIB_M = -lm LUA_DIR = /usr/local LUA_INCDIR = $(LUA_DIR)/include @@ -13,7 +14,7 @@ INSTALL_LIBDIR = $(INSTALL_PREFIX)/lib/lua/$(LUA_VERSION) all: src/lua-cryptorandom.$(LIB_EXTENSION) src/lua-cryptorandom.$(LIB_EXTENSION): src/lua-cryptorandom.$(OBJ_EXTENSION) - $(CC) $(LIBFLAG_EXTRA) $(LIBFLAG) -o $@ $< + $(CC) $(LIBFLAG_EXTRA) $(LIBFLAG) -o $@ $< $(LIB_M) src/lua-cryptorandom.$(OBJ_EXTENSION): src/lua-cryptorandom.c $(CC) -c $(CFLAGS_EXTRA) $(CFLAGS) -I$(LUA_INCDIR) $< -o $@ diff --git a/README.md b/README.md index 12456c3..19ccfb2 100644 --- a/README.md +++ b/README.md @@ -14,13 +14,9 @@ > > ```lua-cryptorandom``` is implemented in C, and also compiles as C++. -> [!WARNING] -> -> Are you using a personalized compilation of Lua? See the [known limitations](#known-limitations). - ## Use cases -Many security operations rely on the high-quality of randomization services to avoid reproducibility and remain resistant to reverse engineering: +Many security operations rely on high-quality randomization services to avoid reproducibility and remain resistant to reverse engineering: * randomized password generation; * nonces (numbers used once) generation; @@ -137,6 +133,7 @@ luarocks install lua-cryptorandom * *Return*: ```number | nil``` as first value, and ```nil | integer``` as the second. * ```number | nil```: the generated float number on success, or ```nil``` when an error occurred; * ```nil | integer```: an error code that is set to ```nil``` on success, or an ```integer``` representing the code used by the underlying library (```OpenSSL``` on Unix, ```bcrypt``` on Windows and ```Security``` framework on macOS / iOS). +* *Remark*: since v0.0.2, in case of success, the returned number is not ```NaN``` or positive/negative infinity values. * *Usage*: ```lua @@ -175,11 +172,16 @@ luarocks install lua-cryptorandom ## Known limitations -* The error code (second return value) on each method might deliver a value different than the one returned by the underlying library. This condition might happen when the Lua type ```lua_Integer``` is shorter than an ```unsigned long``` in size. Even though it can be achieved on personalized compilations of Lua (e.g.: Lua compiled as ANSI C), the usual build of Lua should be safe for most users and platforms. +> [!WARNING] +> +> This section mostly applies to users running a customized build of Lua. + +* The error code (second return value) on each method might deliver a value different than the one returned by the underlying library. This condition might happen when the Lua type ```lua_Integer``` is shorter than an ```unsigned long``` in size. Even though it can be achieved on personalized builds of Lua (e.g.: Lua compiled as ANSI C on some platforms), the usual build of Lua should be safe for most users and platforms. ## Change log -v0.0.1: Initial release. +* v0.0.2: Prevent the generation of ```NaN``` and positive/negative infinity values in the function [number](#number). +* v0.0.1: Initial release. ## Future works diff --git a/rockspecs/lua-cryptorandom-0.0.2-1.rockspec b/rockspecs/lua-cryptorandom-0.0.2-1.rockspec new file mode 100644 index 0000000..11a84a5 --- /dev/null +++ b/rockspecs/lua-cryptorandom-0.0.2-1.rockspec @@ -0,0 +1,105 @@ +package = "lua-cryptorandom" +version = "0.0.2-1" + +source = { + url = "git+https://github.com/luau-project/lua-cryptorandom", + tag = "v0.0.2" +} + +description = { + homepage = "https://github.com/luau-project/lua-cryptorandom", + summary = [[Generate cryptographically secure pseudo random numbers for Lua]], + detailed = [=[ +lua-cryptorandom is a lightweight, native library for Lua aimed to generate cryptographically secure pseudo random numbers, using trusted sources of randomness provided by the operating system. + +Visit the repository for more information.]=], + license = "MIT" +} + +dependencies = { + "lua >= 5.1" +} + +local function external_dependencies_plat() + return { + ["CRYPTO"] = { + header = "openssl/rand.h" + } + } +end + +external_dependencies = { + platforms = { + linux = external_dependencies_plat(), + freebsd = external_dependencies_plat(), + openbsd = external_dependencies_plat(), + netbsd = external_dependencies_plat(), + dragonfly = external_dependencies_plat() + } +} + +local function build_plat(plat) + if (plat == "macosx" or plat == "macos") then + return { + type = "make", + makefile = "Makefile.macosx", + build_variables = { + CFLAGS = "$(CFLAGS)", + LIBFLAG = "$(LIBFLAG)", + CFLAGS_EXTRA = "-DLUA_CRYPTORANDOM_BUILD_SHARED -DLUA_CRYPTORANDOM_USE_APPLE", + LIBFLAG_EXTRA = "-framework Security", + LUA_INCDIR = "$(LUA_INCDIR)", + OBJ_EXTENSION = "$(OBJ_EXTENSION)", + LIB_EXTENSION = "$(LIB_EXTENSION)" + }, + install_variables = { + INSTALL_PREFIX = "$(PREFIX)", + INSTALL_LIBDIR = "$(LIBDIR)", + LUA_VERSION = "$(LUA_VERSION)", + LIB_EXTENSION = "$(LIB_EXTENSION)" + } + } + elseif (plat == "windows" or plat == "cygwin") then + return { + type = "builtin", + modules = { + ["lua-cryptorandom"] = { + sources = { "src/lua-cryptorandom.c" }, + libraries = { "bcrypt" }, + defines = { "LUA_CRYPTORANDOM_BUILD_SHARED", "LUA_CRYPTORANDOM_USE_WIN32" }, + incdirs = { "src" }, + libdirs = { } + } + } + } + elseif (plat == "linux" or plat == "bsd") then + return { + type = "builtin", + modules = { + ["lua-cryptorandom"] = { + sources = { "src/lua-cryptorandom.c" }, + libraries = { "crypto" }, + defines = { "LUA_CRYPTORANDOM_BUILD_SHARED", "LUA_CRYPTORANDOM_USE_OPENSSL" }, + incdirs = { "src", "$(CRYPTO_INCDIR)" }, + libdirs = { "$(CRYPTO_LIBDIR)" } + } + } + } + else + error("Unknown platform", 2) + end +end + +build = { + platforms = { + macosx = build_plat("macosx"), + macos = build_plat("macos"), + windows = build_plat("windows"), + cygwin = build_plat("cygwin"), + linux = build_plat("linux"), + freebsd = build_plat("bsd"), + openbsd = build_plat("bsd"), + netbsd = build_plat("bsd"), + dragonfly = build_plat("bsd") + } +} diff --git a/src/lua-cryptorandom.c b/src/lua-cryptorandom.c index 3a880f7..3f1f54c 100644 --- a/src/lua-cryptorandom.c +++ b/src/lua-cryptorandom.c @@ -18,10 +18,42 @@ #endif #include +#include + #include #include #include +#ifndef isnan +#define isnan(x) (!((x)==(x))) +#endif + +#ifndef isinf +#define isinf(x) ((x)==(HUGE_VAL)?(1):((x)==(-HUGE_VAL)?(-1):(0))) +#endif + +/* +** helper union to the function +** lua_cryptorandom_integer +*/ +typedef union tagLuaCryptoRandomInteger +{ + lua_Integer value; + unsigned char buffer[sizeof(lua_Integer)]; + +} LuaCryptoRandomInteger; + +/* +** helper union to the function +** lua_cryptorandom_number +*/ +typedef union tagLuaCryptoRandomNumber +{ + lua_Number value; + unsigned char buffer[sizeof(lua_Number)]; + +} LuaCryptoRandomNumber; + #define LUA_CRYPTORANDOM_METATABLE "lua_cryptorandom_metatable" /* Implementation to generate cryptographically secure pseudo random bytes */ @@ -112,18 +144,17 @@ static int lua_cryptorandom_take(lua_State *L) static int lua_cryptorandom_integer(lua_State *L) { - unsigned char buffer[sizeof(lua_Integer)]; + LuaCryptoRandomInteger rint; unsigned long err; - if (lua_cryptorandom_bytes_impl(L, (unsigned char *)buffer, sizeof(lua_Integer), &err) == 0) + if (lua_cryptorandom_bytes_impl(L, (unsigned char *)(rint.buffer), sizeof(lua_Integer), &err) == 0) { lua_pushnil(L); lua_pushinteger(L, (lua_Integer)err); } else { - lua_Integer *take_ptr = (lua_Integer *)buffer; - lua_pushinteger(L, *take_ptr); + lua_pushinteger(L, rint.value); lua_pushnil(L); } @@ -132,21 +163,28 @@ static int lua_cryptorandom_integer(lua_State *L) static int lua_cryptorandom_number(lua_State *L) { - unsigned char buffer[sizeof(lua_Number)]; - + LuaCryptoRandomNumber rnum; unsigned long err; - if (lua_cryptorandom_bytes_impl(L, (unsigned char *)buffer, sizeof(lua_Number), &err) == 0) - { - lua_pushnil(L); - lua_pushinteger(L, (lua_Integer)err); - } - else + + int is_nan_or_inf = 1; + int had_error = 0; + + while (!had_error && is_nan_or_inf) { - lua_Number *take_ptr = (lua_Number *)buffer; - lua_pushnumber(L, *take_ptr); - lua_pushnil(L); + if (lua_cryptorandom_bytes_impl(L, (unsigned char *)(rnum.buffer), sizeof(lua_Number), &err) == 0) + { + lua_pushnil(L); + lua_pushinteger(L, (lua_Integer)err); + had_error = 1; + } + else if (!(isnan(rnum.value) || isinf(rnum.value))) + { + lua_pushnumber(L, rnum.value); + lua_pushnil(L); + is_nan_or_inf = 0; + } } - + return 2; }