blob: a507e1c5ecd903e7ed9b67f3dec2ef555a8c33ac [file] [log] [blame]
Cullen Jennings235513a2005-09-21 22:51:36 +00001/*
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 *
jfigus7882dd92013-08-02 16:08:23 -040012 * Copyright (c) 2001-2006,2013 Cisco Systems, Inc.
Cullen Jennings235513a2005-09-21 22:51:36 +000013 * 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
Teerapap Changwichukarn6cffe242014-09-24 11:24:07 +080046#ifdef HAVE_CONFIG_H
47 #include <config.h>
48#endif
49
Cullen Jennings235513a2005-09-21 22:51:36 +000050#include <stdio.h> /* for printf() */
Marcus Sundbergd774edb2005-10-02 20:36:02 +000051#include <stdlib.h> /* for rand() */
Cullen Jennings235513a2005-09-21 22:51:36 +000052#include <string.h> /* for memset() */
53#include <unistd.h> /* for getopt() */
54#include "cipher.h"
jfigusa14b5a02013-03-29 12:24:12 -040055#ifdef OPENSSL
56#include "aes_icm_ossl.h"
jfigus7882dd92013-08-02 16:08:23 -040057#include "aes_gcm_ossl.h"
jfigusa14b5a02013-03-29 12:24:12 -040058#else
Cullen Jennings235513a2005-09-21 22:51:36 +000059#include "aes_icm.h"
jfigusa14b5a02013-03-29 12:24:12 -040060#endif
Cullen Jennings235513a2005-09-21 22:51:36 +000061#include "null_cipher.h"
62
63#define PRINT_DEBUG 0
64
65void
66cipher_driver_test_throughput(cipher_t *c);
67
jfigus857009c2014-11-05 11:17:43 -050068srtp_err_status_t
Cullen Jennings235513a2005-09-21 22:51:36 +000069cipher_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
jfigus857009c2014-11-05 11:17:43 -050078srtp_err_status_t
Cullen Jennings235513a2005-09-21 22:51:36 +000079cipher_driver_test_buffering(cipher_t *c);
80
81
82/*
83 * functions for testing cipher cache thrash
84 */
jfigus857009c2014-11-05 11:17:43 -050085srtp_err_status_t
Cullen Jennings235513a2005-09-21 22:51:36 +000086cipher_driver_test_array_throughput(cipher_type_t *ct,
87 int klen, int num_cipher);
88
89void
90cipher_array_test_throughput(cipher_t *ca[], int num_cipher);
91
Marcus Sundberge544f612005-10-03 16:29:05 +000092uint64_t
Cullen Jennings235513a2005-09-21 22:51:36 +000093cipher_array_bits_per_second(cipher_t *cipher_array[], int num_cipher,
David McGrewfec49dd2005-09-23 19:34:11 +000094 unsigned octets_in_buffer, int num_trials);
Cullen Jennings235513a2005-09-21 22:51:36 +000095
jfigus857009c2014-11-05 11:17:43 -050096srtp_err_status_t
Cullen Jennings235513a2005-09-21 22:51:36 +000097cipher_array_delete(cipher_t *cipher_array[], int num_cipher);
98
jfigus857009c2014-11-05 11:17:43 -050099srtp_err_status_t
Cullen Jennings235513a2005-09-21 22:51:36 +0000100cipher_array_alloc_init(cipher_t ***cipher_array, int num_ciphers,
101 cipher_type_t *ctype, int klen);
102
103void
104usage(char *prog_name) {
105 printf("usage: %s [ -t | -v | -a ]\n", prog_name);
106 exit(255);
107}
108
109void
jfigus857009c2014-11-05 11:17:43 -0500110check_status(srtp_err_status_t s) {
Cullen Jennings235513a2005-09-21 22:51:36 +0000111 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
124extern cipher_type_t null_cipher;
jfigus5a2b2d02014-11-19 14:34:20 -0500125extern cipher_type_t srtp_aes_icm;
jfigus0d3a2682013-04-02 15:42:37 -0400126#ifndef OPENSSL
jfigus5a2b2d02014-11-19 14:34:20 -0500127extern cipher_type_t srtp_aes_cbc;
jfigus7882dd92013-08-02 16:08:23 -0400128#else
jfigus5a2b2d02014-11-19 14:34:20 -0500129extern cipher_type_t srtp_aes_icm_192;
130extern cipher_type_t srtp_aes_icm_256;
131extern cipher_type_t srtp_aes_gcm_128_openssl;
132extern cipher_type_t srtp_aes_gcm_256_openssl;
jfigus0d3a2682013-04-02 15:42:37 -0400133#endif
Cullen Jennings235513a2005-09-21 22:51:36 +0000134
135int
136main(int argc, char *argv[]) {
137 cipher_t *c = NULL;
jfigus857009c2014-11-05 11:17:43 -0500138 srtp_err_status_t status;
Jonathan Lennox5df951a2010-05-20 20:55:54 +0000139 unsigned char test_key[48] = {
Cullen Jennings235513a2005-09-21 22:51:36 +0000140 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
141 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
Jonathan Lennox5df951a2010-05-20 20:55:54 +0000142 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
143 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
144 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
145 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
Cullen Jennings235513a2005-09-21 22:51:36 +0000146 };
147 int q;
148 unsigned do_timing_test = 0;
149 unsigned do_validation = 0;
150 unsigned do_array_timing_test = 0;
151
152 /* process input arguments */
153 while (1) {
154 q = getopt(argc, argv, "tva");
155 if (q == -1)
156 break;
157 switch (q) {
158 case 't':
159 do_timing_test = 1;
160 break;
161 case 'v':
162 do_validation = 1;
163 break;
164 case 'a':
165 do_array_timing_test = 1;
166 break;
167 default:
168 usage(argv[0]);
169 }
170 }
171
172 printf("cipher test driver\n"
173 "David A. McGrew\n"
174 "Cisco Systems, Inc.\n");
175
176 if (!do_validation && !do_timing_test && !do_array_timing_test)
177 usage(argv[0]);
178
179 /* arry timing (cache thrash) test */
180 if (do_array_timing_test) {
181 int max_num_cipher = 1 << 16; /* number of ciphers in cipher_array */
182 int num_cipher;
183
184 for (num_cipher=1; num_cipher < max_num_cipher; num_cipher *=8)
185 cipher_driver_test_array_throughput(&null_cipher, 0, num_cipher);
186
187 for (num_cipher=1; num_cipher < max_num_cipher; num_cipher *=8)
jfigus5a2b2d02014-11-19 14:34:20 -0500188 cipher_driver_test_array_throughput(&srtp_aes_icm, 30, num_cipher);
Cullen Jennings235513a2005-09-21 22:51:36 +0000189
jfigusb5a21772013-11-08 10:05:59 -0500190#ifndef OPENSSL
Cullen Jennings235513a2005-09-21 22:51:36 +0000191 for (num_cipher=1; num_cipher < max_num_cipher; num_cipher *=8)
jfigus5a2b2d02014-11-19 14:34:20 -0500192 cipher_driver_test_array_throughput(&srtp_aes_icm, 46, num_cipher);
Jonathan Lennox5df951a2010-05-20 20:55:54 +0000193
194 for (num_cipher=1; num_cipher < max_num_cipher; num_cipher *=8)
jfigus5a2b2d02014-11-19 14:34:20 -0500195 cipher_driver_test_array_throughput(&srtp_aes_cbc, 16, num_cipher);
Cullen Jennings235513a2005-09-21 22:51:36 +0000196
Jonathan Lennox5df951a2010-05-20 20:55:54 +0000197 for (num_cipher=1; num_cipher < max_num_cipher; num_cipher *=8)
jfigus5a2b2d02014-11-19 14:34:20 -0500198 cipher_driver_test_array_throughput(&srtp_aes_cbc, 32, num_cipher);
jfigus7882dd92013-08-02 16:08:23 -0400199#else
jfigusb5a21772013-11-08 10:05:59 -0500200 for (num_cipher=1; num_cipher < max_num_cipher; num_cipher *=8)
jfigus5a2b2d02014-11-19 14:34:20 -0500201 cipher_driver_test_array_throughput(&srtp_aes_icm_192, 38, num_cipher);
jfigusb5a21772013-11-08 10:05:59 -0500202
203 for (num_cipher=1; num_cipher < max_num_cipher; num_cipher *=8)
jfigus5a2b2d02014-11-19 14:34:20 -0500204 cipher_driver_test_array_throughput(&srtp_aes_icm_256, 46, num_cipher);
jfigusb5a21772013-11-08 10:05:59 -0500205
jfigus7882dd92013-08-02 16:08:23 -0400206 for (num_cipher=1; num_cipher < max_num_cipher; num_cipher *=8) {
jfigus5a2b2d02014-11-19 14:34:20 -0500207 cipher_driver_test_array_throughput(&srtp_aes_gcm_128_openssl, SRTP_AES_128_GCM_KEYSIZE_WSALT, num_cipher);
jfigus7882dd92013-08-02 16:08:23 -0400208 }
209
210 for (num_cipher=1; num_cipher < max_num_cipher; num_cipher *=8) {
jfigus5a2b2d02014-11-19 14:34:20 -0500211 cipher_driver_test_array_throughput(&srtp_aes_gcm_256_openssl, SRTP_AES_256_GCM_KEYSIZE_WSALT, num_cipher);
jfigus7882dd92013-08-02 16:08:23 -0400212 }
jfigus0d3a2682013-04-02 15:42:37 -0400213#endif
Cullen Jennings235513a2005-09-21 22:51:36 +0000214 }
215
216 if (do_validation) {
217 cipher_driver_self_test(&null_cipher);
jfigus5a2b2d02014-11-19 14:34:20 -0500218 cipher_driver_self_test(&srtp_aes_icm);
jfigus0d3a2682013-04-02 15:42:37 -0400219#ifndef OPENSSL
jfigus5a2b2d02014-11-19 14:34:20 -0500220 cipher_driver_self_test(&srtp_aes_cbc);
jfigus7882dd92013-08-02 16:08:23 -0400221#else
jfigus5a2b2d02014-11-19 14:34:20 -0500222 cipher_driver_self_test(&srtp_aes_icm_192);
223 cipher_driver_self_test(&srtp_aes_icm_256);
224 cipher_driver_self_test(&srtp_aes_gcm_128_openssl);
225 cipher_driver_self_test(&srtp_aes_gcm_256_openssl);
jfigus0d3a2682013-04-02 15:42:37 -0400226#endif
Cullen Jennings235513a2005-09-21 22:51:36 +0000227 }
228
229 /* do timing and/or buffer_test on null_cipher */
jfigusc13c1002014-05-08 13:34:53 -0400230 status = cipher_type_alloc(&null_cipher, &c, 0, 0);
Cullen Jennings235513a2005-09-21 22:51:36 +0000231 check_status(status);
232
jfigus7882dd92013-08-02 16:08:23 -0400233 status = cipher_init(c, NULL);
Cullen Jennings235513a2005-09-21 22:51:36 +0000234 check_status(status);
235
236 if (do_timing_test)
237 cipher_driver_test_throughput(c);
238 if (do_validation) {
239 status = cipher_driver_test_buffering(c);
240 check_status(status);
241 }
242 status = cipher_dealloc(c);
243 check_status(status);
244
245
Jonathan Lennox5df951a2010-05-20 20:55:54 +0000246 /* run the throughput test on the aes_icm cipher (128-bit key) */
jfigus5a2b2d02014-11-19 14:34:20 -0500247 status = cipher_type_alloc(&srtp_aes_icm, &c, 30, 0);
Cullen Jennings235513a2005-09-21 22:51:36 +0000248 if (status) {
249 fprintf(stderr, "error: can't allocate cipher\n");
250 exit(status);
251 }
252
jfigus7882dd92013-08-02 16:08:23 -0400253 status = cipher_init(c, test_key);
Cullen Jennings235513a2005-09-21 22:51:36 +0000254 check_status(status);
255
256 if (do_timing_test)
257 cipher_driver_test_throughput(c);
258
259 if (do_validation) {
260 status = cipher_driver_test_buffering(c);
261 check_status(status);
262 }
263
264 status = cipher_dealloc(c);
265 check_status(status);
Jonathan Lennox5df951a2010-05-20 20:55:54 +0000266
267 /* repeat the tests with 256-bit keys */
jfigusb5a21772013-11-08 10:05:59 -0500268#ifndef OPENSSL
jfigus5a2b2d02014-11-19 14:34:20 -0500269 status = cipher_type_alloc(&srtp_aes_icm, &c, 46, 0);
jfigusb5a21772013-11-08 10:05:59 -0500270#else
jfigus5a2b2d02014-11-19 14:34:20 -0500271 status = cipher_type_alloc(&srtp_aes_icm_256, &c, 46, 0);
jfigusb5a21772013-11-08 10:05:59 -0500272#endif
Jonathan Lennox5df951a2010-05-20 20:55:54 +0000273 if (status) {
274 fprintf(stderr, "error: can't allocate cipher\n");
275 exit(status);
276 }
277
jfigus7882dd92013-08-02 16:08:23 -0400278 status = cipher_init(c, test_key);
Jonathan Lennox5df951a2010-05-20 20:55:54 +0000279 check_status(status);
280
281 if (do_timing_test)
282 cipher_driver_test_throughput(c);
283
284 if (do_validation) {
285 status = cipher_driver_test_buffering(c);
286 check_status(status);
287 }
288
289 status = cipher_dealloc(c);
290 check_status(status);
jfigus7882dd92013-08-02 16:08:23 -0400291
292#ifdef OPENSSL
293 /* run the throughput test on the aes_gcm_128_openssl cipher */
jfigus5a2b2d02014-11-19 14:34:20 -0500294 status = cipher_type_alloc(&srtp_aes_gcm_128_openssl, &c, SRTP_AES_128_GCM_KEYSIZE_WSALT, 8);
jfigus7882dd92013-08-02 16:08:23 -0400295 if (status) {
296 fprintf(stderr, "error: can't allocate GCM 128 cipher\n");
297 exit(status);
298 }
299 status = cipher_init(c, test_key);
300 check_status(status);
301 if (do_timing_test) {
302 cipher_driver_test_throughput(c);
303 }
304
305 if (do_validation) {
306 status = cipher_driver_test_buffering(c);
307 check_status(status);
308 }
309 status = cipher_dealloc(c);
310 check_status(status);
311
312 /* run the throughput test on the aes_gcm_256_openssl cipher */
jfigus5a2b2d02014-11-19 14:34:20 -0500313 status = cipher_type_alloc(&srtp_aes_gcm_256_openssl, &c, SRTP_AES_256_GCM_KEYSIZE_WSALT, 16);
jfigus7882dd92013-08-02 16:08:23 -0400314 if (status) {
315 fprintf(stderr, "error: can't allocate GCM 256 cipher\n");
316 exit(status);
317 }
318 status = cipher_init(c, test_key);
319 check_status(status);
320 if (do_timing_test) {
321 cipher_driver_test_throughput(c);
322 }
323
324 if (do_validation) {
325 status = cipher_driver_test_buffering(c);
326 check_status(status);
327 }
328 status = cipher_dealloc(c);
329 check_status(status);
330#endif
331
332 return 0;
Cullen Jennings235513a2005-09-21 22:51:36 +0000333}
334
335void
336cipher_driver_test_throughput(cipher_t *c) {
337 int i;
338 int min_enc_len = 32;
339 int max_enc_len = 2048; /* should be a power of two */
Jonathan Lennox1731e292010-05-20 00:44:24 +0000340 int num_trials = 1000000;
Cullen Jennings235513a2005-09-21 22:51:36 +0000341
Jonathan Lennox5df951a2010-05-20 20:55:54 +0000342 printf("timing %s throughput, key length %d:\n", c->type->description, c->key_len);
Cullen Jennings235513a2005-09-21 22:51:36 +0000343 fflush(stdout);
344 for (i=min_enc_len; i <= max_enc_len; i = i * 2)
345 printf("msg len: %d\tgigabits per second: %f\n",
346 i, cipher_bits_per_second(c, i, num_trials) / 1e9);
347
348}
349
jfigus857009c2014-11-05 11:17:43 -0500350srtp_err_status_t
Cullen Jennings235513a2005-09-21 22:51:36 +0000351cipher_driver_self_test(cipher_type_t *ct) {
jfigus857009c2014-11-05 11:17:43 -0500352 srtp_err_status_t status;
Cullen Jennings235513a2005-09-21 22:51:36 +0000353
354 printf("running cipher self-test for %s...", ct->description);
355 status = cipher_type_self_test(ct);
356 if (status) {
357 printf("failed with error code %d\n", status);
358 exit(status);
359 }
360 printf("passed\n");
361
jfigus857009c2014-11-05 11:17:43 -0500362 return srtp_err_status_ok;
Cullen Jennings235513a2005-09-21 22:51:36 +0000363}
364
365/*
366 * cipher_driver_test_buffering(ct) tests the cipher's output
367 * buffering for correctness by checking the consistency of succesive
368 * calls
369 */
370
jfigus857009c2014-11-05 11:17:43 -0500371srtp_err_status_t
Cullen Jennings235513a2005-09-21 22:51:36 +0000372cipher_driver_test_buffering(cipher_t *c) {
David McGrewfec49dd2005-09-23 19:34:11 +0000373 int i, j, num_trials = 1000;
374 unsigned len, buflen = 1024;
Marcus Sundberg410faaa2005-09-29 12:36:43 +0000375 uint8_t buffer0[buflen], buffer1[buflen], *current, *end;
376 uint8_t idx[16] = {
Cullen Jennings235513a2005-09-21 22:51:36 +0000377 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
378 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x34
379 };
jfigus857009c2014-11-05 11:17:43 -0500380 srtp_err_status_t status;
Cullen Jennings235513a2005-09-21 22:51:36 +0000381
382 printf("testing output buffering for cipher %s...",
383 c->type->description);
384
385 for (i=0; i < num_trials; i++) {
386
387 /* set buffers to zero */
388 for (j=0; j < buflen; j++)
389 buffer0[j] = buffer1[j] = 0;
390
391 /* initialize cipher */
jfigus7882dd92013-08-02 16:08:23 -0400392 status = cipher_set_iv(c, idx, direction_encrypt);
Cullen Jennings235513a2005-09-21 22:51:36 +0000393 if (status)
394 return status;
395
396 /* generate 'reference' value by encrypting all at once */
397 status = cipher_encrypt(c, buffer0, &buflen);
398 if (status)
399 return status;
400
401 /* re-initialize cipher */
jfigus7882dd92013-08-02 16:08:23 -0400402 status = cipher_set_iv(c, idx, direction_encrypt);
Cullen Jennings235513a2005-09-21 22:51:36 +0000403 if (status)
404 return status;
405
406 /* now loop over short lengths until buffer1 is encrypted */
407 current = buffer1;
408 end = buffer1 + buflen;
409 while (current < end) {
410
411 /* choose a short length */
Marcus Sundbergd774edb2005-10-02 20:36:02 +0000412 len = rand() & 0x01f;
Cullen Jennings235513a2005-09-21 22:51:36 +0000413
414 /* make sure that len doesn't cause us to overreach the buffer */
415 if (current + len > end)
416 len = end - current;
417
418 status = cipher_encrypt(c, current, &len);
419 if (status)
420 return status;
421
422 /* advance pointer into buffer1 to reflect encryption */
423 current += len;
424
425 /* if buffer1 is all encrypted, break out of loop */
426 if (current == end)
427 break;
428 }
429
430 /* compare buffers */
431 for (j=0; j < buflen; j++)
432 if (buffer0[j] != buffer1[j]) {
433#if PRINT_DEBUG
434 printf("test case %d failed at byte %d\n", i, j);
435 printf("computed: %s\n", octet_string_hex_string(buffer1, buflen));
436 printf("expected: %s\n", octet_string_hex_string(buffer0, buflen));
437#endif
jfigus857009c2014-11-05 11:17:43 -0500438 return srtp_err_status_algo_fail;
Cullen Jennings235513a2005-09-21 22:51:36 +0000439 }
440 }
441
442 printf("passed\n");
443
jfigus857009c2014-11-05 11:17:43 -0500444 return srtp_err_status_ok;
Cullen Jennings235513a2005-09-21 22:51:36 +0000445}
446
447
448/*
449 * The function cipher_test_throughput_array() tests the effect of CPU
450 * cache thrash on cipher throughput.
451 *
452 * cipher_array_alloc_init(ctype, array, num_ciphers) creates an array
453 * of cipher_t of type ctype
454 */
455
jfigus857009c2014-11-05 11:17:43 -0500456srtp_err_status_t
Cullen Jennings235513a2005-09-21 22:51:36 +0000457cipher_array_alloc_init(cipher_t ***ca, int num_ciphers,
458 cipher_type_t *ctype, int klen) {
459 int i, j;
jfigus857009c2014-11-05 11:17:43 -0500460 srtp_err_status_t status;
Marcus Sundberg410faaa2005-09-29 12:36:43 +0000461 uint8_t *key;
Cullen Jennings235513a2005-09-21 22:51:36 +0000462 cipher_t **cipher_array;
Jonathan Lennox7852d8f2010-05-18 21:36:39 +0000463 /* pad klen allocation, to handle aes_icm reading 16 bytes for the
464 14-byte salt */
465 int klen_pad = ((klen + 15) >> 4) << 4;
Cullen Jennings235513a2005-09-21 22:51:36 +0000466
467 /* allocate array of pointers to ciphers */
468 cipher_array = (cipher_t **) malloc(sizeof(cipher_t *) * num_ciphers);
469 if (cipher_array == NULL)
jfigus857009c2014-11-05 11:17:43 -0500470 return srtp_err_status_alloc_fail;
Cullen Jennings235513a2005-09-21 22:51:36 +0000471
472 /* set ca to location of cipher_array */
473 *ca = cipher_array;
474
475 /* allocate key */
Jonathan Lennox7852d8f2010-05-18 21:36:39 +0000476 key = crypto_alloc(klen_pad);
Cullen Jennings235513a2005-09-21 22:51:36 +0000477 if (key == NULL) {
478 free(cipher_array);
jfigus857009c2014-11-05 11:17:43 -0500479 return srtp_err_status_alloc_fail;
Cullen Jennings235513a2005-09-21 22:51:36 +0000480 }
481
482 /* allocate and initialize an array of ciphers */
483 for (i=0; i < num_ciphers; i++) {
484
485 /* allocate cipher */
jfigusc13c1002014-05-08 13:34:53 -0400486 status = cipher_type_alloc(ctype, cipher_array, klen, 16);
Cullen Jennings235513a2005-09-21 22:51:36 +0000487 if (status)
488 return status;
489
490 /* generate random key and initialize cipher */
491 for (j=0; j < klen; j++)
Marcus Sundbergd774edb2005-10-02 20:36:02 +0000492 key[j] = (uint8_t) rand();
Jonathan Lennox7852d8f2010-05-18 21:36:39 +0000493 for (; j < klen_pad; j++)
494 key[j] = 0;
jfigus7882dd92013-08-02 16:08:23 -0400495 status = cipher_init(*cipher_array, key);
Cullen Jennings235513a2005-09-21 22:51:36 +0000496 if (status)
497 return status;
498
499/* printf("%dth cipher is at %p\n", i, *cipher_array); */
500/* printf("%dth cipher description: %s\n", i, */
501/* (*cipher_array)->type->description); */
502
503 /* advance cipher array pointer */
504 cipher_array++;
505 }
506
Jonathan Lennox7852d8f2010-05-18 21:36:39 +0000507 crypto_free(key);
508
jfigus857009c2014-11-05 11:17:43 -0500509 return srtp_err_status_ok;
Cullen Jennings235513a2005-09-21 22:51:36 +0000510}
511
jfigus857009c2014-11-05 11:17:43 -0500512srtp_err_status_t
Cullen Jennings235513a2005-09-21 22:51:36 +0000513cipher_array_delete(cipher_t *cipher_array[], int num_cipher) {
514 int i;
515
516 for (i=0; i < num_cipher; i++) {
517 cipher_dealloc(cipher_array[i]);
518 }
519
520 free(cipher_array);
521
jfigus857009c2014-11-05 11:17:43 -0500522 return srtp_err_status_ok;
Cullen Jennings235513a2005-09-21 22:51:36 +0000523}
524
525
526/*
527 * cipher_array_bits_per_second(c, l, t) computes (an estimate of) the
528 * number of bits that a cipher implementation can encrypt in a second
529 * when distinct keys are used to encrypt distinct messages
530 *
531 * c is a cipher (which MUST be allocated an initialized already), l
532 * is the length in octets of the test data to be encrypted, and t is
533 * the number of trials
534 *
Marcus Sundberge544f612005-10-03 16:29:05 +0000535 * if an error is encountered, the value 0 is returned
Cullen Jennings235513a2005-09-21 22:51:36 +0000536 */
537
Marcus Sundberge544f612005-10-03 16:29:05 +0000538uint64_t
Cullen Jennings235513a2005-09-21 22:51:36 +0000539cipher_array_bits_per_second(cipher_t *cipher_array[], int num_cipher,
Marcus Sundberge544f612005-10-03 16:29:05 +0000540 unsigned octets_in_buffer, int num_trials) {
Cullen Jennings235513a2005-09-21 22:51:36 +0000541 int i;
542 v128_t nonce;
543 clock_t timer;
544 unsigned char *enc_buf;
Jonathan Lennox7852d8f2010-05-18 21:36:39 +0000545 int cipher_index = rand() % num_cipher;
Cullen Jennings235513a2005-09-21 22:51:36 +0000546
Jonathan Lennox7852d8f2010-05-18 21:36:39 +0000547 /* Over-alloc, for NIST CBC padding */
548 enc_buf = crypto_alloc(octets_in_buffer+17);
Cullen Jennings235513a2005-09-21 22:51:36 +0000549 if (enc_buf == NULL)
Marcus Sundberge544f612005-10-03 16:29:05 +0000550 return 0; /* indicate bad parameters by returning null */
Jonathan Lennox7852d8f2010-05-18 21:36:39 +0000551 memset(enc_buf, 0, octets_in_buffer);
Cullen Jennings235513a2005-09-21 22:51:36 +0000552
553 /* time repeated trials */
554 v128_set_to_zero(&nonce);
555 timer = clock();
556 for(i=0; i < num_trials; i++, nonce.v32[3] = i) {
Jonathan Lennox7852d8f2010-05-18 21:36:39 +0000557 /* length parameter to cipher_encrypt is in/out -- out is total, padded
558 * length -- so reset it each time. */
559 unsigned octets_to_encrypt = octets_in_buffer;
Cullen Jennings235513a2005-09-21 22:51:36 +0000560
561 /* encrypt buffer with cipher */
jfigus7882dd92013-08-02 16:08:23 -0400562 cipher_set_iv(cipher_array[cipher_index], &nonce, direction_encrypt);
Jonathan Lennox7852d8f2010-05-18 21:36:39 +0000563 cipher_encrypt(cipher_array[cipher_index], enc_buf, &octets_to_encrypt);
564
565 /* choose a cipher at random from the array*/
566 cipher_index = (*((uint32_t *)enc_buf)) % num_cipher;
Cullen Jennings235513a2005-09-21 22:51:36 +0000567 }
568 timer = clock() - timer;
569
570 free(enc_buf);
Marcus Sundberge544f612005-10-03 16:29:05 +0000571
572 if (timer == 0) {
573 /* Too fast! */
574 return 0;
575 }
576
Jonathan Lennox7852d8f2010-05-18 21:36:39 +0000577 return (uint64_t)CLOCKS_PER_SEC * num_trials * 8 * octets_in_buffer / timer;
Cullen Jennings235513a2005-09-21 22:51:36 +0000578}
579
580void
581cipher_array_test_throughput(cipher_t *ca[], int num_cipher) {
582 int i;
583 int min_enc_len = 16;
584 int max_enc_len = 2048; /* should be a power of two */
Jonathan Lennox1731e292010-05-20 00:44:24 +0000585 int num_trials = 1000000;
Cullen Jennings235513a2005-09-21 22:51:36 +0000586
Jonathan Lennox5df951a2010-05-20 20:55:54 +0000587 printf("timing %s throughput with key length %d, array size %d:\n",
588 (ca[0])->type->description, (ca[0])->key_len, num_cipher);
Cullen Jennings235513a2005-09-21 22:51:36 +0000589 fflush(stdout);
590 for (i=min_enc_len; i <= max_enc_len; i = i * 4)
591 printf("msg len: %d\tgigabits per second: %f\n", i,
592 cipher_array_bits_per_second(ca, num_cipher, i, num_trials) / 1e9);
593
594}
595
jfigus857009c2014-11-05 11:17:43 -0500596srtp_err_status_t
Cullen Jennings235513a2005-09-21 22:51:36 +0000597cipher_driver_test_array_throughput(cipher_type_t *ct,
598 int klen, int num_cipher) {
599 cipher_t **ca = NULL;
jfigus857009c2014-11-05 11:17:43 -0500600 srtp_err_status_t status;
Cullen Jennings235513a2005-09-21 22:51:36 +0000601
602 status = cipher_array_alloc_init(&ca, num_cipher, ct, klen);
603 if (status) {
604 printf("error: cipher_array_alloc_init() failed with error code %d\n",
605 status);
606 return status;
607 }
608
609 cipher_array_test_throughput(ca, num_cipher);
610
611 cipher_array_delete(ca, num_cipher);
612
jfigus857009c2014-11-05 11:17:43 -0500613 return srtp_err_status_ok;
Cullen Jennings235513a2005-09-21 22:51:36 +0000614}