1 /*
2 * hmac.c
3 *
4 * implementation of hmac srtp_auth_type_t
5 *
6 * David A. McGrew
7 * Cisco Systems, Inc.
8 */
9 /*
10 *
11 * Copyright(c) 2001-2017 Cisco Systems, Inc.
12 * All rights reserved.
13 *
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions
16 * are met:
17 *
18 * Redistributions of source code must retain the above copyright
19 * notice, this list of conditions and the following disclaimer.
20 *
21 * Redistributions in binary form must reproduce the above
22 * copyright notice, this list of conditions and the following
23 * disclaimer in the documentation and/or other materials provided
24 * with the distribution.
25 *
26 * Neither the name of the Cisco Systems, Inc. nor the names of its
27 * contributors may be used to endorse or promote products derived
28 * from this software without specific prior written permission.
29 *
30 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
31 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
32 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
33 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
34 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
35 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
36 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
37 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
40 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
41 * OF THE POSSIBILITY OF SUCH DAMAGE.
42 *
43 */
44
45 #ifdef HAVE_CONFIG_H
46 #include <config.h>
47 #endif
48
49 #include "hmac.h"
50 #include "alloc.h"
51 #include "cipher_types.h"
52
53 /* the debug module for authentiation */
54
55 srtp_debug_module_t srtp_mod_hmac = {
56 0, /* debugging is off by default */
57 "hmac sha-1" /* printable name for module */
58 };
59
srtp_hmac_alloc(srtp_auth_t ** a,int key_len,int out_len)60 static srtp_err_status_t srtp_hmac_alloc(srtp_auth_t **a,
61 int key_len,
62 int out_len)
63 {
64 extern const srtp_auth_type_t srtp_hmac;
65 uint8_t *pointer;
66
67 debug_print(srtp_mod_hmac, "allocating auth func with key length %d",
68 key_len);
69 debug_print(srtp_mod_hmac, " tag length %d",
70 out_len);
71
72 /*
73 * check key length - note that we don't support keys larger
74 * than 20 bytes yet
75 */
76 if (key_len > 20) {
77 return srtp_err_status_bad_param;
78 }
79
80 /* check output length - should be less than 20 bytes */
81 if (out_len > 20) {
82 return srtp_err_status_bad_param;
83 }
84
85 /* allocate memory for auth and srtp_hmac_ctx_t structures */
86 pointer = (uint8_t *)srtp_crypto_alloc(sizeof(srtp_hmac_ctx_t) +
87 sizeof(srtp_auth_t));
88 if (pointer == NULL) {
89 return srtp_err_status_alloc_fail;
90 }
91
92 /* set pointers */
93 *a = (srtp_auth_t *)pointer;
94 (*a)->type = &srtp_hmac;
95 (*a)->state = pointer + sizeof(srtp_auth_t);
96 (*a)->out_len = out_len;
97 (*a)->key_len = key_len;
98 (*a)->prefix_len = 0;
99
100 return srtp_err_status_ok;
101 }
102
srtp_hmac_dealloc(srtp_auth_t * a)103 static srtp_err_status_t srtp_hmac_dealloc(srtp_auth_t *a)
104 {
105 /* zeroize entire state*/
106 octet_string_set_to_zero(a, sizeof(srtp_hmac_ctx_t) + sizeof(srtp_auth_t));
107
108 /* free memory */
109 srtp_crypto_free(a);
110
111 return srtp_err_status_ok;
112 }
113
srtp_hmac_init(void * statev,const uint8_t * key,int key_len)114 static srtp_err_status_t srtp_hmac_init(void *statev,
115 const uint8_t *key,
116 int key_len)
117 {
118 srtp_hmac_ctx_t *state = (srtp_hmac_ctx_t *)statev;
119 int i;
120 uint8_t ipad[64];
121
122 /*
123 * check key length - note that we don't support keys larger
124 * than 20 bytes yet
125 */
126 if (key_len > 20) {
127 return srtp_err_status_bad_param;
128 }
129
130 /*
131 * set values of ipad and opad by exoring the key into the
132 * appropriate constant values
133 */
134 for (i = 0; i < key_len; i++) {
135 ipad[i] = key[i] ^ 0x36;
136 state->opad[i] = key[i] ^ 0x5c;
137 }
138 /* set the rest of ipad, opad to constant values */
139 for (; i < 64; i++) {
140 ipad[i] = 0x36;
141 ((uint8_t *)state->opad)[i] = 0x5c;
142 }
143
144 debug_print(srtp_mod_hmac, "ipad: %s",
145 srtp_octet_string_hex_string(ipad, 64));
146
147 /* initialize sha1 context */
148 srtp_sha1_init(&state->init_ctx);
149
150 /* hash ipad ^ key */
151 srtp_sha1_update(&state->init_ctx, ipad, 64);
152 memcpy(&state->ctx, &state->init_ctx, sizeof(srtp_sha1_ctx_t));
153
154 return srtp_err_status_ok;
155 }
156
srtp_hmac_start(void * statev)157 static srtp_err_status_t srtp_hmac_start(void *statev)
158 {
159 srtp_hmac_ctx_t *state = (srtp_hmac_ctx_t *)statev;
160
161 memcpy(&state->ctx, &state->init_ctx, sizeof(srtp_sha1_ctx_t));
162
163 return srtp_err_status_ok;
164 }
165
srtp_hmac_update(void * statev,const uint8_t * message,int msg_octets)166 static srtp_err_status_t srtp_hmac_update(void *statev,
167 const uint8_t *message,
168 int msg_octets)
169 {
170 srtp_hmac_ctx_t *state = (srtp_hmac_ctx_t *)statev;
171
172 debug_print(srtp_mod_hmac, "input: %s",
173 srtp_octet_string_hex_string(message, msg_octets));
174
175 /* hash message into sha1 context */
176 srtp_sha1_update(&state->ctx, message, msg_octets);
177
178 return srtp_err_status_ok;
179 }
180
srtp_hmac_compute(void * statev,const uint8_t * message,int msg_octets,int tag_len,uint8_t * result)181 static srtp_err_status_t srtp_hmac_compute(void *statev,
182 const uint8_t *message,
183 int msg_octets,
184 int tag_len,
185 uint8_t *result)
186 {
187 srtp_hmac_ctx_t *state = (srtp_hmac_ctx_t *)statev;
188 uint32_t hash_value[5];
189 uint32_t H[5];
190 int i;
191
192 /* check tag length, return error if we can't provide the value expected */
193 if (tag_len > 20) {
194 return srtp_err_status_bad_param;
195 }
196
197 /* hash message, copy output into H */
198 srtp_hmac_update(state, message, msg_octets);
199 srtp_sha1_final(&state->ctx, H);
200
201 /*
202 * note that we don't need to debug_print() the input, since the
203 * function hmac_update() already did that for us
204 */
205 debug_print(srtp_mod_hmac, "intermediate state: %s",
206 srtp_octet_string_hex_string((uint8_t *)H, 20));
207
208 /* re-initialize hash context */
209 srtp_sha1_init(&state->ctx);
210
211 /* hash opad ^ key */
212 srtp_sha1_update(&state->ctx, (uint8_t *)state->opad, 64);
213
214 /* hash the result of the inner hash */
215 srtp_sha1_update(&state->ctx, (uint8_t *)H, 20);
216
217 /* the result is returned in the array hash_value[] */
218 srtp_sha1_final(&state->ctx, hash_value);
219
220 /* copy hash_value to *result */
221 for (i = 0; i < tag_len; i++) {
222 result[i] = ((uint8_t *)hash_value)[i];
223 }
224
225 debug_print(srtp_mod_hmac, "output: %s",
226 srtp_octet_string_hex_string((uint8_t *)hash_value, tag_len));
227
228 return srtp_err_status_ok;
229 }
230
231 /* begin test case 0 */
232 /* clang-format off */
233 static const uint8_t srtp_hmac_test_case_0_key[20] = {
234 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
235 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
236 0x0b, 0x0b, 0x0b, 0x0b
237 };
238 /* clang-format on */
239
240 /* clang-format off */
241 static const uint8_t srtp_hmac_test_case_0_data[8] = {
242 0x48, 0x69, 0x20, 0x54, 0x68, 0x65, 0x72, 0x65 /* "Hi There" */
243 };
244 /* clang-format on */
245
246 /* clang-format off */
247 static const uint8_t srtp_hmac_test_case_0_tag[20] = {
248 0xb6, 0x17, 0x31, 0x86, 0x55, 0x05, 0x72, 0x64,
249 0xe2, 0x8b, 0xc0, 0xb6, 0xfb, 0x37, 0x8c, 0x8e,
250 0xf1, 0x46, 0xbe, 0x00
251 };
252 /* clang-format on */
253
254 static const srtp_auth_test_case_t srtp_hmac_test_case_0 = {
255 20, /* octets in key */
256 srtp_hmac_test_case_0_key, /* key */
257 8, /* octets in data */
258 srtp_hmac_test_case_0_data, /* data */
259 20, /* octets in tag */
260 srtp_hmac_test_case_0_tag, /* tag */
261 NULL /* pointer to next testcase */
262 };
263
264 /* end test case 0 */
265
266 static const char srtp_hmac_description[] =
267 "hmac sha-1 authentication function";
268
269 /*
270 * srtp_auth_type_t hmac is the hmac metaobject
271 */
272
273 const srtp_auth_type_t srtp_hmac = {
274 srtp_hmac_alloc, /* */
275 srtp_hmac_dealloc, /* */
276 srtp_hmac_init, /* */
277 srtp_hmac_compute, /* */
278 srtp_hmac_update, /* */
279 srtp_hmac_start, /* */
280 srtp_hmac_description, /* */
281 &srtp_hmac_test_case_0, /* */
282 SRTP_HMAC_SHA1 /* */
283 };
284