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 <tjh@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/7145)
Richard Levitte
5 years ago
17 | 17 | |
18 | 18 | size_t SipHash_ctx_size(void); |
19 | 19 | size_t SipHash_hash_size(SIPHASH *ctx); |
20 | int SipHash_Init(SIPHASH *ctx, const unsigned char *k, int hash_size, | |
20 | int SipHash_set_hash_size(SIPHASH *ctx, size_t hash_size); | |
21 | int SipHash_Init(SIPHASH *ctx, const unsigned char *k, | |
21 | 22 | int crounds, int drounds); |
22 | 23 | void SipHash_Update(SIPHASH *ctx, const unsigned char *in, size_t inlen); |
23 | 24 | int SipHash_Final(SIPHASH *ctx, unsigned char *out, size_t outlen); |
79 | 79 | return ctx->hash_size; |
80 | 80 | } |
81 | 81 | |
82 | static size_t siphash_adjust_hash_size(size_t hash_size) | |
83 | { | |
84 | if (hash_size == 0) | |
85 | hash_size = SIPHASH_MAX_DIGEST_SIZE; | |
86 | return hash_size; | |
87 | } | |
88 | ||
89 | int SipHash_set_hash_size(SIPHASH *ctx, size_t hash_size) | |
90 | { | |
91 | hash_size = siphash_adjust_hash_size(hash_size); | |
92 | if (hash_size != SIPHASH_MIN_DIGEST_SIZE | |
93 | && hash_size != SIPHASH_MAX_DIGEST_SIZE) | |
94 | return 0; | |
95 | ||
96 | ctx->hash_size = hash_size; | |
97 | return 1; | |
98 | } | |
99 | ||
82 | 100 | /* hash_size = crounds = drounds = 0 means SipHash24 with 16-byte output */ |
83 | int SipHash_Init(SIPHASH *ctx, const unsigned char *k, int hash_size, int crounds, int drounds) | |
101 | int SipHash_Init(SIPHASH *ctx, const unsigned char *k, int crounds, int drounds) | |
84 | 102 | { |
85 | 103 | uint64_t k0 = U8TO64_LE(k); |
86 | 104 | uint64_t k1 = U8TO64_LE(k + 8); |
87 | 105 | |
88 | if (hash_size == 0) | |
89 | hash_size = SIPHASH_MAX_DIGEST_SIZE; | |
90 | else if (hash_size != SIPHASH_MIN_DIGEST_SIZE && | |
91 | hash_size != SIPHASH_MAX_DIGEST_SIZE) | |
92 | return 0; | |
106 | /* If the hash size wasn't set, i.e. is zero */ | |
107 | ctx->hash_size = siphash_adjust_hash_size(ctx->hash_size); | |
93 | 108 | |
94 | 109 | if (drounds == 0) |
95 | 110 | drounds = SIPHASH_D_ROUNDS; |
98 | 113 | |
99 | 114 | ctx->crounds = crounds; |
100 | 115 | ctx->drounds = drounds; |
101 | ctx->hash_size = hash_size; | |
102 | 116 | |
103 | 117 | ctx->len = 0; |
104 | 118 | ctx->total_inlen = 0; |
94 | 94 | SIPHASH_PKEY_CTX *pctx = EVP_PKEY_CTX_get_data(ctx); |
95 | 95 | const unsigned char* key; |
96 | 96 | size_t len; |
97 | int hash_size; | |
98 | 97 | |
99 | 98 | key = EVP_PKEY_get0_siphash(EVP_PKEY_CTX_get0_pkey(ctx), &len); |
100 | 99 | if (key == NULL || len != SIPHASH_KEY_SIZE) |
101 | 100 | return 0; |
102 | 101 | EVP_MD_CTX_set_flags(mctx, EVP_MD_CTX_FLAG_NO_INIT); |
103 | 102 | EVP_MD_CTX_set_update_fn(mctx, int_update); |
104 | /* use default rounds (2,4) */ | |
105 | hash_size = SipHash_hash_size(&pctx->ctx); | |
106 | return SipHash_Init(&pctx->ctx, key, hash_size, 0, 0); | |
103 | return SipHash_Init(&pctx->ctx, key, 0, 0); | |
107 | 104 | } |
108 | 105 | static int siphash_signctx(EVP_PKEY_CTX *ctx, unsigned char *sig, size_t *siglen, |
109 | 106 | EVP_MD_CTX *mctx) |
121 | 118 | SIPHASH_PKEY_CTX *pctx = EVP_PKEY_CTX_get_data(ctx); |
122 | 119 | const unsigned char *key; |
123 | 120 | size_t len; |
124 | int hash_size; | |
125 | 121 | |
126 | 122 | switch (type) { |
127 | 123 | |
130 | 126 | break; |
131 | 127 | |
132 | 128 | case EVP_PKEY_CTRL_SET_DIGEST_SIZE: |
133 | if (p1 != SIPHASH_MIN_DIGEST_SIZE && | |
134 | p1 != SIPHASH_MAX_DIGEST_SIZE) { | |
135 | return 0; | |
136 | } | |
137 | /* use default rounds (2,4) */ | |
138 | return SipHash_Init(&pctx->ctx, ASN1_STRING_get0_data(&pctx->ktmp), p1, 0, 0); | |
129 | return SipHash_set_hash_size(&pctx->ctx, p1); | |
139 | 130 | |
140 | 131 | case EVP_PKEY_CTRL_SET_MAC_KEY: |
141 | 132 | case EVP_PKEY_CTRL_DIGESTINIT: |
151 | 142 | !ASN1_OCTET_STRING_set(&pctx->ktmp, key, len)) |
152 | 143 | return 0; |
153 | 144 | /* use default rounds (2,4) */ |
154 | hash_size = SipHash_hash_size(&pctx->ctx); | |
155 | return SipHash_Init(&pctx->ctx, ASN1_STRING_get0_data(&pctx->ktmp), hash_size, 0, 0); | |
145 | return SipHash_Init(&pctx->ctx, ASN1_STRING_get0_data(&pctx->ktmp), | |
146 | 0, 0); | |
156 | 147 | |
157 | 148 | default: |
158 | 149 | return -2; |
195 | 195 | for (i = 0; i < inlen; i++) |
196 | 196 | in[i] = (unsigned char)i; |
197 | 197 | |
198 | if (!TEST_true(SipHash_Init(&siphash, key, expectedlen, 0, 0))) | |
198 | if (!TEST_true(SipHash_set_hash_size(&siphash, expectedlen)) | |
199 | || !TEST_true(SipHash_Init(&siphash, key, 0, 0))) | |
199 | 200 | return 0; |
200 | 201 | SipHash_Update(&siphash, in, inlen); |
201 | 202 | if (!TEST_true(SipHash_Final(&siphash, out, expectedlen)) |
203 | 204 | return 0; |
204 | 205 | |
205 | 206 | if (inlen > 16) { |
206 | if (!TEST_true(SipHash_Init(&siphash, key, expectedlen, 0, 0))) | |
207 | if (!TEST_true(SipHash_set_hash_size(&siphash, expectedlen)) | |
208 | || !TEST_true(SipHash_Init(&siphash, key, 0, 0))) | |
207 | 209 | return 0; |
208 | 210 | SipHash_Update(&siphash, in, 1); |
209 | 211 | SipHash_Update(&siphash, in+1, inlen-1); |
219 | 221 | if (inlen > 32) { |
220 | 222 | size_t half = inlen / 2; |
221 | 223 | |
222 | if (!TEST_true(SipHash_Init(&siphash, key, expectedlen, 0, 0))) | |
224 | if (!TEST_true(SipHash_set_hash_size(&siphash, expectedlen)) | |
225 | || !TEST_true(SipHash_Init(&siphash, key, 0, 0))) | |
223 | 226 | return 0; |
224 | 227 | SipHash_Update(&siphash, in, half); |
225 | 228 | SipHash_Update(&siphash, in+half, inlen-half); |
232 | 235 | } |
233 | 236 | |
234 | 237 | for (half = 16; half < inlen; half += 16) { |
235 | if (!TEST_true(SipHash_Init(&siphash, key, expectedlen, 0, 0))) | |
238 | if (!TEST_true(SipHash_set_hash_size(&siphash, expectedlen)) | |
239 | || !TEST_true(SipHash_Init(&siphash, key, 0, 0))) | |
236 | 240 | return 0; |
237 | 241 | SipHash_Update(&siphash, in, half); |
238 | 242 | SipHash_Update(&siphash, in+half, inlen-half); |
257 | 261 | unsigned char output[SIPHASH_MAX_DIGEST_SIZE]; |
258 | 262 | |
259 | 263 | /* Use invalid hash size */ |
260 | return TEST_int_eq(SipHash_Init(&siphash, key, 4, 0, 0), 0) | |
264 | return TEST_int_eq(SipHash_set_hash_size(&siphash, 4), 0) | |
261 | 265 | /* Use hash size = 8 */ |
262 | && TEST_true(SipHash_Init(&siphash, key, 8, 0, 0)) | |
266 | && TEST_true(SipHash_set_hash_size(&siphash, 8)) | |
267 | && TEST_true(SipHash_Init(&siphash, key, 0, 0)) | |
263 | 268 | && TEST_true(SipHash_Final(&siphash, output, 8)) |
264 | 269 | && TEST_int_eq(SipHash_Final(&siphash, output, 16), 0) |
265 | 270 | |
266 | 271 | /* Use hash size = 16 */ |
267 | && TEST_true(SipHash_Init(&siphash, key, 16, 0, 0)) | |
272 | && TEST_true(SipHash_set_hash_size(&siphash, 16)) | |
273 | && TEST_true(SipHash_Init(&siphash, key, 0, 0)) | |
268 | 274 | && TEST_int_eq(SipHash_Final(&siphash, output, 8), 0) |
269 | 275 | && TEST_true(SipHash_Final(&siphash, output, 16)) |
270 | 276 | |
271 | 277 | /* Use hash size = 0 (default = 16) */ |
272 | && TEST_true(SipHash_Init(&siphash, key, 0, 0, 0)) | |
278 | && TEST_true(SipHash_set_hash_size(&siphash, 0)) | |
279 | && TEST_true(SipHash_Init(&siphash, key, 0, 0)) | |
273 | 280 | && TEST_int_eq(SipHash_Final(&siphash, output, 8), 0) |
274 | 281 | && TEST_true(SipHash_Final(&siphash, output, 16)); |
275 | 282 | } |