~ubuntu-branches/ubuntu/wily/sflphone/wily

« back to all changes in this revision

Viewing changes to daemon/libs/pjproject-2.0.1/third_party/srtp/crypto/test/cipher_driver.c

  • Committer: Package Import Robot
  • Author(s): Mark Purcell
  • Date: 2014-01-28 18:23:36 UTC
  • mfrom: (1.1.11)
  • mto: This revision was merged to the branch mainline in revision 24.
  • Revision ID: package-import@ubuntu.com-20140128182336-3xenud1kbnwmf3mz
* New upstream release 
  - Fixes "New Upstream Release" (Closes: #735846)
  - Fixes "Ringtone does not stop" (Closes: #727164)
  - Fixes "[sflphone-kde] crash on startup" (Closes: #718178)
  - Fixes "sflphone GUI crashes when call is hung up" (Closes: #736583)
* Build-Depends: ensure GnuTLS 2.6
  - libucommon-dev (>= 6.0.7-1.1), libccrtp-dev (>= 2.0.6-3)
  - Fixes "FTBFS Build-Depends libgnutls{26,28}-dev" (Closes: #722040)
* Fix "boost 1.49 is going away" unversioned Build-Depends: (Closes: #736746)
* Add Build-Depends: libsndfile-dev, nepomuk-core-dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
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[20] = {
124
 
    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
125
 
    0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
126
 
    0x10, 0x11, 0x12, 0x13
127
 
  };
128
 
  int q;
129
 
  unsigned do_timing_test = 0;
130
 
  unsigned do_validation = 0;
131
 
  unsigned do_array_timing_test = 0;
132
 
 
133
 
  /* process input arguments */
134
 
  while (1) {
135
 
    q = getopt(argc, argv, "tva");
136
 
    if (q == -1)
137
 
      break;
138
 
    switch (q) {
139
 
    case 't':
140
 
      do_timing_test = 1;
141
 
      break;
142
 
    case 'v':
143
 
      do_validation = 1;
144
 
      break;
145
 
    case 'a':
146
 
      do_array_timing_test = 1;
147
 
      break;
148
 
    default:
149
 
      usage(argv[0]);
150
 
    }
151
 
  }
152
 
 
153
 
  printf("cipher test driver\n"
154
 
         "David A. McGrew\n"
155
 
         "Cisco Systems, Inc.\n");
156
 
 
157
 
  if (!do_validation && !do_timing_test && !do_array_timing_test)
158
 
    usage(argv[0]);
159
 
 
160
 
   /* arry timing (cache thrash) test */
161
 
  if (do_array_timing_test) {
162
 
    int max_num_cipher = 1 << 16;   /* number of ciphers in cipher_array */
163
 
    int num_cipher;
164
 
 
165
 
    for (num_cipher=1; num_cipher < max_num_cipher; num_cipher *=8)
166
 
      cipher_driver_test_array_throughput(&null_cipher, 0, num_cipher);
167
 
 
168
 
    for (num_cipher=1; num_cipher < max_num_cipher; num_cipher *=8)
169
 
      cipher_driver_test_array_throughput(&aes_icm, 30, num_cipher);
170
 
 
171
 
    for (num_cipher=1; num_cipher < max_num_cipher; num_cipher *=8)
172
 
      cipher_driver_test_array_throughput(&aes_cbc, 16, num_cipher);
173
 
 
174
 
  }
175
 
 
176
 
  if (do_validation) {
177
 
    cipher_driver_self_test(&null_cipher);
178
 
    cipher_driver_self_test(&aes_icm);
179
 
    cipher_driver_self_test(&aes_cbc);
180
 
  }
181
 
 
182
 
  /* do timing and/or buffer_test on null_cipher */
183
 
  status = cipher_type_alloc(&null_cipher, &c, 0);
184
 
  check_status(status);
185
 
 
186
 
  status = cipher_init(c, NULL, direction_encrypt);
187
 
  check_status(status);
188
 
 
189
 
  if (do_timing_test)
190
 
    cipher_driver_test_throughput(c);
191
 
  if (do_validation) {
192
 
    status = cipher_driver_test_buffering(c);
193
 
    check_status(status);
194
 
  }
195
 
  status = cipher_dealloc(c);
196
 
  check_status(status);
197
 
 
198
 
 
199
 
  /* run the throughput test on the aes_icm cipher */
200
 
    status = cipher_type_alloc(&aes_icm, &c, 30);
201
 
    if (status) {
202
 
      fprintf(stderr, "error: can't allocate cipher\n");
203
 
      exit(status);
204
 
    }
205
 
 
206
 
    status = cipher_init(c, test_key, direction_encrypt);
207
 
    check_status(status);
208
 
 
209
 
    if (do_timing_test)
210
 
      cipher_driver_test_throughput(c);
211
 
 
212
 
    if (do_validation) {
213
 
      status = cipher_driver_test_buffering(c);
214
 
      check_status(status);
215
 
    }
216
 
 
217
 
    status = cipher_dealloc(c);
218
 
    check_status(status);
219
 
 
220
 
  return 0;
221
 
}
222
 
 
223
 
void
224
 
cipher_driver_test_throughput(cipher_t *c) {
225
 
  int i;
226
 
  int min_enc_len = 32;
227
 
  int max_enc_len = 2048;   /* should be a power of two */
228
 
  int num_trials = 100000;
229
 
 
230
 
  printf("timing %s throughput:\n", c->type->description);
231
 
  fflush(stdout);
232
 
  for (i=min_enc_len; i <= max_enc_len; i = i * 2)
233
 
    printf("msg len: %d\tgigabits per second: %f\n",
234
 
           i, cipher_bits_per_second(c, i, num_trials) / 1e9);
235
 
 
236
 
}
237
 
 
238
 
err_status_t
239
 
cipher_driver_self_test(cipher_type_t *ct) {
240
 
  err_status_t status;
241
 
 
242
 
  printf("running cipher self-test for %s...", ct->description);
243
 
  status = cipher_type_self_test(ct);
244
 
  if (status) {
245
 
    printf("failed with error code %d\n", status);
246
 
    exit(status);
247
 
  }
248
 
  printf("passed\n");
249
 
 
250
 
  return err_status_ok;
251
 
}
252
 
 
253
 
/*
254
 
 * cipher_driver_test_buffering(ct) tests the cipher's output
255
 
 * buffering for correctness by checking the consistency of succesive
256
 
 * calls
257
 
 */
258
 
 
259
 
err_status_t
260
 
cipher_driver_test_buffering(cipher_t *c) {
261
 
  int i, j, num_trials = 1000;
262
 
  unsigned len, buflen = 1024;
263
 
  uint8_t buffer0[buflen], buffer1[buflen], *current, *end;
264
 
  uint8_t idx[16] = {
265
 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
266
 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x34
267
 
  };
268
 
  err_status_t status;
269
 
 
270
 
  printf("testing output buffering for cipher %s...",
271
 
         c->type->description);
272
 
 
273
 
  for (i=0; i < num_trials; i++) {
274
 
 
275
 
   /* set buffers to zero */
276
 
    for (j=0; j < buflen; j++)
277
 
      buffer0[j] = buffer1[j] = 0;
278
 
 
279
 
    /* initialize cipher  */
280
 
    status = cipher_set_iv(c, idx);
281
 
    if (status)
282
 
      return status;
283
 
 
284
 
    /* generate 'reference' value by encrypting all at once */
285
 
    status = cipher_encrypt(c, buffer0, &buflen);
286
 
    if (status)
287
 
      return status;
288
 
 
289
 
    /* re-initialize cipher */
290
 
    status = cipher_set_iv(c, idx);
291
 
    if (status)
292
 
      return status;
293
 
 
294
 
    /* now loop over short lengths until buffer1 is encrypted */
295
 
    current = buffer1;
296
 
    end = buffer1 + buflen;
297
 
    while (current < end) {
298
 
 
299
 
      /* choose a short length */
300
 
      len = rand() & 0x01f;
301
 
 
302
 
      /* make sure that len doesn't cause us to overreach the buffer */
303
 
      if (current + len > end)
304
 
        len = end - current;
305
 
 
306
 
      status = cipher_encrypt(c, current, &len);
307
 
      if (status)
308
 
        return status;
309
 
 
310
 
      /* advance pointer into buffer1 to reflect encryption */
311
 
      current += len;
312
 
 
313
 
      /* if buffer1 is all encrypted, break out of loop */
314
 
      if (current == end)
315
 
        break;
316
 
    }
317
 
 
318
 
    /* compare buffers */
319
 
    for (j=0; j < buflen; j++)
320
 
      if (buffer0[j] != buffer1[j]) {
321
 
#if PRINT_DEBUG
322
 
        printf("test case %d failed at byte %d\n", i, j);
323
 
        printf("computed: %s\n", octet_string_hex_string(buffer1, buflen));
324
 
        printf("expected: %s\n", octet_string_hex_string(buffer0, buflen));
325
 
#endif
326
 
        return err_status_algo_fail;
327
 
      }
328
 
  }
329
 
 
330
 
  printf("passed\n");
331
 
 
332
 
  return err_status_ok;
333
 
}
334
 
 
335
 
 
336
 
/*
337
 
 * The function cipher_test_throughput_array() tests the effect of CPU
338
 
 * cache thrash on cipher throughput.
339
 
 *
340
 
 * cipher_array_alloc_init(ctype, array, num_ciphers) creates an array
341
 
 * of cipher_t of type ctype
342
 
 */
343
 
 
344
 
err_status_t
345
 
cipher_array_alloc_init(cipher_t ***ca, int num_ciphers,
346
 
                        cipher_type_t *ctype, int klen) {
347
 
  int i, j;
348
 
  err_status_t status;
349
 
  uint8_t *key;
350
 
  cipher_t **cipher_array;
351
 
 
352
 
  /* allocate array of pointers to ciphers */
353
 
  cipher_array = (cipher_t **) malloc(sizeof(cipher_t *) * num_ciphers);
354
 
  if (cipher_array == NULL)
355
 
    return err_status_alloc_fail;
356
 
 
357
 
  /* set ca to location of cipher_array */
358
 
  *ca = cipher_array;
359
 
 
360
 
  /* allocate key */
361
 
  key = crypto_alloc(klen);
362
 
  if (key == NULL) {
363
 
    free(cipher_array);
364
 
    return err_status_alloc_fail;
365
 
  }
366
 
 
367
 
  /* allocate and initialize an array of ciphers */
368
 
  for (i=0; i < num_ciphers; i++) {
369
 
 
370
 
    /* allocate cipher */
371
 
    status = cipher_type_alloc(ctype, cipher_array, klen);
372
 
    if (status)
373
 
      return status;
374
 
 
375
 
    /* generate random key and initialize cipher */
376
 
    for (j=0; j < klen; j++)
377
 
      key[j] = (uint8_t) rand();
378
 
    status = cipher_init(*cipher_array, key, direction_encrypt);
379
 
    if (status)
380
 
      return status;
381
 
 
382
 
/*     printf("%dth cipher is at %p\n", i, *cipher_array); */
383
 
/*     printf("%dth cipher description: %s\n", i,  */
384
 
/*         (*cipher_array)->type->description); */
385
 
 
386
 
    /* advance cipher array pointer */
387
 
    cipher_array++;
388
 
  }
389
 
 
390
 
  return err_status_ok;
391
 
}
392
 
 
393
 
err_status_t
394
 
cipher_array_delete(cipher_t *cipher_array[], int num_cipher) {
395
 
  int i;
396
 
 
397
 
  for (i=0; i < num_cipher; i++) {
398
 
    cipher_dealloc(cipher_array[i]);
399
 
  }
400
 
 
401
 
  free(cipher_array);
402
 
 
403
 
  return err_status_ok;
404
 
}
405
 
 
406
 
 
407
 
/*
408
 
 * cipher_array_bits_per_second(c, l, t) computes (an estimate of) the
409
 
 * number of bits that a cipher implementation can encrypt in a second
410
 
 * when distinct keys are used to encrypt distinct messages
411
 
 *
412
 
 * c is a cipher (which MUST be allocated an initialized already), l
413
 
 * is the length in octets of the test data to be encrypted, and t is
414
 
 * the number of trials
415
 
 *
416
 
 * if an error is encountered, the value 0 is returned
417
 
 */
418
 
 
419
 
uint64_t
420
 
cipher_array_bits_per_second(cipher_t *cipher_array[], int num_cipher,
421
 
                              unsigned octets_in_buffer, int num_trials) {
422
 
  int i;
423
 
  v128_t nonce;
424
 
  clock_t timer;
425
 
  unsigned char *enc_buf;
426
 
  int cipher_index = 0;
427
 
 
428
 
 
429
 
  enc_buf = crypto_alloc(octets_in_buffer);
430
 
  if (enc_buf == NULL)
431
 
    return 0;  /* indicate bad parameters by returning null */
432
 
 
433
 
  /* time repeated trials */
434
 
  v128_set_to_zero(&nonce);
435
 
  timer = clock();
436
 
  for(i=0; i < num_trials; i++, nonce.v32[3] = i) {
437
 
 
438
 
    /* choose a cipher at random from the array*/
439
 
    cipher_index = (*((uint32_t *)enc_buf)) % num_cipher;
440
 
 
441
 
    /* encrypt buffer with cipher */
442
 
    cipher_set_iv(cipher_array[cipher_index], &nonce);
443
 
    cipher_encrypt(cipher_array[cipher_index], enc_buf, &octets_in_buffer);
444
 
  }
445
 
  timer = clock() - timer;
446
 
 
447
 
  free(enc_buf);
448
 
 
449
 
  if (timer == 0) {
450
 
    /* Too fast! */
451
 
    return 0;
452
 
  }
453
 
 
454
 
  return CLOCKS_PER_SEC * num_trials * 8 * octets_in_buffer / timer;
455
 
}
456
 
 
457
 
void
458
 
cipher_array_test_throughput(cipher_t *ca[], int num_cipher) {
459
 
  int i;
460
 
  int min_enc_len = 16;
461
 
  int max_enc_len = 2048;   /* should be a power of two */
462
 
  int num_trials = 10000;
463
 
 
464
 
  printf("timing %s throughput with array size %d:\n",
465
 
         (ca[0])->type->description, num_cipher);
466
 
  fflush(stdout);
467
 
  for (i=min_enc_len; i <= max_enc_len; i = i * 4)
468
 
    printf("msg len: %d\tgigabits per second: %f\n", i,
469
 
           cipher_array_bits_per_second(ca, num_cipher, i, num_trials) / 1e9);
470
 
 
471
 
}
472
 
 
473
 
err_status_t
474
 
cipher_driver_test_array_throughput(cipher_type_t *ct,
475
 
                                    int klen, int num_cipher) {
476
 
  cipher_t **ca = NULL;
477
 
  err_status_t status;
478
 
 
479
 
  status = cipher_array_alloc_init(&ca, num_cipher, ct, klen);
480
 
  if (status) {
481
 
    printf("error: cipher_array_alloc_init() failed with error code %d\n",
482
 
           status);
483
 
    return status;
484
 
  }
485
 
 
486
 
  cipher_array_test_throughput(ca, num_cipher);
487
 
 
488
 
  cipher_array_delete(ca, num_cipher);
489
 
 
490
 
  return err_status_ok;
491
 
}