/src/libcoap/src/coap_prng.c
Line | Count | Source |
1 | | /* |
2 | | * coap_prng.c -- random number generation |
3 | | * |
4 | | * Copyright (C) 2020-2026 Olaf Bergmann <bergmann@tzi.org> |
5 | | * |
6 | | * SPDX-License-Identifier: BSD-2-Clause |
7 | | * |
8 | | * This file is part of the CoAP library libcoap. Please see README |
9 | | * for terms of use. |
10 | | */ |
11 | | |
12 | | /** |
13 | | * @file coap_prng.c |
14 | | * @brief Pseudo Random Number functions |
15 | | */ |
16 | | |
17 | | #include "coap3/coap_libcoap_build.h" |
18 | | |
19 | | |
20 | | #if defined(__ZEPHYR__) |
21 | | #include <zephyr/random/random.h> |
22 | | #elif defined(HAVE_GETRANDOM) |
23 | | #include <sys/random.h> |
24 | | #elif defined(WITH_CONTIKI) |
25 | | #include "lib/csprng.h" |
26 | | #else /* !WITH_CONTIKI */ |
27 | | #include <stdlib.h> |
28 | | #endif /* !WITH_CONTIKI */ |
29 | | |
30 | | #if defined(MBEDTLS_ENTROPY_HARDWARE_ALT) |
31 | | #include <entropy_poll.h> |
32 | | #endif /* MBEDTLS_ENTROPY_HARDWARE_ALT */ |
33 | | |
34 | | #if defined(_WIN32) |
35 | | |
36 | | errno_t __cdecl rand_s(_Out_ unsigned int *_RandomValue); |
37 | | /** |
38 | | * Fills \p buf with \p len random bytes. This is the default implementation for |
39 | | * coap_prng(). You might want to change coap_prng_impl() to use a better |
40 | | * PRNG on your specific platform. |
41 | | */ |
42 | | COAP_STATIC_INLINE int |
43 | | coap_prng_impl(unsigned char *buf, size_t len) { |
44 | | while (len != 0) { |
45 | | uint32_t r = 0; |
46 | | size_t i; |
47 | | |
48 | | if (rand_s(&r) != 0) |
49 | | return 0; |
50 | | for (i = 0; i < len && i < 4; i++) { |
51 | | *buf++ = (uint8_t)r; |
52 | | r >>= 8; |
53 | | } |
54 | | len -= i; |
55 | | } |
56 | | return 1; |
57 | | } |
58 | | |
59 | | #endif /* _WIN32 */ |
60 | | |
61 | | COAP_API void |
62 | 0 | coap_prng_init(unsigned int seed) { |
63 | 0 | coap_lock_lock(return); |
64 | 0 | coap_prng_init_lkd(seed); |
65 | 0 | coap_lock_unlock(); |
66 | 0 | } |
67 | | |
68 | | COAP_API int |
69 | 0 | coap_prng(void *buf, size_t len) { |
70 | 0 | int ret; |
71 | |
|
72 | 0 | coap_lock_lock(return 0); |
73 | 0 | ret = coap_prng_lkd(buf, len); |
74 | 0 | coap_lock_unlock(); |
75 | 0 | return ret; |
76 | 0 | } |
77 | | |
78 | | #if defined(WITH_LWIP) && defined(LWIP_RAND) |
79 | | |
80 | | static unsigned int random_seed; |
81 | | |
82 | | void |
83 | | coap_prng_init_lkd(unsigned int seed) { |
84 | | random_seed = seed; |
85 | | } |
86 | | |
87 | | int |
88 | | coap_prng_lkd(void *bufp, size_t len) { |
89 | | unsigned char *buf = (unsigned char *)bufp; |
90 | | u32_t v = LWIP_RAND() + random_seed; |
91 | | |
92 | | while (len > sizeof(v)) { |
93 | | memcpy(buf, &v, sizeof(v)); |
94 | | len -= sizeof(v); |
95 | | buf += sizeof(v); |
96 | | v = LWIP_RAND(); |
97 | | } |
98 | | |
99 | | memcpy(buf, &v, len); |
100 | | return 1; |
101 | | } |
102 | | |
103 | | #else |
104 | | |
105 | | /* |
106 | | * This, or any user provided alternative, function is expected to |
107 | | * return 0 on failure and 1 on success. |
108 | | */ |
109 | | static int |
110 | 131 | coap_prng_default(void *buf, size_t len) { |
111 | | #if defined(MBEDTLS_ENTROPY_HARDWARE_ALT) |
112 | | /* mbedtls_hardware_poll() returns 0 on success */ |
113 | | return (mbedtls_hardware_poll(NULL, buf, len, NULL) ? 0 : 1); |
114 | | |
115 | | #elif defined(__ZEPHYR__) |
116 | | /* Use Zephyr's cryptographically secure random number generator */ |
117 | | if (!buf || len == 0) { |
118 | | return 0; |
119 | | } |
120 | | |
121 | | sys_rand_get(buf, len); |
122 | | return 1; |
123 | | |
124 | | #elif defined(HAVE_GETRANDOM) |
125 | 131 | return (getrandom(buf, len, 0) > 0) ? 1 : 0; |
126 | | |
127 | | #elif defined(HAVE_RANDOM) |
128 | | #define RAND_BYTES (RAND_MAX >= 0xffffff ? 3 : (RAND_MAX >= 0xffff ? 2 : 1)) |
129 | | unsigned char *dst = (unsigned char *)buf; |
130 | | |
131 | | if (len) { |
132 | | uint8_t byte_counter = RAND_BYTES; |
133 | | uint32_t r_v = random(); |
134 | | |
135 | | while (1) { |
136 | | *dst++ = r_v & 0xFF; |
137 | | if (!--len) { |
138 | | break; |
139 | | } |
140 | | if (--byte_counter) { |
141 | | r_v >>= 8; |
142 | | } else { |
143 | | r_v = random(); |
144 | | byte_counter = RAND_BYTES; |
145 | | } |
146 | | } |
147 | | } |
148 | | return 1; |
149 | | #elif defined(RIOT_VERSION) |
150 | | #include <random.h> |
151 | | random_bytes(buf, len); |
152 | | return 1; |
153 | | |
154 | | #elif defined(WITH_CONTIKI) |
155 | | return csprng_rand(buf, len); |
156 | | |
157 | | #elif defined(_WIN32) |
158 | | return coap_prng_impl(buf,len); |
159 | | |
160 | | #else /* !MBEDTLS_ENTROPY_HARDWARE_ALT && !HAVE_GETRANDOM && |
161 | | !HAVE_RANDOM && !_WIN32 */ |
162 | | #error "CVE-2021-34430: using rand() for crypto randoms is not secure!" |
163 | | #error "Please update you C-library and rerun the auto-configuration." |
164 | | unsigned char *dst = (unsigned char *)buf; |
165 | | while (len--) |
166 | | *dst++ = rand() & 0xFF; |
167 | | return 1; |
168 | | #endif /* !MBEDTLS_ENTROPY_HARDWARE_ALT && !HAVE_GETRANDOM && |
169 | | !HAVE_RANDOM && !_WIN32 */ |
170 | 131 | } |
171 | | |
172 | | static coap_rand_func_t rand_func = coap_prng_default; |
173 | | |
174 | | void |
175 | 0 | coap_set_prng(coap_rand_func_t rng) { |
176 | 0 | rand_func = rng; |
177 | 0 | } |
178 | | |
179 | | void |
180 | 28 | coap_prng_init_lkd(unsigned int seed) { |
181 | 28 | #ifdef HAVE_GETRANDOM |
182 | | /* No seed to seed the random source if getrandom() is used */ |
183 | 28 | (void)seed; |
184 | | #elif defined(HAVE_RANDOM) |
185 | | srandom(seed); |
186 | | #else /* !HAVE_GETRANDOM && !HAVE_RANDOM */ |
187 | | srand(seed); |
188 | | #endif /* !HAVE_GETRANDOM */ |
189 | 28 | } |
190 | | |
191 | | int |
192 | 131 | coap_prng_lkd(void *buf, size_t len) { |
193 | 131 | if (!rand_func) { |
194 | 0 | return 0; |
195 | 0 | } |
196 | | |
197 | 131 | return rand_func(buf, len); |
198 | 131 | } |
199 | | |
200 | | #endif |