2 * cryptsetup kernel RNG access functions
4 * Copyright (C) 2010-2023 Red Hat, Inc. All rights reserved.
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 #include <sys/select.h>
26 #include "libcryptsetup.h"
29 static int random_initialised = 0;
31 #define URANDOM_DEVICE "/dev/urandom"
32 static int urandom_fd = -1;
34 #define RANDOM_DEVICE "/dev/random"
35 static int random_fd = -1;
37 /* Read random chunk - gathered data usually appears with this granularity */
38 #define RANDOM_DEVICE_CHUNK 8
40 /* Timeout to print warning if no random data (entropy) */
41 #define RANDOM_DEVICE_TIMEOUT 5
43 /* URANDOM_DEVICE access */
44 static int _get_urandom(char *buf, size_t len)
50 assert(urandom_fd != -1);
53 r = read(urandom_fd, buf, len);
54 if (r == -1 && errno != EINTR)
63 assert((size_t)(buf - old_buf) == old_len);
68 static void _get_random_progress(struct crypt_device *ctx, int warn,
69 size_t expected_len, size_t read_len)
73 _("System is out of entropy while generating volume key.\n"
74 "Please move mouse or type some text in another window "
75 "to gather some random events.\n"));
77 log_std(ctx, _("Generating key (%d%% done).\n"),
78 (int)((expected_len - read_len) * 100 / expected_len));
81 /* RANDOM_DEVICE access */
82 static int _get_random(struct crypt_device *ctx, char *buf, size_t len)
85 size_t n, old_len = len;
90 assert(random_fd != -1);
94 FD_SET(random_fd, &fds);
96 tv.tv_sec = RANDOM_DEVICE_TIMEOUT;
99 r = select(random_fd + 1, &fds, NULL, NULL, &tv);
104 _get_random_progress(ctx, warn_once, old_len, len);
110 n = RANDOM_DEVICE_CHUNK;
111 if (len < RANDOM_DEVICE_CHUNK)
114 r = read(random_fd, buf, n);
116 if (r == -1 && errno == EINTR) {
125 /* random device is opened with O_NONBLOCK, EAGAIN is expected */
126 if (r == -1 && (errno != EAGAIN && errno != EWOULDBLOCK))
133 } while (len && r > 0);
137 assert((size_t)(buf - old_buf) == old_len);
140 _get_random_progress(ctx, 0, old_len, len);
144 /* Initialisation of both RNG file descriptors is mandatory */
145 int crypt_random_init(struct crypt_device *ctx)
147 if (random_initialised)
150 /* Used for CRYPT_RND_NORMAL */
152 urandom_fd = open(URANDOM_DEVICE, O_RDONLY | O_CLOEXEC);
156 /* Used for CRYPT_RND_KEY */
158 random_fd = open(RANDOM_DEVICE, O_RDONLY | O_NONBLOCK | O_CLOEXEC);
162 if (crypt_fips_mode())
163 log_verbose(ctx, _("Running in FIPS mode."));
165 random_initialised = 1;
169 log_err(ctx, _("Fatal error during RNG initialisation."));
173 /* coverity[ -taint_source : arg-1 ] */
174 int crypt_random_get(struct crypt_device *ctx, char *buf, size_t len, int quality)
176 int status, rng_type;
179 case CRYPT_RND_NORMAL:
180 status = _get_urandom(buf, len);
183 if (crypt_fips_mode())
184 status = crypt_backend_rng(buf, len, quality, 1);
186 status = _get_urandom(buf, len);
189 if (crypt_fips_mode()) {
190 status = crypt_backend_rng(buf, len, quality, 1);
193 rng_type = ctx ? crypt_get_rng_type(ctx) :
194 crypt_random_default_key_rng();
196 case CRYPT_RNG_URANDOM:
197 status = _get_urandom(buf, len);
199 case CRYPT_RNG_RANDOM:
200 status = _get_random(ctx, buf, len);
207 log_err(ctx, _("Unknown RNG quality requested."));
212 log_err(ctx, _("Error reading from RNG."));
217 void crypt_random_exit(void)
219 random_initialised = 0;
221 if(random_fd != -1) {
222 (void)close(random_fd);
226 if(urandom_fd != -1) {
227 (void)close(urandom_fd);
232 int crypt_random_default_key_rng(void)
234 /* coverity[pointless_string_compare] */
235 if (!strcmp(DEFAULT_RNG, RANDOM_DEVICE))
236 return CRYPT_RNG_RANDOM;
238 /* coverity[pointless_string_compare] */
239 if (!strcmp(DEFAULT_RNG, URANDOM_DEVICE))
240 return CRYPT_RNG_URANDOM;
242 /* RNG misconfiguration is fatal */