diff options
| -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); |
