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
CRYPTO_cts128_encrypt_block(const unsigned char * in,unsigned char * out,size_t len,const void * key,unsigned char ivec[16],block128_f block)32 size_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
CRYPTO_nistcts128_encrypt_block(const unsigned char * in,unsigned char * out,size_t len,const void * key,unsigned char ivec[16],block128_f block)63 size_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
CRYPTO_cts128_encrypt(const unsigned char * in,unsigned char * out,size_t len,const void * key,unsigned char ivec[16],cbc128_f cbc)96 size_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
CRYPTO_nistcts128_encrypt(const unsigned char * in,unsigned char * out,size_t len,const void * key,unsigned char ivec[16],cbc128_f cbc)134 size_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
CRYPTO_cts128_decrypt_block(const unsigned char * in,unsigned char * out,size_t len,const void * key,unsigned char ivec[16],block128_f block)171 size_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
CRYPTO_nistcts128_decrypt_block(const unsigned char * in,unsigned char * out,size_t len,const void * key,unsigned char ivec[16],block128_f block)215 size_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
CRYPTO_cts128_decrypt(const unsigned char * in,unsigned char * out,size_t len,const void * key,unsigned char ivec[16],cbc128_f cbc)265 size_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
CRYPTO_nistcts128_decrypt(const unsigned char * in,unsigned char * out,size_t len,const void * key,unsigned char ivec[16],cbc128_f cbc)307 size_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 */
358 static const unsigned char test_key[16] = "chicken teriyaki";
359 static const unsigned char test_input[64] =
360 "I would like the" " General Gau's C"
361 "hicken, please, " "and wonton soup.";
362 static const unsigned char test_iv[16] =
363 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
364
365 static 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
371 static 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
378 static 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
385 static 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
394 static 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
403 static 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
414 static AES_KEY encks, decks;
415
test_vector(const unsigned char * vector,size_t len)416 void 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
test_nistvector(const unsigned char * vector,size_t len)466 void 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
main()523 int 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