/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 | | void |
81 | | coap_prng_init_lkd(unsigned int seed) { |
82 | | (void)seed; |
83 | | } |
84 | | |
85 | | int |
86 | | coap_prng_lkd(void *bufp, size_t len) { |
87 | | unsigned char *buf = (unsigned char *)bufp; |
88 | | u32_t v = LWIP_RAND(); |
89 | | |
90 | | while (len > sizeof(v)) { |
91 | | memcpy(buf, &v, sizeof(v)); |
92 | | len -= sizeof(v); |
93 | | buf += sizeof(v); |
94 | | v = LWIP_RAND(); |
95 | | } |
96 | | |
97 | | memcpy(buf, &v, len); |
98 | | return 1; |
99 | | } |
100 | | |
101 | | #else |
102 | | |
103 | | /* |
104 | | * This, or any user provided alternative, function is expected to |
105 | | * return 0 on failure and 1 on success. |
106 | | */ |
107 | | static int |
108 | 0 | coap_prng_default(void *buf, size_t len) { |
109 | | #if defined(MBEDTLS_ENTROPY_HARDWARE_ALT) |
110 | | /* mbedtls_hardware_poll() returns 0 on success */ |
111 | | return (mbedtls_hardware_poll(NULL, buf, len, NULL) ? 0 : 1); |
112 | | |
113 | | #elif defined(__ZEPHYR__) |
114 | | /* Use Zephyr's cryptographically secure random number generator */ |
115 | | if (!buf || len == 0) { |
116 | | return 0; |
117 | | } |
118 | | |
119 | | sys_rand_get(buf, len); |
120 | | return 1; |
121 | | |
122 | | #elif defined(HAVE_GETRANDOM) |
123 | 0 | return (getrandom(buf, len, 0) > 0) ? 1 : 0; |
124 | |
|
125 | | #elif defined(HAVE_RANDOM) |
126 | | #define RAND_BYTES (RAND_MAX >= 0xffffff ? 3 : (RAND_MAX >= 0xffff ? 2 : 1)) |
127 | | unsigned char *dst = (unsigned char *)buf; |
128 | | |
129 | | if (len) { |
130 | | uint8_t byte_counter = RAND_BYTES; |
131 | | uint32_t r_v = random(); |
132 | | |
133 | | while (1) { |
134 | | *dst++ = r_v & 0xFF; |
135 | | if (!--len) { |
136 | | break; |
137 | | } |
138 | | if (--byte_counter) { |
139 | | r_v >>= 8; |
140 | | } else { |
141 | | r_v = random(); |
142 | | byte_counter = RAND_BYTES; |
143 | | } |
144 | | } |
145 | | } |
146 | | return 1; |
147 | | #elif defined(RIOT_VERSION) |
148 | | #include <random.h> |
149 | | random_bytes(buf, len); |
150 | | return 1; |
151 | | |
152 | | #elif defined(WITH_CONTIKI) |
153 | | return csprng_rand(buf, len); |
154 | | |
155 | | #elif defined(_WIN32) |
156 | | return coap_prng_impl(buf,len); |
157 | | |
158 | | #else /* !MBEDTLS_ENTROPY_HARDWARE_ALT && !HAVE_GETRANDOM && |
159 | | !HAVE_RANDOM && !_WIN32 */ |
160 | | #error "CVE-2021-34430: using rand() for crypto randoms is not secure!" |
161 | | #error "Please update you C-library and rerun the auto-configuration." |
162 | | unsigned char *dst = (unsigned char *)buf; |
163 | | while (len--) |
164 | | *dst++ = rand() & 0xFF; |
165 | | return 1; |
166 | | #endif /* !MBEDTLS_ENTROPY_HARDWARE_ALT && !HAVE_GETRANDOM && |
167 | | !HAVE_RANDOM && !_WIN32 */ |
168 | 0 | } |
169 | | |
170 | | static coap_rand_func_t rand_func = coap_prng_default; |
171 | | |
172 | | void |
173 | 0 | coap_set_prng(coap_rand_func_t rng) { |
174 | 0 | rand_func = rng; |
175 | 0 | } |
176 | | |
177 | | void |
178 | 0 | coap_prng_init_lkd(unsigned int seed) { |
179 | 0 | #ifdef HAVE_GETRANDOM |
180 | | /* No seed to seed the random source if getrandom() is used */ |
181 | 0 | (void)seed; |
182 | | #elif defined(HAVE_RANDOM) |
183 | | srandom(seed); |
184 | | #else /* !HAVE_GETRANDOM && !HAVE_RANDOM */ |
185 | | srand(seed); |
186 | | #endif /* !HAVE_GETRANDOM */ |
187 | 0 | } |
188 | | |
189 | | int |
190 | 0 | coap_prng_lkd(void *buf, size_t len) { |
191 | 0 | if (!rand_func) { |
192 | 0 | return 0; |
193 | 0 | } |
194 | | |
195 | 0 | return rand_func(buf, len); |
196 | 0 | } |
197 | | |
198 | | #endif |