tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

cipher_driver.c (19030B)


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