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

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

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

Powered by Google App Engine
This is Rietveld 408576698