/src/libsrtp/crypto/cipher/aes_icm.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * aes_icm.c |
3 | | * |
4 | | * AES Integer Counter Mode |
5 | | * |
6 | | * David A. McGrew |
7 | | * Cisco Systems, Inc. |
8 | | */ |
9 | | |
10 | | /* |
11 | | * |
12 | | * Copyright (c) 2001-2017 Cisco Systems, Inc. |
13 | | * All rights reserved. |
14 | | * |
15 | | * Redistribution and use in source and binary forms, with or without |
16 | | * modification, are permitted provided that the following conditions |
17 | | * are met: |
18 | | * |
19 | | * Redistributions of source code must retain the above copyright |
20 | | * notice, this list of conditions and the following disclaimer. |
21 | | * |
22 | | * Redistributions in binary form must reproduce the above |
23 | | * copyright notice, this list of conditions and the following |
24 | | * disclaimer in the documentation and/or other materials provided |
25 | | * with the distribution. |
26 | | * |
27 | | * Neither the name of the Cisco Systems, Inc. nor the names of its |
28 | | * contributors may be used to endorse or promote products derived |
29 | | * from this software without specific prior written permission. |
30 | | * |
31 | | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
32 | | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
33 | | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
34 | | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
35 | | * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, |
36 | | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
37 | | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
38 | | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
39 | | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, |
40 | | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
41 | | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED |
42 | | * OF THE POSSIBILITY OF SUCH DAMAGE. |
43 | | * |
44 | | */ |
45 | | |
46 | | #ifdef HAVE_CONFIG_H |
47 | | #include <config.h> |
48 | | #endif |
49 | | |
50 | | #define ALIGN_32 0 |
51 | | |
52 | | #include "aes_icm.h" |
53 | | #include "alloc.h" |
54 | | #include "cipher_types.h" |
55 | | #include "cipher_test_cases.h" |
56 | | |
57 | | srtp_debug_module_t srtp_mod_aes_icm = { |
58 | | false, /* debugging is off by default */ |
59 | | "aes icm" /* printable module name */ |
60 | | }; |
61 | | |
62 | | /* |
63 | | * integer counter mode works as follows: |
64 | | * |
65 | | * 16 bits |
66 | | * <-----> |
67 | | * +------+------+------+------+------+------+------+------+ |
68 | | * | nonce | pakcet index | ctr |---+ |
69 | | * +------+------+------+------+------+------+------+------+ | |
70 | | * | |
71 | | * +------+------+------+------+------+------+------+------+ v |
72 | | * | salt |000000|->(+) |
73 | | * +------+------+------+------+------+------+------+------+ | |
74 | | * | |
75 | | * +---------+ |
76 | | * | encrypt | |
77 | | * +---------+ |
78 | | * | |
79 | | * +------+------+------+------+------+------+------+------+ | |
80 | | * | keystream block |<--+ |
81 | | * +------+------+------+------+------+------+------+------+ |
82 | | * |
83 | | * All fields are big-endian |
84 | | * |
85 | | * ctr is the block counter, which increments from zero for |
86 | | * each packet (16 bits wide) |
87 | | * |
88 | | * packet index is distinct for each packet (48 bits wide) |
89 | | * |
90 | | * nonce can be distinct across many uses of the same key, or |
91 | | * can be a fixed value per key, or can be per-packet randomness |
92 | | * (64 bits) |
93 | | * |
94 | | */ |
95 | | |
96 | | static srtp_err_status_t srtp_aes_icm_alloc(srtp_cipher_t **c, |
97 | | size_t key_len, |
98 | | size_t tlen) |
99 | 27.9k | { |
100 | 27.9k | srtp_aes_icm_ctx_t *icm; |
101 | 27.9k | (void)tlen; |
102 | | |
103 | 27.9k | debug_print(srtp_mod_aes_icm, "allocating cipher with key length %zu", |
104 | 27.9k | key_len); |
105 | | |
106 | | /* |
107 | | * The check for key_len = 30/46 does not apply. Our usage |
108 | | * of aes functions with key_len = values other than 30 |
109 | | * has not broken anything. Don't know what would be the |
110 | | * effect of skipping this check for srtp in general. |
111 | | */ |
112 | 27.9k | if (key_len != SRTP_AES_ICM_128_KEY_LEN_WSALT && |
113 | 27.9k | key_len != SRTP_AES_ICM_256_KEY_LEN_WSALT) { |
114 | 0 | return srtp_err_status_bad_param; |
115 | 0 | } |
116 | | |
117 | | /* allocate memory a cipher of type aes_icm */ |
118 | 27.9k | *c = (srtp_cipher_t *)srtp_crypto_alloc(sizeof(srtp_cipher_t)); |
119 | 27.9k | if (*c == NULL) { |
120 | 0 | return srtp_err_status_alloc_fail; |
121 | 0 | } |
122 | | |
123 | 27.9k | icm = (srtp_aes_icm_ctx_t *)srtp_crypto_alloc(sizeof(srtp_aes_icm_ctx_t)); |
124 | 27.9k | if (icm == NULL) { |
125 | 0 | srtp_crypto_free(*c); |
126 | 0 | *c = NULL; |
127 | 0 | return srtp_err_status_alloc_fail; |
128 | 0 | } |
129 | | |
130 | | /* set pointers */ |
131 | 27.9k | (*c)->state = icm; |
132 | | |
133 | 27.9k | switch (key_len) { |
134 | 2.73k | case SRTP_AES_ICM_256_KEY_LEN_WSALT: |
135 | 2.73k | (*c)->algorithm = SRTP_AES_ICM_256; |
136 | 2.73k | (*c)->type = &srtp_aes_icm_256; |
137 | 2.73k | break; |
138 | 25.2k | default: |
139 | 25.2k | (*c)->algorithm = SRTP_AES_ICM_128; |
140 | 25.2k | (*c)->type = &srtp_aes_icm_128; |
141 | 25.2k | break; |
142 | 27.9k | } |
143 | | |
144 | | /* set key size */ |
145 | 27.9k | icm->key_size = key_len; |
146 | 27.9k | (*c)->key_len = key_len; |
147 | | |
148 | 27.9k | return srtp_err_status_ok; |
149 | 27.9k | } |
150 | | |
151 | | static srtp_err_status_t srtp_aes_icm_dealloc(srtp_cipher_t *c) |
152 | 27.9k | { |
153 | 27.9k | srtp_aes_icm_ctx_t *ctx; |
154 | | |
155 | 27.9k | if (c == NULL) { |
156 | 0 | return srtp_err_status_bad_param; |
157 | 0 | } |
158 | | |
159 | 27.9k | ctx = (srtp_aes_icm_ctx_t *)c->state; |
160 | 27.9k | if (ctx) { |
161 | | /* zeroize the key material */ |
162 | 27.9k | octet_string_set_to_zero(ctx, sizeof(srtp_aes_icm_ctx_t)); |
163 | 27.9k | srtp_crypto_free(ctx); |
164 | 27.9k | } |
165 | | |
166 | | /* free the cipher context */ |
167 | 27.9k | srtp_crypto_free(c); |
168 | | |
169 | 27.9k | return srtp_err_status_ok; |
170 | 27.9k | } |
171 | | |
172 | | /* |
173 | | * aes_icm_context_init(...) initializes the aes_icm_context |
174 | | * using the value in key[]. |
175 | | * |
176 | | * the key is the secret key |
177 | | * |
178 | | * the salt is unpredictable (but not necessarily secret) data which |
179 | | * randomizes the starting point in the keystream |
180 | | */ |
181 | | |
182 | | static srtp_err_status_t srtp_aes_icm_context_init(void *cv, const uint8_t *key) |
183 | 28.9k | { |
184 | 28.9k | srtp_aes_icm_ctx_t *c = (srtp_aes_icm_ctx_t *)cv; |
185 | 28.9k | srtp_err_status_t status; |
186 | 28.9k | size_t base_key_len, copy_len; |
187 | | |
188 | 28.9k | if (c->key_size == SRTP_AES_ICM_128_KEY_LEN_WSALT || |
189 | 28.9k | c->key_size == SRTP_AES_ICM_256_KEY_LEN_WSALT) { |
190 | 28.9k | base_key_len = c->key_size - SRTP_SALT_LEN; |
191 | 28.9k | } else { |
192 | 0 | return srtp_err_status_bad_param; |
193 | 0 | } |
194 | | |
195 | | /* |
196 | | * set counter and initial values to 'offset' value, being careful not to |
197 | | * go past the end of the key buffer |
198 | | */ |
199 | 28.9k | v128_set_to_zero(&c->counter); |
200 | 28.9k | v128_set_to_zero(&c->offset); |
201 | | |
202 | 28.9k | copy_len = c->key_size - base_key_len; |
203 | | /* force last two octets of the offset to be left zero (for srtp |
204 | | * compatibility) */ |
205 | 28.9k | if (copy_len > SRTP_SALT_LEN) { |
206 | 0 | copy_len = SRTP_SALT_LEN; |
207 | 0 | } |
208 | | |
209 | 28.9k | memcpy(&c->counter, key + base_key_len, copy_len); |
210 | 28.9k | memcpy(&c->offset, key + base_key_len, copy_len); |
211 | | |
212 | 28.9k | debug_print(srtp_mod_aes_icm, "key: %s", |
213 | 28.9k | srtp_octet_string_hex_string(key, base_key_len)); |
214 | 28.9k | debug_print(srtp_mod_aes_icm, "offset: %s", v128_hex_string(&c->offset)); |
215 | | |
216 | | /* expand key */ |
217 | 28.9k | status = |
218 | 28.9k | srtp_aes_expand_encryption_key(key, base_key_len, &c->expanded_key); |
219 | 28.9k | if (status) { |
220 | 0 | v128_set_to_zero(&c->counter); |
221 | 0 | v128_set_to_zero(&c->offset); |
222 | 0 | return status; |
223 | 0 | } |
224 | | |
225 | | /* indicate that the keystream_buffer is empty */ |
226 | 28.9k | c->bytes_in_buffer = 0; |
227 | | |
228 | 28.9k | return srtp_err_status_ok; |
229 | 28.9k | } |
230 | | |
231 | | /* |
232 | | * aes_icm_set_iv(c, iv) sets the counter value to the exor of iv with |
233 | | * the offset |
234 | | */ |
235 | | |
236 | | static srtp_err_status_t srtp_aes_icm_set_iv(void *cv, |
237 | | uint8_t *iv, |
238 | | srtp_cipher_direction_t direction) |
239 | 319k | { |
240 | 319k | srtp_aes_icm_ctx_t *c = (srtp_aes_icm_ctx_t *)cv; |
241 | 319k | v128_t nonce; |
242 | 319k | (void)direction; |
243 | | |
244 | | /* set nonce (for alignment) */ |
245 | 319k | v128_copy_octet_string(&nonce, iv); |
246 | | |
247 | 319k | debug_print(srtp_mod_aes_icm, "setting iv: %s", v128_hex_string(&nonce)); |
248 | | |
249 | 319k | v128_xor(&c->counter, &c->offset, &nonce); |
250 | | |
251 | 319k | debug_print(srtp_mod_aes_icm, "set_counter: %s", |
252 | 319k | v128_hex_string(&c->counter)); |
253 | | |
254 | | /* indicate that the keystream_buffer is empty */ |
255 | 319k | c->bytes_in_buffer = 0; |
256 | | |
257 | 319k | return srtp_err_status_ok; |
258 | 319k | } |
259 | | |
260 | | /* |
261 | | * aes_icm_advance(...) refills the keystream_buffer and |
262 | | * advances the block index of the sicm_context forward by one |
263 | | * |
264 | | * this is an internal, hopefully inlined function |
265 | | */ |
266 | | static void srtp_aes_icm_advance(srtp_aes_icm_ctx_t *c) |
267 | 342k | { |
268 | | /* fill buffer with new keystream */ |
269 | 342k | v128_copy(&c->keystream_buffer, &c->counter); |
270 | 342k | srtp_aes_encrypt(&c->keystream_buffer, &c->expanded_key); |
271 | 342k | c->bytes_in_buffer = sizeof(v128_t); |
272 | | |
273 | 342k | debug_print(srtp_mod_aes_icm, "counter: %s", |
274 | 342k | v128_hex_string(&c->counter)); |
275 | 342k | debug_print(srtp_mod_aes_icm, "ciphertext: %s", |
276 | 342k | v128_hex_string(&c->keystream_buffer)); |
277 | | |
278 | | /* clock counter forward */ |
279 | 342k | if (!++(c->counter.v8[15])) { |
280 | 977 | ++(c->counter.v8[14]); |
281 | 977 | } |
282 | 342k | } |
283 | | |
284 | | /* |
285 | | * icm_encrypt deals with the following cases: |
286 | | * |
287 | | * bytes_to_encr < bytes_in_buffer |
288 | | * - add keystream into data |
289 | | * |
290 | | * bytes_to_encr > bytes_in_buffer |
291 | | * - add keystream into data until keystream_buffer is depleted |
292 | | * - loop over blocks, filling keystream_buffer and then |
293 | | * adding keystream into data |
294 | | * - fill buffer then add in remaining (< 16) bytes of keystream |
295 | | */ |
296 | | |
297 | | static srtp_err_status_t srtp_aes_icm_encrypt(void *cv, |
298 | | const uint8_t *src, |
299 | | size_t src_len, |
300 | | uint8_t *dst, |
301 | | size_t *dst_len) |
302 | 417k | { |
303 | 417k | srtp_aes_icm_ctx_t *c = (srtp_aes_icm_ctx_t *)cv; |
304 | 417k | size_t bytes_to_encr = src_len; |
305 | 417k | uint32_t *b; |
306 | 417k | const uint32_t *s; |
307 | | |
308 | 417k | if (*dst_len < src_len) { |
309 | 0 | return srtp_err_status_buffer_small; |
310 | 0 | } |
311 | | |
312 | 417k | *dst_len = src_len; |
313 | | |
314 | 417k | unsigned char *buf = dst; |
315 | | |
316 | | /* check that there's enough segment left*/ |
317 | 417k | size_t bytes_of_new_keystream = bytes_to_encr - c->bytes_in_buffer; |
318 | 417k | size_t blocks_of_new_keystream = (bytes_of_new_keystream + 15) >> 4; |
319 | 417k | if ((blocks_of_new_keystream + htons(c->counter.v16[7])) > 0xffff) { |
320 | 0 | return srtp_err_status_terminus; |
321 | 0 | } |
322 | | |
323 | 417k | debug_print(srtp_mod_aes_icm, "block index: %d", htons(c->counter.v16[7])); |
324 | 417k | if (bytes_to_encr <= c->bytes_in_buffer) { |
325 | | /* deal with odd case of small bytes_to_encr */ |
326 | 383k | for (size_t i = (sizeof(v128_t) - c->bytes_in_buffer); |
327 | 386k | i < (sizeof(v128_t) - c->bytes_in_buffer + bytes_to_encr); i++) { |
328 | 3.21k | *buf++ = *src++ ^ c->keystream_buffer.v8[i]; |
329 | 3.21k | } |
330 | | |
331 | 383k | c->bytes_in_buffer -= bytes_to_encr; |
332 | | |
333 | | /* return now to avoid the main loop */ |
334 | 383k | return srtp_err_status_ok; |
335 | | |
336 | 383k | } else { |
337 | | /* encrypt bytes until the remaining data is 16-byte aligned */ |
338 | 34.6k | for (size_t i = (sizeof(v128_t) - c->bytes_in_buffer); |
339 | 37.1k | i < sizeof(v128_t); i++) { |
340 | 2.57k | *buf++ = *src++ ^ c->keystream_buffer.v8[i]; |
341 | 2.57k | } |
342 | | |
343 | 34.6k | bytes_to_encr -= c->bytes_in_buffer; |
344 | 34.6k | c->bytes_in_buffer = 0; |
345 | 34.6k | } |
346 | | |
347 | | /* now loop over entire 16-byte blocks of keystream */ |
348 | 348k | for (size_t i = 0; i < (bytes_to_encr / sizeof(v128_t)); i++) { |
349 | | /* fill buffer with new keystream */ |
350 | 314k | srtp_aes_icm_advance(c); |
351 | | |
352 | | /* |
353 | | * add keystream into the data buffer (this would be a lot faster |
354 | | * if we could assume 32-bit alignment!) |
355 | | */ |
356 | | |
357 | | #if ALIGN_32 |
358 | | b = (uint32_t *)buf; |
359 | | s = (const uint32_t *)src; |
360 | | *b++ = *s++ ^ c->keystream_buffer.v32[0]; |
361 | | *b++ = *s++ ^ c->keystream_buffer.v32[1]; |
362 | | *b++ = *s++ ^ c->keystream_buffer.v32[2]; |
363 | | *b++ = *s++ ^ c->keystream_buffer.v32[3]; |
364 | | buf = (uint8_t *)b; |
365 | | src = (const uint8_t *)s; |
366 | | #else |
367 | 314k | if ((((uintptr_t)buf) & 0x03) != 0) { |
368 | 250 | *buf++ = *src++ ^ c->keystream_buffer.v8[0]; |
369 | 250 | *buf++ = *src++ ^ c->keystream_buffer.v8[1]; |
370 | 250 | *buf++ = *src++ ^ c->keystream_buffer.v8[2]; |
371 | 250 | *buf++ = *src++ ^ c->keystream_buffer.v8[3]; |
372 | 250 | *buf++ = *src++ ^ c->keystream_buffer.v8[4]; |
373 | 250 | *buf++ = *src++ ^ c->keystream_buffer.v8[5]; |
374 | 250 | *buf++ = *src++ ^ c->keystream_buffer.v8[6]; |
375 | 250 | *buf++ = *src++ ^ c->keystream_buffer.v8[7]; |
376 | 250 | *buf++ = *src++ ^ c->keystream_buffer.v8[8]; |
377 | 250 | *buf++ = *src++ ^ c->keystream_buffer.v8[9]; |
378 | 250 | *buf++ = *src++ ^ c->keystream_buffer.v8[10]; |
379 | 250 | *buf++ = *src++ ^ c->keystream_buffer.v8[11]; |
380 | 250 | *buf++ = *src++ ^ c->keystream_buffer.v8[12]; |
381 | 250 | *buf++ = *src++ ^ c->keystream_buffer.v8[13]; |
382 | 250 | *buf++ = *src++ ^ c->keystream_buffer.v8[14]; |
383 | 250 | *buf++ = *src++ ^ c->keystream_buffer.v8[15]; |
384 | 314k | } else { |
385 | 314k | b = (uint32_t *)buf; |
386 | 314k | s = (const uint32_t *)src; |
387 | 314k | *b++ = *s++ ^ c->keystream_buffer.v32[0]; |
388 | 314k | *b++ = *s++ ^ c->keystream_buffer.v32[1]; |
389 | 314k | *b++ = *s++ ^ c->keystream_buffer.v32[2]; |
390 | 314k | *b++ = *s++ ^ c->keystream_buffer.v32[3]; |
391 | 314k | buf = (uint8_t *)b; |
392 | 314k | src = (const uint8_t *)s; |
393 | 314k | } |
394 | 314k | #endif /* #if ALIGN_32 */ |
395 | 314k | } |
396 | | |
397 | | /* if there is a tail end of the data, process it */ |
398 | 34.6k | if ((bytes_to_encr & 0xf) != 0) { |
399 | | /* fill buffer with new keystream */ |
400 | 27.8k | srtp_aes_icm_advance(c); |
401 | | |
402 | 282k | for (size_t i = 0; i < (bytes_to_encr & 0xf); i++) { |
403 | 254k | *buf++ = *src++ ^ c->keystream_buffer.v8[i]; |
404 | 254k | } |
405 | | |
406 | | /* reset the keystream buffer size to right value */ |
407 | 27.8k | c->bytes_in_buffer = sizeof(v128_t) - (bytes_to_encr & 0xf); |
408 | 27.8k | } else { |
409 | | /* no tail, so just reset the keystream buffer size to zero */ |
410 | 6.80k | c->bytes_in_buffer = 0; |
411 | 6.80k | } |
412 | | |
413 | 34.6k | return srtp_err_status_ok; |
414 | 417k | } |
415 | | |
416 | | static const char srtp_aes_icm_128_description[] = |
417 | | "AES-128 integer counter mode"; |
418 | | static const char srtp_aes_icm_256_description[] = |
419 | | "AES-256 integer counter mode"; |
420 | | |
421 | | /* |
422 | | * note: the encrypt function is identical to the decrypt function |
423 | | */ |
424 | | |
425 | | const srtp_cipher_type_t srtp_aes_icm_128 = { |
426 | | srtp_aes_icm_alloc, /* */ |
427 | | srtp_aes_icm_dealloc, /* */ |
428 | | srtp_aes_icm_context_init, /* */ |
429 | | 0, /* set_aad */ |
430 | | srtp_aes_icm_encrypt, /* */ |
431 | | srtp_aes_icm_encrypt, /* */ |
432 | | srtp_aes_icm_set_iv, /* */ |
433 | | srtp_aes_icm_128_description, /* */ |
434 | | &srtp_aes_icm_128_test_case_0, /* */ |
435 | | SRTP_AES_ICM_128 /* */ |
436 | | }; |
437 | | |
438 | | const srtp_cipher_type_t srtp_aes_icm_256 = { |
439 | | srtp_aes_icm_alloc, /* */ |
440 | | srtp_aes_icm_dealloc, /* */ |
441 | | srtp_aes_icm_context_init, /* */ |
442 | | 0, /* set_aad */ |
443 | | srtp_aes_icm_encrypt, /* */ |
444 | | srtp_aes_icm_encrypt, /* */ |
445 | | srtp_aes_icm_set_iv, /* */ |
446 | | srtp_aes_icm_256_description, /* */ |
447 | | &srtp_aes_icm_256_test_case_0, /* */ |
448 | | SRTP_AES_ICM_256 /* */ |
449 | | }; |