Nilorea Library
C utilities for networking, threading, graphics
Loading...
Searching...
No Matches
n_random.c
Go to the documentation of this file.
1/*
2 * Nilorea Library
3 * Copyright (C) 2005-2026 Castagnier Mickael
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
14 * implied. See the License for the specific language governing
15 * permissions and limitations under the License.
16 *
17 * SPDX-License-Identifier: Apache-2.0
18 */
19
26
27#include "nilorea/n_random.h"
28
29#include "nilorea/n_common.h"
30#include "nilorea/n_hex.h"
31#include "nilorea/n_log.h"
32#include "nilorea/n_str.h"
33
34#include <errno.h>
35#include <stdio.h>
36#include <string.h>
37#include <unistd.h>
38
39/* getrandom(2) exists on glibc >= 2.25; guard its header behind that so the
40 * /dev/urandom path remains the portable fallback (musl, older glibc). */
41#if defined(__GLIBC__) && (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 25))
42#define N_RANDOM_HAVE_GETRANDOM 1
43#include <sys/random.h>
44#endif
45
46#ifdef __windows__
47/* Windows has neither getrandom(2) nor /dev/urandom, so both POSIX sources below
48 * fail there and every caller would get no randomness at all. BCryptGenRandom is
49 * the documented CNG system RNG (bcrypt.dll, Vista and later); link with -lbcrypt.
50 * n_windows.h must come first: bcrypt.h uses LONG/ULONG without defining them. */
51#include "nilorea/n_windows.h"
52#include <bcrypt.h>
53#ifndef STATUS_SUCCESS
54#define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
55#endif
56
57/* Fill buf with n bytes from the Windows system RNG. Returns 0 on success, -1 on error. */
58static int n_random_from_cng(unsigned char* buf, size_t n) {
59 NTSTATUS st = BCryptGenRandom(NULL, (PUCHAR)buf, (ULONG)n, BCRYPT_USE_SYSTEM_PREFERRED_RNG);
60 if (st != STATUS_SUCCESS) {
61 n_log(LOG_ERR, "n_random_bytes: BCryptGenRandom failed with status 0x%08lx", (unsigned long)st);
62 return -1;
63 }
64 return 0;
65}
66#endif
67
68#ifndef __windows__
69/* Read n bytes from /dev/urandom into buf. Returns 0 on success, -1 on error.
70 Guarded: the Windows branch returns before reaching it, so compiling it there
71 is dead code and -Wunused-function says so. */
72static int n_random_from_urandom(unsigned char* buf, size_t n) {
73 FILE* f = fopen("/dev/urandom", "rb");
74 if (!f) {
75 n_log(LOG_ERR, "n_random_bytes: cannot open /dev/urandom: %s", strerror(errno));
76 return -1;
77 }
78 size_t got = fread(buf, 1, n, f);
79 fclose(f);
80 if (got != n) {
81 n_log(LOG_ERR, "n_random_bytes: short read from /dev/urandom (%zu of %zu)", got, n);
82 return -1;
83 }
84 return 0;
85}
86#endif /* !__windows__ */
87
88int n_random_bytes(unsigned char* buf, size_t n) {
89 if (!buf && n > 0) {
90 n_log(LOG_ERR, "n_random_bytes: NULL buffer with n %zu", n);
91 return -1;
92 }
93 if (n == 0) {
94 return 0;
95 }
96
97#ifdef __windows__
98 return n_random_from_cng(buf, n);
99#elif defined(N_RANDOM_HAVE_GETRANDOM)
100 size_t got = 0;
101 while (got < n) {
102 ssize_t r = getrandom(buf + got, n - got, 0);
103 if (r < 0) {
104 if (errno == EINTR) continue;
105 break; /* fall through to the /dev/urandom fallback */
106 }
107 got += (size_t)r;
108 }
109 if (got == n) {
110 return 0;
111 }
112 /* getrandom did not deliver everything; finish from /dev/urandom */
113 return n_random_from_urandom(buf + got, n - got);
114#else
115 return n_random_from_urandom(buf, n);
116#endif
117}
118
119N_STR* n_random_hex_token(size_t nbytes) {
120 if (nbytes == 0) {
121 return n_hex_encode((const unsigned char*)"", 0);
122 }
123 unsigned char* buf = NULL;
124 Malloc(buf, unsigned char, nbytes);
125 __n_assert(buf, return NULL);
126 if (n_random_bytes(buf, nbytes) != 0) {
127 Free(buf);
128 return NULL;
129 }
130 N_STR* hex = n_hex_encode(buf, nbytes);
131 Free(buf);
132 return hex;
133}
#define Malloc(__ptr, __struct, __size)
Malloc Handler to get errors and set to 0.
Definition n_common.h:204
#define __n_assert(__ptr, __ret)
macro to assert things
Definition n_common.h:279
#define Free(__ptr)
Free Handler to get errors.
Definition n_common.h:263
#define n_log(__LEVEL__,...)
Logging function wrapper to get line and func.
Definition n_log.h:113
#define LOG_ERR
error conditions
Definition n_log.h:100
N_STR * n_hex_encode(const unsigned char *data, size_t len)
encode len bytes of data as a lowercase hex N_STR (2*len characters); free with free_nstr.
Definition n_hex.c:48
int n_random_bytes(unsigned char *buf, size_t n)
fill buf with n cryptographically secure random bytes from the system RNG: BCryptGenRandom on Windows...
Definition n_random.c:88
N_STR * n_random_hex_token(size_t nbytes)
generate nbytes secure random bytes and return them as a lowercase hex N_STR (2*nbytes characters); f...
Definition n_random.c:119
A box including a string and his lenght.
Definition n_str.h:61
Common headers and low-level functions & define.
Hexadecimal encode/decode helpers.
Generic log system.
static int n_random_from_urandom(unsigned char *buf, size_t n)
Definition n_random.c:72
Cryptographically secure random bytes and hex tokens.
N_STR and string function declaration.