2 * cryptsetup kernel RNG access functions
4 * Copyright (C) 2010-2012, 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 * version 2 as published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 #include "libcryptsetup.h"
28 #include "crypto_backend.h"
30 static int random_initialised = 0;
32 #define URANDOM_DEVICE "/dev/urandom"
33 static int urandom_fd = -1;
35 #define RANDOM_DEVICE "/dev/random"
36 static int random_fd = -1;
38 /* Read random chunk - gathered data usually appears with this granularity */
39 #define RANDOM_DEVICE_CHUNK 8
41 /* Timeout to print warning if no random data (entropy) */
42 #define RANDOM_DEVICE_TIMEOUT 5
44 /* URANDOM_DEVICE access */
45 static int _get_urandom(struct crypt_device *ctx __attribute__((unused)),
46 char *buf, size_t len)
52 assert(urandom_fd != -1);
55 r = read(urandom_fd, buf, len);
56 if (r == -1 && errno != EINTR)
65 assert((size_t)(buf - old_buf) == old_len);
70 static void _get_random_progress(struct crypt_device *ctx, int warn,
71 size_t expected_len, size_t read_len)
75 _("System is out of entropy while generating volume key.\n"
76 "Please move mouse or type some text in another window "
77 "to gather some random events.\n"));
79 log_std(ctx, _("Generating key (%d%% done).\n"),
80 (int)((expected_len - read_len) * 100 / expected_len));
83 /* RANDOM_DEVICE access */
84 static int _get_random(struct crypt_device *ctx, char *buf, size_t len)
87 size_t n, old_len = len;
92 assert(random_fd != -1);
96 FD_SET(random_fd, &fds);
98 tv.tv_sec = RANDOM_DEVICE_TIMEOUT;
101 r = select(random_fd + 1, &fds, NULL, NULL, &tv);
106 _get_random_progress(ctx, warn_once, old_len, len);
112 n = RANDOM_DEVICE_CHUNK;
113 if (len < RANDOM_DEVICE_CHUNK)
116 r = read(random_fd, buf, n);
118 if (r == -1 && errno == EINTR) {
127 /* random device is opened with O_NONBLOCK, EAGAIN is expected */
128 if (r == -1 && (errno != EAGAIN && errno != EWOULDBLOCK))
135 } while (len && r > 0);
139 assert((size_t)(buf - old_buf) == old_len);
142 _get_random_progress(ctx, 0, old_len, len);
146 /* Initialisation of both RNG file descriptors is mandatory */
147 int crypt_random_init(struct crypt_device *ctx)
149 if (random_initialised)
152 /* Used for CRYPT_RND_NORMAL */
154 urandom_fd = open(URANDOM_DEVICE, O_RDONLY);
158 /* Used for CRYPT_RND_KEY */
160 random_fd = open(RANDOM_DEVICE, O_RDONLY | O_NONBLOCK);
164 random_initialised = 1;
168 log_err(ctx, _("Fatal error during RNG initialisation.\n"));
172 int crypt_random_get(struct crypt_device *ctx, char *buf, size_t len, int quality)
174 int status, rng_type;
177 case CRYPT_RND_NORMAL:
178 status = _get_urandom(ctx, buf, len);
181 if (crypt_fips_mode())
182 status = crypt_backend_fips_rng(buf, len, quality);
184 status = _get_urandom(ctx, buf, len);
187 if (crypt_fips_mode()) {
188 status = crypt_backend_fips_rng(buf, len, quality);
191 rng_type = ctx ? crypt_get_rng_type(ctx) :
192 crypt_random_default_key_rng();
194 case CRYPT_RNG_URANDOM:
195 status = _get_urandom(ctx, buf, len);
197 case CRYPT_RNG_RANDOM:
198 status = _get_random(ctx, buf, len);
205 log_err(ctx, _("Unknown RNG quality requested.\n"));
210 log_err(ctx, _("Error %d reading from RNG: %s\n"),
211 errno, strerror(errno));
216 void crypt_random_exit(void)
218 random_initialised = 0;
220 if(random_fd != -1) {
221 (void)close(random_fd);
225 if(urandom_fd != -1) {
226 (void)close(urandom_fd);
231 int crypt_random_default_key_rng(void)
233 if (!strcmp(DEFAULT_RNG, RANDOM_DEVICE))
234 return CRYPT_RNG_RANDOM;
236 if (!strcmp(DEFAULT_RNG, URANDOM_DEVICE))
237 return CRYPT_RNG_URANDOM;
239 /* RNG misconfiguration is fatal */