* Implement --use-random and --use-urandom for luksFormat to allow setting of RNG...
authorMilan Broz <gmazyland@gmail.com>
Wed, 27 Oct 2010 15:35:23 +0000 (15:35 +0000)
committerMilan Broz <gmazyland@gmail.com>
Wed, 27 Oct 2010 15:35:23 +0000 (15:35 +0000)
* Add crypt_set_rng_type() and crypt_get_rng_type() to API.

git-svn-id: https://cryptsetup.googlecode.com/svn/trunk@354 36d66b0a-2a48-0410-832c-cd162a569da5

19 files changed:
ChangeLog
configure.in
lib/Makefile.am
lib/gcrypt.c
lib/internal.h
lib/libcryptsetup.h
lib/libcryptsetup.sym
lib/random.c [new file with mode: 0644]
lib/setup.c
lib/utils.c
lib/volumekey.c
luks/Makefile.am
luks/af.c
luks/keymanage.c
luks/random.c [deleted file]
luks/random.h [deleted file]
man/cryptsetup.8
po/POTFILES.in
src/cryptsetup.c

index 67f3fec70533d05e8a5e936f063d6d51fb1d08c5..0cb74ed2486f7fdd53a54a1b3ec175cb7ea0c1ad 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,6 +1,9 @@
 2010-10-27  Milan Broz  <mbroz@redhat.com>
        * Rewrite cryptsetup luksFormat, luksOpen, luksAddKey to use new API
          to allow adding new features.
+       * Implement --use-random and --use-urandom for luksFormat to allow
+         setting of RNG for volume key generator.
+       * Add crypt_set_rng_type() and crypt_get_rng_type() to API.
 
 2010-10-17  Milan Broz  <mbroz@redhat.com>
        * Add crypt_get_device_name() to API (get underlying device name).
index f2747b4b37d81fb4b05d278d95a48c8f39898db4..2532852ef9874ad58169fc92377faecd6a06b752 100644 (file)
@@ -1,5 +1,5 @@
 AC_PREREQ([2.67])
-AC_INIT([cryptsetup],[1.1.3])
+AC_INIT([cryptsetup],[1.2.0])
 
 dnl library version from <major>.<minor>.<release>[-<suffix>]
 LIBCRYPTSETUP_VERSION=$(echo $PACKAGE_VERSION | cut -f1 -d-)
@@ -145,6 +145,12 @@ AC_SUBST([LIBGCRYPT_STATIC_LIBS])
 AC_SUBST([LIBCRYPTSETUP_VERSION])
 AC_SUBST([LIBCRYPTSETUP_VERSION_INFO])
 
