/src/libsrtp/crypto/hash/hmac.c
Line | Count | Source (jump to first uncovered line) |
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 | | #include "auth_test_cases.h" |
53 | | |
54 | | /* the debug module for authentiation */ |
55 | | |
56 | | srtp_debug_module_t srtp_mod_hmac = { |
57 | | false, /* debugging is off by default */ |
58 | | "hmac sha-1" /* printable name for module */ |
59 | | }; |
60 | | |
61 | | static srtp_err_status_t srtp_hmac_alloc(srtp_auth_t **a, |
62 | | size_t key_len, |
63 | | size_t out_len) |
64 | 3.83k | { |
65 | 3.83k | extern const srtp_auth_type_t srtp_hmac; |
66 | 3.83k | uint8_t *pointer; |
67 | | |
68 | 3.83k | debug_print(srtp_mod_hmac, "allocating auth func with key length %zu", |
69 | 3.83k | key_len); |
70 | 3.83k | debug_print(srtp_mod_hmac, " tag length %zu", |
71 | 3.83k | out_len); |
72 | | |
73 | | /* |
74 | | * check key length - note that we don't support keys larger |
75 | | * than 20 bytes yet |
76 | | */ |
77 | 3.83k | if (key_len > 20) { |
78 | 0 | return srtp_err_status_bad_param; |
79 | 0 | } |
80 | | |
81 | | /* check output length - should be less than 20 bytes */ |
82 | 3.83k | if (out_len > 20) { |
83 | 0 | return srtp_err_status_bad_param; |
84 | 0 | } |
85 | | |
86 | | /* allocate memory for auth and srtp_hmac_ctx_t structures */ |
87 | 3.83k | pointer = (uint8_t *)srtp_crypto_alloc(sizeof(srtp_hmac_ctx_t) + |
88 | 3.83k | sizeof(srtp_auth_t)); |
89 | 3.83k | if (pointer == NULL) { |
90 | 0 | return srtp_err_status_alloc_fail; |
91 | 0 | } |
92 | | |
93 | | /* set pointers */ |
94 | 3.83k | *a = (srtp_auth_t *)pointer; |
95 | 3.83k | (*a)->type = &srtp_hmac; |
96 | 3.83k | (*a)->state = pointer + sizeof(srtp_auth_t); |
97 | 3.83k | (*a)->out_len = out_len; |
98 | 3.83k | (*a)->key_len = key_len; |
99 | 3.83k | (*a)->prefix_len = 0; |
100 | | |
101 | 3.83k | return srtp_err_status_ok; |
102 | 3.83k | } |
103 | | |
104 | | static srtp_err_status_t srtp_hmac_dealloc(srtp_auth_t *a) |
105 | 3.83k | { |
106 | | /* zeroize entire state*/ |
107 | 3.83k | octet_string_set_to_zero(a, sizeof(srtp_hmac_ctx_t) + sizeof(srtp_auth_t)); |
108 | | |
109 | | /* free memory */ |
110 | 3.83k | srtp_crypto_free(a); |
111 | | |
112 | 3.83k | return srtp_err_status_ok; |
113 | 3.83k | } |
114 | | |
115 | | static srtp_err_status_t srtp_hmac_init(void *statev, |
116 | | const uint8_t *key, |
117 | | size_t key_len) |
118 | 3.76k | { |
119 | 3.76k | srtp_hmac_ctx_t *state = (srtp_hmac_ctx_t *)statev; |
120 | 3.76k | 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 | 3.76k | if (key_len > 20) { |
127 | 0 | return srtp_err_status_bad_param; |
128 | 0 | } |
129 | | |
130 | | /* |
131 | | * set values of ipad and opad by exoring the key into the |
132 | | * appropriate constant values |
133 | | */ |
134 | 79.0k | for (size_t i = 0; i < key_len; i++) { |
135 | 75.3k | ipad[i] = key[i] ^ 0x36; |
136 | 75.3k | state->opad[i] = key[i] ^ 0x5c; |
137 | 75.3k | } |
138 | | /* set the rest of ipad, opad to constant values */ |
139 | 169k | for (size_t i = key_len; i < 64; i++) { |
140 | 165k | ipad[i] = 0x36; |
141 | 165k | ((uint8_t *)state->opad)[i] = 0x5c; |
142 | 165k | } |
143 | | |
144 | 3.76k | debug_print(srtp_mod_hmac, "ipad: %s", |
145 | 3.76k | srtp_octet_string_hex_string(ipad, 64)); |
146 | | |
147 | | /* initialize sha1 context */ |
148 | 3.76k | srtp_sha1_init(&state->init_ctx); |
149 | | |
150 | | /* hash ipad ^ key */ |
151 | 3.76k | srtp_sha1_update(&state->init_ctx, ipad, 64); |
152 | 3.76k | memcpy(&state->ctx, &state->init_ctx, sizeof(srtp_sha1_ctx_t)); |
153 | | |
154 | 3.76k | return srtp_err_status_ok; |
155 | 3.76k | } |
156 | | |
157 | | static srtp_err_status_t srtp_hmac_start(void *statev) |
158 | 23.0k | { |
159 | 23.0k | srtp_hmac_ctx_t *state = (srtp_hmac_ctx_t *)statev; |
160 | | |
161 | 23.0k | memcpy(&state->ctx, &state->init_ctx, sizeof(srtp_sha1_ctx_t)); |
162 | | |
163 | 23.0k | return srtp_err_status_ok; |
164 | 23.0k | } |
165 | | |
166 | | static srtp_err_status_t srtp_hmac_update(void *statev, |
167 | | const uint8_t *message, |
168 | | size_t msg_octets) |
169 | 37.7k | { |
170 | 37.7k | srtp_hmac_ctx_t *state = (srtp_hmac_ctx_t *)statev; |
171 | | |
172 | 37.7k | debug_print(srtp_mod_hmac, "input: %s", |
173 | 37.7k | srtp_octet_string_hex_string(message, msg_octets)); |
174 | | |
175 | | /* hash message into sha1 context */ |
176 | 37.7k | srtp_sha1_update(&state->ctx, message, msg_octets); |
177 | | |
178 | 37.7k | return srtp_err_status_ok; |
179 | 37.7k | } |
180 | | |
181 | | static srtp_err_status_t srtp_hmac_compute(void *statev, |
182 | | const uint8_t *message, |
183 | | size_t msg_octets, |
184 | | size_t tag_len, |
185 | | uint8_t *result) |
186 | 23.0k | { |
187 | 23.0k | srtp_hmac_ctx_t *state = (srtp_hmac_ctx_t *)statev; |
188 | 23.0k | uint32_t hash_value[5]; |
189 | 23.0k | uint32_t H[5]; |
190 | 23.0k | size_t i; |
191 | | |
192 | | /* check tag length, return error if we can't provide the value expected */ |
193 | 23.0k | if (tag_len > 20) { |
194 | 0 | return srtp_err_status_bad_param; |
195 | 0 | } |
196 | | |
197 | | /* hash message, copy output into H */ |
198 | 23.0k | srtp_hmac_update(state, message, msg_octets); |
199 | 23.0k | 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 | 23.0k | debug_print(srtp_mod_hmac, "intermediate state: %s", |
206 | 23.0k | srtp_octet_string_hex_string((uint8_t *)H, 20)); |
207 | | |
208 | | /* re-initialize hash context */ |
209 | 23.0k | srtp_sha1_init(&state->ctx); |
210 | | |
211 | | /* hash opad ^ key */ |
212 | 23.0k | srtp_sha1_update(&state->ctx, (uint8_t *)state->opad, 64); |
213 | | |
214 | | /* hash the result of the inner hash */ |
215 | 23.0k | srtp_sha1_update(&state->ctx, (uint8_t *)H, 20); |
216 | | |
217 | | /* the result is returned in the array hash_value[] */ |
218 | 23.0k | srtp_sha1_final(&state->ctx, hash_value); |
219 | | |
220 | | /* copy hash_value to *result */ |
221 | 186k | for (i = 0; i < tag_len; i++) { |
222 | 163k | result[i] = ((uint8_t *)hash_value)[i]; |
223 | 163k | } |
224 | | |
225 | 23.0k | debug_print(srtp_mod_hmac, "output: %s", |
226 | 23.0k | srtp_octet_string_hex_string((uint8_t *)hash_value, tag_len)); |
227 | | |
228 | 23.0k | return srtp_err_status_ok; |
229 | 23.0k | } |
230 | | |
231 | | static const char srtp_hmac_description[] = |
232 | | "hmac sha-1 authentication function"; |
233 | | |
234 | | /* |
235 | | * srtp_auth_type_t hmac is the hmac metaobject |
236 | | */ |
237 | | |
238 | | const srtp_auth_type_t srtp_hmac = { |
239 | | srtp_hmac_alloc, /* */ |
240 | | srtp_hmac_dealloc, /* */ |
241 | | srtp_hmac_init, /* */ |
242 | | srtp_hmac_compute, /* */ |
243 | | srtp_hmac_update, /* */ |
244 | | srtp_hmac_start, /* */ |
245 | | srtp_hmac_description, /* */ |
246 | | &srtp_hmac_test_case_0, /* */ |
247 | | SRTP_HMAC_SHA1 /* */ |
248 | | }; |