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