From fe34a5fb832defac003841502fbb343299b2594f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= <mpg@elzevir.fr> Date: Thu, 30 Jan 2014 15:06:40 +0100 Subject: [PATCH] Add entropy callbacks to HMAC_DRBG --- include/polarssl/hmac_drbg.h | 66 +++++++++++++++++++++++++---- library/ecdsa.c | 2 +- library/hmac_drbg.c | 80 ++++++++++++++++++++++++++++++++++-- 3 files changed, 135 insertions(+), 13 deletions(-) diff --git a/include/polarssl/hmac_drbg.h b/include/polarssl/hmac_drbg.h index b35d62b3d2..54aa9a4080 100644 --- a/include/polarssl/hmac_drbg.h +++ b/include/polarssl/hmac_drbg.h @@ -29,19 +29,40 @@ #include "md.h" +/* + * ! Same values as ctr_drbg.h ! + */ +#define POLARSSL_ERR_HMAC_DRBG_ENTROPY_SOURCE_FAILED -0x0034 /**< The entropy source failed. */ +#define POLARSSL_ERR_HMAC_DRBG_REQUEST_TOO_BIG -0x0036 /**< Too many random requested in single call. */ +#define POLARSSL_ERR_HMAC_DRBG_INPUT_TOO_BIG -0x0038 /**< Input too large (Entropy + additional). */ +#define POLARSSL_ERR_HMAC_DRBG_FILE_IO_ERROR -0x003A /**< Read/write error in file. */ + +#define HMAC_DRBG_RESEED_INTERVAL 10000 /**< Interval before reseed is performed by default */ +#define HMAC_DRBG_MAX_INPUT 256 /**< Maximum number of additional input bytes */ +#define HMAC_DRBG_MAX_REQUEST 1024 /**< Maximum number of requested bytes per call */ +#define HMAC_DRBG_MAX_SEED_INPUT 384 /**< Maximum size of (re)seed buffer */ + #ifdef __cplusplus extern "C" { #endif -/* - * Simplified HMAC_DRBG context. - * No reseed counter, no prediction resistance flag. +/** + * HMAC_DRBG context. + * TODO: reseed counter, prediction resistance flag. */ typedef struct { md_context_t md_ctx; unsigned char V[POLARSSL_MD_MAX_SIZE]; unsigned char K[POLARSSL_MD_MAX_SIZE]; + + size_t entropy_len; /*!< entropy bytes grabbed on each (re)seed */ + + /* + * Callbacks (Entropy) + */ + int (*f_entropy)(void *, unsigned char *, size_t); + void *p_entropy; /*!< context for the entropy function */ } hmac_drbg_context; /** @@ -49,18 +70,47 @@ typedef struct * * \param ctx HMAC_DRBG context to be initialised * \param md_info MD algorithm to use for HMAC_DRBG - * \param data Concatenation of entropy string and additional data - * \param data_len Length of data in bytes + * \param f_entropy Entropy callback (p_entropy, buffer to fill, buffer + * length) + * \param p_entropy Entropy context + * \param custom Personalization data (Device specific identifiers) + * (Can be NULL) + * \param len Length of personalization data * - * \todo Use entropy callback rather than buffer. + * \note The "security strength" as defined by NIST is set to: + * 128 bits if md_alg is SHA-1, + * 192 bits if md_alg is SHA-224, + * 256 bits if md_alg is SHA-256 or higher. + * Note that SHA-256 is just as efficient as SHA-224. * * \return 0 if successful, or * POLARSSL_ERR_MD_BAD_INPUT_DATA, or - * POLARSSL_ERR_MD_ALLOC_FAILED + * POLARSSL_ERR_MD_ALLOC_FAILED, or + * POLARSSL_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED. */ int hmac_drbg_init( hmac_drbg_context *ctx, const md_info_t * md_info, - const unsigned char *data, size_t data_len ); + int (*f_entropy)(void *, unsigned char *, size_t), + void *p_entropy, + const unsigned char *custom, + size_t len ); + +/** + * \brief Simplified HMAC_DRBG initialisation. + * (For use with deterministic ECDSA.) + * + * \param ctx HMAC_DRBG context to be initialised + * \param md_info MD algorithm to use for HMAC_DRBG + * \param data Concatenation of entropy string and additional data + * \param data_len Length of data in bytes + * + * \return 0 if successful, or + * POLARSSL_ERR_MD_BAD_INPUT_DATA, or + * POLARSSL_ERR_MD_ALLOC_FAILED. + */ +int hmac_drbg_init_buf( hmac_drbg_context *ctx, + const md_info_t * md_info, + const unsigned char *data, size_t data_len ); /** * \brief HMAC_DRBG update state diff --git a/library/ecdsa.c b/library/ecdsa.c index 92f6eef1e3..12076d536f 100644 --- a/library/ecdsa.c +++ b/library/ecdsa.c @@ -193,7 +193,7 @@ int ecdsa_sign_det( ecp_group *grp, mpi *r, mpi *s, MPI_CHK( mpi_write_binary( d, data, grp_len ) ); MPI_CHK( derive_mpi( grp, &h, buf, blen ) ); MPI_CHK( mpi_write_binary( &h, data + grp_len, grp_len ) ); - hmac_drbg_init( &rng_ctx, md_info, data, 2 * grp_len ); + hmac_drbg_init_buf( &rng_ctx, md_info, data, 2 * grp_len ); ret = ecdsa_sign( grp, r, s, d, buf, blen, hmac_drbg_random, &rng_ctx ); diff --git a/library/hmac_drbg.c b/library/hmac_drbg.c index bc5b908162..a8fe486c85 100644 --- a/library/hmac_drbg.c +++ b/library/hmac_drbg.c @@ -63,11 +63,11 @@ void hmac_drbg_update( hmac_drbg_context *ctx, } /* - * Simplified HMAC_DRBG initialisation. + * Simplified HMAC_DRBG initialisation (for use with deterministic ECDSA) */ -int hmac_drbg_init( hmac_drbg_context *ctx, - const md_info_t * md_info, - const unsigned char *data, size_t data_len ) +int hmac_drbg_init_buf( hmac_drbg_context *ctx, + const md_info_t * md_info, + const unsigned char *data, size_t data_len ) { int ret; @@ -84,6 +84,78 @@ int hmac_drbg_init( hmac_drbg_context *ctx, return( 0 ); } +/* + * HMAC_DRBG initialisation + */ +int hmac_drbg_init( hmac_drbg_context *ctx, + const md_info_t * md_info, + int (*f_entropy)(void *, unsigned char *, size_t), + void *p_entropy, + const unsigned char *custom, + size_t len ) +{ + int ret; + unsigned char seed[HMAC_DRBG_MAX_SEED_INPUT]; + size_t seedlen, init_entropy_len; + + memset( ctx, 0, sizeof( hmac_drbg_context ) ); + + if( ( ret = md_init_ctx( &ctx->md_ctx, md_info ) ) != 0 ) + return( ret ); + + /* + * See SP800-57 5.6.1 (p. 65-66) for the security strength provided by + * each hash function, then according to SP800-90A rev1 10.1 table 2, + * min_entropy_len (in bits) is security_strength. + */ + ctx->entropy_len = md_info->size <= 20 ? 16 : /* 160-bits hash -> 128 */ + md_info->size <= 28 ? 24 : /* 224-bits hash -> 192 */ + 32; /* better (256+) -> 256 */ + + ctx->f_entropy = f_entropy; + ctx->p_entropy = p_entropy; + + /* + * For initialisation, use more entropy to emulate a nonce + */ + init_entropy_len = ctx->entropy_len * 3 / 2; + + if( init_entropy_len + len > HMAC_DRBG_MAX_SEED_INPUT ) + return( POLARSSL_ERR_HMAC_DRBG_INPUT_TOO_BIG ); + + memset( seed, 0, HMAC_DRBG_MAX_SEED_INPUT ); + + /* + * Gather init_entropy_len bytes of entropy for initial seed + */ + if( 0 != ctx->f_entropy( ctx->p_entropy, seed, + init_entropy_len ) ) + { + return( POLARSSL_ERR_HMAC_DRBG_ENTROPY_SOURCE_FAILED ); + } + + seedlen = init_entropy_len; + + /* + * Add additional data + */ + if( custom != NULL && len != 0 ) + { + memcpy( seed + seedlen, custom, len ); + seedlen += len; + } + + /* + * Set initial state and update it with initialisation data + */ + memset( ctx->V, 0x01, md_info->size ); + /* ctx->K is already 0 */ + + hmac_drbg_update( ctx, seed, seedlen ); + + return( 0 ); +} + /* * HMAC_DRBG random function with optional additional data (10.1.2.5) */