From f2aafd5070cb290ce92925626db938c14be49ce2 Mon Sep 17 00:00:00 2001 From: Alexander Nutz Date: Wed, 10 Sep 2025 21:29:14 +0200 Subject: [PATCH] WIP systemrand.h --- systemrand.h | 175 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 175 insertions(+) create mode 100644 systemrand.h diff --git a/systemrand.h b/systemrand.h new file mode 100644 index 0000000..280be54 --- /dev/null +++ b/systemrand.h @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2025 Alexander Nutz + * MIT licensed, see below documentation + * + * Latest version can be found at: + * https://gitea.vxcc.dev/alexander.nutz/slow-libs + * + * ======== High-entropy system RNG ========= + * + * Configuration options: + * - SLOWCRYPT_SYSTEMRAND_IMPL + * - SLOWCRYPT_SYSTEMRAND_FUNC + * will be used in front of every function definition / declaration + * + * Tries these sources (depending on platform support), in order: + * - getentropy() + * - getrandom() + * - unless _WIN32 is defined, read from /dev/random or /dev/urandom + * - on _WIN32, try BCryptGenRandom + * - on _WIN32, CryptGenRandom + * - on _WIN32, RtlGenRandom + * - random(), unless bail on insecure + * - rand(), unless bail on insecure + * + * As with all slow-libs, a wide range of supported platforms is a priority, + * so please report any incompatibility issues. + */ + +/* + * Copyright (c) 2025 Alexander Nutz + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: The above copyright + * notice and this permission notice shall be included in all copies or + * substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", + * WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + * TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE + * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef SLOWCRYPT_SYSTEMRAND_H +#define SLOWCRYPT_SYSTEMRAND_H + +#ifndef SLOWCRYPT_SYSTEMRAND_FUNC +#define SLOWCRYPT_SYSTEMRAND_FUNC /**/ +#endif + +typedef enum +{ + SLOWCRYPT_SYSTEMRAND__BAIL_IF_INSECURE = 1 << 0, + SLOWCRYPT_SYSTEMRAND__INSECURE_NON_BLOCKING = 1 << 1 +} slowcrypt_systemrand_flags; + +/* + * Return codes: + * - 0: success + * - 1: unexpected error + * - 2: random number is not secure enough. Only returned with BAIL_IF_INSECURE + */ +SLOWCRYPT_SYSTEMRAND_FUNC int slowcrypt_systemrand( + void* buffer, + unsigned long length, + slowcrypt_systemrand_flags flags); + +#ifdef SLOWCRYPT_SYSTEMRAND_IMPL + +#ifndef _GNU_SOURCE +#define SLOWCRYPT_SYSTEMRAND_UNDEF_GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include +#include + +#ifdef unix +#include +#include +#endif + +#ifdef SLOWCRYPT_SYSTEMRAND_UNDEF_GNU_SOURCE +#undef SLOWCRYPT_SYSTEMRAND_UNDEF_GNU_SOURCE +#undef _GNU_SOURCE +#endif + +static int slowcrypt_systemrand__chunk256(void* buffer, + unsigned long length, + slowcrypt_systemrand_flags flags) +{ + unsigned long i, j; + unsigned char u8; + char const* fpath; + FILE* fp; + +#if defined(unix) && defined(__GLIBC__) && \ + (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 25)) + + if (getentropy(buffer, length)) { + if (errno != ENOSYS) { + return 1; + } + } else { + return 0; + } +#endif + + /* TODO: getrandom (on glibc, freebsd, and probably others) */ + +#ifndef _WIN32 + fpath = (flags & SLOWCRYPT_SYSTEMRAND__INSECURE_NON_BLOCKING) ? "/dev/urandom" + : "/dev/random"; + + fp = fopen(fpath, "rb"); + if (fp) { + i = fread(buffer, 1, length, fp); + fclose(fp); + if (i == length) + return 0; + } +#endif + + /* TODO: windows stuff */ + + if (flags & SLOWCRYPT_SYSTEMRAND__BAIL_IF_INSECURE) + return 2; + + /* TODO: random() */ + + if (RAND_MAX >= 255) { + for (i = 0; i < length; i++) { + ((unsigned char*)buffer)[i] = + (unsigned char)((unsigned int)rand() / (unsigned int)(RAND_MAX)); + } + } else { + /* why would this ever happen... */ + for (i = 0; i < length; i++) { + u8 = 0; + for (j = 0; j < 8; j++) { + u8 <<= 1; + u8 ^= (unsigned char)rand(); + } + ((unsigned char*)buffer)[i] = u8; + } + } + return 0; +} + +SLOWCRYPT_SYSTEMRAND_FUNC int slowcrypt_systemrand( + void* buffer, + unsigned long length, + slowcrypt_systemrand_flags flags) +{ + unsigned int i, j; + int rc; + + /* many random sources have a limit of 256 bytes */ + for (i = 0; i < length; i += 256) { + j = length - i; + if (j > 256) + j = 256; + if ((rc = slowcrypt_systemrand__chunk256(buffer, length, flags))) { + return rc; + } + } + return 0; +} + +#endif + +#endif