xref: /openssl/crypto/modes/cts128.c (revision 25f2138b)
1 /*
2  * Copyright 2008-2016 The OpenSSL Project Authors. All Rights Reserved.
3  *
4  * Licensed under the Apache License 2.0 (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 <string.h>
11 #include <openssl/crypto.h>
12 #include "crypto/modes.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 
CRYPTO_cts128_encrypt_block(const unsigned char * in,unsigned char * out,size_t len,const void * key,unsigned char ivec[16],block128_f block)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 
CRYPTO_nistcts128_encrypt_block(const unsigned char * in,unsigned char * out,size_t len,const void * key,unsigned char ivec[16],block128_f block)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 
CRYPTO_cts128_encrypt(const unsigned char * in,unsigned char * out,size_t len,const void * key,unsigned char ivec[16],cbc128_f cbc)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 
CRYPTO_nistcts128_encrypt(const unsigned char * in,unsigned char * out,size_t len,const void * key,unsigned char ivec[16],cbc128_f cbc)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 
CRYPTO_cts128_decrypt_block(const unsigned char * in,unsigned char * out,size_t len,const void * key,unsigned char ivec[16],block128_f block)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 
CRYPTO_nistcts128_decrypt_block(const unsigned char * in,unsigned char * out,size_t len,const void * key,unsigned char ivec[16],block128_f block)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 
CRYPTO_cts128_decrypt(const unsigned char * in,unsigned char * out,size_t len,const void * key,unsigned char ivec[16],cbc128_f cbc)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 
CRYPTO_nistcts128_decrypt(const unsigned char * in,unsigned char * out,size_t len,const void * key,unsigned char ivec[16],cbc128_f cbc)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