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 "modes.h" 9#include <string.h> 10 11#ifndef MODES_DEBUG 12# ifndef NDEBUG 13# define NDEBUG 14# endif 15#endif 16#include <assert.h> 17 18/* 19 * Trouble with Ciphertext Stealing, CTS, mode is that there is no 20 * common official specification, but couple of cipher/application 21 * specific ones: RFC2040 and RFC3962. Then there is 'Proposal to 22 * Extend CBC Mode By "Ciphertext Stealing"' at NIST site, which 23 * deviates from mentioned RFCs. Most notably it allows input to be 24 * of block length and it doesn't flip the order of the last two 25 * blocks. CTS is being discussed even in ECB context, but it's not 26 * adopted for any known application. This implementation complies 27 * with mentioned RFCs and [as such] extends CBC mode. 28 */ 29 30size_t CRYPTO_cts128_encrypt_block(const unsigned char *in, unsigned char *out, 31 size_t len, const void *key, 32 unsigned char ivec[16], block128_f block) 33{ size_t residue, n; 34 35 assert (in && out && key && ivec); 36 37 if (len <= 16) return 0; 38 39 if ((residue=len%16) == 0) residue = 16; 40 41 len -= residue; 42 43 CRYPTO_cbc128_encrypt(in,out,len,key,ivec,block); 44 45 in += len; 46 out += len; 47 48 for (n=0; n<residue; ++n) 49 ivec[n] ^= in[n]; 50 (*block)(ivec,ivec,key); 51 memcpy(out,out-16,residue); 52 memcpy(out-16,ivec,16); 53 54 return len+residue; 55} 56 57size_t CRYPTO_cts128_encrypt(const unsigned char *in, unsigned char *out, 58 size_t len, const void *key, 59 unsigned char ivec[16], cbc128_f cbc) 60{ size_t residue; 61 union { size_t align; unsigned char c[16]; } tmp; 62 63 assert (in && out && key && ivec); 64 65 if (len <= 16) return 0; 66 67 if ((residue=len%16) == 0) residue = 16; 68 69 len -= residue; 70 71 (*cbc)(in,out,len,key,ivec,1); 72 73 in += len; 74 out += len; 75 76#if defined(CBC_HANDLES_TRUNCATED_IO) 77 memcpy(tmp.c,out-16,16); 78 (*cbc)(in,out-16,residue,key,ivec,1); 79 memcpy(out,tmp.c,residue); 80#else 81 { 82 size_t n; 83 for (n=0; n<16; n+=sizeof(size_t)) 84 *(size_t *)(tmp.c+n) = 0; 85 memcpy(tmp.c,in,residue); 86 } 87 memcpy(out,out-16,residue); 88 (*cbc)(tmp.c,out-16,16,key,ivec,1); 89#endif 90 return len+residue; 91} 92 93size_t CRYPTO_cts128_decrypt_block(const unsigned char *in, unsigned char *out, 94 size_t len, const void *key, 95 unsigned char ivec[16], block128_f block) 96{ size_t residue, n; 97 union { size_t align; unsigned char c[32]; } tmp; 98 99 assert (in && out && key && ivec); 100 101 if (len<=16) return 0; 102 103 if ((residue=len%16) == 0) residue = 16; 104 105 len -= 16+residue; 106 107 if (len) { 108 CRYPTO_cbc128_decrypt(in,out,len,key,ivec,block); 109 in += len; 110 out += len; 111 } 112 113 (*block)(in,tmp.c+16,key); 114 115 for (n=0; n<16; n+=sizeof(size_t)) 116 *(size_t *)(tmp.c+n) = *(size_t *)(tmp.c+16+n); 117 memcpy(tmp.c,in+16,residue); 118 (*block)(tmp.c,tmp.c,key); 119 120 for(n=0; n<16; ++n) { 121 unsigned char c = in[n]; 122 out[n] = tmp.c[n] ^ ivec[n]; 123 ivec[n] = c; 124 } 125 for(residue+=16; n<residue; ++n) 126 out[n] = tmp.c[n] ^ in[n]; 127 128 return len+residue-16; 129} 130 131size_t CRYPTO_cts128_decrypt(const unsigned char *in, unsigned char *out, 132 size_t len, const void *key, 133 unsigned char ivec[16], cbc128_f cbc) 134{ size_t residue, n; 135 union { size_t align; unsigned char c[32]; } tmp; 136 137 assert (in && out && key && ivec); 138 139 if (len<=16) return 0; 140 141 if ((residue=len%16) == 0) residue = 16; 142 143 len -= 16+residue; 144 145 if (len) { 146 (*cbc)(in,out,len,key,ivec,0); 147 in += len; 148 out += len; 149 } 150 151 for (n=16; n<32; n+=sizeof(size_t)) 152 *(size_t *)(tmp.c+n) = 0; 153 /* this places in[16] at &tmp.c[16] and decrypted block at &tmp.c[0] */ 154 (*cbc)(in,tmp.c,16,key,tmp.c+16,0); 155 156 memcpy(tmp.c,in+16,residue); 157#if defined(CBC_HANDLES_TRUNCATED_IO) 158 (*cbc)(tmp.c,out,16+residue,key,ivec,0); 159#else 160 (*cbc)(tmp.c,tmp.c,32,key,ivec,0); 161 memcpy(out,tmp.c,16+residue); 162#endif 163 return len+residue; 164} 165 166#if defined(SELFTEST) 167#include <stdio.h> 168#include <openssl/aes.h> 169 170/* test vectors from RFC 3962 */ 171static const unsigned char test_key[16] = "chicken teriyaki"; 172static const unsigned char test_input[64] = 173 "I would like the" " General Gau's C" 174 "hicken, please, " "and wonton soup."; 175static const unsigned char test_iv[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; 176 177static const unsigned char vector_17[17] = 178{0xc6,0x35,0x35,0x68,0xf2,0xbf,0x8c,0xb4, 0xd8,0xa5,0x80,0x36,0x2d,0xa7,0xff,0x7f, 179 0x97}; 180static const unsigned char vector_31[31] = 181{0xfc,0x00,0x78,0x3e,0x0e,0xfd,0xb2,0xc1, 0xd4,0x45,0xd4,0xc8,0xef,0xf7,0xed,0x22, 182 0x97,0x68,0x72,0x68,0xd6,0xec,0xcc,0xc0, 0xc0,0x7b,0x25,0xe2,0x5e,0xcf,0xe5}; 183static const unsigned char vector_32[32] = 184{0x39,0x31,0x25,0x23,0xa7,0x86,0x62,0xd5, 0xbe,0x7f,0xcb,0xcc,0x98,0xeb,0xf5,0xa8, 185 0x97,0x68,0x72,0x68,0xd6,0xec,0xcc,0xc0, 0xc0,0x7b,0x25,0xe2,0x5e,0xcf,0xe5,0x84}; 186static const unsigned char vector_47[47] = 187{0x97,0x68,0x72,0x68,0xd6,0xec,0xcc,0xc0, 0xc0,0x7b,0x25,0xe2,0x5e,0xcf,0xe5,0x84, 188 0xb3,0xff,0xfd,0x94,0x0c,0x16,0xa1,0x8c, 0x1b,0x55,0x49,0xd2,0xf8,0x38,0x02,0x9e, 189 0x39,0x31,0x25,0x23,0xa7,0x86,0x62,0xd5, 0xbe,0x7f,0xcb,0xcc,0x98,0xeb,0xf5}; 190static const unsigned char vector_48[48] = 191{0x97,0x68,0x72,0x68,0xd6,0xec,0xcc,0xc0, 0xc0,0x7b,0x25,0xe2,0x5e,0xcf,0xe5,0x84, 192 0x9d,0xad,0x8b,0xbb,0x96,0xc4,0xcd,0xc0, 0x3b,0xc1,0x03,0xe1,0xa1,0x94,0xbb,0xd8, 193 0x39,0x31,0x25,0x23,0xa7,0x86,0x62,0xd5, 0xbe,0x7f,0xcb,0xcc,0x98,0xeb,0xf5,0xa8}; 194static const unsigned char vector_64[64] = 195{0x97,0x68,0x72,0x68,0xd6,0xec,0xcc,0xc0, 0xc0,0x7b,0x25,0xe2,0x5e,0xcf,0xe5,0x84, 196 0x39,0x31,0x25,0x23,0xa7,0x86,0x62,0xd5, 0xbe,0x7f,0xcb,0xcc,0x98,0xeb,0xf5,0xa8, 197 0x48,0x07,0xef,0xe8,0x36,0xee,0x89,0xa5, 0x26,0x73,0x0d,0xbc,0x2f,0x7b,0xc8,0x40, 198 0x9d,0xad,0x8b,0xbb,0x96,0xc4,0xcd,0xc0, 0x3b,0xc1,0x03,0xe1,0xa1,0x94,0xbb,0xd8}; 199 200static AES_KEY encks, decks; 201 202void test_vector(const unsigned char *vector,size_t len) 203{ unsigned char cleartext[64]; 204 unsigned char iv[sizeof(test_iv)]; 205 unsigned char ciphertext[64]; 206 size_t tail; 207 208 printf("vector_%d\n",len); fflush(stdout); 209 210 if ((tail=len%16) == 0) tail = 16; 211 tail += 16; 212 213 /* test block-based encryption */ 214 memcpy(iv,test_iv,sizeof(test_iv)); 215 CRYPTO_cts128_encrypt_block(test_input,ciphertext,len,&encks,iv,(block128_f)AES_encrypt); 216 if (memcmp(ciphertext,vector,len)) 217 fprintf(stderr,"output_%d mismatch\n",len), exit(1); 218 if (memcmp(iv,vector+len-tail,sizeof(iv))) 219 fprintf(stderr,"iv_%d mismatch\n",len), exit(1); 220 221 /* test block-based decryption */ 222 memcpy(iv,test_iv,sizeof(test_iv)); 223 CRYPTO_cts128_decrypt_block(ciphertext,cleartext,len,&decks,iv,(block128_f)AES_decrypt); 224 if (memcmp(cleartext,test_input,len)) 225 fprintf(stderr,"input_%d mismatch\n",len), exit(2); 226 if (memcmp(iv,vector+len-tail,sizeof(iv))) 227 fprintf(stderr,"iv_%d mismatch\n",len), exit(2); 228 229 /* test streamed encryption */ 230 memcpy(iv,test_iv,sizeof(test_iv)); 231 CRYPTO_cts128_encrypt(test_input,ciphertext,len,&encks,iv,(cbc128_f)AES_cbc_encrypt); 232 if (memcmp(ciphertext,vector,len)) 233 fprintf(stderr,"output_%d mismatch\n",len), exit(3); 234 if (memcmp(iv,vector+len-tail,sizeof(iv))) 235 fprintf(stderr,"iv_%d mismatch\n",len), exit(3); 236 237 /* test streamed decryption */ 238 memcpy(iv,test_iv,sizeof(test_iv)); 239 CRYPTO_cts128_decrypt(ciphertext,cleartext,len,&decks,iv,(cbc128_f)AES_cbc_encrypt); 240 if (memcmp(cleartext,test_input,len)) 241 fprintf(stderr,"input_%d mismatch\n",len), exit(4); 242 if (memcmp(iv,vector+len-tail,sizeof(iv))) 243 fprintf(stderr,"iv_%d mismatch\n",len), exit(4); 244} 245 246main() 247{ 248 AES_set_encrypt_key(test_key,128,&encks); 249 AES_set_decrypt_key(test_key,128,&decks); 250 251 test_vector(vector_17,sizeof(vector_17)); 252 test_vector(vector_31,sizeof(vector_31)); 253 test_vector(vector_32,sizeof(vector_32)); 254 test_vector(vector_47,sizeof(vector_47)); 255 test_vector(vector_48,sizeof(vector_48)); 256 test_vector(vector_64,sizeof(vector_64)); 257 exit(0); 258} 259#endif 260