cts128.c revision 296341
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
32size_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
63size_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
96size_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
134size_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
171size_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
215size_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
265size_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
307size_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 */
358static const unsigned char test_key[16] = "chicken teriyaki";
359static const unsigned char test_input[64] =
360    "I would like the" " General Gau's C"
361    "hicken, please, " "and wonton soup.";
362static const unsigned char test_iv[16] =
363    { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
364
365static 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
371static 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
378static 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
385static 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
394static 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
403static 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
414static AES_KEY encks, decks;
415
416void 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
466void 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
523int 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