cts128.c revision 280297
1/* ==================================================================== 2 * Copyright (c) 2008 The OpenSSL Project. All rights reserved. 3 * 4 * Rights for redistribution and usage in source and binary 5 * forms are granted according to the OpenSSL license. 6 */ 7 8#include <openssl/crypto.h> 9#include "modes_lcl.h" 10#include <string.h> 11 12#ifndef MODES_DEBUG 13# ifndef NDEBUG 14# define NDEBUG 15# endif 16#endif 17#include <assert.h> 18 19/* 20 * Trouble with Ciphertext Stealing, CTS, mode is that there is no 21 * common official specification, but couple of cipher/application 22 * specific ones: RFC2040 and RFC3962. Then there is 'Proposal to 23 * Extend CBC Mode By "Ciphertext Stealing"' at NIST site, which 24 * deviates from mentioned RFCs. Most notably it allows input to be 25 * of block length and it doesn't flip the order of the last two 26 * blocks. CTS is being discussed even in ECB context, but it's not 27 * adopted for any known application. This implementation provides 28 * two interfaces: one compliant with above mentioned RFCs and one 29 * compliant with the NIST proposal, both extending CBC mode. 30 */ 31 32size_t CRYPTO_cts128_encrypt_block(const unsigned char *in, 33 unsigned char *out, size_t len, 34 const void *key, unsigned char ivec[16], 35 block128_f block) 36{ 37 size_t residue, n; 38 39 assert(in && out && key && ivec); 40 41 if (len <= 16) 42 return 0; 43 44 if ((residue = len % 16) == 0) 45 residue = 16; 46 47 len -= residue; 48 49 CRYPTO_cbc128_encrypt(in, out, len, key, ivec, block); 50 51 in += len; 52 out += len; 53 54 for (n = 0; n < residue; ++n) 55 ivec[n] ^= in[n]; 56 (*block) (ivec, ivec, key); 57 memcpy(out, out - 16, residue); 58 memcpy(out - 16, ivec, 16); 59 60 return len + residue; 61} 62 63size_t CRYPTO_nistcts128_encrypt_block(const unsigned char *in, 64 unsigned char *out, size_t len, 65 const void *key, 66 unsigned char ivec[16], 67 block128_f block) 68{ 69 size_t residue, n; 70 71 assert(in && out && key && ivec); 72 73 if (len < 16) 74 return 0; 75 76 residue = len % 16; 77 78 len -= residue; 79 80 CRYPTO_cbc128_encrypt(in, out, len, key, ivec, block); 81 82 if (residue == 0) 83 return len; 84 85 in += len; 86 out += len; 87 88 for (n = 0; n < residue; ++n) 89 ivec[n] ^= in[n]; 90 (*block) (ivec, ivec, key); 91 memcpy(out - 16 + residue, ivec, 16); 92 93 return len + residue; 94} 95 96size_t CRYPTO_cts128_encrypt(const unsigned char *in, unsigned char *out, 97 size_t len, const void *key, 98 unsigned char ivec[16], cbc128_f cbc) 99{ 100 size_t residue; 101 union { 102 size_t align; 103 unsigned char c[16]; 104 } tmp; 105 106 assert(in && out && key && ivec); 107 108 if (len <= 16) 109 return 0; 110 111 if ((residue = len % 16) == 0) 112 residue = 16; 113 114 len -= residue; 115 116 (*cbc) (in, out, len, key, ivec, 1); 117 118 in += len; 119 out += len; 120 121#if defined(CBC_HANDLES_TRUNCATED_IO) 122 memcpy(tmp.c, out - 16, 16); 123 (*cbc) (in, out - 16, residue, key, ivec, 1); 124 memcpy(out, tmp.c, residue); 125#else 126 memset(tmp.c, 0, sizeof(tmp)); 127 memcpy(tmp.c, in, residue); 128 memcpy(out, out - 16, residue); 129 (*cbc) (tmp.c, out - 16, 16, key, ivec, 1); 130#endif 131 return len + residue; 132} 133 134size_t CRYPTO_nistcts128_encrypt(const unsigned char *in, unsigned char *out, 135 size_t len, const void *key, 136 unsigned char ivec[16], cbc128_f cbc) 137{ 138 size_t residue; 139 union { 140 size_t align; 141 unsigned char c[16]; 142 } tmp; 143 144 assert(in && out && key && ivec); 145 146 if (len < 16) 147 return 0; 148 149 residue = len % 16; 150 151 len -= residue; 152 153 (*cbc) (in, out, len, key, ivec, 1); 154 155 if (residue == 0) 156 return len; 157 158 in += len; 159 out += len; 160 161#if defined(CBC_HANDLES_TRUNCATED_IO) 162 (*cbc) (in, out - 16 + residue, residue, key, ivec, 1); 163#else 164 memset(tmp.c, 0, sizeof(tmp)); 165 memcpy(tmp.c, in, residue); 166 (*cbc) (tmp.c, out - 16 + residue, 16, key, ivec, 1); 167#endif 168 return len + residue; 169} 170 171size_t CRYPTO_cts128_decrypt_block(const unsigned char *in, 172 unsigned char *out, size_t len, 173 const void *key, unsigned char ivec[16], 174 block128_f block) 175{ 176 size_t residue, n; 177 union { 178 size_t align; 179 unsigned char c[32]; 180 } tmp; 181 182 assert(in && out && key && ivec); 183 184 if (len <= 16) 185 return 0; 186 187 if ((residue = len % 16) == 0) 188 residue = 16; 189 190 len -= 16 + residue; 191 192 if (len) { 193 CRYPTO_cbc128_decrypt(in, out, len, key, ivec, block); 194 in += len; 195 out += len; 196 } 197 198 (*block) (in, tmp.c + 16, key); 199 200 memcpy(tmp.c, tmp.c + 16, 16); 201 memcpy(tmp.c, in + 16, residue); 202 (*block) (tmp.c, tmp.c, key); 203 204 for (n = 0; n < 16; ++n) { 205 unsigned char c = in[n]; 206 out[n] = tmp.c[n] ^ ivec[n]; 207 ivec[n] = c; 208 } 209 for (residue += 16; n < residue; ++n) 210 out[n] = tmp.c[n] ^ in[n]; 211 212 return 16 + len + residue; 213} 214 215size_t CRYPTO_nistcts128_decrypt_block(const unsigned char *in, 216 unsigned char *out, size_t len, 217 const void *key, 218 unsigned char ivec[16], 219 block128_f block) 220{ 221 size_t residue, n; 222 union { 223 size_t align; 224 unsigned char c[32]; 225 } tmp; 226 227 assert(in && out && key && ivec); 228 229 if (len < 16) 230 return 0; 231 232 residue = len % 16; 233 234 if (residue == 0) { 235 CRYPTO_cbc128_decrypt(in, out, len, key, ivec, block); 236 return len; 237 } 238 239 len -= 16 + residue; 240 241 if (len) { 242 CRYPTO_cbc128_decrypt(in, out, len, key, ivec, block); 243 in += len; 244 out += len; 245 } 246 247 (*block) (in + residue, tmp.c + 16, key); 248 249 memcpy(tmp.c, tmp.c + 16, 16); 250 memcpy(tmp.c, in, residue); 251 (*block) (tmp.c, tmp.c, key); 252 253 for (n = 0; n < 16; ++n) { 254 unsigned char c = in[n]; 255 out[n] = tmp.c[n] ^ ivec[n]; 256 ivec[n] = in[n + residue]; 257 tmp.c[n] = c; 258 } 259 for (residue += 16; n < residue; ++n) 260 out[n] = tmp.c[n] ^ tmp.c[n - 16]; 261 262 return 16 + len + residue; 263} 264 265size_t CRYPTO_cts128_decrypt(const unsigned char *in, unsigned char *out, 266 size_t len, const void *key, 267 unsigned char ivec[16], cbc128_f cbc) 268{ 269 size_t residue; 270 union { 271 size_t align; 272 unsigned char c[32]; 273 } tmp; 274 275 assert(in && out && key && ivec); 276 277 if (len <= 16) 278 return 0; 279 280 if ((residue = len % 16) == 0) 281 residue = 16; 282 283 len -= 16 + residue; 284 285 if (len) { 286 (*cbc) (in, out, len, key, ivec, 0); 287 in += len; 288 out += len; 289 } 290 291 memset(tmp.c, 0, sizeof(tmp)); 292 /* 293 * this places in[16] at &tmp.c[16] and decrypted block at &tmp.c[0] 294 */ 295 (*cbc) (in, tmp.c, 16, key, tmp.c + 16, 0); 296 297 memcpy(tmp.c, in + 16, residue); 298#if defined(CBC_HANDLES_TRUNCATED_IO) 299 (*cbc) (tmp.c, out, 16 + residue, key, ivec, 0); 300#else 301 (*cbc) (tmp.c, tmp.c, 32, key, ivec, 0); 302 memcpy(out, tmp.c, 16 + residue); 303#endif 304 return 16 + len + residue; 305} 306 307size_t CRYPTO_nistcts128_decrypt(const unsigned char *in, unsigned char *out, 308 size_t len, const void *key, 309 unsigned char ivec[16], cbc128_f cbc) 310{ 311 size_t residue; 312 union { 313 size_t align; 314 unsigned char c[32]; 315 } tmp; 316 317 assert(in && out && key && ivec); 318 319 if (len < 16) 320 return 0; 321 322 residue = len % 16; 323 324 if (residue == 0) { 325 (*cbc) (in, out, len, key, ivec, 0); 326 return len; 327 } 328 329 len -= 16 + residue; 330 331 if (len) { 332 (*cbc) (in, out, len, key, ivec, 0); 333 in += len; 334 out += len; 335 } 336 337 memset(tmp.c, 0, sizeof(tmp)); 338 /* 339 * this places in[16] at &tmp.c[16] and decrypted block at &tmp.c[0] 340 */ 341 (*cbc) (in + residue, tmp.c, 16, key, tmp.c + 16, 0); 342 343 memcpy(tmp.c, in, residue); 344#if defined(CBC_HANDLES_TRUNCATED_IO) 345 (*cbc) (tmp.c, out, 16 + residue, key, ivec, 0); 346#else 347 (*cbc) (tmp.c, tmp.c, 32, key, ivec, 0); 348 memcpy(out, tmp.c, 16 + residue); 349#endif 350 return 16 + len + residue; 351} 352 353#if defined(SELFTEST) 354# include <stdio.h> 355# include <openssl/aes.h> 356 357/* test vectors from RFC 3962 */ 358static const unsigned char test_key[16] = "chicken teriyaki"; 359static const unsigned char test_input[64] = 360 "I would like the" " General Gau's C" 361 "hicken, please, " "and wonton soup."; 362static const unsigned char test_iv[16] = 363 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 364 365static const unsigned char vector_17[17] = { 366 0xc6, 0x35, 0x35, 0x68, 0xf2, 0xbf, 0x8c, 0xb4, 367 0xd8, 0xa5, 0x80, 0x36, 0x2d, 0xa7, 0xff, 0x7f, 368 0x97 369}; 370 371static const unsigned char vector_31[31] = { 372 0xfc, 0x00, 0x78, 0x3e, 0x0e, 0xfd, 0xb2, 0xc1, 373 0xd4, 0x45, 0xd4, 0xc8, 0xef, 0xf7, 0xed, 0x22, 374 0x97, 0x68, 0x72, 0x68, 0xd6, 0xec, 0xcc, 0xc0, 375 0xc0, 0x7b, 0x25, 0xe2, 0x5e, 0xcf, 0xe5 376}; 377 378static const unsigned char vector_32[32] = { 379 0x39, 0x31, 0x25, 0x23, 0xa7, 0x86, 0x62, 0xd5, 380 0xbe, 0x7f, 0xcb, 0xcc, 0x98, 0xeb, 0xf5, 0xa8, 381 0x97, 0x68, 0x72, 0x68, 0xd6, 0xec, 0xcc, 0xc0, 382 0xc0, 0x7b, 0x25, 0xe2, 0x5e, 0xcf, 0xe5, 0x84 383}; 384 385static const unsigned char vector_47[47] = { 386 0x97, 0x68, 0x72, 0x68, 0xd6, 0xec, 0xcc, 0xc0, 387 0xc0, 0x7b, 0x25, 0xe2, 0x5e, 0xcf, 0xe5, 0x84, 388 0xb3, 0xff, 0xfd, 0x94, 0x0c, 0x16, 0xa1, 0x8c, 389 0x1b, 0x55, 0x49, 0xd2, 0xf8, 0x38, 0x02, 0x9e, 390 0x39, 0x31, 0x25, 0x23, 0xa7, 0x86, 0x62, 0xd5, 391 0xbe, 0x7f, 0xcb, 0xcc, 0x98, 0xeb, 0xf5 392}; 393 394static const unsigned char vector_48[48] = { 395 0x97, 0x68, 0x72, 0x68, 0xd6, 0xec, 0xcc, 0xc0, 396 0xc0, 0x7b, 0x25, 0xe2, 0x5e, 0xcf, 0xe5, 0x84, 397 0x9d, 0xad, 0x8b, 0xbb, 0x96, 0xc4, 0xcd, 0xc0, 398 0x3b, 0xc1, 0x03, 0xe1, 0xa1, 0x94, 0xbb, 0xd8, 399 0x39, 0x31, 0x25, 0x23, 0xa7, 0x86, 0x62, 0xd5, 400 0xbe, 0x7f, 0xcb, 0xcc, 0x98, 0xeb, 0xf5, 0xa8 401}; 402 403static const unsigned char vector_64[64] = { 404 0x97, 0x68, 0x72, 0x68, 0xd6, 0xec, 0xcc, 0xc0, 405 0xc0, 0x7b, 0x25, 0xe2, 0x5e, 0xcf, 0xe5, 0x84, 406 0x39, 0x31, 0x25, 0x23, 0xa7, 0x86, 0x62, 0xd5, 407 0xbe, 0x7f, 0xcb, 0xcc, 0x98, 0xeb, 0xf5, 0xa8, 408 0x48, 0x07, 0xef, 0xe8, 0x36, 0xee, 0x89, 0xa5, 409 0x26, 0x73, 0x0d, 0xbc, 0x2f, 0x7b, 0xc8, 0x40, 410 0x9d, 0xad, 0x8b, 0xbb, 0x96, 0xc4, 0xcd, 0xc0, 411 0x3b, 0xc1, 0x03, 0xe1, 0xa1, 0x94, 0xbb, 0xd8 412}; 413 414static AES_KEY encks, decks; 415 416void test_vector(const unsigned char *vector, size_t len) 417{ 418 unsigned char iv[sizeof(test_iv)]; 419 unsigned char cleartext[64], ciphertext[64]; 420 size_t tail; 421 422 printf("vector_%d\n", len); 423 fflush(stdout); 424 425 if ((tail = len % 16) == 0) 426 tail = 16; 427 tail += 16; 428 429 /* test block-based encryption */ 430 memcpy(iv, test_iv, sizeof(test_iv)); 431 CRYPTO_cts128_encrypt_block(test_input, ciphertext, len, &encks, iv, 432 (block128_f) AES_encrypt); 433 if (memcmp(ciphertext, vector, len)) 434 fprintf(stderr, "output_%d mismatch\n", len), exit(1); 435 if (memcmp(iv, vector + len - tail, sizeof(iv))) 436 fprintf(stderr, "iv_%d mismatch\n", len), exit(1); 437 438 /* test block-based decryption */ 439 memcpy(iv, test_iv, sizeof(test_iv)); 440 CRYPTO_cts128_decrypt_block(ciphertext, cleartext, len, &decks, iv, 441 (block128_f) AES_decrypt); 442 if (memcmp(cleartext, test_input, len)) 443 fprintf(stderr, "input_%d mismatch\n", len), exit(2); 444 if (memcmp(iv, vector + len - tail, sizeof(iv))) 445 fprintf(stderr, "iv_%d mismatch\n", len), exit(2); 446 447 /* test streamed encryption */ 448 memcpy(iv, test_iv, sizeof(test_iv)); 449 CRYPTO_cts128_encrypt(test_input, ciphertext, len, &encks, iv, 450 (cbc128_f) AES_cbc_encrypt); 451 if (memcmp(ciphertext, vector, len)) 452 fprintf(stderr, "output_%d mismatch\n", len), exit(3); 453 if (memcmp(iv, vector + len - tail, sizeof(iv))) 454 fprintf(stderr, "iv_%d mismatch\n", len), exit(3); 455 456 /* test streamed decryption */ 457 memcpy(iv, test_iv, sizeof(test_iv)); 458 CRYPTO_cts128_decrypt(ciphertext, cleartext, len, &decks, iv, 459 (cbc128_f) AES_cbc_encrypt); 460 if (memcmp(cleartext, test_input, len)) 461 fprintf(stderr, "input_%d mismatch\n", len), exit(4); 462 if (memcmp(iv, vector + len - tail, sizeof(iv))) 463 fprintf(stderr, "iv_%d mismatch\n", len), exit(4); 464} 465 466void test_nistvector(const unsigned char *vector, size_t len) 467{ 468 unsigned char iv[sizeof(test_iv)]; 469 unsigned char cleartext[64], ciphertext[64], nistvector[64]; 470 size_t tail; 471 472 printf("nistvector_%d\n", len); 473 fflush(stdout); 474 475 if ((tail = len % 16) == 0) 476 tail = 16; 477 478 len -= 16 + tail; 479 memcpy(nistvector, vector, len); 480 /* flip two last blocks */ 481 memcpy(nistvector + len, vector + len + 16, tail); 482 memcpy(nistvector + len + tail, vector + len, 16); 483 len += 16 + tail; 484 tail = 16; 485 486 /* test block-based encryption */ 487 memcpy(iv, test_iv, sizeof(test_iv)); 488 CRYPTO_nistcts128_encrypt_block(test_input, ciphertext, len, &encks, iv, 489 (block128_f) AES_encrypt); 490 if (memcmp(ciphertext, nistvector, len)) 491 fprintf(stderr, "output_%d mismatch\n", len), exit(1); 492 if (memcmp(iv, nistvector + len - tail, sizeof(iv))) 493 fprintf(stderr, "iv_%d mismatch\n", len), exit(1); 494 495 /* test block-based decryption */ 496 memcpy(iv, test_iv, sizeof(test_iv)); 497 CRYPTO_nistcts128_decrypt_block(ciphertext, cleartext, len, &decks, iv, 498 (block128_f) AES_decrypt); 499 if (memcmp(cleartext, test_input, len)) 500 fprintf(stderr, "input_%d mismatch\n", len), exit(2); 501 if (memcmp(iv, nistvector + len - tail, sizeof(iv))) 502 fprintf(stderr, "iv_%d mismatch\n", len), exit(2); 503 504 /* test streamed encryption */ 505 memcpy(iv, test_iv, sizeof(test_iv)); 506 CRYPTO_nistcts128_encrypt(test_input, ciphertext, len, &encks, iv, 507 (cbc128_f) AES_cbc_encrypt); 508 if (memcmp(ciphertext, nistvector, len)) 509 fprintf(stderr, "output_%d mismatch\n", len), exit(3); 510 if (memcmp(iv, nistvector + len - tail, sizeof(iv))) 511 fprintf(stderr, "iv_%d mismatch\n", len), exit(3); 512 513 /* test streamed decryption */ 514 memcpy(iv, test_iv, sizeof(test_iv)); 515 CRYPTO_nistcts128_decrypt(ciphertext, cleartext, len, &decks, iv, 516 (cbc128_f) AES_cbc_encrypt); 517 if (memcmp(cleartext, test_input, len)) 518 fprintf(stderr, "input_%d mismatch\n", len), exit(4); 519 if (memcmp(iv, nistvector + len - tail, sizeof(iv))) 520 fprintf(stderr, "iv_%d mismatch\n", len), exit(4); 521} 522 523int main() 524{ 525 AES_set_encrypt_key(test_key, 128, &encks); 526 AES_set_decrypt_key(test_key, 128, &decks); 527 528 test_vector(vector_17, sizeof(vector_17)); 529 test_vector(vector_31, sizeof(vector_31)); 530 test_vector(vector_32, sizeof(vector_32)); 531 test_vector(vector_47, sizeof(vector_47)); 532 test_vector(vector_48, sizeof(vector_48)); 533 test_vector(vector_64, sizeof(vector_64)); 534 535 test_nistvector(vector_17, sizeof(vector_17)); 536 test_nistvector(vector_31, sizeof(vector_31)); 537 test_nistvector(vector_32, sizeof(vector_32)); 538 test_nistvector(vector_47, sizeof(vector_47)); 539 test_nistvector(vector_48, sizeof(vector_48)); 540 test_nistvector(vector_64, sizeof(vector_64)); 541 542 return 0; 543} 544#endif 545