diff -uNr a/linux/drivers/char/random.c b/linux/drivers/char/random.c --- a/linux/drivers/char/random.c 578e3cebb0401af4b3fc30e1d7449bcfe67e60d581c718765783b29caa8aa6a4b54d750e94d3bc7212040f15e9f535be21fc40f13c467e576d390b7568691f9a +++ b/linux/drivers/char/random.c 4ebb9960f9c2c37b05ff5bda22c34912155c8b74b52c82ba7987ef0e5252882a9566359dbcf81cc9e6dfe63f33072f3ee06d2a0b3ccffaca0e27a5da05afa51e @@ -6,13 +6,9 @@ #include #include #include -#include #include -#include #include -#include - #define INNER_RING_SIZE (16*1024) #define OUTER_RING_SIZE (2*1024*1024) @@ -25,163 +21,54 @@ static DEFINE_SPINLOCK(inner_lock); static DEFINE_SPINLOCK(outer_lock); -union sha1state { - u8 c[20]; - __u32 w[5]; -}; - - -typedef int (*Fn_Good_Hash)(const unsigned char __user *data, size_t data_len); -typedef int (*Fn_Fast_Hash)(const unsigned char __user *data, size_t data_len, size_t output_len); -typedef void (*Fn_Self_Hash)(size_t to_hash); - -static int hash_good_sha1(const unsigned char __user *data, size_t data_len); -static int hash_fast_sha1(const unsigned char __user *data, size_t data_len, size_t output_len); -static void _outer_self_hash_sha1(size_t to_hash); - -static int hash_good_chacha20(const unsigned char __user *data, size_t data_len); -static int hash_fast_chacha20(const unsigned char __user *data, size_t data_len, size_t output_len); -static void _outer_self_hash_chacha20(size_t to_hash); - -static int hash_good_serpent(const unsigned char __user *data, size_t data_len); -static int hash_fast_serpent(const unsigned char __user *data, size_t data_len, size_t output_len); -static void _outer_self_hash_serpent(size_t to_hash); - -static int hash_good_keccak(const unsigned char __user *data, size_t data_len); -static int hash_fast_keccak(const unsigned char __user *data, size_t data_len, size_t output_len); -static void _outer_self_hash_keccak(size_t to_hash); - -static unsigned current_hashing_impl = 0; -static struct hashing_impl { - const char *name; - Fn_Good_Hash fn_good; - Fn_Fast_Hash fn_fast; - Fn_Self_Hash fn_self; -} hashing_impls[] = { - {"default", hash_good_sha1, hash_fast_chacha20, _outer_self_hash_sha1}, - {"sha1", hash_good_sha1, hash_fast_sha1, _outer_self_hash_sha1}, - {"serpent", hash_good_serpent, hash_fast_serpent, _outer_self_hash_serpent}, - {"chacha20", hash_good_chacha20, hash_fast_chacha20, _outer_self_hash_chacha20}, - {"keccak", hash_good_keccak, hash_fast_keccak, _outer_self_hash_keccak}, -}; - -static int -set_hashing_impl(int val) -{ - unsigned long flags; - - if (val < 0 || val >= ARRAY_SIZE(hashing_impls)) { - printk("Fail to set hashing implementation %d\n", val); - return -EINVAL; - } - - spin_lock_irqsave(&outer_lock, flags); - current_hashing_impl = val; - spin_unlock_irqrestore(&outer_lock, flags); - printk("Set RNG hash function set to %s\n", hashing_impls[val].name); - return 0; -} - - -static int -hash_good(const unsigned char __user *data, size_t data_len) -{ - return hashing_impls[current_hashing_impl].fn_good(data, data_len); -} - -static int -hash_fast(const unsigned char __user *data, size_t data_len, size_t output_len) -{ - return hashing_impls[current_hashing_impl].fn_fast(data, data_len, output_len); -} - -static void -_outer_self_hash(size_t to_hash) -{ - return hashing_impls[current_hashing_impl].fn_self(to_hash); -} +static struct keccak_state init_keccak_state; static int -hash_good_sha1(const unsigned char __user *data, size_t data_len) +rand_initialize(void) { - union sha1state hash; - __u32 workspace[SHA_WORKSPACE_WORDS]; - u8 s_block[SHA_MESSAGE_BYTES]; - size_t nbytes; - size_t hashed = 0; - - sha_init(hash.w); - while (hashed < data_len) { - nbytes = data_len - hashed; - nbytes = min_t(size_t, sizeof(s_block), nbytes); - memset(s_block, 0, sizeof(s_block)); - if (copy_from_user(s_block, data + hashed, nbytes)) { - return -EFAULT; - } - sha_transform(hash.w, s_block, workspace); - kfifo_in(&outer_ring, &hash.c[0], sizeof(hash)); - hashed += nbytes; - } - return 0; -} - -static struct serpent_ctx zero_key_serpent; -static int rand_initialize(void) -{ - /* s_key can be customizable in future */ - u8 s_key[SERPENT_MAX_KEY_SIZE] = {0}; - __serpent_setkey(&zero_key_serpent, &s_key[0], sizeof(s_key)); + keccak_init(&init_keccak_state); return 0; } early_initcall(rand_initialize); static int -hash_good_serpent(const unsigned char __user *data, size_t data_len) +set_hash_key(const unsigned char __user *user_key, size_t key_len) { - struct serpent_ctx sctx; - u8 s_block[SERPENT_BLOCK_SIZE]; - size_t nbytes; size_t hashed = 0; + size_t nbytes; + int r = 0; + unsigned long flags; + u8 block[KECCAK_BLOCK_SIZE]; - sctx = zero_key_serpent; - while (hashed < data_len) { - nbytes = data_len - hashed; - nbytes = min_t(size_t, sizeof(s_block), nbytes); - memset(s_block, 0, sizeof(s_block)); - if (copy_from_user(s_block, data + hashed, nbytes)) { - return -EFAULT; + spin_lock_irqsave(&outer_lock, flags); + + keccak_init(&init_keccak_state); + while (hashed < key_len) { + nbytes = min_t(size_t, key_len - hashed, sizeof(block)); + if (copy_from_user(&block[0], &user_key[hashed], nbytes)) { + r = -EINVAL; + keccak_init(&init_keccak_state); + goto out; } - __serpent_encrypt(&sctx, s_block, s_block); - kfifo_in(&outer_ring, &s_block[0], sizeof(s_block)); + keccak_update(&init_keccak_state, &block[0], nbytes); hashed += nbytes; } - return 0; + keccak_pad(&init_keccak_state); + +out: + spin_unlock_irqrestore(&outer_lock, flags); + return r; } -static int -hash_good_chacha20(const unsigned char __user *data, size_t data_len) +static void +random_init_keccak(struct keccak_state *kst) { - u32 ctx[16] = {0}; - u8 s_block[CHACHA20_BLOCK_SIZE]; - size_t nbytes; - size_t hashed = 0; - - while (hashed < data_len) { - nbytes = data_len - hashed; - nbytes = min_t(size_t, sizeof(s_block), nbytes); - memset(s_block, 0, sizeof(s_block)); - if (copy_from_user(s_block, data + hashed, nbytes)) { - return -EFAULT; - } - chacha20_block(&ctx[0], s_block); - kfifo_in(&outer_ring, &s_block[0], nbytes); - hashed += nbytes; - } - return 0; + keccak_init(kst); + memcpy(&kst->st, &init_keccak_state.st, sizeof(kst->st)); } static int -hash_good_keccak(const unsigned char __user *data, size_t data_len) +hash_good(const unsigned char __user *data, size_t data_len) { struct keccak_state kst; u8 s_block[KECCAK_BLOCK_SIZE]; @@ -189,7 +76,7 @@ size_t hashed = 0; size_t squeezed = 0; - keccak_init(&kst); + random_init_keccak(&kst); while (hashed < data_len) { nbytes = data_len - hashed; nbytes = min_t(size_t, sizeof(s_block), nbytes); @@ -197,7 +84,7 @@ return -EFAULT; } keccak_update(&kst, &s_block[0], nbytes); - hashed += nbytes; + hashed += nbytes; } keccak_pad(&kst); @@ -211,94 +98,20 @@ return 0; } - -static int -hash_fast_sha1(const unsigned char __user *data, size_t data_len, size_t output_len) -{ - union sha1state hash; - __u32 workspace[SHA_WORKSPACE_WORDS]; - u8 s_block[SHA_MESSAGE_BYTES] = {0}; - size_t nbytes; - size_t hashed = 0; - - data_len = min_t(size_t, data_len, sizeof(hash)); - if (copy_from_user(&hash.c[0], data, data_len)) { - return -EFAULT; - } - - while (hashed < output_len) { - nbytes = output_len - hashed; - nbytes = min_t(size_t, sizeof(hash), nbytes); - sha_transform(hash.w, s_block, workspace); - nbytes = kfifo_in(&outer_ring, &hash.c[0], nbytes); - hashed += nbytes; - } - return 0; -} - -static int -hash_fast_serpent(const unsigned char __user *data, size_t data_len, size_t output_len) -{ - struct serpent_ctx sctx; - u8 s_key[SERPENT_MAX_KEY_SIZE]; - u8 s_block[SERPENT_BLOCK_SIZE] = {0}; - size_t nbytes; - size_t hashed = 0; - - data_len = min_t(size_t, data_len, sizeof(s_key)); - if (copy_from_user(&s_key[0], data, data_len)) { - return -EFAULT; - } - - __serpent_setkey(&sctx, &s_key[0], sizeof(s_key)); - while (hashed < output_len) { - nbytes = output_len - hashed; - nbytes = min_t(size_t, sizeof(s_block), nbytes); - __serpent_encrypt(&sctx, s_block, s_block); - nbytes = kfifo_in(&outer_ring, &s_block[0], nbytes); - hashed += nbytes; - } - return 0; -} - - -static int -hash_fast_chacha20(const unsigned char __user *data, size_t data_len, size_t output_len) -{ - u32 ctx[16] = {0}; - u8 s_block[CHACHA20_BLOCK_SIZE] = {0}; - size_t nbytes; - size_t hashed = 0; - - data_len = min_t(size_t, data_len, sizeof(ctx)); - if (copy_from_user(&ctx[0], data, data_len)) { - return -EFAULT; - } - - while (hashed < output_len) { - nbytes = output_len - hashed; - nbytes = min_t(size_t, CHACHA20_BLOCK_SIZE, nbytes); - chacha20_block(&ctx[0], s_block); - nbytes = kfifo_in(&outer_ring, s_block, nbytes); - hashed += nbytes; - } - return 0; -} - static int -hash_fast_keccak(const unsigned char __user *data, size_t data_len, size_t output_len) +hash_fast(const unsigned char __user *data, size_t data_len, size_t output_len) { struct keccak_state kst; u8 s_block[KECCAK_BLOCK_SIZE] = {0}; size_t nbytes; size_t hashed = 0; - data_len = min_t(size_t, data_len, sizeof(s_block)); + data_len = min_t(size_t, data_len, sizeof(s_block)); if (copy_from_user(&s_block[0], data, data_len)) { return -EFAULT; } - keccak_init(&kst); + random_init_keccak(&kst); keccak_update(&kst, s_block, data_len); keccak_pad(&kst); while (hashed < output_len) { @@ -426,7 +239,7 @@ /* Avoid situations where CPRNG generates outer ring content * without complete seed */ - if (count - written < SHA_MESSAGE_BYTES) { + if (count - written < KECCAK_BLOCK_SIZE) { return count; } r = transfer_to_outer(buffer + written, count - written); @@ -440,75 +253,21 @@ random_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) { - return _random_write(buffer, count); -} - -static void -_outer_self_hash_sha1(size_t to_hash) -{ - union sha1state hash; - __u32 workspace[SHA_WORKSPACE_WORDS]; - u8 s_block[SHA_MESSAGE_BYTES]; - size_t nbytes, peeked; - size_t hashed = 0; - - sha_init(hash.w); - while (hashed < to_hash) { - memset(s_block, 0, sizeof(s_block)); - nbytes = min_t(size_t, sizeof(hash), (to_hash - hashed)); - peeked = kfifo_out_peek_forward(&outer_ring, s_block, nbytes); - sha_transform(hash.w, s_block, workspace); - nbytes = kfifo_in(&outer_ring, &hash.c[0], nbytes); - hashed += nbytes; - } -} - -static void -_outer_self_hash_serpent(size_t to_hash) -{ - struct serpent_ctx sctx; - u8 s_block[SERPENT_BLOCK_SIZE]; - size_t nbytes, peeked; - size_t hashed = 0; - - sctx = zero_key_serpent; - while (hashed < to_hash) { - memset(s_block, 0, sizeof(s_block)); - nbytes = min_t(size_t, sizeof(s_block), (to_hash - hashed)); - peeked = kfifo_out_peek_forward(&outer_ring, s_block, nbytes); - __serpent_encrypt(&sctx, s_block, s_block); - nbytes = kfifo_in(&outer_ring, &s_block[0], nbytes); - hashed += nbytes; - } -} - -static void -_outer_self_hash_chacha20(size_t to_hash) -{ - u32 ctx[16] = {0}; - u8 s_block[CHACHA20_BLOCK_SIZE]; - size_t nbytes, peeked; - size_t hashed = 0; - - while (hashed < to_hash) { - memset(s_block, 0, sizeof(s_block)); - nbytes = min_t(size_t, sizeof(s_block), (to_hash - hashed)); - peeked = kfifo_out_peek_forward(&outer_ring, s_block, nbytes); - chacha20_block(&ctx[0], s_block); - nbytes = kfifo_in(&outer_ring, &s_block[0], nbytes); - hashed += nbytes; + if (!capable(CAP_SYS_ADMIN)) { + return -EPERM; } + return _random_write(buffer, count); } static void -_outer_self_hash_keccak(size_t to_hash) +_outer_self_hash(size_t to_hash) { struct keccak_state kst; u8 s_block[KECCAK_BLOCK_SIZE]; size_t nbytes, peeked; size_t hashed = 0; - keccak_init(&kst); + random_init_keccak(&kst); while (hashed < to_hash) { nbytes = min_t(size_t, sizeof(s_block), (to_hash - hashed)); peeked = kfifo_out_peek_forward(&outer_ring, s_block, nbytes); @@ -536,7 +295,7 @@ unsigned long flags; int outer_ring_length; ssize_t cnt = 0; - int r; + int r = 0; spin_lock_irqsave(&outer_lock, flags); outer_ring_length = kfifo_len(&outer_ring); @@ -554,7 +313,7 @@ { int nread = 0; ssize_t r = 0; - unsigned int written; + unsigned int written = 0; while (nread < nbytes) { /* This preserves the semantics of urandom_read @@ -627,9 +386,13 @@ static long random_ioctl(struct file *f, unsigned int cmd, unsigned long arg) { - int size, ent_count, val; + int size, ent_count; int __user *p = (int __user *)arg; int retval; + uintptr_t __user *u_p; + uintptr_t key_ptr; + size_t __user *s_p; + size_t key_len; switch (cmd) { case RNDGETENTCNT: @@ -639,11 +402,7 @@ return -EFAULT; return 0; case RNDADDTOENTCNT: - /* This is temporary hijacked to set the function index */ - if (get_user(val, p)) { - return -EFAULT; - } - return set_hashing_impl(val); + return 0; case RNDADDENTROPY: if (!capable(CAP_SYS_ADMIN)) return -EPERM; @@ -668,6 +427,20 @@ kfifo_reset(&inner_ring); kfifo_reset(&outer_ring); return 0; + case RNDSETKEY: + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + s_p = (size_t __user *)p; + if (get_user(key_len, s_p++)) + return -EFAULT; + u_p = (uintptr_t __user *)s_p; + if (get_user(key_ptr, u_p)) + return -EFAULT; + retval = set_hash_key((const char __user *)key_ptr, key_len); + if (retval < 0) + return retval; + return 0; + default: return -EINVAL; } @@ -731,10 +504,11 @@ void del_random_ready_callback(struct random_ready_callback *rdy) {} EXPORT_SYMBOL(del_random_ready_callback); +#define BATCHED_ENTROPY_BYTES 128 struct batched_entropy { union { - unsigned long entropy_long[CHACHA20_BLOCK_SIZE / sizeof(unsigned long)]; - unsigned int entropy_int[CHACHA20_BLOCK_SIZE / sizeof(unsigned int)]; + unsigned long entropy_long[BATCHED_ENTROPY_BYTES / sizeof(unsigned long)]; + unsigned int entropy_int[BATCHED_ENTROPY_BYTES / sizeof(unsigned int)]; }; unsigned int position; }; @@ -876,6 +650,39 @@ return proc_dostring(&fake_table, write, buffer, lenp, ppos); } +static int +proc_do_key_hash(struct ctl_table *table, int write, + void __user *buffer, size_t *lenp, loff_t *ppos) +{ + struct ctl_table fake_table; + unsigned char buf[2*KECCAK_DIGEST_SIZE+1]; + u8 hash[KECCAK_DIGEST_SIZE]; + struct keccak_state kst; + unsigned long flags; + size_t i = 0; + + spin_lock_irqsave(&outer_lock, flags); + random_init_keccak(&kst); + spin_unlock_irqrestore(&outer_lock, flags); + + while (i < sizeof(hash)) { + u8 tmpbuf[KECCAK_BLOCK_SIZE]; + size_t nbytes = min_t(size_t, sizeof(tmpbuf), sizeof(hash) - i); + keccak_squeeze(&kst, tmpbuf); + memcpy(&hash[i], tmpbuf, nbytes); + i += nbytes; + } + + bin2hex(buf, hash, sizeof(hash)); + buf[2*KECCAK_DIGEST_SIZE] = 0; + + fake_table.data = buf; + fake_table.maxlen = sizeof(buf); + + return proc_dostring(&fake_table, write, buffer, lenp, ppos); + +} + static int _proc_do_entropy(struct ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos, int entropy) @@ -922,7 +729,7 @@ .data = 0, }, { - .procname = "outer_ring_avail", + .procname = "outer_ring_avail", .maxlen = sizeof(int), .mode = 0444, .proc_handler = proc_do_outer_entropy, @@ -941,6 +748,12 @@ .mode = 0444, .proc_handler = proc_do_uuid, }, + { + .procname = "key_hash", + .maxlen = (2*KECCAK_DIGEST_SIZE), + .mode = 0444, + .proc_handler = proc_do_key_hash, + }, { } }; #endif /* CONFIG_SYSCTL */ diff -uNr a/linux/fs/compat_ioctl.c b/linux/fs/compat_ioctl.c --- a/linux/fs/compat_ioctl.c 58e63d5c7409f2c10dbd525b9d2956b10b76cda1b4ae4a0ac0b4d0d0f538551785b31b2c6920577c91251198ab0df2efa6efb2f6df4f44e317a3e4eb5aa0c1bc +++ b/linux/fs/compat_ioctl.c 41f4975b3655a44b8f6a1bec2f0c093a6e37395dd58001f9eed02b171861556fa7084a59cb2d9ceb411318fecfaaf6a2a4f65adc61df0fd3e64213e85ba108e5 @@ -1218,6 +1218,7 @@ COMPATIBLE_IOCTL(RNDADDENTROPY) COMPATIBLE_IOCTL(RNDZAPENTCNT) COMPATIBLE_IOCTL(RNDCLEARPOOL) +COMPATIBLE_IOCTL(RNDSETKEY) /* Bluetooth */ COMPATIBLE_IOCTL(HCIDEVUP) COMPATIBLE_IOCTL(HCIDEVDOWN) diff -uNr a/linux/include/uapi/linux/random.h b/linux/include/uapi/linux/random.h --- a/linux/include/uapi/linux/random.h e17438cbfcae1cb39456816559470a75815a04553aaa814267baf923441d11f7b3fc2482ea5d6e2af34d31490893c92438a29dbe3fc65fde7c2d2821653033e3 +++ b/linux/include/uapi/linux/random.h 2a114448c1369bf37eec6ee00a4deabf262e7e6fc9df8919de5f6301bd7a53a6adb5feb439fc11d1347f7270d71b3af1cb50b4302939c08d3c04d1c9ee964a9e @@ -34,6 +34,9 @@ /* Clear the entropy pool and associated counters. (Superuser only.) */ #define RNDCLEARPOOL _IO( 'R', 0x06 ) +/* Sets the per-machine key for outer ring hash */ +#define RNDSETKEY _IOW( 'R', 0x7, int [2] ) + struct rand_pool_info { int entropy_count; int buf_size; diff -uNr a/linux/lib/keccak.c b/linux/lib/keccak.c --- a/linux/lib/keccak.c ea43cabc717b8aea3cee16c445d42498da069f910fc28837c3edae94886a70f8f09d33a5913358a3a0d9c6cdc7f9c8260a10df27500e08c598c1ee2082a1c05e +++ b/linux/lib/keccak.c ccd3fb8f031076fbb4beb2ea7245ddae4d31c240b6726ba03e3685889c2ca603f66808e28f74e514c6eed134f48adbaf9bb27d29b4a90ee50b5c08add1c06f9f @@ -122,7 +122,7 @@ void keccak_pad(struct keccak_state *sctx) { - unsigned int i; + unsigned int i; unsigned int inlen = sctx->partial; sctx->buf[inlen++] = 0x01; @@ -132,13 +132,12 @@ for (i = 0; i < sctx->rsizw; i++) { sctx->st[i] ^= get_unaligned_le64(sctx->buf + 8 * i); } - } void keccak_squeeze(struct keccak_state *sctx, u8 *out) { - unsigned int i; + unsigned int i; u64 st[KECCAK_STATE_SIZE] = {0}; keccakf(sctx->st); for (i = 0; i < KECCAK_STATE_SIZE; i++) { diff -uNr a/linux/manifest b/linux/manifest --- a/linux/manifest 5fff8a3f1417b67e7af4c5400fd7eb23961789761c6a93018bb80234f395679d5b717a4c582b85f82d47b793b80f43622f9ef6c2fc11b7f0bdfa675c19259072 +++ b/linux/manifest 4affe338f5d3040dd7fcfd5dceac7b72393641ce9d5f28550fe0fefcb71c5fa13b23f31d93e7df3f795ee740256b075571f2c4bc3c44ec44d2227a66448ef94c @@ -2,3 +2,4 @@ 600263 bvt linux-fuckgoats-rng Add userspace-driven RNG code 602756 bvt linux-keccak Add keccak implementation, enabled by default 606513 bvt linux-benchmark-v2 Benchmark for different implementations of fast-, good-, and self- hashing; added fix for keccak_squeeze bug +606528 bvt keccak-rng Keccak-based RNG; allow setting machine RNG key; simplify feeder. diff -uNr a/linux/tools/rng/Makefile b/linux/tools/rng/Makefile --- a/linux/tools/rng/Makefile b7e8416b1eb373052dcd9288432aa2d7f9850eb7e66567c9045a142cd3b6ea3f4766f86c11bc1c0c5d30b27a5a37943426ae25e3c0ed62111836ff014a5e3cd7 +++ b/linux/tools/rng/Makefile 3c42f06590b408d71e3d302689a1fbc705ad3afdfd70d7f756db228acfd6fdea50f7bc762d880c8b62c88167ee9adb582598cee576a3584e21c73153ab36df75 @@ -1,10 +1,12 @@ -all: random-feeder change-rng-hashfns +PROGS := random-feeder change-rng-key +CFLAGS := -static -O2 -Wall +all: $(PROGS) random-feeder: random-feeder.c - $(CC) -static -O2 -Wall -o $@ $^ + $(CC) $(CFLAGS) -o $@ $^ -change-rng-hashfns: change-rng-hashfns.c - $(CC) -static -O2 -Wall -o $@ $^ +change-rng-key: change-rng-key.c + $(CC) $(CFLAGS) -o $@ $^ clean: - rm random-feeder change-rng-hashfns + rm $(PROGS) diff -uNr a/linux/tools/rng/change-rng-hashfns.c b/linux/tools/rng/change-rng-hashfns.c --- a/linux/tools/rng/change-rng-hashfns.c ed1421919e30bc74b25e959d0d66023005b932e0c0ac67f48e174d55da76b07e0eba4daa60daafd5457fe5e0faed0684d5b17e00948edea9a767f34ab8986084 +++ b/linux/tools/rng/change-rng-hashfns.c false @@ -1,33 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -int main(int argc, char *argv[]) -{ - int impl; - int fd; - int r; - - if (argc != 2) { - fprintf(stderr, "usage: %s impl_no\n", argv[0]); - exit(EXIT_FAILURE); - } - fd = open("/dev/random", O_RDWR); - if (fd == -1) { - fprintf(stderr, "Error opening file: %s\n", strerror(errno)); - exit(EXIT_FAILURE); - } - impl = atoi(argv[1]); - r = ioctl(fd, RNDADDTOENTCNT, &impl); - if (r == -1) { - fprintf(stderr, "Error setting hash implementation: %s\n", strerror(errno)); - exit(EXIT_FAILURE); - } - return 0; -} diff -uNr a/linux/tools/rng/change-rng-key.c b/linux/tools/rng/change-rng-key.c --- a/linux/tools/rng/change-rng-key.c false +++ b/linux/tools/rng/change-rng-key.c 0025f916ff2a257d5e00a4591ec834fd84fd55510a9d120dd2add25f9cc6d301d2669b276e24e2a1ecfb4585b832287c794bafb3b41fa18daaa3e20099aadd3a @@ -0,0 +1,61 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MY_RNDSETKEY _IOW( 'R', 0x7, int [2] ) + +struct { + size_t size; + void *buf; +} user_key; + +static void +read_user_key(const char *path) +{ + struct stat st; + int fd = open(path, O_RDONLY); + if (fd == -1) { + fprintf(stderr, "Cannot open key file %s: %s", path, strerror(errno)); + exit(EXIT_FAILURE); + } + fstat(fd, &st); + user_key.size = st.st_size; + user_key.buf = mmap(0, user_key.size, PROT_READ, MAP_PRIVATE, fd, 0); + if (user_key.buf == MAP_FAILED) { + fprintf(stderr, "Cannot map key file %s: %s", path, strerror(errno)); + exit(EXIT_FAILURE); + } + close(fd); +} + +int main(int argc, char *argv[]) +{ + int fd; + int r; + + + if (argc != 2) { + fprintf(stderr, "usage: %s key_file\n", argv[0]); + exit(EXIT_FAILURE); + } + fd = open("/dev/random", O_RDWR); + if (fd == -1) { + fprintf(stderr, "Error opening file: %s\n", strerror(errno)); + exit(EXIT_FAILURE); + } + read_user_key(argv[1]); + r = ioctl(fd, MY_RNDSETKEY, &user_key); + if (r == -1) { + fprintf(stderr, "Error setting hash key: %s\n", strerror(errno)); + exit(EXIT_FAILURE); + } + return 0; +} diff -uNr a/linux/tools/rng/random-feeder.c b/linux/tools/rng/random-feeder.c --- a/linux/tools/rng/random-feeder.c 924bd8018748a2591f7a86384e9591175c5e2b565d7efdebec1bf5887d8c2a89f39be9686f279a058347e9563c8d2816bf58e73095dd3a0f2c08f802dabbe74a +++ b/linux/tools/rng/random-feeder.c 4250d19b428c26abc5b79be4547725dbe29cc9e8560684cfd509211559d455384b7e21caab995f773bdfc40a538fa920751af12894048cf2f3a6e75bcdc68a08 @@ -24,7 +24,6 @@ exit(EXIT_FAILURE); } cfmakeraw(&term); - term.c_cc[VMIN] = 255; r = cfsetspeed(&term, B115200); if (r == -1) { fprintf(stderr, "Error setting serial speed: %s\n", strerror(errno)); @@ -49,17 +48,13 @@ out = open("/dev/random", O_WRONLY); while (1) { char buf[4096]; - ssize_t nread = 0; - while (nread != sizeof(buf)) { - usleep(500000); - ssize_t l = read(in, &buf[nread], sizeof(buf) - nread); - if (l == -1) { - fprintf(stderr, "Read failed: %s\n", strerror(errno)); - exit(EXIT_FAILURE); - } - nread += l; + ssize_t nread = read(in, &buf[0], sizeof(buf)); + if (nread == -1) { + fprintf(stderr, "Read failed: %s\n", strerror(errno)); + exit(EXIT_FAILURE); } write(out, &buf[0], nread); + usleep(500000); } return 0; }