cts128.c revision 238405
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, unsigned char *out,
33			size_t len, const void *key,
34			unsigned char ivec[16], block128_f block)
35{	size_t residue, n;
36
37	assert (in && out && key && ivec);
38
39	if (len <= 16) return 0;
40
41	if ((residue=len%16) == 0) residue = 16;
42
43	len -= residue;
44
45	CRYPTO_cbc128_encrypt(in,out,len,key,ivec,block);
46
47	in  += len;
48	out += len;
49
50	for (n=0; n<residue; ++n)
51		ivec[n] ^= in[n];
52	(*block)(ivec,ivec,key);
53	memcpy(out,out-16,residue);
54	memcpy(out-16,ivec,16);
55
56	return len+residue;
57}
58
59size_t CRYPTO_nistcts128_encrypt_block(const unsigned char *in, unsigned char *out,
60			size_t len, const void *key,
61			unsigned char ivec[16], block128_f block)
62{	size_t residue, n;
63
64	assert (in && out && key && ivec);
65
66	if (len < 16) return 0;
67
68	residue=len%16;
69
70	len -= residue;
71
72	CRYPTO_cbc128_encrypt(in,out,len,key,ivec,block);
73
74	if (residue==0)	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
87size_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{	size_t residue;
91	union { size_t align; unsigned char c[16]; } tmp;
92
93	assert (in && out && key && ivec);
94
95	if (len <= 16) return 0;
96
97	if ((residue=len%16) == 0) residue = 16;
98
99	len -= residue;
100
101	(*cbc)(in,out,len,key,ivec,1);
102
103	in  += len;
104	out += len;
105
106#if defined(CBC_HANDLES_TRUNCATED_IO)
107	memcpy(tmp.c,out-16,16);
108	(*cbc)(in,out-16,residue,key,ivec,1);
109	memcpy(out,tmp.c,residue);
110#else
111	{
112	size_t n;
113	for (n=0; n<16; n+=sizeof(size_t))
114		*(size_t *)(tmp.c+n) = 0;
115	memcpy(tmp.c,in,residue);
116	}
117	memcpy(out,out-16,residue);
118	(*cbc)(tmp.c,out-16,16,key,ivec,1);
119#endif
120	return len+residue;
121}
122
123size_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{	size_t residue;
127	union { size_t align; unsigned char c[16]; } tmp;
128
129	assert (in && out && key && ivec);
130
131	if (len < 16) return 0;
132
133	residue=len%16;
134
135	len -= residue;
136
137	(*cbc)(in,out,len,key,ivec,1);
138
139	if (residue==0) return len;
140
141	in  += len;
142	out += len;
143
144#if defined(CBC_HANDLES_TRUNCATED_IO)
145	(*cbc)(in,out-16+residue,residue,key,ivec,1);
146#else
147	{
148	size_t n;
149	for (n=0; n<16; n+=sizeof(size_t))
150		*(size_t *)(tmp.c+n) = 0;
151	memcpy(tmp.c,in,residue);
152	}
153	(*cbc)(tmp.c,out-16+residue,16,key,ivec,1);
154#endif
155	return len+residue;
156}
157
158size_t CRYPTO_cts128_decrypt_block(const unsigned char *in, unsigned char *out,
159			size_t len, const void *key,
160			unsigned char ivec[16], block128_f block)
161{	size_t residue, n;
162	union { size_t align; unsigned char c[32]; } tmp;
163
164	assert (in && out && key && ivec);
165
166	if (len<=16) return 0;
167
168	if ((residue=len%16) == 0) residue = 16;
169
170	len -= 16+residue;
171
172	if (len) {
173		CRYPTO_cbc128_decrypt(in,out,len,key,ivec,block);
174		in  += len;
175		out += len;
176	}
177
178	(*block)(in,tmp.c+16,key);
179
180	for (n=0; n<16; n+=sizeof(size_t))
181		*(size_t *)(tmp.c+n) = *(size_t *)(tmp.c+16+n);
182	memcpy(tmp.c,in+16,residue);
183	(*block)(tmp.c,tmp.c,key);
184
185	for(n=0; n<16; ++n) {
186		unsigned char c = in[n];
187		out[n] = tmp.c[n] ^ ivec[n];
188		ivec[n] = c;
189	}
190	for(residue+=16; n<residue; ++n)
191		out[n] = tmp.c[n] ^ in[n];
192
193	return 16+len+residue;
194}
195
196size_t CRYPTO_nistcts128_decrypt_block(const unsigned char *in, unsigned char *out,
197			size_t len, const void *key,
198			unsigned char ivec[16], block128_f block)
199{	size_t residue, n;
200	union { size_t align; unsigned char c[32]; } tmp;
201
202	assert (in && out && key && ivec);
203
204	if (len<16) return 0;
205
206	residue=len%16;
207
208	if (residue==0) {
209		CRYPTO_cbc128_decrypt(in,out,len,key,ivec,block);
210		return len;
211	}
212
213	len -= 16+residue;
214
215	if (len) {
216		CRYPTO_cbc128_decrypt(in,out,len,key,ivec,block);
217		in  += len;
218		out += len;
219	}
220
221	(*block)(in+residue,tmp.c+16,key);
222
223	for (n=0; n<16; n+=sizeof(size_t))
224		*(size_t *)(tmp.c+n) = *(size_t *)(tmp.c+16+n);
225	memcpy(tmp.c,in,residue);
226	(*block)(tmp.c,tmp.c,key);
227
228	for(n=0; n<16; ++n) {
229		unsigned char c = in[n];
230		out[n] = tmp.c[n] ^ ivec[n];
231		ivec[n] = in[n+residue];
232		tmp.c[n] = c;
233	}
234	for(residue+=16; n<residue; ++n)
235		out[n] = tmp.c[n] ^ tmp.c[n-16];
236
237	return 16+len+residue;
238}
239
240size_t CRYPTO_cts128_decrypt(const unsigned char *in, unsigned char *out,
241			size_t len, const void *key,
242			unsigned char ivec[16], cbc128_f cbc)
243{	size_t residue, n;
244	union { size_t align; unsigned char c[32]; } tmp;
245
246	assert (in && out && key && ivec);
247
248	if (len<=16) return 0;
249
250	if ((residue=len%16) == 0) residue = 16;
251
252	len -= 16+residue;
253
254	if (len) {
255		(*cbc)(in,out,len,key,ivec,0);
256		in  += len;
257		out += len;
258	}
259
260	for (n=16; n<32; n+=sizeof(size_t))
261		*(size_t *)(tmp.c+n) = 0;
262	/* this places in[16] at &tmp.c[16] and decrypted block at &tmp.c[0] */
263	(*cbc)(in,tmp.c,16,key,tmp.c+16,0);
264
265	memcpy(tmp.c,in+16,residue);
266#if defined(CBC_HANDLES_TRUNCATED_IO)
267	(*cbc)(tmp.c,out,16+residue,key,ivec,0);
268#else
269	(*cbc)(tmp.c,tmp.c,32,key,ivec,0);
270	memcpy(out,tmp.c,16+residue);
271#endif
272	return 16+len+residue;
273}
274
275size_t CRYPTO_nistcts128_decrypt(const unsigned char *in, unsigned char *out,
276			size_t len, const void *key,
277			unsigned char ivec[16], cbc128_f cbc)
278{	size_t residue, n;
279	union { size_t align; unsigned char c[32]; } tmp;
280
281	assert (in && out && key && ivec);
282
283	if (len<16) return 0;
284
285	residue=len%16;
286
287	if (residue==0) {
288		(*cbc)(in,out,len,key,ivec,0);
289		return len;
290	}
291
292	len -= 16+residue;
293
294	if (len) {
295		(*cbc)(in,out,len,key,ivec,0);
296		in  += len;
297		out += len;
298	}
299
300	for (n=16; n<32; n+=sizeof(size_t))
301		*(size_t *)(tmp.c+n) = 0;
302	/* this places in[16] at &tmp.c[16] and decrypted block at &tmp.c[0] */
303	(*cbc)(in+residue,tmp.c,16,key,tmp.c+16,0);
304
305	memcpy(tmp.c,in,residue);
306#if defined(CBC_HANDLES_TRUNCATED_IO)
307	(*cbc)(tmp.c,out,16+residue,key,ivec,0);
308#else
309	(*cbc)(tmp.c,tmp.c,32,key,ivec,0);
310	memcpy(out,tmp.c,16+residue);
311#endif
312	return 16+len+residue;
313}
314
315#if defined(SELFTEST)
316#include <stdio.h>
317#include <openssl/aes.h>
318
319/* test vectors from RFC 3962 */
320static const unsigned char test_key[16] = "chicken teriyaki";
321static const unsigned char test_input[64] =
322		"I would like the" " General Gau's C"
323		"hicken, please, " "and wonton soup.";
324static const unsigned char test_iv[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
325
326static const unsigned char vector_17[17] =
327{0xc6,0x35,0x35,0x68,0xf2,0xbf,0x8c,0xb4, 0xd8,0xa5,0x80,0x36,0x2d,0xa7,0xff,0x7f,
328 0x97};
329static const unsigned char vector_31[31] =
330{0xfc,0x00,0x78,0x3e,0x0e,0xfd,0xb2,0xc1, 0xd4,0x45,0xd4,0xc8,0xef,0xf7,0xed,0x22,
331 0x97,0x68,0x72,0x68,0xd6,0xec,0xcc,0xc0, 0xc0,0x7b,0x25,0xe2,0x5e,0xcf,0xe5};
332static const unsigned char vector_32[32] =
333{0x39,0x31,0x25,0x23,0xa7,0x86,0x62,0xd5, 0xbe,0x7f,0xcb,0xcc,0x98,0xeb,0xf5,0xa8,
334 0x97,0x68,0x72,0x68,0xd6,0xec,0xcc,0xc0, 0xc0,0x7b,0x25,0xe2,0x5e,0xcf,0xe5,0x84};
335static const unsigned char vector_47[47] =
336{0x97,0x68,0x72,0x68,0xd6,0xec,0xcc,0xc0, 0xc0,0x7b,0x25,0xe2,0x5e,0xcf,0xe5,0x84,
337 0xb3,0xff,0xfd,0x94,0x0c,0x16,0xa1,0x8c, 0x1b,0x55,0x49,0xd2,0xf8,0x38,0x02,0x9e,
338 0x39,0x31,0x25,0x23,0xa7,0x86,0x62,0xd5, 0xbe,0x7f,0xcb,0xcc,0x98,0xeb,0xf5};
339static const unsigned char vector_48[48] =
340{0x97,0x68,0x72,0x68,0xd6,0xec,0xcc,0xc0, 0xc0,0x7b,0x25,0xe2,0x5e,0xcf,0xe5,0x84,
341 0x9d,0xad,0x8b,0xbb,0x96,0xc4,0xcd,0xc0, 0x3b,0xc1,0x03,0xe1,0xa1,0x94,0xbb,0xd8,
342 0x39,0x31,0x25,0x23,0xa7,0x86,0x62,0xd5, 0xbe,0x7f,0xcb,0xcc,0x98,0xeb,0xf5,0xa8};
343static const unsigned char vector_64[64] =
344{0x97,0x68,0x72,0x68,0xd6,0xec,0xcc,0xc0, 0xc0,0x7b,0x25,0xe2,0x5e,0xcf,0xe5,0x84,
345 0x39,0x31,0x25,0x23,0xa7,0x86,0x62,0xd5, 0xbe,0x7f,0xcb,0xcc,0x98,0xeb,0xf5,0xa8,
346 0x48,0x07,0xef,0xe8,0x36,0xee,0x89,0xa5, 0x26,0x73,0x0d,0xbc,0x2f,0x7b,0xc8,0x40,
347 0x9d,0xad,0x8b,0xbb,0x96,0xc4,0xcd,0xc0, 0x3b,0xc1,0x03,0xe1,0xa1,0x94,0xbb,0xd8};
348
349static AES_KEY encks, decks;
350
351void test_vector(const unsigned char *vector,size_t len)
352{	unsigned char iv[sizeof(test_iv)];
353	unsigned char cleartext[64],ciphertext[64];
354	size_t tail;
355
356	printf("vector_%d\n",len); fflush(stdout);
357
358	if ((tail=len%16) == 0) tail = 16;
359	tail += 16;
360
361	/* test block-based encryption */
362	memcpy(iv,test_iv,sizeof(test_iv));
363	CRYPTO_cts128_encrypt_block(test_input,ciphertext,len,&encks,iv,(block128_f)AES_encrypt);
364	if (memcmp(ciphertext,vector,len))
365		fprintf(stderr,"output_%d mismatch\n",len), exit(1);
366	if (memcmp(iv,vector+len-tail,sizeof(iv)))
367		fprintf(stderr,"iv_%d mismatch\n",len), exit(1);
368
369	/* test block-based decryption */
370	memcpy(iv,test_iv,sizeof(test_iv));
371	CRYPTO_cts128_decrypt_block(ciphertext,cleartext,len,&decks,iv,(block128_f)AES_decrypt);
372	if (memcmp(cleartext,test_input,len))
373		fprintf(stderr,"input_%d mismatch\n",len), exit(2);
374	if (memcmp(iv,vector+len-tail,sizeof(iv)))
375		fprintf(stderr,"iv_%d mismatch\n",len), exit(2);
376
377	/* test streamed encryption */
378	memcpy(iv,test_iv,sizeof(test_iv));
379	CRYPTO_cts128_encrypt(test_input,ciphertext,len,&encks,iv,(cbc128_f)AES_cbc_encrypt);
380	if (memcmp(ciphertext,vector,len))
381		fprintf(stderr,"output_%d mismatch\n",len), exit(3);
382	if (memcmp(iv,vector+len-tail,sizeof(iv)))
383		fprintf(stderr,"iv_%d mismatch\n",len), exit(3);
384
385	/* test streamed decryption */
386	memcpy(iv,test_iv,sizeof(test_iv));
387	CRYPTO_cts128_decrypt(ciphertext,cleartext,len,&decks,iv,(cbc128_f)AES_cbc_encrypt);
388	if (memcmp(cleartext,test_input,len))
389		fprintf(stderr,"input_%d mismatch\n",len), exit(4);
390	if (memcmp(iv,vector+len-tail,sizeof(iv)))
391		fprintf(stderr,"iv_%d mismatch\n",len), exit(4);
392}
393
394void test_nistvector(const unsigned char *vector,size_t len)
395{	unsigned char iv[sizeof(test_iv)];
396	unsigned char cleartext[64],ciphertext[64],nistvector[64];
397	size_t tail;
398
399	printf("nistvector_%d\n",len); fflush(stdout);
400
401	if ((tail=len%16) == 0) tail = 16;
402
403	len -= 16 + tail;
404	memcpy(nistvector,vector,len);
405	/* flip two last blocks */
406	memcpy(nistvector+len,vector+len+16,tail);
407	memcpy(nistvector+len+tail,vector+len,16);
408	len += 16 + tail;
409	tail = 16;
410
411	/* test block-based encryption */
412	memcpy(iv,test_iv,sizeof(test_iv));
413	CRYPTO_nistcts128_encrypt_block(test_input,ciphertext,len,&encks,iv,(block128_f)AES_encrypt);
414	if (memcmp(ciphertext,nistvector,len))
415		fprintf(stderr,"output_%d mismatch\n",len), exit(1);
416	if (memcmp(iv,nistvector+len-tail,sizeof(iv)))
417		fprintf(stderr,"iv_%d mismatch\n",len), exit(1);
418
419	/* test block-based decryption */
420	memcpy(iv,test_iv,sizeof(test_iv));
421	CRYPTO_nistcts128_decrypt_block(ciphertext,cleartext,len,&decks,iv,(block128_f)AES_decrypt);
422	if (memcmp(cleartext,test_input,len))
423		fprintf(stderr,"input_%d mismatch\n",len), exit(2);
424	if (memcmp(iv,nistvector+len-tail,sizeof(iv)))
425		fprintf(stderr,"iv_%d mismatch\n",len), exit(2);
426
427	/* test streamed encryption */
428	memcpy(iv,test_iv,sizeof(test_iv));
429	CRYPTO_nistcts128_encrypt(test_input,ciphertext,len,&encks,iv,(cbc128_f)AES_cbc_encrypt);
430	if (memcmp(ciphertext,nistvector,len))
431		fprintf(stderr,"output_%d mismatch\n",len), exit(3);
432	if (memcmp(iv,nistvector+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_nistcts128_decrypt(ciphertext,cleartext,len,&decks,iv,(cbc128_f)AES_cbc_encrypt);
438	if (memcmp(cleartext,test_input,len))
439		fprintf(stderr,"input_%d mismatch\n",len), exit(4);
440	if (memcmp(iv,nistvector+len-tail,sizeof(iv)))
441		fprintf(stderr,"iv_%d mismatch\n",len), exit(4);
442}
443
444int main()
445{
446	AES_set_encrypt_key(test_key,128,&encks);
447	AES_set_decrypt_key(test_key,128,&decks);
448
449	test_vector(vector_17,sizeof(vector_17));
450	test_vector(vector_31,sizeof(vector_31));
451	test_vector(vector_32,sizeof(vector_32));
452	test_vector(vector_47,sizeof(vector_47));
453	test_vector(vector_48,sizeof(vector_48));
454	test_vector(vector_64,sizeof(vector_64));
455
456	test_nistvector(vector_17,sizeof(vector_17));
457	test_nistvector(vector_31,sizeof(vector_31));
458	test_nistvector(vector_32,sizeof(vector_32));
459	test_nistvector(vector_47,sizeof(vector_47));
460	test_nistvector(vector_48,sizeof(vector_48));
461	test_nistvector(vector_64,sizeof(vector_64));
462
463	return 0;
464}
465#endif
466