Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3)

Side by Side Diff: srtp/crypto/test/cipher_driver.c

Issue 2344973002: Update libsrtp to version 2.0 (Closed)
Patch Set: Add '.' back to include_dirs Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « srtp/crypto/test/auth_driver.c ('k') | srtp/crypto/test/datatypes_driver.c » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /*
2 * cipher_driver.c
3 *
4 * A driver for the generic cipher type
5 *
6 * David A. McGrew
7 * Cisco Systems, Inc.
8 */
9
10 /*
11 *
12 * Copyright (c) 2001-2006,2013 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 #include <stdio.h> /* for printf() */
51 #include <stdlib.h> /* for rand() */
52 #include <string.h> /* for memset() */
53 #include "getopt_s.h"
54 #include "cipher.h"
55 #ifdef OPENSSL
56 #include "aes_icm_ossl.h"
57 #include "aes_gcm_ossl.h"
58 #else
59 #include "aes_icm.h"
60 #endif
61 #include "null_cipher.h"
62
63 #define PRINT_DEBUG 0
64
65 void
66 cipher_driver_test_throughput(cipher_t *c);
67
68 err_status_t
69 cipher_driver_self_test(cipher_type_t *ct);
70
71
72 /*
73 * cipher_driver_test_buffering(ct) tests the cipher's output
74 * buffering for correctness by checking the consistency of succesive
75 * calls
76 */
77
78 err_status_t
79 cipher_driver_test_buffering(cipher_t *c);
80
81
82 /*
83 * functions for testing cipher cache thrash
84 */
85 err_status_t
86 cipher_driver_test_array_throughput(cipher_type_t *ct,
87 int klen, int num_cipher);
88
89 void
90 cipher_array_test_throughput(cipher_t *ca[], int num_cipher);
91
92 uint64_t
93 cipher_array_bits_per_second(cipher_t *cipher_array[], int num_cipher,
94 unsigned octets_in_buffer, int num_trials);
95
96 err_status_t
97 cipher_array_delete(cipher_t *cipher_array[], int num_cipher);
98
99 err_status_t
100 cipher_array_alloc_init(cipher_t ***cipher_array, int num_ciphers,
101 cipher_type_t *ctype, int klen);
102
103 void
104 usage(char *prog_name) {
105 printf("usage: %s [ -t | -v | -a ]\n", prog_name);
106 exit(255);
107 }
108
109 void
110 check_status(err_status_t s) {
111 if (s) {
112 printf("error (code %d)\n", s);
113 exit(s);
114 }
115 return;
116 }
117
118 /*
119 * null_cipher, aes_icm, and aes_cbc are the cipher meta-objects
120 * defined in the files in crypto/cipher subdirectory. these are
121 * declared external so that we can use these cipher types here
122 */
123
124 extern cipher_type_t null_cipher;
125 extern cipher_type_t aes_icm;
126 #ifndef OPENSSL
127 extern cipher_type_t aes_cbc;
128 #else
129 #ifndef SRTP_NO_AES192
130 extern cipher_type_t aes_icm_192;
131 #endif
132 extern cipher_type_t aes_icm_256;
133 extern cipher_type_t aes_gcm_128_openssl;
134 extern cipher_type_t aes_gcm_256_openssl;
135 #endif
136
137 int
138 main(int argc, char *argv[]) {
139 cipher_t *c = NULL;
140 err_status_t status;
141 unsigned char test_key[48] = {
142 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
143 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
144 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
145 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
146 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
147 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
148 };
149 int q;
150 unsigned do_timing_test = 0;
151 unsigned do_validation = 0;
152 unsigned do_array_timing_test = 0;
153
154 /* process input arguments */
155 while (1) {
156 q = getopt_s(argc, argv, "tva");
157 if (q == -1)
158 break;
159 switch (q) {
160 case 't':
161 do_timing_test = 1;
162 break;
163 case 'v':
164 do_validation = 1;
165 break;
166 case 'a':
167 do_array_timing_test = 1;
168 break;
169 default:
170 usage(argv[0]);
171 }
172 }
173
174 printf("cipher test driver\n"
175 "David A. McGrew\n"
176 "Cisco Systems, Inc.\n");
177
178 if (!do_validation && !do_timing_test && !do_array_timing_test)
179 usage(argv[0]);
180
181 /* arry timing (cache thrash) test */
182 if (do_array_timing_test) {
183 int max_num_cipher = 1 << 16; /* number of ciphers in cipher_array */
184 int num_cipher;
185
186 for (num_cipher=1; num_cipher < max_num_cipher; num_cipher *=8)
187 cipher_driver_test_array_throughput(&null_cipher, 0, num_cipher);
188
189 for (num_cipher=1; num_cipher < max_num_cipher; num_cipher *=8)
190 cipher_driver_test_array_throughput(&aes_icm, 30, num_cipher);
191
192 #ifndef OPENSSL
193 for (num_cipher=1; num_cipher < max_num_cipher; num_cipher *=8)
194 cipher_driver_test_array_throughput(&aes_icm, 46, num_cipher);
195
196 for (num_cipher=1; num_cipher < max_num_cipher; num_cipher *=8)
197 cipher_driver_test_array_throughput(&aes_cbc, 16, num_cipher);
198
199 for (num_cipher=1; num_cipher < max_num_cipher; num_cipher *=8)
200 cipher_driver_test_array_throughput(&aes_cbc, 32, num_cipher);
201 #else
202 #ifndef SRTP_NO_AES192
203 for (num_cipher=1; num_cipher < max_num_cipher; num_cipher *=8)
204 cipher_driver_test_array_throughput(&aes_icm_192, 38, num_cipher);
205 #endif
206 for (num_cipher=1; num_cipher < max_num_cipher; num_cipher *=8)
207 cipher_driver_test_array_throughput(&aes_icm_256, 46, num_cipher);
208
209 for (num_cipher=1; num_cipher < max_num_cipher; num_cipher *=8) {
210 cipher_driver_test_array_throughput(&aes_gcm_128_openssl, AES_128_GCM_KE YSIZE_WSALT, num_cipher);
211 }
212
213 for (num_cipher=1; num_cipher < max_num_cipher; num_cipher *=8) {
214 cipher_driver_test_array_throughput(&aes_gcm_256_openssl, AES_256_GCM_KE YSIZE_WSALT, num_cipher);
215 }
216 #endif
217 }
218
219 if (do_validation) {
220 cipher_driver_self_test(&null_cipher);
221 cipher_driver_self_test(&aes_icm);
222 #ifndef OPENSSL
223 cipher_driver_self_test(&aes_cbc);
224 #else
225 #ifndef SRTP_NO_AES192
226 cipher_driver_self_test(&aes_icm_192);
227 #endif
228 cipher_driver_self_test(&aes_icm_256);
229 cipher_driver_self_test(&aes_gcm_128_openssl);
230 cipher_driver_self_test(&aes_gcm_256_openssl);
231 #endif
232 }
233
234 /* do timing and/or buffer_test on null_cipher */
235 status = cipher_type_alloc(&null_cipher, &c, 0, 0);
236 check_status(status);
237
238 status = cipher_init(c, NULL);
239 check_status(status);
240
241 if (do_timing_test)
242 cipher_driver_test_throughput(c);
243 if (do_validation) {
244 status = cipher_driver_test_buffering(c);
245 check_status(status);
246 }
247 status = cipher_dealloc(c);
248 check_status(status);
249
250
251 /* run the throughput test on the aes_icm cipher (128-bit key) */
252 status = cipher_type_alloc(&aes_icm, &c, 30, 0);
253 if (status) {
254 fprintf(stderr, "error: can't allocate cipher\n");
255 exit(status);
256 }
257
258 status = cipher_init(c, test_key);
259 check_status(status);
260
261 if (do_timing_test)
262 cipher_driver_test_throughput(c);
263
264 if (do_validation) {
265 status = cipher_driver_test_buffering(c);
266 check_status(status);
267 }
268
269 status = cipher_dealloc(c);
270 check_status(status);
271
272 /* repeat the tests with 256-bit keys */
273 #ifndef OPENSSL
274 status = cipher_type_alloc(&aes_icm, &c, 46, 0);
275 #else
276 status = cipher_type_alloc(&aes_icm_256, &c, 46, 0);
277 #endif
278 if (status) {
279 fprintf(stderr, "error: can't allocate cipher\n");
280 exit(status);
281 }
282
283 status = cipher_init(c, test_key);
284 check_status(status);
285
286 if (do_timing_test)
287 cipher_driver_test_throughput(c);
288
289 if (do_validation) {
290 status = cipher_driver_test_buffering(c);
291 check_status(status);
292 }
293
294 status = cipher_dealloc(c);
295 check_status(status);
296
297 #ifdef OPENSSL
298 /* run the throughput test on the aes_gcm_128_openssl cipher */
299 status = cipher_type_alloc(&aes_gcm_128_openssl, &c, AES_128_GCM_KEYSIZE_WSA LT, 8);
300 if (status) {
301 fprintf(stderr, "error: can't allocate GCM 128 cipher\n");
302 exit(status);
303 }
304 status = cipher_init(c, test_key);
305 check_status(status);
306 if (do_timing_test) {
307 cipher_driver_test_throughput(c);
308 }
309
310 if (do_validation) {
311 status = cipher_driver_test_buffering(c);
312 check_status(status);
313 }
314 status = cipher_dealloc(c);
315 check_status(status);
316
317 /* run the throughput test on the aes_gcm_256_openssl cipher */
318 status = cipher_type_alloc(&aes_gcm_256_openssl, &c, AES_256_GCM_KEYSIZE_WSA LT, 16);
319 if (status) {
320 fprintf(stderr, "error: can't allocate GCM 256 cipher\n");
321 exit(status);
322 }
323 status = cipher_init(c, test_key);
324 check_status(status);
325 if (do_timing_test) {
326 cipher_driver_test_throughput(c);
327 }
328
329 if (do_validation) {
330 status = cipher_driver_test_buffering(c);
331 check_status(status);
332 }
333 status = cipher_dealloc(c);
334 check_status(status);
335 #endif
336
337 return 0;
338 }
339
340 void
341 cipher_driver_test_throughput(cipher_t *c) {
342 int i;
343 int min_enc_len = 32;
344 int max_enc_len = 2048; /* should be a power of two */
345 int num_trials = 1000000;
346
347 printf("timing %s throughput, key length %d:\n", c->type->description, c->key_ len);
348 fflush(stdout);
349 for (i=min_enc_len; i <= max_enc_len; i = i * 2)
350 printf("msg len: %d\tgigabits per second: %f\n",
351 i, cipher_bits_per_second(c, i, num_trials) / 1e9);
352
353 }
354
355 err_status_t
356 cipher_driver_self_test(cipher_type_t *ct) {
357 err_status_t status;
358
359 printf("running cipher self-test for %s...", ct->description);
360 status = cipher_type_self_test(ct);
361 if (status) {
362 printf("failed with error code %d\n", status);
363 exit(status);
364 }
365 printf("passed\n");
366
367 return err_status_ok;
368 }
369
370 /*
371 * cipher_driver_test_buffering(ct) tests the cipher's output
372 * buffering for correctness by checking the consistency of succesive
373 * calls
374 */
375
376 #define INITIAL_BUFLEN 1024
377 err_status_t
378 cipher_driver_test_buffering(cipher_t *c) {
379 int i, j, num_trials = 1000;
380 unsigned len, buflen = INITIAL_BUFLEN;
381 uint8_t buffer0[INITIAL_BUFLEN], buffer1[INITIAL_BUFLEN], *current, *end;
382 uint8_t idx[16] = {
383 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
384 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x34
385 };
386 err_status_t status;
387
388 printf("testing output buffering for cipher %s...",
389 c->type->description);
390
391 for (i=0; i < num_trials; i++) {
392
393 /* set buffers to zero */
394 for (j=0; j < (int) buflen; j++) {
395 buffer0[j] = buffer1[j] = 0;
396 }
397
398 /* initialize cipher */
399 status = cipher_set_iv(c, idx, direction_encrypt);
400 if (status)
401 return status;
402
403 /* generate 'reference' value by encrypting all at once */
404 status = cipher_encrypt(c, buffer0, &buflen);
405 if (status)
406 return status;
407
408 /* re-initialize cipher */
409 status = cipher_set_iv(c, idx, direction_encrypt);
410 if (status)
411 return status;
412
413 /* now loop over short lengths until buffer1 is encrypted */
414 current = buffer1;
415 end = buffer1 + buflen;
416 while (current < end) {
417
418 /* choose a short length */
419 len = rand() & 0x01f;
420
421 /* make sure that len doesn't cause us to overreach the buffer */
422 if (current + len > end)
423 len = end - current;
424
425 status = cipher_encrypt(c, current, &len);
426 if (status)
427 return status;
428
429 /* advance pointer into buffer1 to reflect encryption */
430 current += len;
431
432 /* if buffer1 is all encrypted, break out of loop */
433 if (current == end)
434 break;
435 }
436
437 /* compare buffers */
438 for (j=0; j < (int) buflen; j++) {
439 if (buffer0[j] != buffer1[j]) {
440 #if PRINT_DEBUG
441 printf("test case %d failed at byte %d\n", i, j);
442 printf("computed: %s\n", octet_string_hex_string(buffer1, buflen));
443 printf("expected: %s\n", octet_string_hex_string(buffer0, buflen));
444 #endif
445 return err_status_algo_fail;
446 }
447 }
448 }
449
450 printf("passed\n");
451
452 return err_status_ok;
453 }
454
455
456 /*
457 * The function cipher_test_throughput_array() tests the effect of CPU
458 * cache thrash on cipher throughput.
459 *
460 * cipher_array_alloc_init(ctype, array, num_ciphers) creates an array
461 * of cipher_t of type ctype
462 */
463
464 err_status_t
465 cipher_array_alloc_init(cipher_t ***ca, int num_ciphers,
466 cipher_type_t *ctype, int klen) {
467 int i, j;
468 err_status_t status;
469 uint8_t *key;
470 cipher_t **cipher_array;
471 /* pad klen allocation, to handle aes_icm reading 16 bytes for the
472 14-byte salt */
473 int klen_pad = ((klen + 15) >> 4) << 4;
474
475 /* allocate array of pointers to ciphers */
476 cipher_array = (cipher_t **) malloc(sizeof(cipher_t *) * num_ciphers);
477 if (cipher_array == NULL)
478 return err_status_alloc_fail;
479
480 /* set ca to location of cipher_array */
481 *ca = cipher_array;
482
483 /* allocate key */
484 key = crypto_alloc(klen_pad);
485 if (key == NULL) {
486 free(cipher_array);
487 return err_status_alloc_fail;
488 }
489
490 /* allocate and initialize an array of ciphers */
491 for (i=0; i < num_ciphers; i++) {
492
493 /* allocate cipher */
494 status = cipher_type_alloc(ctype, cipher_array, klen, 16);
495 if (status)
496 return status;
497
498 /* generate random key and initialize cipher */
499 for (j=0; j < klen; j++)
500 key[j] = (uint8_t) rand();
501 for (; j < klen_pad; j++)
502 key[j] = 0;
503 status = cipher_init(*cipher_array, key);
504 if (status)
505 return status;
506
507 /* printf("%dth cipher is at %p\n", i, *cipher_array); */
508 /* printf("%dth cipher description: %s\n", i, */
509 /* (*cipher_array)->type->description); */
510
511 /* advance cipher array pointer */
512 cipher_array++;
513 }
514
515 crypto_free(key);
516
517 return err_status_ok;
518 }
519
520 err_status_t
521 cipher_array_delete(cipher_t *cipher_array[], int num_cipher) {
522 int i;
523
524 for (i=0; i < num_cipher; i++) {
525 cipher_dealloc(cipher_array[i]);
526 }
527
528 free(cipher_array);
529
530 return err_status_ok;
531 }
532
533
534 /*
535 * cipher_array_bits_per_second(c, l, t) computes (an estimate of) the
536 * number of bits that a cipher implementation can encrypt in a second
537 * when distinct keys are used to encrypt distinct messages
538 *
539 * c is a cipher (which MUST be allocated an initialized already), l
540 * is the length in octets of the test data to be encrypted, and t is
541 * the number of trials
542 *
543 * if an error is encountered, the value 0 is returned
544 */
545
546 uint64_t
547 cipher_array_bits_per_second(cipher_t *cipher_array[], int num_cipher,
548 unsigned octets_in_buffer, int num_trials) {
549 int i;
550 v128_t nonce;
551 clock_t timer;
552 unsigned char *enc_buf;
553 int cipher_index = rand() % num_cipher;
554
555 /* Over-alloc, for NIST CBC padding */
556 enc_buf = crypto_alloc(octets_in_buffer+17);
557 if (enc_buf == NULL)
558 return 0; /* indicate bad parameters by returning null */
559 memset(enc_buf, 0, octets_in_buffer);
560
561 /* time repeated trials */
562 v128_set_to_zero(&nonce);
563 timer = clock();
564 for(i=0; i < num_trials; i++, nonce.v32[3] = i) {
565 /* length parameter to cipher_encrypt is in/out -- out is total, padded
566 * length -- so reset it each time. */
567 unsigned octets_to_encrypt = octets_in_buffer;
568
569 /* encrypt buffer with cipher */
570 cipher_set_iv(cipher_array[cipher_index], &nonce, direction_encrypt);
571 cipher_encrypt(cipher_array[cipher_index], enc_buf, &octets_to_encrypt);
572
573 /* choose a cipher at random from the array*/
574 cipher_index = (*((uint32_t *)enc_buf)) % num_cipher;
575 }
576 timer = clock() - timer;
577
578 free(enc_buf);
579
580 if (timer == 0) {
581 /* Too fast! */
582 return 0;
583 }
584
585 return (uint64_t)CLOCKS_PER_SEC * num_trials * 8 * octets_in_buffer / timer;
586 }
587
588 void
589 cipher_array_test_throughput(cipher_t *ca[], int num_cipher) {
590 int i;
591 int min_enc_len = 16;
592 int max_enc_len = 2048; /* should be a power of two */
593 int num_trials = 1000000;
594
595 printf("timing %s throughput with key length %d, array size %d:\n",
596 (ca[0])->type->description, (ca[0])->key_len, num_cipher);
597 fflush(stdout);
598 for (i=min_enc_len; i <= max_enc_len; i = i * 4)
599 printf("msg len: %d\tgigabits per second: %f\n", i,
600 cipher_array_bits_per_second(ca, num_cipher, i, num_trials) / 1e9);
601
602 }
603
604 err_status_t
605 cipher_driver_test_array_throughput(cipher_type_t *ct,
606 int klen, int num_cipher) {
607 cipher_t **ca = NULL;
608 err_status_t status;
609
610 status = cipher_array_alloc_init(&ca, num_cipher, ct, klen);
611 if (status) {
612 printf("error: cipher_array_alloc_init() failed with error code %d\n",
613 status);
614 return status;
615 }
616
617 cipher_array_test_throughput(ca, num_cipher);
618
619 cipher_array_delete(ca, num_cipher);
620
621 return err_status_ok;
622 }
OLDNEW
« no previous file with comments | « srtp/crypto/test/auth_driver.c ('k') | srtp/crypto/test/datatypes_driver.c » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698