Commit 20f12e63 authored by Dr. Stephen Henson's avatar Dr. Stephen Henson
Browse files

Add HMAC DRBG from SP800-90

parent b38fd40d
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -4,6 +4,10 @@

 Changes between 1.0.1 and 1.1.0  [xx XXX xxxx]

  *) Add support for HMAC DRBG from SP800-90. Update algorithm and POST
     to handle HMAC cases.
     [Steve Henson]

  *) Add GCM support to TLS library. Some custom code is needed to split
     the IV between the fixed (from PRF) and explicit (from TLS record)
     portions. This adds all GCM ciphersuites supported by RFC5288 and 
+5 −0
Original line number Diff line number Diff line
@@ -679,6 +679,11 @@ POST_ID id_list[] = {
	{NID_sha256, "SHA256"},
	{NID_sha384, "SHA384"},
	{NID_sha512, "SHA512"},
	{NID_hmacWithSHA1, "HMAC-SHA1"},
	{NID_hmacWithSHA224, "HMAC-SHA224"},
	{NID_hmacWithSHA256, "HMAC-SHA256"},
	{NID_hmacWithSHA384, "HMAC-SHA384"},
	{NID_hmacWithSHA512, "HMAC-SHA512"},
	{EVP_PKEY_RSA, "RSA"},
	{EVP_PKEY_DSA, "DSA"},
	{EVP_PKEY_EC, "ECDSA"},
+0 −2
Original line number Diff line number Diff line
@@ -54,8 +54,6 @@
#include <stdlib.h>
#include <string.h>
#include <openssl/crypto.h>
#include <openssl/evp.h>
#include <openssl/aes.h>
#include <openssl/fips.h>
#include <openssl/fips_rand.h>
#include "fips_rand_lcl.h"
+0 −2
Original line number Diff line number Diff line
@@ -56,8 +56,6 @@
#include <stdlib.h>
#include <string.h>
#include <openssl/crypto.h>
#include <openssl/evp.h>
#include <openssl/aes.h>
#include <openssl/fips.h>
#include <openssl/fips_rand.h>
#include "fips_rand_lcl.h"
+215 −1
Original line number Diff line number Diff line
@@ -61,7 +61,221 @@
#include <openssl/fips_rand.h>
#include "fips_rand_lcl.h"

static int drbg_hmac_update(DRBG_CTX *dctx,
				const unsigned char *in1, size_t in1len,
				const unsigned char *in2, size_t in2len,
				const unsigned char *in3, size_t in3len
			)
	{
	static unsigned char c0 = 0, c1 = 1;
	DRBG_HMAC_CTX *hmac = &dctx->d.hmac;
	HMAC_CTX *hctx = &hmac->hctx;

	if (!HMAC_Init_ex(hctx, hmac->K, dctx->blocklength, hmac->md, NULL))
		return 0;
	if (!HMAC_Update(hctx, hmac->V, dctx->blocklength))
		return 0;
	if (!HMAC_Update(hctx, &c0, 1))
		return 0;
	if (in1len && !HMAC_Update(hctx, in1, in1len))
		return 0;
	if (in2len && !HMAC_Update(hctx, in2, in2len))
		return 0;
	if (in3len && !HMAC_Update(hctx, in3, in3len))
		return 0;

	if (!HMAC_Final(hctx, hmac->K, NULL))
		return 0;

	if (!HMAC_Init_ex(hctx, hmac->K, dctx->blocklength, hmac->md, NULL))
		return 0;
	if (!HMAC_Update(hctx, hmac->V, dctx->blocklength))
		return 0;

	if (!HMAC_Final(hctx, hmac->V, NULL))
		return 0;

	if (!in1len && !in2len && !in3len)
		return 1;

	if (!HMAC_Init_ex(hctx, hmac->K, dctx->blocklength, hmac->md, NULL))
		return 0;
	if (!HMAC_Update(hctx, hmac->V, dctx->blocklength))
		return 0;
	if (!HMAC_Update(hctx, &c1, 1))
		return 0;
	if (in1len && !HMAC_Update(hctx, in1, in1len))
		return 0;
	if (in2len && !HMAC_Update(hctx, in2, in2len))
		return 0;
	if (in3len && !HMAC_Update(hctx, in3, in3len))
		return 0;

	if (!HMAC_Final(hctx, hmac->K, NULL))
		return 0;

	if (!HMAC_Init_ex(hctx, hmac->K, dctx->blocklength, hmac->md, NULL))
		return 0;
	if (!HMAC_Update(hctx, hmac->V, dctx->blocklength))
		return 0;

	if (!HMAC_Final(hctx, hmac->V, NULL))
		return 0;

	return 1;

	}

static int drbg_hmac_instantiate(DRBG_CTX *dctx,
				const unsigned char *ent, size_t ent_len,
				const unsigned char *nonce, size_t nonce_len,
				const unsigned char *pstr, size_t pstr_len)
	{
	DRBG_HMAC_CTX *hmac = &dctx->d.hmac;
	memset(hmac->K, 0, dctx->blocklength);
	memset(hmac->V, 1, dctx->blocklength);
	if (!drbg_hmac_update(dctx,
			ent, ent_len, nonce, nonce_len, pstr, pstr_len))
		return 0;

#ifdef HMAC_DRBG_TRACE
	fprintf(stderr, "K+V after instantiate:\n");
	hexprint(stderr, hmac->K, hmac->blocklength);
	hexprint(stderr, hmac->V, hmac->blocklength);
#endif
	return 1;
	}

static int drbg_hmac_reseed(DRBG_CTX *dctx,
				const unsigned char *ent, size_t ent_len,
				const unsigned char *adin, size_t adin_len)
	{
	if (!drbg_hmac_update(dctx,
			ent, ent_len, adin, adin_len, NULL, 0))
		return 0;

#ifdef HMAC_DRBG_TRACE
	{
		DRBG_HMAC_CTX *hmac = &dctx->d.hmac;
		fprintf(stderr, "K+V after reseed:\n");
		hexprint(stderr, hmac->K, hmac->blocklength);
		hexprint(stderr, hmac->V, hmac->blocklength);
	}
#endif
	return 1;
	}

static int drbg_hmac_generate(DRBG_CTX *dctx,
				unsigned char *out, size_t outlen,
				const unsigned char *adin, size_t adin_len)
	{
	DRBG_HMAC_CTX *hmac = &dctx->d.hmac;
	HMAC_CTX *hctx = &hmac->hctx;
	const unsigned char *Vtmp = hmac->V;
	if (adin_len && !drbg_hmac_update(dctx, adin, adin_len,
						NULL, 0, NULL, 0))
		return 0;
	for (;;)
		{
		if (!HMAC_Init_ex(hctx, hmac->K, dctx->blocklength,
							hmac->md, NULL))
			return 0;
		if (!HMAC_Update(hctx, Vtmp, dctx->blocklength))
			return 0;
		if (!(dctx->flags & DRBG_FLAG_TEST) && !dctx->lb_valid)
			{
			if (!HMAC_Final(hctx, dctx->lb, NULL))
				return 0;
			dctx->lb_valid = 1;
			Vtmp = dctx->lb;
			continue;
			}
		else if (outlen > dctx->blocklength)
			{
			if (!HMAC_Final(hctx, out, NULL))
				return 0;
			if (!fips_drbg_cprng_test(dctx, out))
				return 0;
			Vtmp = out;
			}
		else
			{
			if (!HMAC_Final(hctx, hmac->V, NULL))
				return 0;
			if (!fips_drbg_cprng_test(dctx, hmac->V))
				return 0;
			memcpy(out, hmac->V, outlen);
			break;
			}
		out += dctx->blocklength;
		outlen -= dctx->blocklength;
		}
	if (!drbg_hmac_update(dctx, adin, adin_len, NULL, 0, NULL, 0))
		return 0;

	return 1;
	}

static int drbg_hmac_uninstantiate(DRBG_CTX *dctx)
	{
	HMAC_CTX_cleanup(&dctx->d.hmac.hctx);
	OPENSSL_cleanse(&dctx->d.hmac, sizeof(DRBG_HMAC_CTX));
	return 1;
	}

int fips_drbg_hmac_init(DRBG_CTX *dctx)
	{
	const EVP_MD *md = NULL;
	DRBG_HMAC_CTX *hctx = &dctx->d.hmac;
	dctx->strength = 256;
	switch (dctx->type)
		{
		case NID_hmacWithSHA1:
		md = EVP_sha1();
		dctx->strength = 128;
		break;

		case NID_hmacWithSHA224:
		md = EVP_sha224();
		dctx->strength = 192;
		break;

		case NID_hmacWithSHA256:
		md = EVP_sha256();
		break;

		case NID_hmacWithSHA384:
		md = EVP_sha384();
		break;

		case NID_hmacWithSHA512:
		md = EVP_sha512();
		break;

		default:
		dctx->strength = 0;
		return -2;
		}
        dctx->instantiate = drbg_hmac_instantiate;
        dctx->reseed = drbg_hmac_reseed;
        dctx->generate = drbg_hmac_generate;
        dctx->uninstantiate = drbg_hmac_uninstantiate;
	HMAC_CTX_init(&hctx->hctx);
	hctx->md = md;
	dctx->blocklength = M_EVP_MD_size(md);
	dctx->seedlen = M_EVP_MD_size(md);

        dctx->min_entropy = dctx->strength / 8;
        dctx->max_entropy = DRBG_MAX_LENGTH;

        dctx->min_nonce = dctx->min_entropy / 2;
        dctx->max_nonce = DRBG_MAX_LENGTH;

        dctx->max_pers = DRBG_MAX_LENGTH;
        dctx->max_adin = DRBG_MAX_LENGTH;

        dctx->max_request = 1<<19;
        dctx->reseed_interval = 1<<24;

	return 1;
	}
Loading