Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F160787497
D19475.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
9 KB
Referenced Files
None
Subscribers
None
D19475.diff
View Options
Index: head/sys/dev/random/fortuna.c
===================================================================
--- head/sys/dev/random/fortuna.c
+++ head/sys/dev/random/fortuna.c
@@ -109,7 +109,7 @@
} fs_pool[RANDOM_FORTUNA_NPOOLS];
u_int fs_reseedcount; /* ReseedCnt */
uint128_t fs_counter; /* C */
- struct randomdev_key fs_key; /* K */
+ union randomdev_key fs_key; /* K */
u_int fs_minpoolsize; /* Extras */
/* Extras for the OS */
#ifdef _KERNEL
@@ -271,16 +271,27 @@
{
struct randomdev_hash context;
uint8_t hash[RANDOM_KEYSIZE];
+ const void *keymaterial;
+ size_t keysz;
+ bool seeded;
RANDOM_RESEED_ASSERT_LOCK_OWNED();
+
+ seeded = random_fortuna_seeded();
+ if (seeded) {
+ randomdev_getkey(&fortuna_state.fs_key, &keymaterial, &keysz);
+ KASSERT(keysz == RANDOM_KEYSIZE, ("%s: key size %zu not %u",
+ __func__, keysz, (unsigned)RANDOM_KEYSIZE));
+ }
+
/*-
* FS&K - K = Hd(K|s) where Hd(m) is H(H(0^512|m))
* - C = C + 1
*/
randomdev_hash_init(&context);
randomdev_hash_iterate(&context, zero_region, RANDOM_ZERO_BLOCKSIZE);
- randomdev_hash_iterate(&context, &fortuna_state.fs_key.key.keyMaterial,
- fortuna_state.fs_key.key.keyLen / 8);
+ if (seeded)
+ randomdev_hash_iterate(&context, keymaterial, keysz);
randomdev_hash_iterate(&context, entropy_data, RANDOM_KEYSIZE*blockcount);
randomdev_hash_finish(&context, hash);
randomdev_hash_init(&context);
Index: head/sys/dev/random/hash.h
===================================================================
--- head/sys/dev/random/hash.h
+++ head/sys/dev/random/hash.h
@@ -29,6 +29,7 @@
#ifndef SYS_DEV_RANDOM_HASH_H_INCLUDED
#define SYS_DEV_RANDOM_HASH_H_INCLUDED
+#include <crypto/chacha20/_chacha.h>
#include <dev/random/uint128.h>
/* Keys are formed from cipher blocks */
@@ -45,15 +46,22 @@
SHA256_CTX sha;
};
-struct randomdev_key {
- keyInstance key; /* Key schedule */
- cipherInstance cipher; /* Rijndael internal */
+union randomdev_key {
+ struct {
+ keyInstance key; /* Key schedule */
+ cipherInstance cipher; /* Rijndael internal */
+ };
+ struct chacha_ctx chacha;
};
+extern bool fortuna_chachamode;
+
void randomdev_hash_init(struct randomdev_hash *);
void randomdev_hash_iterate(struct randomdev_hash *, const void *, size_t);
void randomdev_hash_finish(struct randomdev_hash *, void *);
-void randomdev_encrypt_init(struct randomdev_key *, const void *);
-void randomdev_keystream(struct randomdev_key *context, uint128_t *, void *, u_int);
+
+void randomdev_encrypt_init(union randomdev_key *, const void *);
+void randomdev_keystream(union randomdev_key *context, uint128_t *, void *, u_int);
+void randomdev_getkey(union randomdev_key *, const void **, size_t *);
#endif /* SYS_DEV_RANDOM_HASH_H_INCLUDED */
Index: head/sys/dev/random/hash.c
===================================================================
--- head/sys/dev/random/hash.c
+++ head/sys/dev/random/hash.c
@@ -30,6 +30,9 @@
#ifdef _KERNEL
#include <sys/param.h>
+#include <sys/malloc.h>
+#include <sys/random.h>
+#include <sys/sysctl.h>
#include <sys/systm.h>
#else /* !_KERNEL */
#include <sys/param.h>
@@ -42,14 +45,39 @@
#include "unit_test.h"
#endif /* _KERNEL */
+#define CHACHA_EMBED
+#define KEYSTREAM_ONLY
+#define CHACHA_NONCE0_CTR128
+#include <crypto/chacha20/chacha.c>
#include <crypto/rijndael/rijndael-api-fst.h>
#include <crypto/sha2/sha256.h>
#include <dev/random/hash.h>
+#ifdef _KERNEL
+#include <dev/random/randomdev.h>
+#endif
/* This code presumes that RANDOM_KEYSIZE is twice as large as RANDOM_BLOCKSIZE */
CTASSERT(RANDOM_KEYSIZE == 2*RANDOM_BLOCKSIZE);
+/* Validate that full Chacha IV is as large as the 128-bit counter */
+_Static_assert(CHACHA_STATELEN == RANDOM_BLOCKSIZE, "");
+
+/*
+ * Experimental Chacha20-based PRF for Fortuna keystream primitive. For now,
+ * disabled by default. But we may enable it in the future.
+ *
+ * Benefits include somewhat faster keystream generation compared with
+ * unaccelerated AES-ICM.
+ */
+bool random_chachamode = false;
+#ifdef _KERNEL
+SYSCTL_BOOL(_kern_random, OID_AUTO, use_chacha20_cipher, CTLFLAG_RDTUN,
+ &random_chachamode, 0,
+ "If non-zero, use the ChaCha20 cipher for randomdev PRF. "
+ "If zero, use AES-ICM cipher for randomdev PRF (default).");
+#endif
+
/* Initialise the hash */
void
randomdev_hash_init(struct randomdev_hash *context)
@@ -81,11 +109,15 @@
* data.
*/
void
-randomdev_encrypt_init(struct randomdev_key *context, const void *data)
+randomdev_encrypt_init(union randomdev_key *context, const void *data)
{
- rijndael_cipherInit(&context->cipher, MODE_ECB, NULL);
- rijndael_makeKey(&context->key, DIR_ENCRYPT, RANDOM_KEYSIZE*8, data);
+ if (random_chachamode) {
+ chacha_keysetup(&context->chacha, data, RANDOM_KEYSIZE * 8);
+ } else {
+ rijndael_cipherInit(&context->cipher, MODE_ECB, NULL);
+ rijndael_makeKey(&context->key, DIR_ENCRYPT, RANDOM_KEYSIZE*8, data);
+ }
}
/*
@@ -95,19 +127,96 @@
* bytes are generated.
*/
void
-randomdev_keystream(struct randomdev_key *context, uint128_t *ctr,
+randomdev_keystream(union randomdev_key *context, uint128_t *ctr,
void *d_out, u_int blockcount)
{
u_int i;
- for (i = 0; i < blockcount; i++) {
- /*-
- * FS&K - r = r|E(K,C)
- * - C = C + 1
+ if (random_chachamode) {
+ uint128_t lectr;
+
+ /*
+ * Chacha always encodes and increments the counter little
+ * endian. So on BE machines, we must provide a swapped
+ * counter to chacha, and swap the output too.
*/
- rijndael_blockEncrypt(&context->cipher, &context->key,
- (void *)ctr, RANDOM_BLOCKSIZE * 8, d_out);
- d_out = (char *)d_out + RANDOM_BLOCKSIZE;
- uint128_increment(ctr);
+ le128enc(&lectr, *ctr);
+
+ chacha_ivsetup(&context->chacha, NULL, (const void *)&lectr);
+ chacha_encrypt_bytes(&context->chacha, NULL, d_out,
+ RANDOM_BLOCKSIZE * blockcount);
+
+ /*
+ * Decode Chacha-updated LE counter to native endian and store
+ * it back in the caller's in-out parameter.
+ */
+ chacha_ctrsave(&context->chacha, (void *)&lectr);
+ *ctr = le128dec(&lectr);
+ } else {
+ for (i = 0; i < blockcount; i++) {
+ /*-
+ * FS&K - r = r|E(K,C)
+ * - C = C + 1
+ */
+ rijndael_blockEncrypt(&context->cipher, &context->key,
+ (void *)ctr, RANDOM_BLOCKSIZE * 8, d_out);
+ d_out = (char *)d_out + RANDOM_BLOCKSIZE;
+ uint128_increment(ctr);
+ }
}
+}
+
+/*
+ * Fetch a pointer to the relevant key material and its size.
+ *
+ * This API is expected to only be used only for reseeding, where the
+ * endianness does not matter; the goal is to simply incorporate the key
+ * material into the hash iterator that will produce key'.
+ *
+ * Do not expect the buffer pointed to by this API to match the exact
+ * endianness, etc, as the key material that was supplied to
+ * randomdev_encrypt_init().
+ */
+void
+randomdev_getkey(union randomdev_key *context, const void **keyp, size_t *szp)
+{
+
+ if (!random_chachamode) {
+ *keyp = &context->key.keyMaterial;
+ *szp = context->key.keyLen / 8;
+ return;
+ }
+
+ /* Chacha20 mode */
+ *keyp = (const void *)&context->chacha.input[4];
+
+ /* Sanity check keysize */
+ if (context->chacha.input[0] == U8TO32_LITTLE(sigma) &&
+ context->chacha.input[1] == U8TO32_LITTLE(&sigma[4]) &&
+ context->chacha.input[2] == U8TO32_LITTLE(&sigma[8]) &&
+ context->chacha.input[3] == U8TO32_LITTLE(&sigma[12])) {
+ *szp = 32;
+ return;
+ }
+
+#if 0
+ /*
+ * Included for the sake of completeness; as-implemented, Fortuna
+ * doesn't need or use 128-bit Chacha20.
+ */
+ if (context->chacha->input[0] == U8TO32_LITTLE(tau) &&
+ context->chacha->input[1] == U8TO32_LITTLE(&tau[4]) &&
+ context->chacha->input[2] == U8TO32_LITTLE(&tau[8]) &&
+ context->chacha->input[3] == U8TO32_LITTLE(&tau[12])) {
+ *szp = 16;
+ return;
+ }
+#endif
+
+#ifdef _KERNEL
+ panic("%s: Invalid chacha20 keysize: %16D\n", __func__,
+ (void *)context->chacha.input, " ");
+#else
+ raise(SIGKILL);
+#endif
}
Index: head/sys/dev/random/uint128.h
===================================================================
--- head/sys/dev/random/uint128.h
+++ head/sys/dev/random/uint128.h
@@ -29,6 +29,8 @@
#ifndef SYS_DEV_RANDOM_UINT128_H_INCLUDED
#define SYS_DEV_RANDOM_UINT128_H_INCLUDED
+#include <sys/endian.h>
+
/* This whole thing is a crock :-(
*
* Everyone knows you always need the __uint128_t types!
@@ -63,13 +65,49 @@
#endif
}
+static __inline bool
+uint128_equals(uint128_t a, uint128_t b)
+{
+#ifdef USE_REAL_UINT128_T
+ return (a == b);
+#else
+ return (a.u128t_word0 == b.u128t_word0 &&
+ a.u128t_word1 == b.u128t_word1);
+#endif
+}
+
static __inline int
uint128_is_zero(uint128_t big_uint)
{
+ return (uint128_equals(big_uint, UINT128_ZERO));
+}
+
+static __inline uint128_t
+le128dec(const void *pp)
+{
+ const uint8_t *p = pp;
+
#ifdef USE_REAL_UINT128_T
- return (big_uint == UINT128_ZERO);
+ return (((uint128_t)le64dec(p + 8) << 64) | le64dec(p));
#else
- return (big_uint.u128t_word0 == 0UL && big_uint.u128t_word1 == 0UL);
+ return ((uint128_t){
+ .u128t_word0 = le64dec(p),
+ .u128t_word1 = le64dec(p + 8),
+ });
+#endif
+}
+
+static __inline void
+le128enc(void *pp, uint128_t u)
+{
+ uint8_t *p = pp;
+
+#ifdef USE_REAL_UINT128_T
+ le64enc(p, (uint64_t)(u & UINT64_MAX));
+ le64enc(p + 8, (uint64_t)(u >> 64));
+#else
+ le64enc(p, u.u128t_word0);
+ le64enc(p + 8, u.u128t_word1);
#endif
}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sun, Jun 28, 8:54 PM (9 h, 37 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
34443320
Default Alt Text
D19475.diff (9 KB)
Attached To
Mode
D19475: Fortuna: Add Chacha20 as an alternative stream cipher
Attached
Detach File
Event Timeline
Log In to Comment