From 66a3ce2ec1f028dcac32485ed228eb59f938e461 Mon Sep 17 00:00:00 2001 From: John Safranek Date: Tue, 27 Nov 2012 22:17:25 -0800 Subject: [PATCH] added SHA-256 based RNG when setting NO_RC4 compile flag --- configure.ac | 2 +- ctaocrypt/src/asn.c | 6 + ctaocrypt/src/random.c | 265 ++++++++++++++++++++++++++++++++++++++ cyassl/ctaocrypt/random.h | 25 +++- cyassl/internal.h | 3 + src/internal.c | 3 + src/ssl.c | 9 +- src/tls.c | 4 + 8 files changed, 314 insertions(+), 3 deletions(-) diff --git a/configure.ac b/configure.ac index a2a316266..a21e9726c 100644 --- a/configure.ac +++ b/configure.ac @@ -217,7 +217,7 @@ AC_ARG_ENABLE(leanpsk, if test "$ENABLED_LEANPSK" = "yes" then - AM_CFLAGS="$AM_CFLAGS -DCYASSL_LEANPSK -DHAVE_NULL_CIPHER -DNO_AES -DNO_FILESYSTEM -DNO_RSA -DNO_DSA -DNO_DH -DNO_CERTS -DNO_PWDBASED -DNO_DES3 -DNO_MD4 -DNO_MD5 -DNO_ERROR_STRINGS -DNO_OLD_TLS" + AM_CFLAGS="$AM_CFLAGS -DCYASSL_LEANPSK -DHAVE_NULL_CIPHER -DNO_AES -DNO_FILESYSTEM -DNO_RSA -DNO_DSA -DNO_DH -DNO_CERTS -DNO_PWDBASED -DNO_DES3 -DNO_MD4 -DNO_MD5 -DNO_ERROR_STRINGS -DNO_OLD_TLS -DNO_RC4" ENABLED_SLOWMATH="no" fi diff --git a/ctaocrypt/src/asn.c b/ctaocrypt/src/asn.c index 19c196cd7..f703241e2 100644 --- a/ctaocrypt/src/asn.c +++ b/ctaocrypt/src/asn.c @@ -44,6 +44,10 @@ #include #include +#ifndef NO_RC4 + #include +#endif + #ifdef HAVE_NTRU #include "crypto_ntru.h" #endif @@ -750,6 +754,7 @@ static int DecryptKey(const char* password, int passwordSz, byte* salt, break; } #endif +#ifndef NO_RC4 case RC4_TYPE: { Arc4 dec; @@ -758,6 +763,7 @@ static int DecryptKey(const char* password, int passwordSz, byte* salt, Arc4Process(&dec, input, input, length); break; } +#endif default: return ALGO_ID_E; diff --git a/ctaocrypt/src/random.c b/ctaocrypt/src/random.c index 58d485fcd..edb3b8bb3 100644 --- a/ctaocrypt/src/random.c +++ b/ctaocrypt/src/random.c @@ -31,6 +31,15 @@ #include #include +#ifdef NO_RC4 + #include + + #ifdef NO_INLINE + #include + #else + #include + #endif +#endif #if defined(USE_WINDOWS_API) #ifndef _WIN32_WINNT @@ -50,6 +59,260 @@ #endif /* USE_WINDOWS_API */ +#ifdef NO_RC4 + +/* Start NIST DRBG code */ + +#define OUTPUT_BLOCK_LEN (256/8) +#define MAX_REQUEST_LEN (0x1000) +#define MAX_STRING_LEN (0x100000000) +#define RESEED_MAX (0x100000000000LL) +#define ENTROPY_SZ 256 + +#define DBRG_SUCCESS 0 +#define DBRG_ERROR 1 +#define DBRG_NEED_RESEED 2 + + +enum { + dbrgInitC = 0, + dbrgReseed = 1, + dbrgGenerateW = 2, + dbrgGenerateH = 3, + dbrgInitV +}; + + +static int Hash_df(byte* out, word32 outSz, byte type, byte* inA, word32 inASz, + byte* inB, word32 inBSz, byte* inC, word32 inCSz) +{ + byte ctr; + int i; + int len; + Sha256 sha; + byte digest[SHA256_DIGEST_SIZE]; + word32 bits = (outSz * 8); // reverse byte order + + #ifdef LITTLE_ENDIAN_ORDER + bits = ByteReverseWord32(bits); + #endif + len = (outSz / SHA256_DIGEST_SIZE) + + ((outSz % SHA256_DIGEST_SIZE) ? 1 : 0); + + for (i = 0, ctr = 1; i < len; i++, ctr++) + { + InitSha256(&sha); + Sha256Update(&sha, &ctr, sizeof(ctr)); + Sha256Update(&sha, (byte*)&bits, sizeof(bits)); + /* churning V is the only string that doesn't have + * the type added */ + if (type != dbrgInitV) + Sha256Update(&sha, &type, sizeof(type)); + Sha256Update(&sha, inA, inASz); + if (inB != NULL && inBSz > 0) + Sha256Update(&sha, inB, inBSz); + if (inC != NULL && inCSz > 0) + Sha256Update(&sha, inC, inCSz); + Sha256Final(&sha, digest); + + if (outSz > SHA256_DIGEST_SIZE) { + XMEMCPY(out, digest, SHA256_DIGEST_SIZE); + outSz -= SHA256_DIGEST_SIZE; + out += SHA256_DIGEST_SIZE; + } + else { + XMEMCPY(out, digest, outSz); + } + } + XMEMSET(digest, 0, SHA256_DIGEST_SIZE); + XMEMSET(&sha, 0, sizeof(sha)); + + return DBRG_SUCCESS; +} + + +static int Hash_DBRG_Reseed(RNG* rng, byte* entropy, word32 entropySz) +{ + byte seed[DBRG_SEED_LEN]; + + Hash_df(seed, sizeof(seed), dbrgInitV, rng->V, sizeof(rng->V), + entropy, entropySz, NULL, 0); + XMEMCPY(rng->V, seed, sizeof(rng->V)); + XMEMSET(seed, 0, sizeof(seed)); + + Hash_df(rng->C, sizeof(rng->C), dbrgInitC, rng->V, sizeof(rng->V), + NULL, 0, NULL, 0); + rng->reseed_ctr = 1; + return 0; +} + +static INLINE void array_add_one(byte* data, word32 dataSz) +{ + int i; + + for (i = dataSz - 1; i >= 0; i--) + { + data[i]++; + if (data[i] != 0) break; + } +} + +static void Hash_gen(byte* out, word32 outSz, byte* V) +{ + Sha256 sha; + byte data[DBRG_SEED_LEN]; + byte digest[SHA256_DIGEST_SIZE]; + int i; + int len = (outSz / SHA256_DIGEST_SIZE) + + ((outSz % SHA256_DIGEST_SIZE) ? 1 : 0); + + XMEMCPY(data, V, sizeof(data)); + for (i = 0; i < len; i++) { + InitSha256(&sha); + Sha256Update(&sha, data, sizeof(data)); + Sha256Final(&sha, digest); + if (outSz > SHA256_DIGEST_SIZE) { + XMEMCPY(out, digest, SHA256_DIGEST_SIZE); + outSz -= SHA256_DIGEST_SIZE; + out += SHA256_DIGEST_SIZE; + array_add_one(data, DBRG_SEED_LEN); + } + else { + XMEMCPY(out, digest, outSz); + } + } + XMEMSET(data, 0, sizeof(data)); + XMEMSET(digest, 0, sizeof(digest)); + XMEMSET(&sha, 0, sizeof(sha)); +} + + +static INLINE void array_add(byte* d, word32 dLen, byte* s, word32 sLen) +{ + word16 carry = 0; + + if (dLen > 0 && sLen > 0 && dLen >= sLen) { + int sIdx, dIdx; + + for (sIdx = dLen - 1, dIdx = dLen - 1; sIdx >= 0; dIdx--, sIdx--) + { + carry += d[dIdx] + s[sIdx]; + d[dIdx] = carry; + carry >>= 8; + } + if (dIdx > 0) + d[dIdx] += carry; + } +} + + +static int Hash_DBRG_Generate(RNG* rng, byte* out, word32 outSz) +{ + int ret; + + if (rng->reseed_ctr != RESEED_MAX) { + Sha256 sha; + byte digest[SHA256_DIGEST_SIZE]; + byte type = dbrgGenerateH; + + Hash_gen(out, outSz, rng->V); + InitSha256(&sha); + Sha256Update(&sha, &type, sizeof(type)); + Sha256Update(&sha, rng->V, sizeof(rng->V)); + Sha256Final(&sha, digest); + array_add(rng->V, sizeof(rng->V), digest, sizeof(digest)); + array_add(rng->V, sizeof(rng->V), rng->C, sizeof(rng->C)); + array_add(rng->V, sizeof(rng->V), + (byte*)&rng->reseed_ctr, sizeof(rng->reseed_ctr)); + rng->reseed_ctr++; + XMEMSET(&sha, 0, sizeof(sha)); + XMEMSET(digest, 0, sizeof(digest)); + ret = DBRG_SUCCESS; + } + else { + ret = DBRG_NEED_RESEED; + } + return ret; +} + + +static void Hash_DBRG_Instantiate(RNG* rng, byte* seed, word32 seedSz) +{ + XMEMSET(rng, 0, sizeof(*rng)); + Hash_df(rng->V, sizeof(rng->V), dbrgInitV, seed, seedSz, NULL, 0, NULL, 0); + Hash_df(rng->C, sizeof(rng->C), dbrgInitC, rng->V, sizeof(rng->V), + NULL, 0, NULL, 0); + rng->reseed_ctr = 1; +} + + +static int Hash_DBRG_Uninstantiate(RNG* rng) +{ + int result = DBRG_ERROR; + + if (rng != NULL) { + XMEMSET(rng, 0, sizeof(*rng)); + result = DBRG_SUCCESS; + } + + return result; +} + +/* End NIST DRBG Code */ + + + +/* Get seed and key cipher */ +int InitRng(RNG* rng) +{ + byte entropy[ENTROPY_SZ]; + int ret = DBRG_ERROR; + + if (GenerateSeed(&rng->seed, entropy, sizeof(entropy)) == 0) { + Hash_DBRG_Instantiate(rng, entropy, sizeof(entropy)); + ret = DBRG_SUCCESS; + } + XMEMSET(entropy, 0, sizeof(entropy)); + return ret; +} + + +/* place a generated block in output */ +void RNG_GenerateBlock(RNG* rng, byte* output, word32 sz) +{ + int ret; + + XMEMSET(output, 0, sz); + ret = Hash_DBRG_Generate(rng, output, sz); + if (ret == DBRG_NEED_RESEED) { + byte entropy[ENTROPY_SZ]; + ret = GenerateSeed(&rng->seed, entropy, sizeof(entropy)); + if (ret == 0) { + Hash_DBRG_Reseed(rng, entropy, sizeof(entropy)); + ret = Hash_DBRG_Generate(rng, output, sz); + } + else + ret = DBRG_ERROR; + XMEMSET(entropy, 0, sizeof(entropy)); + } +} + + +byte RNG_GenerateByte(RNG* rng) +{ + byte b; + RNG_GenerateBlock(rng, &b, 1); + + return b; +} + + +void FreeRng(RNG* rng) +{ + Hash_DBRG_Uninstantiate(rng); +} + +#else /* NO_RC4 */ /* Get seed and key cipher */ int InitRng(RNG* rng) @@ -84,6 +347,8 @@ byte RNG_GenerateByte(RNG* rng) return b; } +#endif /* NO_RC4 */ + #if defined(USE_WINDOWS_API) diff --git a/cyassl/ctaocrypt/random.h b/cyassl/ctaocrypt/random.h index 3bd911b51..f23f9a559 100644 --- a/cyassl/ctaocrypt/random.h +++ b/cyassl/ctaocrypt/random.h @@ -23,7 +23,11 @@ #ifndef CTAO_CRYPT_RANDOM_H #define CTAO_CRYPT_RANDOM_H -#include +#include + +#ifndef NO_RC4 + #include +#endif #ifdef __cplusplus extern "C" { @@ -49,9 +53,11 @@ typedef struct OS_Seed { #endif } OS_Seed; + CYASSL_LOCAL int GenerateSeed(OS_Seed* os, byte* seed, word32 sz); +#ifndef NO_RC4 /* secure Random Nnumber Generator */ typedef struct RNG { @@ -59,11 +65,28 @@ typedef struct RNG { Arc4 cipher; } RNG; +#else /* NO_RC4 */ + +#define DBRG_SEED_LEN (440/8) + +/* secure Random Nnumber Generator */ +typedef struct RNG { + OS_Seed seed; + + byte V[DBRG_SEED_LEN]; + byte C[DBRG_SEED_LEN]; + word64 reseed_ctr; +} RNG; + +#endif CYASSL_API int InitRng(RNG*); CYASSL_API void RNG_GenerateBlock(RNG*, byte*, word32 sz); CYASSL_API byte RNG_GenerateByte(RNG*); +#ifdef NO_RC4 + CYASSL_API void FreeRng(RNG*); +#endif #ifdef __cplusplus } /* extern "C" */ diff --git a/cyassl/internal.h b/cyassl/internal.h index b8693ac2c..ff848490c 100644 --- a/cyassl/internal.h +++ b/cyassl/internal.h @@ -35,6 +35,9 @@ #include #include #include +#ifndef NO_RC4 + #include +#endif #ifdef HAVE_ECC #include #endif diff --git a/src/internal.c b/src/internal.c index 36b5b0eb5..9179aada8 100644 --- a/src/internal.c +++ b/src/internal.c @@ -1476,6 +1476,7 @@ int DtlsPoolSend(CYASSL* ssl) #endif +#ifndef NO_OLD_TLS ProtocolVersion MakeSSLv3(void) { @@ -1486,6 +1487,8 @@ ProtocolVersion MakeSSLv3(void) return pv; } +#endif /* NO_OLD_TLS */ + #ifdef CYASSL_DTLS diff --git a/src/ssl.c b/src/ssl.c index 01cd1441e..671d80be2 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -681,11 +681,14 @@ int CyaSSL_SetVersion(CYASSL* ssl, int version) } switch (version) { +#ifndef NO_OLD_TLS case CYASSL_SSLV3: ssl->version = MakeSSLv3(); break; +#endif #ifndef NO_TLS + #ifndef NO_OLD_TLS case CYASSL_TLSV1: ssl->version = MakeTLSv1(); break; @@ -693,7 +696,7 @@ int CyaSSL_SetVersion(CYASSL* ssl, int version) case CYASSL_TLSV1_1: ssl->version = MakeTLSv1_1(); break; - + #endif case CYASSL_TLSV1_2: ssl->version = MakeTLSv1_2(); break; @@ -2421,6 +2424,7 @@ int CyaSSL_dtls_got_timeout(CYASSL* ssl) /* client only parts */ #ifndef NO_CYASSL_CLIENT + #ifndef NO_OLD_TLS CYASSL_METHOD* CyaSSLv3_client_method(void) { CYASSL_METHOD* method = @@ -2431,6 +2435,7 @@ int CyaSSL_dtls_got_timeout(CYASSL* ssl) InitSSL_Method(method, MakeSSLv3()); return method; } + #endif #ifdef CYASSL_DTLS CYASSL_METHOD* CyaDTLSv1_client_method(void) @@ -2651,6 +2656,7 @@ int CyaSSL_dtls_got_timeout(CYASSL* ssl) /* server only parts */ #ifndef NO_CYASSL_SERVER + #ifndef NO_OLD_TLS CYASSL_METHOD* CyaSSLv3_server_method(void) { CYASSL_METHOD* method = @@ -2663,6 +2669,7 @@ int CyaSSL_dtls_got_timeout(CYASSL* ssl) } return method; } + #endif #ifdef CYASSL_DTLS diff --git a/src/tls.c b/src/tls.c index 5b12f0b00..48ee867ea 100644 --- a/src/tls.c +++ b/src/tls.c @@ -251,6 +251,8 @@ void BuildTlsFinished(CYASSL* ssl, Hashes* hashes, const byte* sender) } +#ifndef NO_OLD_TLS + ProtocolVersion MakeTLSv1(void) { ProtocolVersion pv; @@ -270,6 +272,8 @@ ProtocolVersion MakeTLSv1_1(void) return pv; } +#endif + ProtocolVersion MakeTLSv1_2(void) {