]>
Commit | Line | Data |
---|---|---|
4f22f405 RS |
1 | /* |
2 | * Copyright 2008-2016 The OpenSSL Project Authors. All Rights Reserved. | |
fe150ac2 | 3 | * |
81cae8ce | 4 | * Licensed under the Apache License 2.0 (the "License"). You may not use |
4f22f405 RS |
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 | |
fe150ac2 AP |
8 | */ |
9 | ||
a3654f05 | 10 | #include <openssl/crypto.h> |
f472ec8c | 11 | #include "modes_lcl.h" |
fe150ac2 AP |
12 | #include <string.h> |
13 | ||
fe150ac2 AP |
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 | |
67a315b6 AP |
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. | |
fe150ac2 AP |
25 | */ |
26 | ||
0f113f3e MC |
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; | |
fe150ac2 | 33 | |
0f113f3e MC |
34 | if (len <= 16) |
35 | return 0; | |
fe150ac2 | 36 | |
0f113f3e MC |
37 | if ((residue = len % 16) == 0) |
38 | residue = 16; | |
fe150ac2 | 39 | |
0f113f3e | 40 | len -= residue; |
fe150ac2 | 41 | |
0f113f3e | 42 | CRYPTO_cbc128_encrypt(in, out, len, key, ivec, block); |
fe150ac2 | 43 | |
0f113f3e MC |
44 | in += len; |
45 | out += len; | |
fe150ac2 | 46 | |
0f113f3e MC |
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); | |
fe150ac2 | 52 | |
0f113f3e | 53 | return len + residue; |
fe150ac2 AP |
54 | } |
55 | ||
0f113f3e MC |
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; | |
67a315b6 | 63 | |
0f113f3e MC |
64 | if (len < 16) |
65 | return 0; | |
67a315b6 | 66 | |
0f113f3e | 67 | residue = len % 16; |
67a315b6 | 68 | |
0f113f3e | 69 | len -= residue; |
67a315b6 | 70 | |
0f113f3e | 71 | CRYPTO_cbc128_encrypt(in, out, len, key, ivec, block); |
67a315b6 | 72 | |
0f113f3e MC |
73 | if (residue == 0) |
74 | return len; | |
67a315b6 | 75 | |
0f113f3e MC |
76 | in += len; |
77 | out += len; | |
67a315b6 | 78 | |
0f113f3e MC |
79 | for (n = 0; n < residue; ++n) |
80 | ivec[n] ^= in[n]; | |
81 | (*block) (ivec, ivec, key); | |
82 | memcpy(out - 16 + residue, ivec, 16); | |
67a315b6 | 83 | |
0f113f3e | 84 | return len + residue; |
67a315b6 AP |
85 | } |
86 | ||
fe150ac2 | 87 | size_t CRYPTO_cts128_encrypt(const unsigned char *in, unsigned char *out, |
0f113f3e MC |
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; | |
fe150ac2 | 96 | |
0f113f3e MC |
97 | if (len <= 16) |
98 | return 0; | |
fe150ac2 | 99 | |
0f113f3e MC |
100 | if ((residue = len % 16) == 0) |
101 | residue = 16; | |
fe150ac2 | 102 | |
0f113f3e | 103 | len -= residue; |
fe150ac2 | 104 | |
0f113f3e | 105 | (*cbc) (in, out, len, key, ivec, 1); |
fe150ac2 | 106 | |
0f113f3e MC |
107 | in += len; |
108 | out += len; | |
fe150ac2 AP |
109 | |
110 | #if defined(CBC_HANDLES_TRUNCATED_IO) | |
0f113f3e MC |
111 | memcpy(tmp.c, out - 16, 16); |
112 | (*cbc) (in, out - 16, residue, key, ivec, 1); | |
113 | memcpy(out, tmp.c, residue); | |
fe150ac2 | 114 | #else |
0f113f3e MC |
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); | |
fe150ac2 | 119 | #endif |
0f113f3e | 120 | return len + residue; |
fe150ac2 AP |
121 | } |
122 | ||
67a315b6 | 123 | size_t CRYPTO_nistcts128_encrypt(const unsigned char *in, unsigned char *out, |
0f113f3e MC |
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; | |
67a315b6 | 132 | |
0f113f3e MC |
133 | if (len < 16) |
134 | return 0; | |
67a315b6 | 135 | |
0f113f3e | 136 | residue = len % 16; |
67a315b6 | 137 | |
0f113f3e | 138 | len -= residue; |
67a315b6 | 139 | |
0f113f3e | 140 | (*cbc) (in, out, len, key, ivec, 1); |
67a315b6 | 141 | |
0f113f3e MC |
142 | if (residue == 0) |
143 | return len; | |
67a315b6 | 144 | |
0f113f3e MC |
145 | in += len; |
146 | out += len; | |
67a315b6 AP |
147 | |
148 | #if defined(CBC_HANDLES_TRUNCATED_IO) | |
0f113f3e | 149 | (*cbc) (in, out - 16 + residue, residue, key, ivec, 1); |
67a315b6 | 150 | #else |
0f113f3e MC |
151 | memset(tmp.c, 0, sizeof(tmp)); |
152 | memcpy(tmp.c, in, residue); | |
153 | (*cbc) (tmp.c, out - 16 + residue, 16, key, ivec, 1); | |
67a315b6 | 154 | #endif |
0f113f3e | 155 | return len + residue; |
67a315b6 AP |
156 | } |
157 | ||
0f113f3e MC |
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; | |
fe150ac2 | 168 | |
0f113f3e MC |
169 | if (len <= 16) |
170 | return 0; | |
fe150ac2 | 171 | |
0f113f3e MC |
172 | if ((residue = len % 16) == 0) |
173 | residue = 16; | |
fe150ac2 | 174 | |
0f113f3e | 175 | len -= 16 + residue; |
fe150ac2 | 176 | |
0f113f3e MC |
177 | if (len) { |
178 | CRYPTO_cbc128_decrypt(in, out, len, key, ivec, block); | |
179 | in += len; | |
180 | out += len; | |
181 | } | |
fe150ac2 | 182 | |
0f113f3e | 183 | (*block) (in, tmp.c + 16, key); |
fe150ac2 | 184 | |
0f113f3e MC |
185 | memcpy(tmp.c, tmp.c + 16, 16); |
186 | memcpy(tmp.c, in + 16, residue); | |
187 | (*block) (tmp.c, tmp.c, key); | |
fe150ac2 | 188 | |
0f113f3e MC |
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]; | |
fe150ac2 | 196 | |
0f113f3e | 197 | return 16 + len + residue; |
67a315b6 AP |
198 | } |
199 | ||
0f113f3e MC |
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; | |
67a315b6 | 211 | |
0f113f3e MC |
212 | if (len < 16) |
213 | return 0; | |
67a315b6 | 214 | |
0f113f3e | 215 | residue = len % 16; |
67a315b6 | 216 | |
0f113f3e MC |
217 | if (residue == 0) { |
218 | CRYPTO_cbc128_decrypt(in, out, len, key, ivec, block); | |
219 | return len; | |
220 | } | |
67a315b6 | 221 | |
0f113f3e | 222 | len -= 16 + residue; |
67a315b6 | 223 | |
0f113f3e MC |
224 | if (len) { |
225 | CRYPTO_cbc128_decrypt(in, out, len, key, ivec, block); | |
226 | in += len; | |
227 | out += len; | |
228 | } | |
67a315b6 | 229 | |
0f113f3e | 230 | (*block) (in + residue, tmp.c + 16, key); |
67a315b6 | 231 | |
0f113f3e MC |
232 | memcpy(tmp.c, tmp.c + 16, 16); |
233 | memcpy(tmp.c, in, residue); | |
234 | (*block) (tmp.c, tmp.c, key); | |
67a315b6 | 235 | |
0f113f3e MC |
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]; | |
67a315b6 | 244 | |
0f113f3e | 245 | return 16 + len + residue; |
fe150ac2 AP |
246 | } |
247 | ||
248 | size_t CRYPTO_cts128_decrypt(const unsigned char *in, unsigned char *out, | |
0f113f3e MC |
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; | |
fe150ac2 | 257 | |
0f113f3e MC |
258 | if (len <= 16) |
259 | return 0; | |
fe150ac2 | 260 | |
0f113f3e MC |
261 | if ((residue = len % 16) == 0) |
262 | residue = 16; | |
fe150ac2 | 263 | |
0f113f3e | 264 | len -= 16 + residue; |
fe150ac2 | 265 | |
0f113f3e MC |
266 | if (len) { |
267 | (*cbc) (in, out, len, key, ivec, 0); | |
268 | in += len; | |
269 | out += len; | |
270 | } | |
fe150ac2 | 271 | |
0f113f3e MC |
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); | |
fe150ac2 | 277 | |
0f113f3e | 278 | memcpy(tmp.c, in + 16, residue); |
fe150ac2 | 279 | #if defined(CBC_HANDLES_TRUNCATED_IO) |
0f113f3e | 280 | (*cbc) (tmp.c, out, 16 + residue, key, ivec, 0); |
fe150ac2 | 281 | #else |
0f113f3e MC |
282 | (*cbc) (tmp.c, tmp.c, 32, key, ivec, 0); |
283 | memcpy(out, tmp.c, 16 + residue); | |
fe150ac2 | 284 | #endif |
0f113f3e | 285 | return 16 + len + residue; |
67a315b6 AP |
286 | } |
287 | ||
288 | size_t CRYPTO_nistcts128_decrypt(const unsigned char *in, unsigned char *out, | |
0f113f3e MC |
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; | |
67a315b6 | 297 | |
0f113f3e MC |
298 | if (len < 16) |
299 | return 0; | |
67a315b6 | 300 | |
0f113f3e | 301 | residue = len % 16; |
67a315b6 | 302 | |
0f113f3e MC |
303 | if (residue == 0) { |
304 | (*cbc) (in, out, len, key, ivec, 0); | |
305 | return len; | |
306 | } | |
67a315b6 | 307 | |
0f113f3e | 308 | len -= 16 + residue; |
67a315b6 | 309 | |
0f113f3e MC |
310 | if (len) { |
311 | (*cbc) (in, out, len, key, ivec, 0); | |
312 | in += len; | |
313 | out += len; | |
314 | } | |
67a315b6 | 315 | |
0f113f3e MC |
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); | |
67a315b6 | 321 | |
0f113f3e | 322 | memcpy(tmp.c, in, residue); |
67a315b6 | 323 | #if defined(CBC_HANDLES_TRUNCATED_IO) |
0f113f3e | 324 | (*cbc) (tmp.c, out, 16 + residue, key, ivec, 0); |
67a315b6 | 325 | #else |
0f113f3e MC |
326 | (*cbc) (tmp.c, tmp.c, 32, key, ivec, 0); |
327 | memcpy(out, tmp.c, 16 + residue); | |
67a315b6 | 328 | #endif |
0f113f3e | 329 | return 16 + len + residue; |
fe150ac2 | 330 | } |