cts128.c revision 238405
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, unsigned char *out, 33 size_t len, const void *key, 34 unsigned char ivec[16], block128_f block) 35{ size_t residue, n; 36 37 assert (in && out && key && ivec); 38 39 if (len <= 16) return 0; 40 41 if ((residue=len%16) == 0) residue = 16; 42 43 len -= residue; 44 45 CRYPTO_cbc128_encrypt(in,out,len,key,ivec,block); 46 47 in += len; 48 out += len; 49 50 for (n=0; n<residue; ++n) 51 ivec[n] ^= in[n]; 52 (*block)(ivec,ivec,key); 53 memcpy(out,out-16,residue); 54 memcpy(out-16,ivec,16); 55 56 return len+residue; 57} 58 59size_t CRYPTO_nistcts128_encrypt_block(const unsigned char *in, unsigned char *out, 60 size_t len, const void *key, 61 unsigned char ivec[16], block128_f block) 62{ size_t residue, n; 63 64 assert (in && out && key && ivec); 65 66 if (len < 16) return 0; 67 68 residue=len%16; 69 70 len -= residue; 71 72 CRYPTO_cbc128_encrypt(in,out,len,key,ivec,block); 73 74 if (residue==0) return len; 75 76 in += len; 77 out += len; 78 79 for (n=0; n<residue; ++n) 80 ivec[n] ^= in[n]; 81 (*block)(ivec,ivec,key); 82 memcpy(out-16+residue,ivec,16); 83 84 return len+residue; 85} 86 87size_t CRYPTO_cts128_encrypt(const unsigned char *in, unsigned char *out, 88 size_t len, const void *key, 89 unsigned char ivec[16], cbc128_f cbc) 90{ size_t residue; 91 union { size_t align; unsigned char c[16]; } tmp; 92 93 assert (in && out && key && ivec); 94 95 if (len <= 16) return 0; 96 97 if ((residue=len%16) == 0) residue = 16; 98 99 len -= residue; 100 101 (*cbc)(in,out,len,key,ivec,1); 102 103 in += len; 104 out += len; 105 106#if defined(CBC_HANDLES_TRUNCATED_IO) 107 memcpy(tmp.c,out-16,16); 108 (*cbc)(in,out-16,residue,key,ivec,1); 109 memcpy(out,tmp.c,residue); 110#else 111 { 112 size_t n; 113 for (n=0; n<16; n+=sizeof(size_t)) 114 *(size_t *)(tmp.c+n) = 0; 115 memcpy(tmp.c,in,residue); 116 } 117 memcpy(out,out-16,residue); 118 (*cbc)(tmp.c,out-16,16,key,ivec,1); 119#endif 120 return len+residue; 121} 122 123size_t CRYPTO_nistcts128_encrypt(const unsigned char *in, unsigned char *out, 124 size_t len, const void *key, 125 unsigned char ivec[16], cbc128_f cbc) 126{ size_t residue; 127 union { size_t align; unsigned char c[16]; } tmp; 128 129 assert (in && out && key && ivec); 130 131 if (len < 16) return 0; 132 133 residue=len%16; 134 135 len -= residue; 136 137 (*cbc)(in,out,len,key,ivec,1); 138 139 if (residue==0) return len; 140 141 in += len; 142 out += len; 143 144#if defined(CBC_HANDLES_TRUNCATED_IO) 145 (*cbc)(in,out-16+residue,residue,key,ivec,1); 146#else 147 { 148 size_t n; 149 for (n=0; n<16; n+=sizeof(size_t)) 150 *(size_t *)(tmp.c+n) = 0; 151 memcpy(tmp.c,in,residue); 152 } 153 (*cbc)(tmp.c,out-16+residue,16,key,ivec,1); 154#endif 155 return len+residue; 156} 157 158size_t CRYPTO_cts128_decrypt_block(const unsigned char *in, unsigned char *out, 159 size_t len, const void *key, 160 unsigned char ivec[16], block128_f block) 161{ size_t residue, n; 162 union { size_t align; unsigned char c[32]; } tmp; 163 164 assert (in && out && key && ivec); 165 166 if (len<=16) return 0; 167 168 if ((residue=len%16) == 0) residue = 16; 169 170 len -= 16+residue; 171 172 if (len) { 173 CRYPTO_cbc128_decrypt(in,out,len,key,ivec,block); 174 in += len; 175 out += len; 176 } 177 178 (*block)(in,tmp.c+16,key); 179 180 for (n=0; n<16; n+=sizeof(size_t)) 181 *(size_t *)(tmp.c+n) = *(size_t *)(tmp.c+16+n); 182 memcpy(tmp.c,in+16,residue); 183 (*block)(tmp.c,tmp.c,key); 184 185 for(n=0; n<16; ++n) { 186 unsigned char c = in[n]; 187 out[n] = tmp.c[n] ^ ivec[n]; 188 ivec[n] = c; 189 } 190 for(residue+=16; n<residue; ++n) 191 out[n] = tmp.c[n] ^ in[n]; 192 193 return 16+len+residue; 194} 195 196size_t CRYPTO_nistcts128_decrypt_block(const unsigned char *in, unsigned char *out, 197 size_t len, const void *key, 198 unsigned char ivec[16], block128_f block) 199{ size_t residue, n; 200 union { size_t align; unsigned char c[32]; } tmp; 201 202 assert (in && out && key && ivec); 203 204 if (len<16) return 0; 205 206 residue=len%16; 207 208 if (residue==0) { 209 CRYPTO_cbc128_decrypt(in,out,len,key,ivec,block); 210 return len; 211 } 212 213 len -= 16+residue; 214 215 if (len) { 216 CRYPTO_cbc128_decrypt(in,out,len,key,ivec,block); 217 in += len; 218 out += len; 219 } 220 221 (*block)(in+residue,tmp.c+16,key); 222 223 for (n=0; n<16; n+=sizeof(size_t)) 224 *(size_t *)(tmp.c+n) = *(size_t *)(tmp.c+16+n); 225 memcpy(tmp.c,in,residue); 226 (*block)(tmp.c,tmp.c,key); 227 228 for(n=0; n<16; ++n) { 229 unsigned char c = in[n]; 230 out[n] = tmp.c[n] ^ ivec[n]; 231 ivec[n] = in[n+residue]; 232 tmp.c[n] = c; 233 } 234 for(residue+=16; n<residue; ++n) 235 out[n] = tmp.c[n] ^ tmp.c[n-16]; 236 237 return 16+len+residue; 238} 239 240size_t CRYPTO_cts128_decrypt(const unsigned char *in, unsigned char *out, 241 size_t len, const void *key, 242 unsigned char ivec[16], cbc128_f cbc) 243{ size_t residue, n; 244 union { size_t align; unsigned char c[32]; } tmp; 245 246 assert (in && out && key && ivec); 247 248 if (len<=16) return 0; 249 250 if ((residue=len%16) == 0) residue = 16; 251 252 len -= 16+residue; 253 254 if (len) { 255 (*cbc)(in,out,len,key,ivec,0); 256 in += len; 257 out += len; 258 } 259 260 for (n=16; n<32; n+=sizeof(size_t)) 261 *(size_t *)(tmp.c+n) = 0; 262 /* this places in[16] at &tmp.c[16] and decrypted block at &tmp.c[0] */ 263 (*cbc)(in,tmp.c,16,key,tmp.c+16,0); 264 265 memcpy(tmp.c,in+16,residue); 266#if defined(CBC_HANDLES_TRUNCATED_IO) 267 (*cbc)(tmp.c,out,16+residue,key,ivec,0); 268#else 269 (*cbc)(tmp.c,tmp.c,32,key,ivec,0); 270 memcpy(out,tmp.c,16+residue); 271#endif 272 return 16+len+residue; 273} 274 275size_t CRYPTO_nistcts128_decrypt(const unsigned char *in, unsigned char *out, 276 size_t len, const void *key, 277 unsigned char ivec[16], cbc128_f cbc) 278{ size_t residue, n; 279 union { size_t align; unsigned char c[32]; } tmp; 280 281 assert (in && out && key && ivec); 282 283 if (len<16) return 0; 284 285 residue=len%16; 286 287 if (residue==0) { 288 (*cbc)(in,out,len,key,ivec,0); 289 return len; 290 } 291 292 len -= 16+residue; 293 294 if (len) { 295 (*cbc)(in,out,len,key,ivec,0); 296 in += len; 297 out += len; 298 } 299 300 for (n=16; n<32; n+=sizeof(size_t)) 301 *(size_t *)(tmp.c+n) = 0; 302 /* this places in[16] at &tmp.c[16] and decrypted block at &tmp.c[0] */ 303 (*cbc)(in+residue,tmp.c,16,key,tmp.c+16,0); 304 305 memcpy(tmp.c,in,residue); 306#if defined(CBC_HANDLES_TRUNCATED_IO) 307 (*cbc)(tmp.c,out,16+residue,key,ivec,0); 308#else 309 (*cbc)(tmp.c,tmp.c,32,key,ivec,0); 310 memcpy(out,tmp.c,16+residue); 311#endif 312 return 16+len+residue; 313} 314 315#if defined(SELFTEST) 316#include <stdio.h> 317#include <openssl/aes.h> 318 319/* test vectors from RFC 3962 */ 320static const unsigned char test_key[16] = "chicken teriyaki"; 321static const unsigned char test_input[64] = 322 "I would like the" " General Gau's C" 323 "hicken, please, " "and wonton soup."; 324static const unsigned char test_iv[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; 325 326static const unsigned char vector_17[17] = 327{0xc6,0x35,0x35,0x68,0xf2,0xbf,0x8c,0xb4, 0xd8,0xa5,0x80,0x36,0x2d,0xa7,0xff,0x7f, 328 0x97}; 329static const unsigned char vector_31[31] = 330{0xfc,0x00,0x78,0x3e,0x0e,0xfd,0xb2,0xc1, 0xd4,0x45,0xd4,0xc8,0xef,0xf7,0xed,0x22, 331 0x97,0x68,0x72,0x68,0xd6,0xec,0xcc,0xc0, 0xc0,0x7b,0x25,0xe2,0x5e,0xcf,0xe5}; 332static const unsigned char vector_32[32] = 333{0x39,0x31,0x25,0x23,0xa7,0x86,0x62,0xd5, 0xbe,0x7f,0xcb,0xcc,0x98,0xeb,0xf5,0xa8, 334 0x97,0x68,0x72,0x68,0xd6,0xec,0xcc,0xc0, 0xc0,0x7b,0x25,0xe2,0x5e,0xcf,0xe5,0x84}; 335static const unsigned char vector_47[47] = 336{0x97,0x68,0x72,0x68,0xd6,0xec,0xcc,0xc0, 0xc0,0x7b,0x25,0xe2,0x5e,0xcf,0xe5,0x84, 337 0xb3,0xff,0xfd,0x94,0x0c,0x16,0xa1,0x8c, 0x1b,0x55,0x49,0xd2,0xf8,0x38,0x02,0x9e, 338 0x39,0x31,0x25,0x23,0xa7,0x86,0x62,0xd5, 0xbe,0x7f,0xcb,0xcc,0x98,0xeb,0xf5}; 339static const unsigned char vector_48[48] = 340{0x97,0x68,0x72,0x68,0xd6,0xec,0xcc,0xc0, 0xc0,0x7b,0x25,0xe2,0x5e,0xcf,0xe5,0x84, 341 0x9d,0xad,0x8b,0xbb,0x96,0xc4,0xcd,0xc0, 0x3b,0xc1,0x03,0xe1,0xa1,0x94,0xbb,0xd8, 342 0x39,0x31,0x25,0x23,0xa7,0x86,0x62,0xd5, 0xbe,0x7f,0xcb,0xcc,0x98,0xeb,0xf5,0xa8}; 343static const unsigned char vector_64[64] = 344{0x97,0x68,0x72,0x68,0xd6,0xec,0xcc,0xc0, 0xc0,0x7b,0x25,0xe2,0x5e,0xcf,0xe5,0x84, 345 0x39,0x31,0x25,0x23,0xa7,0x86,0x62,0xd5, 0xbe,0x7f,0xcb,0xcc,0x98,0xeb,0xf5,0xa8, 346 0x48,0x07,0xef,0xe8,0x36,0xee,0x89,0xa5, 0x26,0x73,0x0d,0xbc,0x2f,0x7b,0xc8,0x40, 347 0x9d,0xad,0x8b,0xbb,0x96,0xc4,0xcd,0xc0, 0x3b,0xc1,0x03,0xe1,0xa1,0x94,0xbb,0xd8}; 348 349static AES_KEY encks, decks; 350 351void test_vector(const unsigned char *vector,size_t len) 352{ unsigned char iv[sizeof(test_iv)]; 353 unsigned char cleartext[64],ciphertext[64]; 354 size_t tail; 355 356 printf("vector_%d\n",len); fflush(stdout); 357 358 if ((tail=len%16) == 0) tail = 16; 359 tail += 16; 360 361 /* test block-based encryption */ 362 memcpy(iv,test_iv,sizeof(test_iv)); 363 CRYPTO_cts128_encrypt_block(test_input,ciphertext,len,&encks,iv,(block128_f)AES_encrypt); 364 if (memcmp(ciphertext,vector,len)) 365 fprintf(stderr,"output_%d mismatch\n",len), exit(1); 366 if (memcmp(iv,vector+len-tail,sizeof(iv))) 367 fprintf(stderr,"iv_%d mismatch\n",len), exit(1); 368 369 /* test block-based decryption */ 370 memcpy(iv,test_iv,sizeof(test_iv)); 371 CRYPTO_cts128_decrypt_block(ciphertext,cleartext,len,&decks,iv,(block128_f)AES_decrypt); 372 if (memcmp(cleartext,test_input,len)) 373 fprintf(stderr,"input_%d mismatch\n",len), exit(2); 374 if (memcmp(iv,vector+len-tail,sizeof(iv))) 375 fprintf(stderr,"iv_%d mismatch\n",len), exit(2); 376 377 /* test streamed encryption */ 378 memcpy(iv,test_iv,sizeof(test_iv)); 379 CRYPTO_cts128_encrypt(test_input,ciphertext,len,&encks,iv,(cbc128_f)AES_cbc_encrypt); 380 if (memcmp(ciphertext,vector,len)) 381 fprintf(stderr,"output_%d mismatch\n",len), exit(3); 382 if (memcmp(iv,vector+len-tail,sizeof(iv))) 383 fprintf(stderr,"iv_%d mismatch\n",len), exit(3); 384 385 /* test streamed decryption */ 386 memcpy(iv,test_iv,sizeof(test_iv)); 387 CRYPTO_cts128_decrypt(ciphertext,cleartext,len,&decks,iv,(cbc128_f)AES_cbc_encrypt); 388 if (memcmp(cleartext,test_input,len)) 389 fprintf(stderr,"input_%d mismatch\n",len), exit(4); 390 if (memcmp(iv,vector+len-tail,sizeof(iv))) 391 fprintf(stderr,"iv_%d mismatch\n",len), exit(4); 392} 393 394void test_nistvector(const unsigned char *vector,size_t len) 395{ unsigned char iv[sizeof(test_iv)]; 396 unsigned char cleartext[64],ciphertext[64],nistvector[64]; 397 size_t tail; 398 399 printf("nistvector_%d\n",len); fflush(stdout); 400 401 if ((tail=len%16) == 0) tail = 16; 402 403 len -= 16 + tail; 404 memcpy(nistvector,vector,len); 405 /* flip two last blocks */ 406 memcpy(nistvector+len,vector+len+16,tail); 407 memcpy(nistvector+len+tail,vector+len,16); 408 len += 16 + tail; 409 tail = 16; 410 411 /* test block-based encryption */ 412 memcpy(iv,test_iv,sizeof(test_iv)); 413 CRYPTO_nistcts128_encrypt_block(test_input,ciphertext,len,&encks,iv,(block128_f)AES_encrypt); 414 if (memcmp(ciphertext,nistvector,len)) 415 fprintf(stderr,"output_%d mismatch\n",len), exit(1); 416 if (memcmp(iv,nistvector+len-tail,sizeof(iv))) 417 fprintf(stderr,"iv_%d mismatch\n",len), exit(1); 418 419 /* test block-based decryption */ 420 memcpy(iv,test_iv,sizeof(test_iv)); 421 CRYPTO_nistcts128_decrypt_block(ciphertext,cleartext,len,&decks,iv,(block128_f)AES_decrypt); 422 if (memcmp(cleartext,test_input,len)) 423 fprintf(stderr,"input_%d mismatch\n",len), exit(2); 424 if (memcmp(iv,nistvector+len-tail,sizeof(iv))) 425 fprintf(stderr,"iv_%d mismatch\n",len), exit(2); 426 427 /* test streamed encryption */ 428 memcpy(iv,test_iv,sizeof(test_iv)); 429 CRYPTO_nistcts128_encrypt(test_input,ciphertext,len,&encks,iv,(cbc128_f)AES_cbc_encrypt); 430 if (memcmp(ciphertext,nistvector,len)) 431 fprintf(stderr,"output_%d mismatch\n",len), exit(3); 432 if (memcmp(iv,nistvector+len-tail,sizeof(iv))) 433 fprintf(stderr,"iv_%d mismatch\n",len), exit(3); 434 435 /* test streamed decryption */ 436 memcpy(iv,test_iv,sizeof(test_iv)); 437 CRYPTO_nistcts128_decrypt(ciphertext,cleartext,len,&decks,iv,(cbc128_f)AES_cbc_encrypt); 438 if (memcmp(cleartext,test_input,len)) 439 fprintf(stderr,"input_%d mismatch\n",len), exit(4); 440 if (memcmp(iv,nistvector+len-tail,sizeof(iv))) 441 fprintf(stderr,"iv_%d mismatch\n",len), exit(4); 442} 443 444int main() 445{ 446 AES_set_encrypt_key(test_key,128,&encks); 447 AES_set_decrypt_key(test_key,128,&decks); 448 449 test_vector(vector_17,sizeof(vector_17)); 450 test_vector(vector_31,sizeof(vector_31)); 451 test_vector(vector_32,sizeof(vector_32)); 452 test_vector(vector_47,sizeof(vector_47)); 453 test_vector(vector_48,sizeof(vector_48)); 454 test_vector(vector_64,sizeof(vector_64)); 455 456 test_nistvector(vector_17,sizeof(vector_17)); 457 test_nistvector(vector_31,sizeof(vector_31)); 458 test_nistvector(vector_32,sizeof(vector_32)); 459 test_nistvector(vector_47,sizeof(vector_47)); 460 test_nistvector(vector_48,sizeof(vector_48)); 461 test_nistvector(vector_64,sizeof(vector_64)); 462 463 return 0; 464} 465#endif 466