make depend
[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 #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,
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
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
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
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
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
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
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
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
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
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
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