PKCS#7: avoid NULL pointer dereferences with missing content
[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 "modes.h"
9 #include <string.h>
10
11 #ifndef MODES_DEBUG
12 # ifndef NDEBUG
13 #  define NDEBUG
14 # endif
15 #endif
16 #include <assert.h>
17
18 /*
19  * Trouble with Ciphertext Stealing, CTS, mode is that there is no
20  * common official specification, but couple of cipher/application
21  * specific ones: RFC2040 and RFC3962. Then there is 'Proposal to
22  * Extend CBC Mode By "Ciphertext Stealing"' at NIST site, which
23  * deviates from mentioned RFCs. Most notably it allows input to be
24  * of block length and it doesn't flip the order of the last two
25  * blocks. CTS is being discussed even in ECB context, but it's not
26  * adopted for any known application. This implementation complies
27  * with mentioned RFCs and [as such] extends CBC mode.
28  */
29
30 size_t CRYPTO_cts128_encrypt_block(const unsigned char *in,
31                                    unsigned char *out, size_t len,
32                                    const void *key, unsigned char ivec[16],
33                                    block128_f block)
34 {
35     size_t residue, n;
36
37     assert(in && out && key && ivec);
38
39     if (len <= 16)
40         return 0;
41
42     if ((residue = len % 16) == 0)
43         residue = 16;
44
45     len -= residue;
46
47     CRYPTO_cbc128_encrypt(in, out, len, key, ivec, block);
48
49     in += len;
50     out += len;
51
52     for (n = 0; n < residue; ++n)
53         ivec[n] ^= in[n];
54     (*block) (ivec, ivec, key);
55     memcpy(out, out - 16, residue);
56     memcpy(out - 16, ivec, 16);
57
58     return len + residue;
59 }
60
61 size_t CRYPTO_cts128_encrypt(const unsigned char *in, unsigned char *out,
62                              size_t len, const void *key,
63                              unsigned char ivec[16], cbc128_f cbc)
64 {
65     size_t residue;
66     union {
67         size_t align;
68         unsigned char c[16];
69     } tmp;
70
71     assert(in && out && key && ivec);
72
73     if (len <= 16)
74         return 0;
75
76     if ((residue = len % 16) == 0)
77         residue = 16;
78
79     len -= residue;
80
81     (*cbc) (in, out, len, key, ivec, 1);
82
83     in += len;
84     out += len;
85
86 #if defined(CBC_HANDLES_TRUNCATED_IO)
87     memcpy(tmp.c, out - 16, 16);
88     (*cbc) (in, out - 16, residue, key, ivec, 1);
89     memcpy(out, tmp.c, residue);
90 #else
91     memset(tmp.c, 0, sizeof(tmp));
92     memcpy(tmp.c, in, residue);
93     memcpy(out, out - 16, residue);
94     (*cbc) (tmp.c, out - 16, 16, key, ivec, 1);
95 #endif
96     return len + residue;
97 }
98
99 size_t CRYPTO_cts128_decrypt_block(const unsigned char *in,
100                                    unsigned char *out, size_t len,
101                                    const void *key, unsigned char ivec[16],
102                                    block128_f block)
103 {
104     size_t residue, n;
105     union {
106         size_t align;
107         unsigned char c[32];
108     } tmp;
109
110     assert(in && out && key && ivec);
111
112     if (len <= 16)
113         return 0;
114
115     if ((residue = len % 16) == 0)
116         residue = 16;
117
118     len -= 16 + residue;
119
120     if (len) {
121         CRYPTO_cbc128_decrypt(in, out, len, key, ivec, block);
122         in += len;
123         out += len;
124     }
125
126     (*block) (in, tmp.c + 16, key);
127
128     memcpy(tmp.c, tmp.c + 16, 16);
129     memcpy(tmp.c, in + 16, residue);
130     (*block) (tmp.c, tmp.c, key);
131
132     for (n = 0; n < 16; ++n) {
133         unsigned char c = in[n];
134         out[n] = tmp.c[n] ^ ivec[n];
135         ivec[n] = c;
136     }
137     for (residue += 16; n < residue; ++n)
138         out[n] = tmp.c[n] ^ in[n];
139
140     return len + residue - 16;
141 }
142
143 size_t CRYPTO_cts128_decrypt(const unsigned char *in, unsigned char *out,
144                              size_t len, const void *key,
145                              unsigned char ivec[16], cbc128_f cbc)
146 {
147     size_t residue;
148     union {
149         size_t align;
150         unsigned char c[32];
151     } tmp;
152
153     assert(in && out && key && ivec);
154
155     if (len <= 16)
156         return 0;
157
158     if ((residue = len % 16) == 0)
159         residue = 16;
160
161     len -= 16 + residue;
162
163     if (len) {
164         (*cbc) (in, out, len, key, ivec, 0);
165         in += len;
166         out += len;
167     }
168
169     memset(tmp.c, 0, sizeof(tmp));
170     /*
171      * this places in[16] at &tmp.c[16] and decrypted block at &tmp.c[0]
172      */
173     (*cbc) (in, tmp.c, 16, key, tmp.c + 16, 0);
174
175     memcpy(tmp.c, in + 16, residue);
176 #if defined(CBC_HANDLES_TRUNCATED_IO)
177     (*cbc) (tmp.c, out, 16 + residue, key, ivec, 0);
178 #else
179     (*cbc) (tmp.c, tmp.c, 32, key, ivec, 0);
180     memcpy(out, tmp.c, 16 + residue);
181 #endif
182     return len + residue;
183 }
184
185 #if defined(SELFTEST)
186 # include <stdio.h>
187 # include <openssl/aes.h>
188
189 /* test vectors from RFC 3962 */
190 static const unsigned char test_key[16] = "chicken teriyaki";
191 static const unsigned char test_input[64] =
192     "I would like the" " General Gau's C"
193     "hicken, please, " "and wonton soup.";
194 static const unsigned char test_iv[16] =
195     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
196
197 static const unsigned char vector_17[17] = {
198     0xc6, 0x35, 0x35, 0x68, 0xf2, 0xbf, 0x8c, 0xb4,
199     0xd8, 0xa5, 0x80, 0x36, 0x2d, 0xa7, 0xff, 0x7f,
200     0x97
201 };
202
203 static const unsigned char vector_31[31] = {
204     0xfc, 0x00, 0x78, 0x3e, 0x0e, 0xfd, 0xb2, 0xc1,
205     0xd4, 0x45, 0xd4, 0xc8, 0xef, 0xf7, 0xed, 0x22,
206     0x97, 0x68, 0x72, 0x68, 0xd6, 0xec, 0xcc, 0xc0,
207     0xc0, 0x7b, 0x25, 0xe2, 0x5e, 0xcf, 0xe5
208 };
209
210 static const unsigned char vector_32[32] = {
211     0x39, 0x31, 0x25, 0x23, 0xa7, 0x86, 0x62, 0xd5,
212     0xbe, 0x7f, 0xcb, 0xcc, 0x98, 0xeb, 0xf5, 0xa8,
213     0x97, 0x68, 0x72, 0x68, 0xd6, 0xec, 0xcc, 0xc0,
214     0xc0, 0x7b, 0x25, 0xe2, 0x5e, 0xcf, 0xe5, 0x84
215 };
216
217 static const unsigned char vector_47[47] = {
218     0x97, 0x68, 0x72, 0x68, 0xd6, 0xec, 0xcc, 0xc0,
219     0xc0, 0x7b, 0x25, 0xe2, 0x5e, 0xcf, 0xe5, 0x84,
220     0xb3, 0xff, 0xfd, 0x94, 0x0c, 0x16, 0xa1, 0x8c,
221     0x1b, 0x55, 0x49, 0xd2, 0xf8, 0x38, 0x02, 0x9e,
222     0x39, 0x31, 0x25, 0x23, 0xa7, 0x86, 0x62, 0xd5,
223     0xbe, 0x7f, 0xcb, 0xcc, 0x98, 0xeb, 0xf5
224 };
225
226 static const unsigned char vector_48[48] = {
227     0x97, 0x68, 0x72, 0x68, 0xd6, 0xec, 0xcc, 0xc0,
228     0xc0, 0x7b, 0x25, 0xe2, 0x5e, 0xcf, 0xe5, 0x84,
229     0x9d, 0xad, 0x8b, 0xbb, 0x96, 0xc4, 0xcd, 0xc0,
230     0x3b, 0xc1, 0x03, 0xe1, 0xa1, 0x94, 0xbb, 0xd8,
231     0x39, 0x31, 0x25, 0x23, 0xa7, 0x86, 0x62, 0xd5,
232     0xbe, 0x7f, 0xcb, 0xcc, 0x98, 0xeb, 0xf5, 0xa8
233 };
234
235 static const unsigned char vector_64[64] = {
236     0x97, 0x68, 0x72, 0x68, 0xd6, 0xec, 0xcc, 0xc0,
237     0xc0, 0x7b, 0x25, 0xe2, 0x5e, 0xcf, 0xe5, 0x84,
238     0x39, 0x31, 0x25, 0x23, 0xa7, 0x86, 0x62, 0xd5,
239     0xbe, 0x7f, 0xcb, 0xcc, 0x98, 0xeb, 0xf5, 0xa8,
240     0x48, 0x07, 0xef, 0xe8, 0x36, 0xee, 0x89, 0xa5,
241     0x26, 0x73, 0x0d, 0xbc, 0x2f, 0x7b, 0xc8, 0x40,
242     0x9d, 0xad, 0x8b, 0xbb, 0x96, 0xc4, 0xcd, 0xc0,
243     0x3b, 0xc1, 0x03, 0xe1, 0xa1, 0x94, 0xbb, 0xd8
244 };
245
246 static AES_KEY encks, decks;
247
248 void test_vector(const unsigned char *vector, size_t len)
249 {
250     unsigned char cleartext[64];
251     unsigned char iv[sizeof(test_iv)];
252     unsigned char ciphertext[64];
253     size_t tail;
254
255     printf("vector_%d\n", len);
256     fflush(stdout);
257
258     if ((tail = len % 16) == 0)
259         tail = 16;
260     tail += 16;
261
262     /* test block-based encryption */
263     memcpy(iv, test_iv, sizeof(test_iv));
264     CRYPTO_cts128_encrypt_block(test_input, ciphertext, len, &encks, iv,
265                                 (block128_f) AES_encrypt);
266     if (memcmp(ciphertext, vector, len))
267         fprintf(stderr, "output_%d mismatch\n", len), exit(1);
268     if (memcmp(iv, vector + len - tail, sizeof(iv)))
269         fprintf(stderr, "iv_%d mismatch\n", len), exit(1);
270
271     /* test block-based decryption */
272     memcpy(iv, test_iv, sizeof(test_iv));
273     CRYPTO_cts128_decrypt_block(ciphertext, cleartext, len, &decks, iv,
274                                 (block128_f) AES_decrypt);
275     if (memcmp(cleartext, test_input, len))
276         fprintf(stderr, "input_%d mismatch\n", len), exit(2);
277     if (memcmp(iv, vector + len - tail, sizeof(iv)))
278         fprintf(stderr, "iv_%d mismatch\n", len), exit(2);
279
280     /* test streamed encryption */
281     memcpy(iv, test_iv, sizeof(test_iv));
282     CRYPTO_cts128_encrypt(test_input, ciphertext, len, &encks, iv,
283                           (cbc128_f) AES_cbc_encrypt);
284     if (memcmp(ciphertext, vector, len))
285         fprintf(stderr, "output_%d mismatch\n", len), exit(3);
286     if (memcmp(iv, vector + len - tail, sizeof(iv)))
287         fprintf(stderr, "iv_%d mismatch\n", len), exit(3);
288
289     /* test streamed decryption */
290     memcpy(iv, test_iv, sizeof(test_iv));
291     CRYPTO_cts128_decrypt(ciphertext, cleartext, len, &decks, iv,
292                           (cbc128_f) AES_cbc_encrypt);
293     if (memcmp(cleartext, test_input, len))
294         fprintf(stderr, "input_%d mismatch\n", len), exit(4);
295     if (memcmp(iv, vector + len - tail, sizeof(iv)))
296         fprintf(stderr, "iv_%d mismatch\n", len), exit(4);
297 }
298
299 main()
300 {
301     AES_set_encrypt_key(test_key, 128, &encks);
302     AES_set_decrypt_key(test_key, 128, &decks);
303
304     test_vector(vector_17, sizeof(vector_17));
305     test_vector(vector_31, sizeof(vector_31));
306     test_vector(vector_32, sizeof(vector_32));
307     test_vector(vector_47, sizeof(vector_47));
308     test_vector(vector_48, sizeof(vector_48));
309     test_vector(vector_64, sizeof(vector_64));
310     exit(0);
311 }
312 #endif