77ec994b4f608ccd3cd5fefa4fa883635ada508a
[openssl.git] / crypto / modes / cts128.c
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_lcl.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
332 #if defined(SELFTEST)
333 # include <stdio.h>
334 # include <openssl/aes.h>
335
336 /* test vectors from RFC 3962 */
337 static const unsigned char test_key[16] = "chicken teriyaki";
338 static const unsigned char test_input[64] =
339     "I would like the" " General Gau's C"
340     "hicken, please, " "and wonton soup.";
341 static const unsigned char test_iv[16] =
342     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
343
344 static const unsigned char vector_17[17] = {
345     0xc6, 0x35, 0x35, 0x68, 0xf2, 0xbf, 0x8c, 0xb4,
346     0xd8, 0xa5, 0x80, 0x36, 0x2d, 0xa7, 0xff, 0x7f,
347     0x97
348 };
349
350 static const unsigned char vector_31[31] = {
351     0xfc, 0x00, 0x78, 0x3e, 0x0e, 0xfd, 0xb2, 0xc1,
352     0xd4, 0x45, 0xd4, 0xc8, 0xef, 0xf7, 0xed, 0x22,
353     0x97, 0x68, 0x72, 0x68, 0xd6, 0xec, 0xcc, 0xc0,
354     0xc0, 0x7b, 0x25, 0xe2, 0x5e, 0xcf, 0xe5
355 };
356
357 static const unsigned char vector_32[32] = {
358     0x39, 0x31, 0x25, 0x23, 0xa7, 0x86, 0x62, 0xd5,
359     0xbe, 0x7f, 0xcb, 0xcc, 0x98, 0xeb, 0xf5, 0xa8,
360     0x97, 0x68, 0x72, 0x68, 0xd6, 0xec, 0xcc, 0xc0,
361     0xc0, 0x7b, 0x25, 0xe2, 0x5e, 0xcf, 0xe5, 0x84
362 };
363
364 static const unsigned char vector_47[47] = {
365     0x97, 0x68, 0x72, 0x68, 0xd6, 0xec, 0xcc, 0xc0,
366     0xc0, 0x7b, 0x25, 0xe2, 0x5e, 0xcf, 0xe5, 0x84,
367     0xb3, 0xff, 0xfd, 0x94, 0x0c, 0x16, 0xa1, 0x8c,
368     0x1b, 0x55, 0x49, 0xd2, 0xf8, 0x38, 0x02, 0x9e,
369     0x39, 0x31, 0x25, 0x23, 0xa7, 0x86, 0x62, 0xd5,
370     0xbe, 0x7f, 0xcb, 0xcc, 0x98, 0xeb, 0xf5
371 };
372
373 static const unsigned char vector_48[48] = {
374     0x97, 0x68, 0x72, 0x68, 0xd6, 0xec, 0xcc, 0xc0,
375     0xc0, 0x7b, 0x25, 0xe2, 0x5e, 0xcf, 0xe5, 0x84,
376     0x9d, 0xad, 0x8b, 0xbb, 0x96, 0xc4, 0xcd, 0xc0,
377     0x3b, 0xc1, 0x03, 0xe1, 0xa1, 0x94, 0xbb, 0xd8,
378     0x39, 0x31, 0x25, 0x23, 0xa7, 0x86, 0x62, 0xd5,
379     0xbe, 0x7f, 0xcb, 0xcc, 0x98, 0xeb, 0xf5, 0xa8
380 };
381
382 static const unsigned char vector_64[64] = {
383     0x97, 0x68, 0x72, 0x68, 0xd6, 0xec, 0xcc, 0xc0,
384     0xc0, 0x7b, 0x25, 0xe2, 0x5e, 0xcf, 0xe5, 0x84,
385     0x39, 0x31, 0x25, 0x23, 0xa7, 0x86, 0x62, 0xd5,
386     0xbe, 0x7f, 0xcb, 0xcc, 0x98, 0xeb, 0xf5, 0xa8,
387     0x48, 0x07, 0xef, 0xe8, 0x36, 0xee, 0x89, 0xa5,
388     0x26, 0x73, 0x0d, 0xbc, 0x2f, 0x7b, 0xc8, 0x40,
389     0x9d, 0xad, 0x8b, 0xbb, 0x96, 0xc4, 0xcd, 0xc0,
390     0x3b, 0xc1, 0x03, 0xe1, 0xa1, 0x94, 0xbb, 0xd8
391 };
392
393 static AES_KEY encks, decks;
394
395 void test_vector(const unsigned char *vector, size_t len)
396 {
397     unsigned char iv[sizeof(test_iv)];
398     unsigned char cleartext[64], ciphertext[64];
399     size_t tail;
400
401     printf("vector_%d\n", len);
402     fflush(stdout);
403
404     if ((tail = len % 16) == 0)
405         tail = 16;
406     tail += 16;
407
408     /* test block-based encryption */
409     memcpy(iv, test_iv, sizeof(test_iv));
410     CRYPTO_cts128_encrypt_block(test_input, ciphertext, len, &encks, iv,
411                                 (block128_f) AES_encrypt);
412     if (memcmp(ciphertext, vector, len))
413         fprintf(stderr, "output_%d mismatch\n", len), exit(1);
414     if (memcmp(iv, vector + len - tail, sizeof(iv)))
415         fprintf(stderr, "iv_%d mismatch\n", len), exit(1);
416
417     /* test block-based decryption */
418     memcpy(iv, test_iv, sizeof(test_iv));
419     CRYPTO_cts128_decrypt_block(ciphertext, cleartext, len, &decks, iv,
420                                 (block128_f) AES_decrypt);
421     if (memcmp(cleartext, test_input, len))
422         fprintf(stderr, "input_%d mismatch\n", len), exit(2);
423     if (memcmp(iv, vector + len - tail, sizeof(iv)))
424         fprintf(stderr, "iv_%d mismatch\n", len), exit(2);
425
426     /* test streamed encryption */
427     memcpy(iv, test_iv, sizeof(test_iv));
428     CRYPTO_cts128_encrypt(test_input, ciphertext, len, &encks, iv,
429                           (cbc128_f) AES_cbc_encrypt);
430     if (memcmp(ciphertext, vector, len))
431         fprintf(stderr, "output_%d mismatch\n", len), exit(3);
432     if (memcmp(iv, vector + len - tail, sizeof(iv)))
433         fprintf(stderr, "iv_%d mismatch\n", len), exit(3);
434
435     /* test streamed decryption */
436     memcpy(iv, test_iv, sizeof(test_iv));
437     CRYPTO_cts128_decrypt(ciphertext, cleartext, len, &decks, iv,
438                           (cbc128_f) AES_cbc_encrypt);
439     if (memcmp(cleartext, test_input, len))
440         fprintf(stderr, "input_%d mismatch\n", len), exit(4);
441     if (memcmp(iv, vector + len - tail, sizeof(iv)))
442         fprintf(stderr, "iv_%d mismatch\n", len), exit(4);
443 }
444
445 void test_nistvector(const unsigned char *vector, size_t len)
446 {
447     unsigned char iv[sizeof(test_iv)];
448     unsigned char cleartext[64], ciphertext[64], nistvector[64];
449     size_t tail;
450
451     printf("nistvector_%d\n", len);
452     fflush(stdout);
453
454     if ((tail = len % 16) == 0)
455         tail = 16;
456
457     len -= 16 + tail;
458     memcpy(nistvector, vector, len);
459     /* flip two last blocks */
460     memcpy(nistvector + len, vector + len + 16, tail);
461     memcpy(nistvector + len + tail, vector + len, 16);
462     len += 16 + tail;
463     tail = 16;
464
465     /* test block-based encryption */
466     memcpy(iv, test_iv, sizeof(test_iv));
467     CRYPTO_nistcts128_encrypt_block(test_input, ciphertext, len, &encks, iv,
468                                     (block128_f) AES_encrypt);
469     if (memcmp(ciphertext, nistvector, len))
470         fprintf(stderr, "output_%d mismatch\n", len), exit(1);
471     if (memcmp(iv, nistvector + len - tail, sizeof(iv)))
472         fprintf(stderr, "iv_%d mismatch\n", len), exit(1);
473
474     /* test block-based decryption */
475     memcpy(iv, test_iv, sizeof(test_iv));
476     CRYPTO_nistcts128_decrypt_block(ciphertext, cleartext, len, &decks, iv,
477                                     (block128_f) AES_decrypt);
478     if (memcmp(cleartext, test_input, len))
479         fprintf(stderr, "input_%d mismatch\n", len), exit(2);
480     if (memcmp(iv, nistvector + len - tail, sizeof(iv)))
481         fprintf(stderr, "iv_%d mismatch\n", len), exit(2);
482
483     /* test streamed encryption */
484     memcpy(iv, test_iv, sizeof(test_iv));
485     CRYPTO_nistcts128_encrypt(test_input, ciphertext, len, &encks, iv,
486                               (cbc128_f) AES_cbc_encrypt);
487     if (memcmp(ciphertext, nistvector, len))
488         fprintf(stderr, "output_%d mismatch\n", len), exit(3);
489     if (memcmp(iv, nistvector + len - tail, sizeof(iv)))
490         fprintf(stderr, "iv_%d mismatch\n", len), exit(3);
491
492     /* test streamed decryption */
493     memcpy(iv, test_iv, sizeof(test_iv));
494     CRYPTO_nistcts128_decrypt(ciphertext, cleartext, len, &decks, iv,
495                               (cbc128_f) AES_cbc_encrypt);
496     if (memcmp(cleartext, test_input, len))
497         fprintf(stderr, "input_%d mismatch\n", len), exit(4);
498     if (memcmp(iv, nistvector + len - tail, sizeof(iv)))
499         fprintf(stderr, "iv_%d mismatch\n", len), exit(4);
500 }
501
502 int main()
503 {
504     AES_set_encrypt_key(test_key, 128, &encks);
505     AES_set_decrypt_key(test_key, 128, &decks);
506
507     test_vector(vector_17, sizeof(vector_17));
508     test_vector(vector_31, sizeof(vector_31));
509     test_vector(vector_32, sizeof(vector_32));
510     test_vector(vector_47, sizeof(vector_47));
511     test_vector(vector_48, sizeof(vector_48));
512     test_vector(vector_64, sizeof(vector_64));
513
514     test_nistvector(vector_17, sizeof(vector_17));
515     test_nistvector(vector_31, sizeof(vector_31));
516     test_nistvector(vector_32, sizeof(vector_32));
517     test_nistvector(vector_47, sizeof(vector_47));
518     test_nistvector(vector_48, sizeof(vector_48));
519     test_nistvector(vector_64, sizeof(vector_64));
520
521     return 0;
522 }
523 #endif