1 /* 2 * Copyright 2008-2016 The OpenSSL Project Authors. All Rights Reserved. 3 * 4 * Licensed under the OpenSSL license (the "License"). You may not use 5 * this file except in compliance with the License. You can obtain a copy 6 * in the file LICENSE in the source distribution or at 7 * https://www.openssl.org/source/license.html 8 */ 9 10 #include <openssl/crypto.h> 11 #include "modes_local.h" 12 #include <string.h> 13 14 /* 15 * Trouble with Ciphertext Stealing, CTS, mode is that there is no 16 * common official specification, but couple of cipher/application 17 * specific ones: RFC2040 and RFC3962. Then there is 'Proposal to 18 * Extend CBC Mode By "Ciphertext Stealing"' at NIST site, which 19 * deviates from mentioned RFCs. Most notably it allows input to be 20 * of block length and it doesn't flip the order of the last two 21 * blocks. CTS is being discussed even in ECB context, but it's not 22 * adopted for any known application. This implementation provides 23 * two interfaces: one compliant with above mentioned RFCs and one 24 * compliant with the NIST proposal, both extending CBC mode. 25 */ 26 27 size_t CRYPTO_cts128_encrypt_block(const unsigned char *in, 28 unsigned char *out, size_t len, 29 const void *key, unsigned char ivec[16], 30 block128_f block) 31 { 32 size_t residue, n; 33 34 if (len <= 16) 35 return 0; 36 37 if ((residue = len % 16) == 0) 38 residue = 16; 39 40 len -= residue; 41 42 CRYPTO_cbc128_encrypt(in, out, len, key, ivec, block); 43 44 in += len; 45 out += len; 46 47 for (n = 0; n < residue; ++n) 48 ivec[n] ^= in[n]; 49 (*block) (ivec, ivec, key); 50 memcpy(out, out - 16, residue); 51 memcpy(out - 16, ivec, 16); 52 53 return len + residue; 54 } 55 56 size_t CRYPTO_nistcts128_encrypt_block(const unsigned char *in, 57 unsigned char *out, size_t len, 58 const void *key, 59 unsigned char ivec[16], 60 block128_f block) 61 { 62 size_t residue, n; 63 64 if (len < 16) 65 return 0; 66 67 residue = len % 16; 68 69 len -= residue; 70 71 CRYPTO_cbc128_encrypt(in, out, len, key, ivec, block); 72 73 if (residue == 0) 74 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 { 91 size_t residue; 92 union { 93 size_t align; 94 unsigned char c[16]; 95 } tmp; 96 97 if (len <= 16) 98 return 0; 99 100 if ((residue = len % 16) == 0) 101 residue = 16; 102 103 len -= residue; 104 105 (*cbc) (in, out, len, key, ivec, 1); 106 107 in += len; 108 out += len; 109 110 #if defined(CBC_HANDLES_TRUNCATED_IO) 111 memcpy(tmp.c, out - 16, 16); 112 (*cbc) (in, out - 16, residue, key, ivec, 1); 113 memcpy(out, tmp.c, residue); 114 #else 115 memset(tmp.c, 0, sizeof(tmp)); 116 memcpy(tmp.c, in, residue); 117 memcpy(out, out - 16, residue); 118 (*cbc) (tmp.c, out - 16, 16, key, ivec, 1); 119 #endif 120 return len + residue; 121 } 122 123 size_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 { 127 size_t residue; 128 union { 129 size_t align; 130 unsigned char c[16]; 131 } tmp; 132 133 if (len < 16) 134 return 0; 135 136 residue = len % 16; 137 138 len -= residue; 139 140 (*cbc) (in, out, len, key, ivec, 1); 141 142 if (residue == 0) 143 return len; 144 145 in += len; 146 out += len; 147 148 #if defined(CBC_HANDLES_TRUNCATED_IO) 149 (*cbc) (in, out - 16 + residue, residue, key, ivec, 1); 150 #else 151 memset(tmp.c, 0, sizeof(tmp)); 152 memcpy(tmp.c, in, residue); 153 (*cbc) (tmp.c, out - 16 + residue, 16, key, ivec, 1); 154 #endif 155 return len + residue; 156 } 157 158 size_t CRYPTO_cts128_decrypt_block(const unsigned char *in, 159 unsigned char *out, size_t len, 160 const void *key, unsigned char ivec[16], 161 block128_f block) 162 { 163 size_t residue, n; 164 union { 165 size_t align; 166 unsigned char c[32]; 167 } tmp; 168 169 if (len <= 16) 170 return 0; 171 172 if ((residue = len % 16) == 0) 173 residue = 16; 174 175 len -= 16 + residue; 176 177 if (len) { 178 CRYPTO_cbc128_decrypt(in, out, len, key, ivec, block); 179 in += len; 180 out += len; 181 } 182 183 (*block) (in, tmp.c + 16, key); 184 185 memcpy(tmp.c, tmp.c + 16, 16); 186 memcpy(tmp.c, in + 16, residue); 187 (*block) (tmp.c, tmp.c, key); 188 189 for (n = 0; n < 16; ++n) { 190 unsigned char c = in[n]; 191 out[n] = tmp.c[n] ^ ivec[n]; 192 ivec[n] = c; 193 } 194 for (residue += 16; n < residue; ++n) 195 out[n] = tmp.c[n] ^ in[n]; 196 197 return 16 + len + residue; 198 } 199 200 size_t CRYPTO_nistcts128_decrypt_block(const unsigned char *in, 201 unsigned char *out, size_t len, 202 const void *key, 203 unsigned char ivec[16], 204 block128_f block) 205 { 206 size_t residue, n; 207 union { 208 size_t align; 209 unsigned char c[32]; 210 } tmp; 211 212 if (len < 16) 213 return 0; 214 215 residue = len % 16; 216 217 if (residue == 0) { 218 CRYPTO_cbc128_decrypt(in, out, len, key, ivec, block); 219 return len; 220 } 221 222 len -= 16 + residue; 223 224 if (len) { 225 CRYPTO_cbc128_decrypt(in, out, len, key, ivec, block); 226 in += len; 227 out += len; 228 } 229 230 (*block) (in + residue, tmp.c + 16, key); 231 232 memcpy(tmp.c, tmp.c + 16, 16); 233 memcpy(tmp.c, in, residue); 234 (*block) (tmp.c, tmp.c, key); 235 236 for (n = 0; n < 16; ++n) { 237 unsigned char c = in[n]; 238 out[n] = tmp.c[n] ^ ivec[n]; 239 ivec[n] = in[n + residue]; 240 tmp.c[n] = c; 241 } 242 for (residue += 16; n < residue; ++n) 243 out[n] = tmp.c[n] ^ tmp.c[n - 16]; 244 245 return 16 + len + residue; 246 } 247 248 size_t CRYPTO_cts128_decrypt(const unsigned char *in, unsigned char *out, 249 size_t len, const void *key, 250 unsigned char ivec[16], cbc128_f cbc) 251 { 252 size_t residue; 253 union { 254 size_t align; 255 unsigned char c[32]; 256 } tmp; 257 258 if (len <= 16) 259 return 0; 260 261 if ((residue = len % 16) == 0) 262 residue = 16; 263 264 len -= 16 + residue; 265 266 if (len) { 267 (*cbc) (in, out, len, key, ivec, 0); 268 in += len; 269 out += len; 270 } 271 272 memset(tmp.c, 0, sizeof(tmp)); 273 /* 274 * this places in[16] at &tmp.c[16] and decrypted block at &tmp.c[0] 275 */ 276 (*cbc) (in, tmp.c, 16, key, tmp.c + 16, 0); 277 278 memcpy(tmp.c, in + 16, residue); 279 #if defined(CBC_HANDLES_TRUNCATED_IO) 280 (*cbc) (tmp.c, out, 16 + residue, key, ivec, 0); 281 #else 282 (*cbc) (tmp.c, tmp.c, 32, key, ivec, 0); 283 memcpy(out, tmp.c, 16 + residue); 284 #endif 285 return 16 + len + residue; 286 } 287 288 size_t CRYPTO_nistcts128_decrypt(const unsigned char *in, unsigned char *out, 289 size_t len, const void *key, 290 unsigned char ivec[16], cbc128_f cbc) 291 { 292 size_t residue; 293 union { 294 size_t align; 295 unsigned char c[32]; 296 } tmp; 297 298 if (len < 16) 299 return 0; 300 301 residue = len % 16; 302 303 if (residue == 0) { 304 (*cbc) (in, out, len, key, ivec, 0); 305 return len; 306 } 307 308 len -= 16 + residue; 309 310 if (len) { 311 (*cbc) (in, out, len, key, ivec, 0); 312 in += len; 313 out += len; 314 } 315 316 memset(tmp.c, 0, sizeof(tmp)); 317 /* 318 * this places in[16] at &tmp.c[16] and decrypted block at &tmp.c[0] 319 */ 320 (*cbc) (in + residue, tmp.c, 16, key, tmp.c + 16, 0); 321 322 memcpy(tmp.c, in, residue); 323 #if defined(CBC_HANDLES_TRUNCATED_IO) 324 (*cbc) (tmp.c, out, 16 + residue, key, ivec, 0); 325 #else 326 (*cbc) (tmp.c, tmp.c, 32, key, ivec, 0); 327 memcpy(out, tmp.c, 16 + residue); 328 #endif 329 return 16 + len + residue; 330 } 331