netwerk/srtp/src/crypto/cipher/cipher.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /*
michael@0 2 * cipher.c
michael@0 3 *
michael@0 4 * cipher meta-functions
michael@0 5 *
michael@0 6 * David A. McGrew
michael@0 7 * Cisco Systems, Inc.
michael@0 8 *
michael@0 9 */
michael@0 10
michael@0 11 /*
michael@0 12 *
michael@0 13 * Copyright (c) 2001-2006, Cisco Systems, Inc.
michael@0 14 * All rights reserved.
michael@0 15 *
michael@0 16 * Redistribution and use in source and binary forms, with or without
michael@0 17 * modification, are permitted provided that the following conditions
michael@0 18 * are met:
michael@0 19 *
michael@0 20 * Redistributions of source code must retain the above copyright
michael@0 21 * notice, this list of conditions and the following disclaimer.
michael@0 22 *
michael@0 23 * Redistributions in binary form must reproduce the above
michael@0 24 * copyright notice, this list of conditions and the following
michael@0 25 * disclaimer in the documentation and/or other materials provided
michael@0 26 * with the distribution.
michael@0 27 *
michael@0 28 * Neither the name of the Cisco Systems, Inc. nor the names of its
michael@0 29 * contributors may be used to endorse or promote products derived
michael@0 30 * from this software without specific prior written permission.
michael@0 31 *
michael@0 32 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
michael@0 33 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
michael@0 34 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
michael@0 35 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
michael@0 36 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
michael@0 37 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
michael@0 38 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
michael@0 39 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
michael@0 40 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
michael@0 41 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
michael@0 42 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
michael@0 43 * OF THE POSSIBILITY OF SUCH DAMAGE.
michael@0 44 *
michael@0 45 */
michael@0 46
michael@0 47 #include "cipher.h"
michael@0 48 #include "rand_source.h" /* used in invertibiltiy tests */
michael@0 49 #include "alloc.h" /* for crypto_alloc(), crypto_free() */
michael@0 50
michael@0 51 debug_module_t mod_cipher = {
michael@0 52 0, /* debugging is off by default */
michael@0 53 "cipher" /* printable module name */
michael@0 54 };
michael@0 55
michael@0 56 err_status_t
michael@0 57 cipher_output(cipher_t *c, uint8_t *buffer, int num_octets_to_output) {
michael@0 58
michael@0 59 /* zeroize the buffer */
michael@0 60 octet_string_set_to_zero(buffer, num_octets_to_output);
michael@0 61
michael@0 62 /* exor keystream into buffer */
michael@0 63 return cipher_encrypt(c, buffer, (unsigned int *) &num_octets_to_output);
michael@0 64 }
michael@0 65
michael@0 66 /* some bookkeeping functions */
michael@0 67
michael@0 68 int
michael@0 69 cipher_get_key_length(const cipher_t *c) {
michael@0 70 return c->key_len;
michael@0 71 }
michael@0 72
michael@0 73 /*
michael@0 74 * cipher_type_test(ct, test_data) tests a cipher of type ct against
michael@0 75 * test cases provided in a list test_data of values of key, salt, iv,
michael@0 76 * plaintext, and ciphertext that is known to be good
michael@0 77 */
michael@0 78
michael@0 79 #define SELF_TEST_BUF_OCTETS 128
michael@0 80 #define NUM_RAND_TESTS 128
michael@0 81 #define MAX_KEY_LEN 64
michael@0 82
michael@0 83 err_status_t
michael@0 84 cipher_type_test(const cipher_type_t *ct, const cipher_test_case_t *test_data) {
michael@0 85 const cipher_test_case_t *test_case = test_data;
michael@0 86 cipher_t *c;
michael@0 87 err_status_t status;
michael@0 88 uint8_t buffer[SELF_TEST_BUF_OCTETS];
michael@0 89 uint8_t buffer2[SELF_TEST_BUF_OCTETS];
michael@0 90 unsigned int len;
michael@0 91 int i, j, case_num = 0;
michael@0 92
michael@0 93 debug_print(mod_cipher, "running self-test for cipher %s",
michael@0 94 ct->description);
michael@0 95
michael@0 96 /*
michael@0 97 * check to make sure that we have at least one test case, and
michael@0 98 * return an error if we don't - we need to be paranoid here
michael@0 99 */
michael@0 100 if (test_case == NULL)
michael@0 101 return err_status_cant_check;
michael@0 102
michael@0 103 /*
michael@0 104 * loop over all test cases, perform known-answer tests of both the
michael@0 105 * encryption and decryption functions
michael@0 106 */
michael@0 107 while (test_case != NULL) {
michael@0 108
michael@0 109 /* allocate cipher */
michael@0 110 status = cipher_type_alloc(ct, &c, test_case->key_length_octets);
michael@0 111 if (status)
michael@0 112 return status;
michael@0 113
michael@0 114 /*
michael@0 115 * test the encrypt function
michael@0 116 */
michael@0 117 debug_print(mod_cipher, "testing encryption", NULL);
michael@0 118
michael@0 119 /* initialize cipher */
michael@0 120 status = cipher_init(c, test_case->key, direction_encrypt);
michael@0 121 if (status) {
michael@0 122 cipher_dealloc(c);
michael@0 123 return status;
michael@0 124 }
michael@0 125
michael@0 126 /* copy plaintext into test buffer */
michael@0 127 if (test_case->ciphertext_length_octets > SELF_TEST_BUF_OCTETS) {
michael@0 128 cipher_dealloc(c);
michael@0 129 return err_status_bad_param;
michael@0 130 }
michael@0 131 for (i=0; i < test_case->plaintext_length_octets; i++)
michael@0 132 buffer[i] = test_case->plaintext[i];
michael@0 133
michael@0 134 debug_print(mod_cipher, "plaintext: %s",
michael@0 135 octet_string_hex_string(buffer,
michael@0 136 test_case->plaintext_length_octets));
michael@0 137
michael@0 138 /* set the initialization vector */
michael@0 139 status = cipher_set_iv(c, test_case->idx);
michael@0 140 if (status) {
michael@0 141 cipher_dealloc(c);
michael@0 142 return status;
michael@0 143 }
michael@0 144
michael@0 145 /* encrypt */
michael@0 146 len = test_case->plaintext_length_octets;
michael@0 147 status = cipher_encrypt(c, buffer, &len);
michael@0 148 if (status) {
michael@0 149 cipher_dealloc(c);
michael@0 150 return status;
michael@0 151 }
michael@0 152
michael@0 153 debug_print(mod_cipher, "ciphertext: %s",
michael@0 154 octet_string_hex_string(buffer,
michael@0 155 test_case->ciphertext_length_octets));
michael@0 156
michael@0 157 /* compare the resulting ciphertext with that in the test case */
michael@0 158 if (len != (unsigned int)test_case->ciphertext_length_octets)
michael@0 159 return err_status_algo_fail;
michael@0 160 status = err_status_ok;
michael@0 161 for (i=0; i < test_case->ciphertext_length_octets; i++)
michael@0 162 if (buffer[i] != test_case->ciphertext[i]) {
michael@0 163 status = err_status_algo_fail;
michael@0 164 debug_print(mod_cipher, "test case %d failed", case_num);
michael@0 165 debug_print(mod_cipher, "(failure at byte %d)", i);
michael@0 166 break;
michael@0 167 }
michael@0 168 if (status) {
michael@0 169
michael@0 170 debug_print(mod_cipher, "c computed: %s",
michael@0 171 octet_string_hex_string(buffer,
michael@0 172 2*test_case->plaintext_length_octets));
michael@0 173 debug_print(mod_cipher, "c expected: %s",
michael@0 174 octet_string_hex_string(test_case->ciphertext,
michael@0 175 2*test_case->plaintext_length_octets));
michael@0 176
michael@0 177 cipher_dealloc(c);
michael@0 178 return err_status_algo_fail;
michael@0 179 }
michael@0 180
michael@0 181 /*
michael@0 182 * test the decrypt function
michael@0 183 */
michael@0 184 debug_print(mod_cipher, "testing decryption", NULL);
michael@0 185
michael@0 186 /* re-initialize cipher for decryption */
michael@0 187 status = cipher_init(c, test_case->key, direction_decrypt);
michael@0 188 if (status) {
michael@0 189 cipher_dealloc(c);
michael@0 190 return status;
michael@0 191 }
michael@0 192
michael@0 193 /* copy ciphertext into test buffer */
michael@0 194 if (test_case->ciphertext_length_octets > SELF_TEST_BUF_OCTETS) {
michael@0 195 cipher_dealloc(c);
michael@0 196 return err_status_bad_param;
michael@0 197 }
michael@0 198 for (i=0; i < test_case->ciphertext_length_octets; i++)
michael@0 199 buffer[i] = test_case->ciphertext[i];
michael@0 200
michael@0 201 debug_print(mod_cipher, "ciphertext: %s",
michael@0 202 octet_string_hex_string(buffer,
michael@0 203 test_case->plaintext_length_octets));
michael@0 204
michael@0 205 /* set the initialization vector */
michael@0 206 status = cipher_set_iv(c, test_case->idx);
michael@0 207 if (status) {
michael@0 208 cipher_dealloc(c);
michael@0 209 return status;
michael@0 210 }
michael@0 211
michael@0 212 /* decrypt */
michael@0 213 len = test_case->ciphertext_length_octets;
michael@0 214 status = cipher_decrypt(c, buffer, &len);
michael@0 215 if (status) {
michael@0 216 cipher_dealloc(c);
michael@0 217 return status;
michael@0 218 }
michael@0 219
michael@0 220 debug_print(mod_cipher, "plaintext: %s",
michael@0 221 octet_string_hex_string(buffer,
michael@0 222 test_case->plaintext_length_octets));
michael@0 223
michael@0 224 /* compare the resulting plaintext with that in the test case */
michael@0 225 if (len != (unsigned int)test_case->plaintext_length_octets)
michael@0 226 return err_status_algo_fail;
michael@0 227 status = err_status_ok;
michael@0 228 for (i=0; i < test_case->plaintext_length_octets; i++)
michael@0 229 if (buffer[i] != test_case->plaintext[i]) {
michael@0 230 status = err_status_algo_fail;
michael@0 231 debug_print(mod_cipher, "test case %d failed", case_num);
michael@0 232 debug_print(mod_cipher, "(failure at byte %d)", i);
michael@0 233 }
michael@0 234 if (status) {
michael@0 235
michael@0 236 debug_print(mod_cipher, "p computed: %s",
michael@0 237 octet_string_hex_string(buffer,
michael@0 238 2*test_case->plaintext_length_octets));
michael@0 239 debug_print(mod_cipher, "p expected: %s",
michael@0 240 octet_string_hex_string(test_case->plaintext,
michael@0 241 2*test_case->plaintext_length_octets));
michael@0 242
michael@0 243 cipher_dealloc(c);
michael@0 244 return err_status_algo_fail;
michael@0 245 }
michael@0 246
michael@0 247 /* deallocate the cipher */
michael@0 248 status = cipher_dealloc(c);
michael@0 249 if (status)
michael@0 250 return status;
michael@0 251
michael@0 252 /*
michael@0 253 * the cipher passed the test case, so move on to the next test
michael@0 254 * case in the list; if NULL, we'l proceed to the next test
michael@0 255 */
michael@0 256 test_case = test_case->next_test_case;
michael@0 257 ++case_num;
michael@0 258 }
michael@0 259
michael@0 260 /* now run some random invertibility tests */
michael@0 261
michael@0 262 /* allocate cipher, using paramaters from the first test case */
michael@0 263 test_case = test_data;
michael@0 264 status = cipher_type_alloc(ct, &c, test_case->key_length_octets);
michael@0 265 if (status)
michael@0 266 return status;
michael@0 267
michael@0 268 rand_source_init();
michael@0 269
michael@0 270 for (j=0; j < NUM_RAND_TESTS; j++) {
michael@0 271 unsigned length;
michael@0 272 int plaintext_len;
michael@0 273 uint8_t key[MAX_KEY_LEN];
michael@0 274 uint8_t iv[MAX_KEY_LEN];
michael@0 275
michael@0 276 /* choose a length at random (leaving room for IV and padding) */
michael@0 277 length = rand() % (SELF_TEST_BUF_OCTETS - 64);
michael@0 278 debug_print(mod_cipher, "random plaintext length %d\n", length);
michael@0 279 status = rand_source_get_octet_string(buffer, length);
michael@0 280 if (status) return status;
michael@0 281
michael@0 282 debug_print(mod_cipher, "plaintext: %s",
michael@0 283 octet_string_hex_string(buffer, length));
michael@0 284
michael@0 285 /* copy plaintext into second buffer */
michael@0 286 for (i=0; (unsigned int)i < length; i++)
michael@0 287 buffer2[i] = buffer[i];
michael@0 288
michael@0 289 /* choose a key at random */
michael@0 290 if (test_case->key_length_octets > MAX_KEY_LEN)
michael@0 291 return err_status_cant_check;
michael@0 292 status = rand_source_get_octet_string(key, test_case->key_length_octets);
michael@0 293 if (status) return status;
michael@0 294
michael@0 295 /* chose a random initialization vector */
michael@0 296 status = rand_source_get_octet_string(iv, MAX_KEY_LEN);
michael@0 297 if (status) return status;
michael@0 298
michael@0 299 /* initialize cipher */
michael@0 300 status = cipher_init(c, key, direction_encrypt);
michael@0 301 if (status) {
michael@0 302 cipher_dealloc(c);
michael@0 303 return status;
michael@0 304 }
michael@0 305
michael@0 306 /* set initialization vector */
michael@0 307 status = cipher_set_iv(c, test_case->idx);
michael@0 308 if (status) {
michael@0 309 cipher_dealloc(c);
michael@0 310 return status;
michael@0 311 }
michael@0 312
michael@0 313 /* encrypt buffer with cipher */
michael@0 314 plaintext_len = length;
michael@0 315 status = cipher_encrypt(c, buffer, &length);
michael@0 316 if (status) {
michael@0 317 cipher_dealloc(c);
michael@0 318 return status;
michael@0 319 }
michael@0 320 debug_print(mod_cipher, "ciphertext: %s",
michael@0 321 octet_string_hex_string(buffer, length));
michael@0 322
michael@0 323 /*
michael@0 324 * re-initialize cipher for decryption, re-set the iv, then
michael@0 325 * decrypt the ciphertext
michael@0 326 */
michael@0 327 status = cipher_init(c, key, direction_decrypt);
michael@0 328 if (status) {
michael@0 329 cipher_dealloc(c);
michael@0 330 return status;
michael@0 331 }
michael@0 332 status = cipher_set_iv(c, test_case->idx);
michael@0 333 if (status) {
michael@0 334 cipher_dealloc(c);
michael@0 335 return status;
michael@0 336 }
michael@0 337 status = cipher_decrypt(c, buffer, &length);
michael@0 338 if (status) {
michael@0 339 cipher_dealloc(c);
michael@0 340 return status;
michael@0 341 }
michael@0 342
michael@0 343 debug_print(mod_cipher, "plaintext[2]: %s",
michael@0 344 octet_string_hex_string(buffer, length));
michael@0 345
michael@0 346 /* compare the resulting plaintext with the original one */
michael@0 347 if (length != (unsigned)plaintext_len)
michael@0 348 return err_status_algo_fail;
michael@0 349 status = err_status_ok;
michael@0 350 for (i=0; i < plaintext_len; i++)
michael@0 351 if (buffer[i] != buffer2[i]) {
michael@0 352 status = err_status_algo_fail;
michael@0 353 debug_print(mod_cipher, "random test case %d failed", case_num);
michael@0 354 debug_print(mod_cipher, "(failure at byte %d)", i);
michael@0 355 }
michael@0 356 if (status) {
michael@0 357 cipher_dealloc(c);
michael@0 358 return err_status_algo_fail;
michael@0 359 }
michael@0 360
michael@0 361 }
michael@0 362
michael@0 363 status = cipher_dealloc(c);
michael@0 364 if (status)
michael@0 365 return status;
michael@0 366
michael@0 367 return err_status_ok;
michael@0 368 }
michael@0 369
michael@0 370
michael@0 371 /*
michael@0 372 * cipher_type_self_test(ct) performs cipher_type_test on ct's internal
michael@0 373 * list of test data.
michael@0 374 */
michael@0 375
michael@0 376 err_status_t
michael@0 377 cipher_type_self_test(const cipher_type_t *ct) {
michael@0 378 return cipher_type_test(ct, ct->test_data);
michael@0 379 }
michael@0 380
michael@0 381 /*
michael@0 382 * cipher_bits_per_second(c, l, t) computes (an estimate of) the
michael@0 383 * number of bits that a cipher implementation can encrypt in a second
michael@0 384 *
michael@0 385 * c is a cipher (which MUST be allocated and initialized already), l
michael@0 386 * is the length in octets of the test data to be encrypted, and t is
michael@0 387 * the number of trials
michael@0 388 *
michael@0 389 * if an error is encountered, the value 0 is returned
michael@0 390 */
michael@0 391
michael@0 392 uint64_t
michael@0 393 cipher_bits_per_second(cipher_t *c, int octets_in_buffer, int num_trials) {
michael@0 394 int i;
michael@0 395 v128_t nonce;
michael@0 396 clock_t timer;
michael@0 397 unsigned char *enc_buf;
michael@0 398 unsigned int len = octets_in_buffer;
michael@0 399
michael@0 400 enc_buf = (unsigned char*) crypto_alloc(octets_in_buffer);
michael@0 401 if (enc_buf == NULL)
michael@0 402 return 0; /* indicate bad parameters by returning null */
michael@0 403
michael@0 404 /* time repeated trials */
michael@0 405 v128_set_to_zero(&nonce);
michael@0 406 timer = clock();
michael@0 407 for(i=0; i < num_trials; i++, nonce.v32[3] = i) {
michael@0 408 cipher_set_iv(c, &nonce);
michael@0 409 cipher_encrypt(c, enc_buf, &len);
michael@0 410 }
michael@0 411 timer = clock() - timer;
michael@0 412
michael@0 413 crypto_free(enc_buf);
michael@0 414
michael@0 415 if (timer == 0) {
michael@0 416 /* Too fast! */
michael@0 417 return 0;
michael@0 418 }
michael@0 419
michael@0 420 return (uint64_t)CLOCKS_PER_SEC * num_trials * 8 * octets_in_buffer / timer;
michael@0 421 }

mercurial