aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTheodore Ts'o <tytso@mit.edu>2012-07-05 10:35:23 -0400
committerTheodore Ts'o <tytso@mit.edu>2012-07-14 20:17:47 -0400
commitc2557a303ab6712bb6e09447df828c557c710ac9 (patch)
tree6459a604fa95e7cabdf78a30b1a5fa203e3252bb
parente6d4947b12e8ad947add1032dd754803c6004824 (diff)
random: add new get_random_bytes_arch() function
Create a new function, get_random_bytes_arch() which will use the architecture-specific hardware random number generator if it is present. Change get_random_bytes() to not use the HW RNG, even if it is avaiable. The reason for this is that the hw random number generator is fast (if it is present), but it requires that we trust the hardware manufacturer to have not put in a back door. (For example, an increasing counter encrypted by an AES key known to the NSA.) It's unlikely that Intel (for example) was paid off by the US Government to do this, but it's impossible for them to prove otherwise --- especially since Bull Mountain is documented to use AES as a whitener. Hence, the output of an evil, trojan-horse version of RDRAND is statistically indistinguishable from an RDRAND implemented to the specifications claimed by Intel. Short of using a tunnelling electronic microscope to reverse engineer an Ivy Bridge chip and disassembling and analyzing the CPU microcode, there's no way for us to tell for sure. Since users of get_random_bytes() in the Linux kernel need to be able to support hardware systems where the HW RNG is not present, most time-sensitive users of this interface have already created their own cryptographic RNG interface which uses get_random_bytes() as a seed. So it's much better to use the HW RNG to improve the existing random number generator, by mixing in any entropy returned by the HW RNG into /dev/random's entropy pool, but to always _use_ /dev/random's entropy pool. This way we get almost of the benefits of the HW RNG without any potential liabilities. The only benefits we forgo is the speed/performance enhancements --- and generic kernel code can't depend on depend on get_random_bytes() having the speed of a HW RNG anyway. For those places that really want access to the arch-specific HW RNG, if it is available, we provide get_random_bytes_arch(). Signed-off-by: "Theodore Ts'o" <tytso@mit.edu> Cc: stable@vger.kernel.org
-rw-r--r--drivers/char/random.c29
-rw-r--r--include/linux/random.h1
2 files changed, 25 insertions, 5 deletions
diff --git a/drivers/char/random.c b/drivers/char/random.c
index f67ae3e473ba..eacd61479112 100644
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -1038,17 +1038,34 @@ static ssize_t extract_entropy_user(struct entropy_store *r, void __user *buf,
1038 1038
1039/* 1039/*
1040 * This function is the exported kernel interface. It returns some 1040 * This function is the exported kernel interface. It returns some
1041 * number of good random numbers, suitable for seeding TCP sequence 1041 * number of good random numbers, suitable for key generation, seeding
1042 * numbers, etc. 1042 * TCP sequence numbers, etc. It does not use the hw random number
1043 * generator, if available; use get_random_bytes_arch() for that.
1043 */ 1044 */
1044void get_random_bytes(void *buf, int nbytes) 1045void get_random_bytes(void *buf, int nbytes)
1045{ 1046{
1047 extract_entropy(&nonblocking_pool, buf, nbytes, 0, 0);
1048}
1049EXPORT_SYMBOL(get_random_bytes);
1050
1051/*
1052 * This function will use the architecture-specific hardware random
1053 * number generator if it is available. The arch-specific hw RNG will
1054 * almost certainly be faster than what we can do in software, but it
1055 * is impossible to verify that it is implemented securely (as
1056 * opposed, to, say, the AES encryption of a sequence number using a
1057 * key known by the NSA). So it's useful if we need the speed, but
1058 * only if we're willing to trust the hardware manufacturer not to
1059 * have put in a back door.
1060 */
1061void get_random_bytes_arch(void *buf, int nbytes)
1062{
1046 char *p = buf; 1063 char *p = buf;
1047 1064
1048 while (nbytes) { 1065 while (nbytes) {
1049 unsigned long v; 1066 unsigned long v;
1050 int chunk = min(nbytes, (int)sizeof(unsigned long)); 1067 int chunk = min(nbytes, (int)sizeof(unsigned long));
1051 1068
1052 if (!arch_get_random_long(&v)) 1069 if (!arch_get_random_long(&v))
1053 break; 1070 break;
1054 1071
@@ -1057,9 +1074,11 @@ void get_random_bytes(void *buf, int nbytes)
1057 nbytes -= chunk; 1074 nbytes -= chunk;
1058 } 1075 }
1059 1076
1060 extract_entropy(&nonblocking_pool, p, nbytes, 0, 0); 1077 if (nbytes)
1078 extract_entropy(&nonblocking_pool, p, nbytes, 0, 0);
1061} 1079}
1062EXPORT_SYMBOL(get_random_bytes); 1080EXPORT_SYMBOL(get_random_bytes_arch);
1081
1063 1082
1064/* 1083/*
1065 * init_std_data - initialize pool with system data 1084 * init_std_data - initialize pool with system data
diff --git a/include/linux/random.h b/include/linux/random.h
index e14b4387354a..29e217a7e6d0 100644
--- a/include/linux/random.h
+++ b/include/linux/random.h
@@ -56,6 +56,7 @@ extern void add_input_randomness(unsigned int type, unsigned int code,
56extern void add_interrupt_randomness(int irq, int irq_flags); 56extern void add_interrupt_randomness(int irq, int irq_flags);
57 57
58extern void get_random_bytes(void *buf, int nbytes); 58extern void get_random_bytes(void *buf, int nbytes);
59extern void get_random_bytes_arch(void *buf, int nbytes);
59void generate_random_uuid(unsigned char uuid_out[16]); 60void generate_random_uuid(unsigned char uuid_out[16]);
60 61
61#ifndef MODULE 62#ifndef MODULE