+dnl ==========================================================================
+AC_ARG_ENABLE([dev-random], AS_HELP_STRING([--enable-dev-random],
+[use blocking /dev/random by default for key generator (otherwise use /dev/urandom)]),
+[default_rng=/dev/random], [default_rng=/dev/urandom])
+AC_DEFINE_UNQUOTED(DEFAULT_RNG, ["$default_rng"], [default RNG type for key generator])
+
 dnl ==========================================================================
 AC_DEFUN([CS_DEFINE],
        [AC_DEFINE_UNQUOTED(DEFAULT_[]m4_translit([$1], [-a-z], [_A-Z]), [$2], [$3])
index c95037726a04fe2a26e51db1bfbf3f33798d9921..dc78b3c98b04e9f5252b209192ce9c6bbf638efb 100644 (file)
@@ -44,6 +44,7 @@ libcryptsetup_la_SOURCES = \
        backends.c                              \
        libdevmapper.c                          \
        volumekey.c                             \
+       random.c                                \
        gcrypt.c
 
 include_HEADERS = libcryptsetup.h
index e4cc72a64440a4a0f9bc5c47f1bb07a75f5722f6..87dc97e4974687140d9f49ff6c67a8d77322d5ad 100644 (file)
@@ -14,6 +14,10 @@ int init_crypto(struct crypt_device *ctx)
 {
        int r;
 
+       r = crypt_random_init(ctx);
+       if (r < 0)
+               goto fail;
+
        if (!gcry_control (GCRYCTL_INITIALIZATION_FINISHED_P)) {
                if (!gcry_check_version (GCRYPT_REQ_VERSION)) {
                        r = -ENOSYS;
index c7574af869e0d847b5d9efd356fcd9c47f7dad8f..5bd15ef9fa18b0b8c09eff3d345e6404ade546d3 100644 (file)
@@ -27,6 +27,8 @@
 
 #define at_least(a, b) ({ __typeof__(a) __at_least = (a); (__at_least >= (b))?__at_least:(b); })
 
+struct crypt_device;
+
 struct hash_type {
        char            *name;
        void            *private;
@@ -49,11 +51,11 @@ struct volume_key {
        size_t keylength;
        char key[];
 };
+
 struct volume_key *crypt_alloc_volume_key(unsigned keylength, const char *key);
-struct volume_key *crypt_generate_volume_key(unsigned keylength);
-void crypt_free_volume_key(struct volume_key *mk);
+struct volume_key *crypt_generate_volume_key(struct crypt_device *cd, unsigned keylength);
+void crypt_free_volume_key(struct volume_key *vk);
 
-struct crypt_device;
 int crypt_confirm(struct crypt_device *cd, const char *msg);
 
 void set_error_va(const char *fmt, va_list va);
@@ -122,4 +124,10 @@ void get_topology_alignment(const char *device,
                            unsigned long *alignment_offset,   /* bytes */
                            unsigned long default_alignment);
 
+enum { CRYPT_RND_NORMAL = 0, CRYPT_RND_KEY = 1 };
+int crypt_random_init(struct crypt_device *ctx);
+int crypt_random_get(struct crypt_device *ctx, char *buf, size_t len, int quality);
+void crypt_random_exit(void);
+int crypt_random_default_key_rng(void);
+
 #endif /* INTERNAL_H */
index 8206164a7b6374b0d045e8f50778ec96baa47988..bed49fcb77e4f2bcdcc35598256f026b403f5b93 100644 (file)
@@ -109,6 +109,27 @@ void crypt_set_password_retry(struct crypt_device *cd, int tries);
 void crypt_set_iterarion_time(struct crypt_device *cd, uint64_t iteration_time_ms);
 void crypt_set_password_verify(struct crypt_device *cd, int password_verify);
 
+/**
+ * Set which RNG (random number generator) is used for generating long term key
+ * @cd - crypt device handle
+ * @rng_type - kernel random number generator to use
+ *
+ * CRYPT_RNG_URANDOM - use /dev/urandom
+ * CRYPT_RNG_RANDOM  - use /dev/random (waits if no entropy in system)
+ */
+#define CRYPT_RNG_URANDOM 0
+#define CRYPT_RNG_RANDOM  1
+void crypt_set_rng_type(struct crypt_device *cd, int rng_type);
+
+/**
+ * Get which RNG (random number generator) is used for generating long term key
+ *
+ * Returns RNG type on success or negative errno value otherwise.
+ *
+ * @cd - crypt device handle
+ */
+int crypt_get_rng_type(struct crypt_device *cd);
+
 /**
  * Helper to lock/unlock memory to avoid swap sensitive data to disk
  *
index 61fd17ac973b940d6a36f5c9119fe8b20db02eda..9d2546343f17c2dab41fdb44032b8e43f6d2bcbb 100644 (file)
@@ -37,6 +37,9 @@ CRYPTSETUP_1.0 {
                crypt_get_volume_key_size;
                crypt_get_device_name;
 
+               crypt_set_rng_type;
+               crypt_get_rng_type;
+
                crypt_keyslot_status;
                crypt_get_error;
                crypt_get_dir;
diff --git a/lib/random.c b/lib/random.c
new file mode 100644 (file)
index 0000000..fb359e4
--- /dev/null
@@ -0,0 +1,222 @@
+/*
+ * cryptsetup kernel RNG access functions
+ *
+ * Copyright (C) 2010 Red Hat, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <assert.h>
+
+#include "libcryptsetup.h"
+#include "internal.h"
+
+static int random_initialised = 0;
+
+#define URANDOM_DEVICE "/dev/urandom"
+static int urandom_fd = -1;
+
+#define RANDOM_DEVICE  "/dev/random"
+static int random_fd = -1;
+
+/* Read random chunk - gathered data usually appears with this granularity */
+#define RANDOM_DEVICE_CHUNK    8
+
+/* Timeout after the warning is printed when there is random data (entropy) */
+#define RANDOM_DEVICE_TIMEOUT  5
+
+/* URANDOM_DEVICE access */
+static int _get_urandom(struct crypt_device *ctx, char *buf, size_t len)
+{
+       int r;
+       size_t old_len = len;
+       char *old_buf = buf;
+
+       assert(urandom_fd != -1);
+
+       while(len) {
+               r = read(urandom_fd, buf, len);
+               if (r == -1 && errno != EINTR)
+                       return -EINVAL;
+               len -= r;
+               buf += r;
+       }
+
+       assert(len == 0);
+       assert((size_t)(buf - old_buf) == old_len);
+
+       return 0;
+}
+
+static void _get_random_progress(struct crypt_device *ctx, int warn,
+                                size_t expected_len, size_t read_len)
+{
+       if (warn)
+               log_std(ctx,
+                       _("System is out of entropy while generating volume key.\n"
+                         "Please move mouse or type some text in another window "
+                         "to gather some random events.\n"));
+
+       log_std(ctx, _("Generating key (%d%% done).\n"),
+               (int)((expected_len - read_len) * 100 / expected_len));
+}
+
+/* RANDOM_DEVICE access */
+static int _get_random(struct crypt_device *ctx, char *buf, size_t len)
+{
+       int r, warn_once = 1;
+       size_t n, old_len = len;
+       char *old_buf = buf;
+       fd_set fds;
+       struct timeval tv;
+
+       assert(random_fd != -1);
+
+       while (len) {
+               FD_ZERO(&fds);
+               FD_SET(random_fd, &fds);
+
+               tv.tv_sec = RANDOM_DEVICE_TIMEOUT;
+               tv.tv_usec = 0;
+
+               r = select(random_fd + 1, &fds, NULL, NULL, &tv);
+               if(r == -1)
+                       return -EINVAL;
+
+               if(!r) {
+                       _get_random_progress(ctx, warn_once, old_len, len);
+                       warn_once = 0;
+                       continue;
+               }
+
+               do {
+                       n = RANDOM_DEVICE_CHUNK;
+                       if (len < RANDOM_DEVICE_CHUNK)
+                               n = len;
+
+                       r = read(random_fd, buf, n);
+
+                       if (r == -1 && errno == EINTR)
+                               continue;
+
+                       /* bogus read? */
+                       if(r > (int)n)
+                               return -EINVAL;
+
+                       /* random device is opened with O_NONBLOCK, EAGAIN is expected */
+                       if (r == -1 && (errno != EAGAIN || errno != EWOULDBLOCK))
+                               return -EINVAL;
+
+                       if (r > 0) {
+                               len -= r;
+                               buf += r;
+                       }
+               } while (len && r > 0);
+       }
+
+       assert(len == 0);
+       assert((size_t)(buf - old_buf) == old_len);
+
+       if (!warn_once)
+               _get_random_progress(ctx, 0, old_len, len);
+
+       return 0;
+}
+/* Initialisation of both RNG file descriptors is mandatory */
+int crypt_random_init(struct crypt_device *ctx)
+{
+       /* Used for CRYPT_RND_NORMAL */
+       if(urandom_fd == -1)
+               urandom_fd = open(URANDOM_DEVICE, O_RDONLY);
+       if(urandom_fd == -1)
+               goto fail;
+
+       /* Used for CRYPT_RND_KEY */
+       if(random_fd == -1)
+               random_fd = open(RANDOM_DEVICE, O_RDONLY | O_NONBLOCK);
+       if(random_fd == -1)
+               goto fail;
+
+       random_initialised = 1;
+       return 0;
+fail:
+       crypt_random_exit();
+       log_err(ctx, _("Fatal error during RNG initialisation.\n"));
+       return -ENOSYS;
+}
+
+int crypt_random_get(struct crypt_device *ctx, char *buf, size_t len, int quality)
+{
+       int status, rng_type;
+
+       switch(quality) {
+       case CRYPT_RND_NORMAL:
+               status = _get_urandom(ctx, buf, len);
+               break;
+       case CRYPT_RND_KEY:
+               rng_type = ctx ? crypt_get_rng_type(ctx) :
+                                crypt_random_default_key_rng();
+               switch (rng_type) {
+               case CRYPT_RNG_URANDOM:
+                       status = _get_urandom(ctx, buf, len);
+                       break;
+               case CRYPT_RNG_RANDOM:
+                       status = _get_random(ctx, buf, len);
+                       break;
+               default:
+                       abort();
+               }
+               break;
+       default:
+               log_err(ctx, _("Unknown RNG quality requested.\n"));
+               return -EINVAL;
+       }
+
+       if (status)
+               log_err(ctx, _("Error %d reading from RNG: %s\n"),
+                       errno, strerror(errno));
+
+       return status;
+}
+
+void crypt_random_exit()
+{
+       random_initialised = 0;
+
+       if(random_fd != -1) {
+               (void)close(random_fd);
+               random_fd = -1;
+       }
+
+       if(urandom_fd != -1) {
+               (void)close(urandom_fd);
+               urandom_fd = -1;
+       }
+}
+
+int crypt_random_default_key_rng()
+{
+       if (!strcmp(DEFAULT_RNG, RANDOM_DEVICE))
+               return CRYPT_RNG_RANDOM;
+
+       if (!strcmp(DEFAULT_RNG, URANDOM_DEVICE))
+               return CRYPT_RNG_URANDOM;
+
+       /* RNG misconfiguration is fatal */
+       abort();
+}
index dd137f7d7eb7bf5bb26db57b97af75293f40787f..eb34b47dfeae1718af9cfd660b8ff9b4b546d367 100644 (file)
@@ -18,6 +18,7 @@ struct crypt_device {
        uint64_t iteration_time;
        int tries;
        int password_verify;
+       int rng_type;
 
        /* used in CRYPT_LUKS1 */
        struct luks_phdr hdr;
@@ -981,6 +982,7 @@ int crypt_init(struct crypt_device **cd, const char *device)
        h->iteration_time = 1000;
        h->password_verify = 0;
        h->tries = 3;
+       h->rng_type = crypt_random_default_key_rng();
        *cd = h;
        return 0;
 }
@@ -1077,7 +1079,7 @@ static int _crypt_format_luks1(struct crypt_device *cd,
                cd->volume_key = crypt_alloc_volume_key(volume_key_size,
                                                      volume_key);
        else
-               cd->volume_key = crypt_generate_volume_key(volume_key_size);
+               cd->volume_key = crypt_generate_volume_key(cd, volume_key_size);
 
        if(!cd->volume_key)
                return -ENOMEM;
@@ -1911,6 +1913,24 @@ void crypt_set_password_verify(struct crypt_device *cd, int password_verify)
        cd->password_verify = password_verify ? 1 : 0;
 }
 
+void crypt_set_rng_type(struct crypt_device *cd, int rng_type)
+{
+       switch (rng_type) {
+       case CRYPT_RNG_URANDOM:
+       case CRYPT_RNG_RANDOM:
+               log_dbg("RNG set to %d (%s).", rng_type, rng_type ? "random" : "urandom");
+               cd->rng_type = rng_type;
+       }
+}
+
+int crypt_get_rng_type(struct crypt_device *cd)
+{
+       if (!cd)
+               return -EINVAL;
+
+       return cd->rng_type;
+}
+
 int crypt_memory_lock(struct crypt_device *cd, int lock)
 {
        return lock ? crypt_memlock_inc(cd) : crypt_memlock_dec(cd);
index eec28ec1fd2b54f8b2c1af8315906bbae232c079..e1d0e4a5582f9952695996ece800f0fd9772f1c5 100644 (file)
@@ -11,7 +11,6 @@
 #include <sys/stat.h>
 #include <sys/ioctl.h>
 #include <fcntl.h>
-#include <termios.h>
 #include <sys/mman.h>
 #include <sys/resource.h>
 
index 5dec0bfec1e1f35e82e422c810d1a6d4df21ba6e..0e30b9f2ed5d276349535604ed7b697903e9d73a 100644 (file)
@@ -23,8 +23,6 @@
 
 #include "internal.h"
 
-int getRandom(char *buf, size_t len);
-
 struct volume_key *crypt_alloc_volume_key(unsigned keylength, const char *key)
 {
        struct volume_key *vk = malloc(sizeof(*vk) + keylength);
@@ -48,7 +46,7 @@ void crypt_free_volume_key(struct volume_key *vk)
        }
 }
 
-struct volume_key *crypt_generate_volume_key(unsigned keylength)
+struct volume_key *crypt_generate_volume_key(struct crypt_device *cd, unsigned keylength)
 {
        int r;
        struct volume_key *vk;
@@ -57,11 +55,10 @@ struct volume_key *crypt_generate_volume_key(unsigned keylength)
        if (!vk)
                return NULL;
 
-       r = getRandom(vk->key, keylength);
+       r = crypt_random_get(cd, vk->key, keylength, CRYPT_RND_KEY);
        if(r < 0) {
                crypt_free_volume_key(vk);
                return NULL;
        }
        return vk;
 }
-
index cb7850363d55ed9f7491dac8b5812b0cc780ecae..0ff1d9fb7098db7165d57d8f1b2ac43119f73045 100644 (file)
@@ -9,9 +9,7 @@ libluks_la_SOURCES = \
        pbkdf.c \
        keymanage.c \
        keyencryption.c \
-       random.c \
        pbkdf.h \
-       random.h \
        af.h \
        luks.h
 
index a11ceacf31502eda855f9700442f086412611a73..e86af78f43019cdbc94b92e69bbaeab0e58c1bbb 100644 (file)
--- a/luks/af.c
+++ b/luks/af.c
@@ -26,7 +26,7 @@
 #include <netinet/in.h>
 #include <errno.h>
 #include <gcrypt.h>
-#include "random.h"
+#include <../lib/internal.h>
 
 static void XORblock(char const *src1, char const *src2, char *dst, size_t n)
 {
@@ -99,7 +99,7 @@ int AF_split(char *src, char *dst, size_t blocksize, unsigned int blocknumbers,
 
        /* process everything except the last block */
        for(i=0; i<blocknumbers-1; i++) {
-               r = getRandom(dst+(blocksize*i),blocksize);
+               r = crypt_random_get(NULL, dst+(blocksize*i), blocksize, CRYPT_RND_NORMAL);
                if(r < 0) goto out;
 
                XORblock(dst+(blocksize*i),bufblock,bufblock,blocksize);
index 4fbad0dc445ca6f744a9fb8efc963a5b21aaaed2..68b119b13e394e19334fd3f7e650201bfc17464f 100644 (file)
@@ -33,7 +33,6 @@
 #include "luks.h"
 #include "af.h"
 #include "pbkdf.h"
-#include "random.h"
 #include <uuid/uuid.h>
 #include <../lib/internal.h>
 
@@ -429,7 +428,7 @@ int LUKS_generate_phdr(struct luks_phdr *header,
                header->version, header->hashSpec ,header->cipherName, header->cipherMode,
                header->keyBytes);
 
-       r = getRandom(header->mkDigestSalt,LUKS_SALTSIZE);
+       r = crypt_random_get(ctx, header->mkDigestSalt, LUKS_SALTSIZE, CRYPT_RND_NORMAL);
        if(r < 0) {
                log_err(ctx,  _("Cannot create LUKS header: reading random salt failed.\n"));
                return r;
@@ -522,7 +521,8 @@ int LUKS_set_key(const char *device, unsigned int keyIndex,
 
        log_dbg("Key slot %d use %d password iterations.", keyIndex, hdr->keyblock[keyIndex].passwordIterations);
 
-       r = getRandom(hdr->keyblock[keyIndex].passwordSalt, LUKS_SALTSIZE);
+       r = crypt_random_get(ctx, hdr->keyblock[keyIndex].passwordSalt,
+                      LUKS_SALTSIZE, CRYPT_RND_NORMAL);
        if(r < 0) return r;
 
 //     assert((vk->keylength % TWOFISH_BLOCKSIZE) == 0); FIXME
@@ -723,9 +723,9 @@ static int wipe(const char *device, unsigned int from, unsigned int to)
        if(!buffer) return -ENOMEM;
 
        for(i = 0; i < 39; ++i) {
-               if     (i >=  0 && i <  5) getRandom(buffer, bufLen);
+               if     (i >=  0 && i <  5) crypt_random_get(NULL, buffer, bufLen, CRYPT_RND_NORMAL);
                else if(i >=  5 && i < 32) wipeSpecial(buffer, bufLen, i - 5);
-               else if(i >= 32 && i < 38) getRandom(buffer, bufLen);
+               else if(i >= 32 && i < 38) crypt_random_get(NULL, buffer, bufLen, CRYPT_RND_NORMAL);
                else if(i >= 38 && i < 39) memset(buffer, 0xFF, bufLen);
 
                if(write_lseek_blockwise(devfd, buffer, bufLen, from * SECTOR_SIZE) < 0) {
diff --git a/luks/random.c b/luks/random.c
deleted file mode 100644 (file)
index 711a7b5..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- *     Random supply helper
- * Copyright 2004, Clemens Fruhwirth <clemens@endorphin.org>
- *
- */
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <stdio.h>
-#include <unistd.h>
-
-static int randomfd = -1; 
-
-int openRandom() {
-    if(randomfd == -1) 
-       randomfd = open("/dev/urandom", O_RDONLY);
-    return randomfd;
-}
-
-/* This method leaks a file descriptor that can be obtained by calling
-   closeRandom */
-int getRandom(char *buf, size_t len)
-{
-    if(openRandom() == -1) {
-       perror("getRandom:");
-       return -EINVAL;
-    }
-    while(len) {
-       int r;
-       r = read(randomfd,buf,len);
-       if (-1 == r && errno != -EINTR) {       
-           perror("read: "); return -EINVAL;
-       }
-       len-= r; buf += r;
-    }
-    return 0;
-}
-
-void closeRandom() {
-    if(randomfd != -1) {
-       close(randomfd);
-       randomfd = -1;
-    }
-}
diff --git a/luks/random.h b/luks/random.h
deleted file mode 100644 (file)
index 8cbab00..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef INCLUDED_CRYPTSETUP_LUKS_RANDOM_H
-#define INCLUDED_CRYPTSETUP_LUKS_RANDOM_H
-
-#include <stddef.h>
-
-int getRandom(char *buf, size_t len);
-
-#endif
index 5505ad458d8de57af6a9a3a700925f362584043d..542152d179affd9c1a02089c6ff47f8189d8bdae 100644 (file)
@@ -43,7 +43,7 @@ These are valid LUKS actions:
 initializes a LUKS partition and sets the initial key, either via prompting or via <key file>.
 
 \fB<options>\fR can be [\-\-cipher, \-\-verify-passphrase, \-\-key-size, \-\-key-slot,
-\-\-key-file (takes precedence over optional second argument)].
+\-\-key-file (takes precedence over optional second argument), \-\-use-random | \-\-use-urandom].
 
 .PP
 \fIluksOpen\fR <device> <name>
@@ -179,6 +179,13 @@ Use pre-generated master key stored in file. For \fIluksFormat\fR it allows LUKS
 
 For \fIluksAddKey\fR it allows adding new passphrase with only master key knowledge.
 .TP
+.B "\-\-use-random"
+.TP
+.B "\-\-use-urandom"
+For \fIluksFormat\fR it defines which kernel random number generator will be used for long-term key (volume key).
+
+See \fBNOTES ON RNG\fR for more information. Use \fIcryptsetup \-\-help\fR to show default RNG.
+.TP
 .B "\-\-key-slot, \-S"
 For LUKS operations that add key material, this options allows to you specify which key slot is selected for the new key. This option can be used for \fIluksFormat\fR and \fIluksAddKey\fR.
 .TP
@@ -254,6 +261,20 @@ The available combinations of ciphers, modes, hashes and key sizes depend on ker
 For \-\-hash option all algorithms supported by gcrypt library are available.
 .SH NOTES ON PASSWORDS
 Mathematics can't be bribed. Make sure you keep your passwords safe. There are a few nice tricks for constructing a fallback, when suddenly out of (or after being) blue, your brain refuses to cooperate. These fallbacks are possible with LUKS, as it's only possible with LUKS to have multiple passwords.
+.SH NOTES ON RNG
+Random Number Generator (RNG) used in cryptsetup always uses kernel RNG without
+any modifications or additions to data stream procudes by kernel (like internal
+random pool operations or mixing with the other random sources).
+
+There are two types of randomness cryptsetup/LUKS needs. One type (which always
+uses /dev/urandom) is used for salt, AF splitter and for wiping removed
+keyslot.
+
+Second type is used for volume (master) key. You can switch between
+using /dev/random and /dev/urandom  here, see \fP--use-random\fR and \fP--use-urandom\fR
+options. Using /dev/random on system without enough entropy sources
+can cause \fPluksFormat\fR to block until the requested amount of random data is gathered.
+See \fPurandom(4)\fR for more information.
 .SH AUTHORS
 cryptsetup is written by Christophe Saout <christophe@saout.de>
 .br
index 27e56dcba8fd300ae2648e1f5a7058c77fa4f21c..3c1ee49c6c9549f34f93c4caf6caf79e45f74e0a 100644 (file)
@@ -1,6 +1,7 @@
 lib/backends.c
 lib/gcrypt.c
 lib/libdevmapper.c
+lib/random.c
 lib/setup.c
 lib/utils.c
 lib/utils_crypt.c
@@ -9,5 +10,4 @@ luks/af.c
 luks/keyencryption.c
 luks/keymanage.c
 luks/pbkdf.c
-luks/random.c
 src/cryptsetup.c
index 31cdef8fa52e04f766f120c39ab1fef0714f18cc..ac6f3aab3c51320f5cc198f6f6918fff7fac4edc 100644 (file)
@@ -37,6 +37,8 @@ static int opt_timeout = 0;
 static int opt_tries = 3;
 static int opt_align_payload = 0;
 static int opt_non_exclusive = 0;
+static int opt_random = 0;
+static int opt_urandom = 0;
 
 static const char **action_argv;
 static int action_argc;
@@ -377,6 +379,11 @@ static int action_luksFormat(int arg)
        if (opt_iteration_time)
                crypt_set_iterarion_time(cd, opt_iteration_time);
 
+       if (opt_random)
+               crypt_set_rng_type(cd, CRYPT_RNG_RANDOM);
+       else if (opt_urandom)
+               crypt_set_rng_type(cd, CRYPT_RNG_URANDOM);
+
        if (opt_master_key_file) {
                r = _read_mk(opt_master_key_file, &key, keysize);
                if (r < 0)
@@ -677,9 +684,10 @@ static void help(poptContext popt_context, enum poptCallbackReason reason,
 
                log_std(_("\nDefault compiled-in device cipher parameters:\n"
                         "\tplain: %s, Key: %d bits, Password hashing: %s\n"
-                        "\tLUKS1: %s, Key: %d bits, LUKS header hashing: %s\n"),
+                        "\tLUKS1: %s, Key: %d bits, LUKS header hashing: %s, RNG: %s\n"),
                         DEFAULT_CIPHER(PLAIN), DEFAULT_PLAIN_KEYBITS, DEFAULT_PLAIN_HASH,
-                        DEFAULT_CIPHER(LUKS1), DEFAULT_LUKS1_KEYBITS, DEFAULT_LUKS1_HASH);
+                        DEFAULT_CIPHER(LUKS1), DEFAULT_LUKS1_KEYBITS, DEFAULT_LUKS1_HASH,
+                        DEFAULT_RNG);
                exit(0);
        } else
                usage(popt_context, 0, NULL, NULL);
@@ -749,6 +757,8 @@ int main(int argc, char **argv)
                { "align-payload",     '\0', POPT_ARG_INT, &opt_align_payload,          0, N_("Align payload at <n> sector boundaries - for luksFormat"), N_("SECTORS") },
                { "non-exclusive",     '\0', POPT_ARG_NONE, &opt_non_exclusive,         0, N_("(Obsoleted, see man page.)"), NULL },
                { "header-backup-file",'\0', POPT_ARG_STRING, &opt_header_backup_file,  0, N_("File with LUKS header and keyslots backup."), NULL },
+               { "use-random",        '\0', POPT_ARG_NONE, &opt_random,                0, N_("Use /dev/random for generating volume key."), NULL },
+               { "use-urandom",       '\0', POPT_ARG_NONE, &opt_urandom,               0, N_("Use /dev/urandom for generating volume key."), NULL },
                POPT_TABLEEND
        };
        poptContext popt_context;
@@ -822,6 +832,13 @@ int main(int argc, char **argv)
                usage(popt_context, 1, _("Unknown action."),
                      poptGetInvocationName(popt_context));
 
+       if (opt_random && opt_urandom)
+               usage(popt_context, 1, _("Only one of --use-[u]random options is allowed."),
+                     poptGetInvocationName(popt_context));
+       if ((opt_random || opt_urandom) && strcmp(aname, "luksFormat"))
+               usage(popt_context, 1, _("Option --use-[u]random is allowed only for luksFormat."),
+                     poptGetInvocationName(popt_context));
+
        action_argc = 0;
        action_argv = poptGetArgs(popt_context);
        /* Make return values of poptGetArgs more consistent in case of remaining argc = 0 */