1 /* ====================================================================
2 * Copyright (c) 2008 The OpenSSL Project. All rights reserved.
4 * Rights for redistribution and usage in source and binary
5 * forms are granted according to the OpenSSL license.
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.
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],
37 assert(in && out && key && ivec);
42 if ((residue = len % 16) == 0)
47 CRYPTO_cbc128_encrypt(in, out, len, key, ivec, block);
52 for (n = 0; n < residue; ++n)
54 (*block) (ivec, ivec, key);
55 memcpy(out, out - 16, residue);
56 memcpy(out - 16, ivec, 16);
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)
71 assert(in && out && key && ivec);
76 if ((residue = len % 16) == 0)
81 (*cbc) (in, out, len, key, ivec, 1);
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);
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);
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],
110 assert(in && out && key && ivec);
115 if ((residue = len % 16) == 0)
121 CRYPTO_cbc128_decrypt(in, out, len, key, ivec, block);
126 (*block) (in, tmp.c + 16, key);
128 memcpy(tmp.c, tmp.c + 16, 16);
129 memcpy(tmp.c, in + 16, residue);
130 (*block) (tmp.c, tmp.c, key);
132 for (n = 0; n < 16; ++n) {
133 unsigned char c = in[n];
134 out[n] = tmp.c[n] ^ ivec[n];
137 for (residue += 16; n < residue; ++n)
138 out[n] = tmp.c[n] ^ in[n];
140 return len + residue - 16;
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)
153 assert(in && out && key && ivec);
158 if ((residue = len % 16) == 0)
164 (*cbc) (in, out, len, key, ivec, 0);
169 memset(tmp.c, 0, sizeof(tmp));
171 * this places in[16] at &tmp.c[16] and decrypted block at &tmp.c[0]
173 (*cbc) (in, tmp.c, 16, key, tmp.c + 16, 0);
175 memcpy(tmp.c, in + 16, residue);
176 #if defined(CBC_HANDLES_TRUNCATED_IO)
177 (*cbc) (tmp.c, out, 16 + residue, key, ivec, 0);
179 (*cbc) (tmp.c, tmp.c, 32, key, ivec, 0);
180 memcpy(out, tmp.c, 16 + residue);
182 return len + residue;
185 #if defined(SELFTEST)
187 # include <openssl/aes.h>
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 };
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,
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
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
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
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
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
246 static AES_KEY encks, decks;
248 void test_vector(const unsigned char *vector, size_t len)
250 unsigned char cleartext[64];
251 unsigned char iv[sizeof(test_iv)];
252 unsigned char ciphertext[64];
255 printf("vector_%d\n", len);
258 if ((tail = len % 16) == 0)
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);
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);
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);
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);
301 AES_set_encrypt_key(test_key, 128, &encks);
302 AES_set_decrypt_key(test_key, 128, &decks);
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));