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