From d74f23d2dbf2de0f374bff004c135242cfb65174 Mon Sep 17 00:00:00 2001 From: Richard Levitte Date: Thu, 6 Sep 2018 22:52:38 +0200 Subject: [PATCH] SipHash: add separate setter for the hash size This was originally part of SipHash_Init. However, there are cases where there isn't any key material to initialize from when setting the hash size, and we do allow doing so with a EVP_PKEY control. The solution is to provide a separate hash_size setter and to use it in the corresponding EVP_PKEY_METHOD. Fixes #7143 Reviewed-by: Tim Hudson (Merged from https://github.com/openssl/openssl/pull/7145) --- crypto/include/internal/siphash.h | 3 ++- crypto/siphash/siphash.c | 28 +++++++++++++++++++++------- crypto/siphash/siphash_pmeth.c | 17 ++++------------- test/siphash_internal_test.c | 23 +++++++++++++++-------- 4 files changed, 42 insertions(+), 29 deletions(-) diff --git a/crypto/include/internal/siphash.h b/crypto/include/internal/siphash.h index e086859622..d8bcdcaa4a 100644 --- a/crypto/include/internal/siphash.h +++ b/crypto/include/internal/siphash.h @@ -18,7 +18,8 @@ typedef struct siphash_st SIPHASH; size_t SipHash_ctx_size(void); size_t SipHash_hash_size(SIPHASH *ctx); -int SipHash_Init(SIPHASH *ctx, const unsigned char *k, int hash_size, +int SipHash_set_hash_size(SIPHASH *ctx, size_t hash_size); +int SipHash_Init(SIPHASH *ctx, const unsigned char *k, int crounds, int drounds); void SipHash_Update(SIPHASH *ctx, const unsigned char *in, size_t inlen); int SipHash_Final(SIPHASH *ctx, unsigned char *out, size_t outlen); diff --git a/crypto/siphash/siphash.c b/crypto/siphash/siphash.c index 72fd5198b8..e2352fc730 100644 --- a/crypto/siphash/siphash.c +++ b/crypto/siphash/siphash.c @@ -80,17 +80,32 @@ size_t SipHash_hash_size(SIPHASH *ctx) return ctx->hash_size; } +static size_t siphash_adjust_hash_size(size_t hash_size) +{ + if (hash_size == 0) + hash_size = SIPHASH_MAX_DIGEST_SIZE; + return hash_size; +} + +int SipHash_set_hash_size(SIPHASH *ctx, size_t hash_size) +{ + hash_size = siphash_adjust_hash_size(hash_size); + if (hash_size != SIPHASH_MIN_DIGEST_SIZE + && hash_size != SIPHASH_MAX_DIGEST_SIZE) + return 0; + + ctx->hash_size = hash_size; + return 1; +} + /* hash_size = crounds = drounds = 0 means SipHash24 with 16-byte output */ -int SipHash_Init(SIPHASH *ctx, const unsigned char *k, int hash_size, int crounds, int drounds) +int SipHash_Init(SIPHASH *ctx, const unsigned char *k, int crounds, int drounds) { uint64_t k0 = U8TO64_LE(k); uint64_t k1 = U8TO64_LE(k + 8); - if (hash_size == 0) - hash_size = SIPHASH_MAX_DIGEST_SIZE; - else if (hash_size != SIPHASH_MIN_DIGEST_SIZE && - hash_size != SIPHASH_MAX_DIGEST_SIZE) - return 0; + /* If the hash size wasn't set, i.e. is zero */ + ctx->hash_size = siphash_adjust_hash_size(ctx->hash_size); if (drounds == 0) drounds = SIPHASH_D_ROUNDS; @@ -99,7 +114,6 @@ int SipHash_Init(SIPHASH *ctx, const unsigned char *k, int hash_size, int cround ctx->crounds = crounds; ctx->drounds = drounds; - ctx->hash_size = hash_size; ctx->len = 0; ctx->total_inlen = 0; diff --git a/crypto/siphash/siphash_pmeth.c b/crypto/siphash/siphash_pmeth.c index 5c981bdb0b..66e552fec5 100644 --- a/crypto/siphash/siphash_pmeth.c +++ b/crypto/siphash/siphash_pmeth.c @@ -95,16 +95,13 @@ static int siphash_signctx_init(EVP_PKEY_CTX *ctx, EVP_MD_CTX *mctx) SIPHASH_PKEY_CTX *pctx = EVP_PKEY_CTX_get_data(ctx); const unsigned char* key; size_t len; - int hash_size; key = EVP_PKEY_get0_siphash(EVP_PKEY_CTX_get0_pkey(ctx), &len); if (key == NULL || len != SIPHASH_KEY_SIZE) return 0; EVP_MD_CTX_set_flags(mctx, EVP_MD_CTX_FLAG_NO_INIT); EVP_MD_CTX_set_update_fn(mctx, int_update); - /* use default rounds (2,4) */ - hash_size = SipHash_hash_size(&pctx->ctx); - return SipHash_Init(&pctx->ctx, key, hash_size, 0, 0); + return SipHash_Init(&pctx->ctx, key, 0, 0); } static int siphash_signctx(EVP_PKEY_CTX *ctx, unsigned char *sig, size_t *siglen, EVP_MD_CTX *mctx) @@ -122,7 +119,6 @@ static int pkey_siphash_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2) SIPHASH_PKEY_CTX *pctx = EVP_PKEY_CTX_get_data(ctx); const unsigned char *key; size_t len; - int hash_size; switch (type) { @@ -131,12 +127,7 @@ static int pkey_siphash_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2) break; case EVP_PKEY_CTRL_SET_DIGEST_SIZE: - if (p1 != SIPHASH_MIN_DIGEST_SIZE && - p1 != SIPHASH_MAX_DIGEST_SIZE) { - return 0; - } - /* use default rounds (2,4) */ - return SipHash_Init(&pctx->ctx, ASN1_STRING_get0_data(&pctx->ktmp), p1, 0, 0); + return SipHash_set_hash_size(&pctx->ctx, p1); case EVP_PKEY_CTRL_SET_MAC_KEY: case EVP_PKEY_CTRL_DIGESTINIT: @@ -152,8 +143,8 @@ static int pkey_siphash_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2) !ASN1_OCTET_STRING_set(&pctx->ktmp, key, len)) return 0; /* use default rounds (2,4) */ - hash_size = SipHash_hash_size(&pctx->ctx); - return SipHash_Init(&pctx->ctx, ASN1_STRING_get0_data(&pctx->ktmp), hash_size, 0, 0); + return SipHash_Init(&pctx->ctx, ASN1_STRING_get0_data(&pctx->ktmp), + 0, 0); default: return -2; diff --git a/test/siphash_internal_test.c b/test/siphash_internal_test.c index 573c15d254..dfdce48d13 100644 --- a/test/siphash_internal_test.c +++ b/test/siphash_internal_test.c @@ -196,7 +196,8 @@ static int test_siphash(int idx) for (i = 0; i < inlen; i++) in[i] = (unsigned char)i; - if (!TEST_true(SipHash_Init(&siphash, key, expectedlen, 0, 0))) + if (!TEST_true(SipHash_set_hash_size(&siphash, expectedlen)) + || !TEST_true(SipHash_Init(&siphash, key, 0, 0))) return 0; SipHash_Update(&siphash, in, inlen); if (!TEST_true(SipHash_Final(&siphash, out, expectedlen)) @@ -204,7 +205,8 @@ static int test_siphash(int idx) return 0; if (inlen > 16) { - if (!TEST_true(SipHash_Init(&siphash, key, expectedlen, 0, 0))) + if (!TEST_true(SipHash_set_hash_size(&siphash, expectedlen)) + || !TEST_true(SipHash_Init(&siphash, key, 0, 0))) return 0; SipHash_Update(&siphash, in, 1); SipHash_Update(&siphash, in+1, inlen-1); @@ -220,7 +222,8 @@ static int test_siphash(int idx) if (inlen > 32) { size_t half = inlen / 2; - if (!TEST_true(SipHash_Init(&siphash, key, expectedlen, 0, 0))) + if (!TEST_true(SipHash_set_hash_size(&siphash, expectedlen)) + || !TEST_true(SipHash_Init(&siphash, key, 0, 0))) return 0; SipHash_Update(&siphash, in, half); SipHash_Update(&siphash, in+half, inlen-half); @@ -233,7 +236,8 @@ static int test_siphash(int idx) } for (half = 16; half < inlen; half += 16) { - if (!TEST_true(SipHash_Init(&siphash, key, expectedlen, 0, 0))) + if (!TEST_true(SipHash_set_hash_size(&siphash, expectedlen)) + || !TEST_true(SipHash_Init(&siphash, key, 0, 0))) return 0; SipHash_Update(&siphash, in, half); SipHash_Update(&siphash, in+half, inlen-half); @@ -258,19 +262,22 @@ static int test_siphash_basic(void) unsigned char output[SIPHASH_MAX_DIGEST_SIZE]; /* Use invalid hash size */ - return TEST_int_eq(SipHash_Init(&siphash, key, 4, 0, 0), 0) + return TEST_int_eq(SipHash_set_hash_size(&siphash, 4), 0) /* Use hash size = 8 */ - && TEST_true(SipHash_Init(&siphash, key, 8, 0, 0)) + && TEST_true(SipHash_set_hash_size(&siphash, 8)) + && TEST_true(SipHash_Init(&siphash, key, 0, 0)) && TEST_true(SipHash_Final(&siphash, output, 8)) && TEST_int_eq(SipHash_Final(&siphash, output, 16), 0) /* Use hash size = 16 */ - && TEST_true(SipHash_Init(&siphash, key, 16, 0, 0)) + && TEST_true(SipHash_set_hash_size(&siphash, 16)) + && TEST_true(SipHash_Init(&siphash, key, 0, 0)) && TEST_int_eq(SipHash_Final(&siphash, output, 8), 0) && TEST_true(SipHash_Final(&siphash, output, 16)) /* Use hash size = 0 (default = 16) */ - && TEST_true(SipHash_Init(&siphash, key, 0, 0, 0)) + && TEST_true(SipHash_set_hash_size(&siphash, 0)) + && TEST_true(SipHash_Init(&siphash, key, 0, 0)) && TEST_int_eq(SipHash_Final(&siphash, output, 8), 0) && TEST_true(SipHash_Final(&siphash, output, 16)); } -- 2.34.1