diff options
author | Thijs Schreijer <thijs@thijsschreijer.nl> | 2025-02-06 17:56:34 +0100 |
---|---|---|
committer | Thijs <thijs@thijsschreijer.nl> | 2025-02-06 21:22:47 +0100 |
commit | 6cd431d64d604ccfaa9c6174acb8878d2cf82e93 (patch) | |
tree | 6794ca9710c07748e5550e71e316c008824aea31 | |
parent | 6f4b532a2142c605aa23f1d78a1b48bd09af669f (diff) | |
download | luasystem-refactor/random.tar.gz luasystem-refactor/random.tar.bz2 luasystem-refactor/random.zip |
refactor(random): on linux+bsd use api instead of /dev/urandomrefactor/random
the api is faster and equally good
-rw-r--r-- | CHANGELOG.md | 2 | ||||
-rw-r--r-- | src/random.c | 34 |
2 files changed, 31 insertions, 5 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 7ae7189..9a127e5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md | |||
@@ -31,6 +31,8 @@ The scope of what is covered by the version number excludes: | |||
31 | ### unreleased | 31 | ### unreleased |
32 | 32 | ||
33 | - Fix: NetBSD fix compilation, undeclared directives | 33 | - Fix: NetBSD fix compilation, undeclared directives |
34 | - Refactor: random bytes; remove deprecated API usage on Windows, move to | ||
35 | binary api instead of /dev/urandom file on linux and bsd | ||
34 | 36 | ||
35 | ### version 0.4.5, released 18-Dec-2024 | 37 | ### version 0.4.5, released 18-Dec-2024 |
36 | 38 | ||
diff --git a/src/random.c b/src/random.c index ee544c4..70bf13b 100644 --- a/src/random.c +++ b/src/random.c | |||
@@ -13,15 +13,21 @@ | |||
13 | #include <windows.h> | 13 | #include <windows.h> |
14 | #include <bcrypt.h> | 14 | #include <bcrypt.h> |
15 | #else | 15 | #else |
16 | #include <errno.h> | 16 | #include <errno.h> |
17 | #include <unistd.h> | 17 | #include <unistd.h> |
18 | #include <string.h> | 18 | #include <string.h> |
19 | #if defined(__linux__) | ||
20 | #include <sys/random.h> // getrandom() | ||
21 | #elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) | ||
22 | #include <stdlib.h> // arc4random_buf() | ||
23 | #endif | ||
19 | #endif | 24 | #endif |
20 | 25 | ||
21 | 26 | ||
22 | /*** | 27 | /*** |
23 | Generate random bytes. | 28 | Generate random bytes. |
24 | This uses `BCryptGenRandom()` on Windows, and `/dev/urandom` on other platforms. It will return the | 29 | This uses `BCryptGenRandom()` on Windows, `getrandom()` on Linux, `arc4random_buf` on BSD, |
30 | and `/dev/urandom` on other platforms. It will return the | ||
25 | requested number of bytes, or an error, never a partial result. | 31 | requested number of bytes, or an error, never a partial result. |
26 | @function random | 32 | @function random |
27 | @tparam[opt=1] int length number of bytes to get | 33 | @tparam[opt=1] int length number of bytes to get |
@@ -53,6 +59,7 @@ static int lua_get_random_bytes(lua_State* L) { | |||
53 | ssize_t total_read = 0; | 59 | ssize_t total_read = 0; |
54 | 60 | ||
55 | #ifdef _WIN32 | 61 | #ifdef _WIN32 |
62 | // Use BCryptGenRandom() on Windows | ||
56 | if (!BCRYPT_SUCCESS(BCryptGenRandom(NULL, buffer, num_bytes, BCRYPT_USE_SYSTEM_PREFERRED_RNG))) { | 63 | if (!BCRYPT_SUCCESS(BCryptGenRandom(NULL, buffer, num_bytes, BCRYPT_USE_SYSTEM_PREFERRED_RNG))) { |
57 | DWORD error = GetLastError(); | 64 | DWORD error = GetLastError(); |
58 | lua_pushnil(L); | 65 | lua_pushnil(L); |
@@ -60,8 +67,25 @@ static int lua_get_random_bytes(lua_State* L) { | |||
60 | return 2; | 67 | return 2; |
61 | } | 68 | } |
62 | 69 | ||
70 | #elif defined(__linux__) | ||
71 | // Use getrandom() on Linux (Kernel 3.17+, 2014) | ||
72 | while (total_read < num_bytes) { | ||
73 | ssize_t n = getrandom(buffer + total_read, num_bytes - total_read, 0); | ||
74 | if (n < 0) { | ||
75 | if (errno == EINTR) continue; // Retry on interrupt | ||
76 | lua_pushnil(L); | ||
77 | lua_pushfstring(L, "getrandom() failed: %s", strerror(errno)); | ||
78 | return 2; | ||
79 | } | ||
80 | total_read += n; | ||
81 | } | ||
82 | |||
83 | #elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) | ||
84 | // Use arc4random_buf() on BSD/macOS | ||
85 | arc4random_buf(buffer, num_bytes); | ||
86 | |||
63 | #else | 87 | #else |
64 | // for macOS/unixes use /dev/urandom for non-blocking | 88 | // fall back to /dev/urandom for anything else |
65 | int fd = open("/dev/urandom", O_RDONLY | O_CLOEXEC); | 89 | int fd = open("/dev/urandom", O_RDONLY | O_CLOEXEC); |
66 | if (fd < 0) { | 90 | if (fd < 0) { |
67 | lua_pushnil(L); | 91 | lua_pushnil(L); |