DRBG Update

1. picked better values for entropy and nonce sizes based on
   security strength
2. changed output block length to be the SHA-256 digest size
3. use constant drbgReseed when reseeding
4. renamed the "drgb" type constants from "dbrg"
5. removed the small stack change due to buffer size changes
6. internal helper function Hash_DRBG_Instantiate now also
   takes a pointer to a nonce and a personalization string
7. the InitRng gathers enough bits from GenerateSeed() to
   supply the entropy input and a nonce
8. lowered the reseed interval to 1 million
This commit is contained in:
John Safranek
2014-05-06 14:05:52 -07:00
parent d6b98c1fab
commit ac18ce03df

View File

@@ -67,11 +67,13 @@
/* Start NIST DRBG code */ /* Start NIST DRBG code */
#define OUTPUT_BLOCK_LEN (256/8) #define OUTPUT_BLOCK_LEN (SHA256_DIGEST_SIZE)
#define MAX_REQUEST_LEN (0x1000) #define MAX_REQUEST_LEN (0x10000)
#define MAX_STRING_LEN (0x100000000) #define RESEED_INTERVAL (1000000)
#define RESEED_INTERVAL (0xFFFFFFFF) #define SECURITY_STRENGTH (256)
#define ENTROPY_SZ 256 #define ENTROPY_SZ (SECURITY_STRENGTH/8)
#define NONCE_SZ (ENTROPY_SZ/2)
#define ENTROPY_NONCE_SZ (ENTROPY_SZ+NONCE_SZ)
#define DRBG_SUCCESS 0 #define DRBG_SUCCESS 0
#define DRBG_ERROR 1 #define DRBG_ERROR 1
@@ -79,11 +81,11 @@
enum { enum {
dbrgInitC = 0, drbgInitC = 0,
dbrgReseed = 1, drbgReseed = 1,
dbrgGenerateW = 2, drbgGenerateW = 2,
dbrgGenerateH = 3, drbgGenerateH = 3,
dbrgInitV drbgInitV
}; };
@@ -100,8 +102,8 @@ static int Hash_df(RNG* rng, byte* out, word32 outSz, byte type,
#ifdef LITTLE_ENDIAN_ORDER #ifdef LITTLE_ENDIAN_ORDER
bits = ByteReverseWord32(bits); bits = ByteReverseWord32(bits);
#endif #endif
len = (outSz / SHA256_DIGEST_SIZE) len = (outSz / OUTPUT_BLOCK_LEN)
+ ((outSz % SHA256_DIGEST_SIZE) ? 1 : 0); + ((outSz % OUTPUT_BLOCK_LEN) ? 1 : 0);
for (i = 0, ctr = 1; i < len; i++, ctr++) for (i = 0, ctr = 1; i < len; i++, ctr++)
{ {
@@ -116,7 +118,7 @@ static int Hash_df(RNG* rng, byte* out, word32 outSz, byte type,
/* churning V is the only string that doesn't have /* churning V is the only string that doesn't have
* the type added */ * the type added */
if (type != dbrgInitV) if (type != drbgInitV)
if (Sha256Update(&rng->sha, &type, sizeof(type)) != 0) if (Sha256Update(&rng->sha, &type, sizeof(type)) != 0)
return DRBG_ERROR; return DRBG_ERROR;
@@ -134,10 +136,10 @@ static int Hash_df(RNG* rng, byte* out, word32 outSz, byte type,
if (Sha256Final(&rng->sha, rng->digest) != 0) if (Sha256Final(&rng->sha, rng->digest) != 0)
return DRBG_ERROR; return DRBG_ERROR;
if (outSz > SHA256_DIGEST_SIZE) { if (outSz > OUTPUT_BLOCK_LEN) {
XMEMCPY(out, rng->digest, SHA256_DIGEST_SIZE); XMEMCPY(out, rng->digest, OUTPUT_BLOCK_LEN);
outSz -= SHA256_DIGEST_SIZE; outSz -= OUTPUT_BLOCK_LEN;
out += SHA256_DIGEST_SIZE; out += OUTPUT_BLOCK_LEN;
} }
else { else {
XMEMCPY(out, rng->digest, outSz); XMEMCPY(out, rng->digest, outSz);
@@ -153,7 +155,7 @@ static int Hash_DRBG_Reseed(RNG* rng, byte* entropy, word32 entropySz)
int ret; int ret;
byte seed[DRBG_SEED_LEN]; byte seed[DRBG_SEED_LEN];
ret = Hash_df(rng, seed, sizeof(seed), dbrgInitV, rng->V, sizeof(rng->V), ret = Hash_df(rng, seed, sizeof(seed), drbgReseed, rng->V, sizeof(rng->V),
entropy, entropySz, NULL, 0); entropy, entropySz, NULL, 0);
if (ret != 0) if (ret != 0)
return ret; return ret;
@@ -161,7 +163,7 @@ static int Hash_DRBG_Reseed(RNG* rng, byte* entropy, word32 entropySz)
XMEMCPY(rng->V, seed, sizeof(rng->V)); XMEMCPY(rng->V, seed, sizeof(rng->V));
XMEMSET(seed, 0, sizeof(seed)); XMEMSET(seed, 0, sizeof(seed));
ret = Hash_df(rng, rng->C, sizeof(rng->C), dbrgInitC, rng->V, ret = Hash_df(rng, rng->C, sizeof(rng->C), drbgInitC, rng->V,
sizeof(rng->V), NULL, 0, NULL, 0); sizeof(rng->V), NULL, 0, NULL, 0);
if (ret != 0) if (ret != 0)
return ret; return ret;
@@ -185,8 +187,8 @@ static int Hash_gen(RNG* rng, byte* out, word32 outSz, byte* V)
{ {
byte data[DRBG_SEED_LEN]; byte data[DRBG_SEED_LEN];
int i, ret; int i, ret;
int len = (outSz / SHA256_DIGEST_SIZE) int len = (outSz / OUTPUT_BLOCK_LEN)
+ ((outSz % SHA256_DIGEST_SIZE) ? 1 : 0); + ((outSz % OUTPUT_BLOCK_LEN) ? 1 : 0);
XMEMCPY(data, V, sizeof(data)); XMEMCPY(data, V, sizeof(data));
for (i = 0; i < len; i++) { for (i = 0; i < len; i++) {
@@ -202,10 +204,10 @@ static int Hash_gen(RNG* rng, byte* out, word32 outSz, byte* V)
if (ret != 0) if (ret != 0)
return ret; return ret;
if (outSz > SHA256_DIGEST_SIZE) { if (outSz > OUTPUT_BLOCK_LEN) {
XMEMCPY(out, rng->digest, SHA256_DIGEST_SIZE); XMEMCPY(out, rng->digest, OUTPUT_BLOCK_LEN);
outSz -= SHA256_DIGEST_SIZE; outSz -= OUTPUT_BLOCK_LEN;
out += SHA256_DIGEST_SIZE; out += OUTPUT_BLOCK_LEN;
array_add_one(data, DRBG_SEED_LEN); array_add_one(data, DRBG_SEED_LEN);
} }
else { else {
@@ -242,7 +244,7 @@ static int Hash_DRBG_Generate(RNG* rng, byte* out, word32 outSz)
int ret; int ret;
if (rng->reseedCtr != RESEED_INTERVAL) { if (rng->reseedCtr != RESEED_INTERVAL) {
byte type = dbrgGenerateH; byte type = drbgGenerateH;
word32 reseedCtr = rng->reseedCtr; word32 reseedCtr = rng->reseedCtr;
rng->reseedCtr++; rng->reseedCtr++;
@@ -272,17 +274,19 @@ static int Hash_DRBG_Generate(RNG* rng, byte* out, word32 outSz)
} }
static int Hash_DRBG_Instantiate(RNG* rng, byte* seed, word32 seedSz) static int Hash_DRBG_Instantiate(RNG* rng, byte* seed, word32 seedSz,
byte* nonce, word32 nonceSz, byte* personal, word32 personalSz)
{ {
int ret; int ret;
XMEMSET(rng, 0, sizeof(*rng)); XMEMSET(rng, 0, sizeof(*rng));
ret = Hash_df(rng, rng->V, sizeof(rng->V), dbrgInitV, seed, seedSz, NULL, 0, ret = Hash_df(rng, rng->V, sizeof(rng->V), drbgInitV, seed, seedSz,
NULL, 0); nonce, nonceSz, personal, personalSz);
if (ret != 0) if (ret != 0)
return ret; return ret;
ret = Hash_df(rng, rng->C, sizeof(rng->C), dbrgInitC, rng->V, ret = Hash_df(rng, rng->C, sizeof(rng->C), drbgInitC, rng->V,
sizeof(rng->V), NULL, 0, NULL, 0); sizeof(rng->V), NULL, 0, NULL, 0);
if (ret != 0) if (ret != 0)
return ret; return ret;
@@ -308,31 +312,20 @@ static int Hash_DRBG_Uninstantiate(RNG* rng)
/* End NIST DRBG Code */ /* End NIST DRBG Code */
/* Get seed and key cipher */ /* Get seed and key cipher */
int InitRng(RNG* rng) int InitRng(RNG* rng)
{ {
#ifdef CYASSL_SMALL_STACK byte entropy[ENTROPY_NONCE_SZ];
byte* entropy;
#else
byte entropy[ENTROPY_SZ];
#endif
int ret = DRBG_ERROR; int ret = DRBG_ERROR;
#ifdef CYASSL_SMALL_STACK /* This doesn't use a separate nonce. The entropy input will be
entropy = (byte*)XMALLOC(ENTROPY_SZ, NULL, DYNAMIC_TYPE_TMP_BUFFER); * the default size plus the size of the nonce making the seed
if (entropy == NULL) * size. */
return MEMORY_E; if (GenerateSeed(&rng->seed, entropy, ENTROPY_NONCE_SZ) == 0)
#endif ret = Hash_DRBG_Instantiate(rng, entropy, ENTROPY_NONCE_SZ,
NULL, 0, NULL, 0);
if (GenerateSeed(&rng->seed, entropy, ENTROPY_SZ) == 0) XMEMSET(entropy, 0, ENTROPY_NONCE_SZ);
ret = Hash_DRBG_Instantiate(rng, entropy, ENTROPY_SZ);
XMEMSET(entropy, 0, ENTROPY_SZ);
#ifdef CYASSL_SMALL_STACK
XFREE(entropy, NULL, DYNAMIC_TYPE_TMP_BUFFER);
#endif
return ret; return ret;
} }
@@ -347,17 +340,7 @@ int RNG_GenerateBlock(RNG* rng, byte* output, word32 sz)
ret = Hash_DRBG_Generate(rng, output, sz); ret = Hash_DRBG_Generate(rng, output, sz);
if (ret == DRBG_NEED_RESEED) { if (ret == DRBG_NEED_RESEED) {
#ifdef CYASSL_SMALL_STACK
byte* entropy;
#else
byte entropy[ENTROPY_SZ]; byte entropy[ENTROPY_SZ];
#endif
#ifdef CYASSL_SMALL_STACK
entropy = (byte*)XMALLOC(ENTROPY_SZ, NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (entropy == NULL)
return MEMORY_E;
#endif
ret = GenerateSeed(&rng->seed, entropy, ENTROPY_SZ); ret = GenerateSeed(&rng->seed, entropy, ENTROPY_SZ);
if (ret == 0) { if (ret == 0) {
@@ -370,10 +353,6 @@ int RNG_GenerateBlock(RNG* rng, byte* output, word32 sz)
ret = DRBG_ERROR; ret = DRBG_ERROR;
XMEMSET(entropy, 0, ENTROPY_SZ); XMEMSET(entropy, 0, ENTROPY_SZ);
#ifdef CYASSL_SMALL_STACK
XFREE(entropy, NULL, DYNAMIC_TYPE_TMP_BUFFER);
#endif
} }
return ret; return ret;