]>
Commit | Line | Data |
---|---|---|
7cc355c2 | 1 | /* |
fecb3aae | 2 | * Copyright 2020-2022 The OpenSSL Project Authors. All Rights Reserved. |
7cc355c2 SL |
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 | ||
3dafbd44 | 10 | /* |
42281f26 | 11 | * Helper functions for 128 bit CBC CTS ciphers (Currently AES and Camellia). |
3dafbd44 SL |
12 | * |
13 | * The function dispatch tables are embedded into cipher_aes.c | |
42281f26 | 14 | * and cipher_camellia.c using cipher_aes_cts.inc and cipher_camellia_cts.inc |
3dafbd44 | 15 | */ |
7cc355c2 SL |
16 | |
17 | /* | |
18 | * Refer to SP800-38A-Addendum | |
19 | * | |
20 | * Ciphertext stealing encrypts plaintext using a block cipher, without padding | |
21 | * the message to a multiple of the block size, so the ciphertext is the same | |
22 | * size as the plaintext. | |
23 | * It does this by altering processing of the last two blocks of the message. | |
24 | * The processing of all but the last two blocks is unchanged, but a portion of | |
25 | * the second-last block's ciphertext is "stolen" to pad the last plaintext | |
26 | * block. The padded final block is then encrypted as usual. | |
27 | * The final ciphertext for the last two blocks, consists of the partial block | |
28 | * (with the "stolen" portion omitted) plus the full final block, | |
29 | * which are the same size as the original plaintext. | |
30 | * Decryption requires decrypting the final block first, then restoring the | |
31 | * stolen ciphertext to the partial block, which can then be decrypted as usual. | |
32 | ||
33 | * AES_CBC_CTS has 3 variants: | |
34 | * (1) CS1 The NIST variant. | |
35 | * If the length is a multiple of the blocksize it is the same as CBC mode. | |
36 | * otherwise it produces C1||C2||(C(n-1))*||Cn. | |
37 | * Where C(n-1)* is a partial block. | |
38 | * (2) CS2 | |
39 | * If the length is a multiple of the blocksize it is the same as CBC mode. | |
40 | * otherwise it produces C1||C2||Cn||(C(n-1))*. | |
41 | * Where C(n-1)* is a partial block. | |
42 | * (3) CS3 The Kerberos5 variant. | |
43 | * Produces C1||C2||Cn||(C(n-1))* regardless of the length. | |
44 | * If the length is a multiple of the blocksize it looks similar to CBC mode | |
45 | * with the last 2 blocks swapped. | |
46 | * Otherwise it is the same as CS2. | |
47 | */ | |
48 | ||
7cc355c2 | 49 | #include <openssl/core_names.h> |
7cc355c2 SL |
50 | #include "prov/ciphercommon.h" |
51 | #include "internal/nelem.h" | |
42281f26 | 52 | #include "cipher_cts.h" |
7cc355c2 SL |
53 | |
54 | /* The value assigned to 0 is the default */ | |
55 | #define CTS_CS1 0 | |
56 | #define CTS_CS2 1 | |
57 | #define CTS_CS3 2 | |
58 | ||
42281f26 SL |
59 | #define CTS_BLOCK_SIZE 16 |
60 | ||
7cc355c2 SL |
61 | typedef union { |
62 | size_t align; | |
42281f26 | 63 | unsigned char c[CTS_BLOCK_SIZE]; |
7cc355c2 SL |
64 | } aligned_16bytes; |
65 | ||
66 | typedef struct cts_mode_name2id_st { | |
67 | unsigned int id; | |
68 | const char *name; | |
69 | } CTS_MODE_NAME2ID; | |
70 | ||
71 | static CTS_MODE_NAME2ID cts_modes[] = | |
72 | { | |
73 | { CTS_CS1, OSSL_CIPHER_CTS_MODE_CS1 }, | |
7cc355c2 SL |
74 | { CTS_CS2, OSSL_CIPHER_CTS_MODE_CS2 }, |
75 | { CTS_CS3, OSSL_CIPHER_CTS_MODE_CS3 }, | |
7cc355c2 SL |
76 | }; |
77 | ||
42281f26 | 78 | const char *ossl_cipher_cbc_cts_mode_id2name(unsigned int id) |
7cc355c2 SL |
79 | { |
80 | size_t i; | |
81 | ||
82 | for (i = 0; i < OSSL_NELEM(cts_modes); ++i) { | |
83 | if (cts_modes[i].id == id) | |
84 | return cts_modes[i].name; | |
85 | } | |
86 | return NULL; | |
87 | } | |
88 | ||
42281f26 | 89 | int ossl_cipher_cbc_cts_mode_name2id(const char *name) |
7cc355c2 SL |
90 | { |
91 | size_t i; | |
92 | ||
93 | for (i = 0; i < OSSL_NELEM(cts_modes); ++i) { | |
fba140c7 | 94 | if (OPENSSL_strcasecmp(name, cts_modes[i].name) == 0) |
7cc355c2 SL |
95 | return (int)cts_modes[i].id; |
96 | } | |
97 | return -1; | |
98 | } | |
99 | ||
100 | static size_t cts128_cs1_encrypt(PROV_CIPHER_CTX *ctx, const unsigned char *in, | |
101 | unsigned char *out, size_t len) | |
102 | { | |
103 | aligned_16bytes tmp_in; | |
104 | size_t residue; | |
105 | ||
42281f26 | 106 | residue = len % CTS_BLOCK_SIZE; |
7cc355c2 SL |
107 | len -= residue; |
108 | if (!ctx->hw->cipher(ctx, out, in, len)) | |
109 | return 0; | |
110 | ||
111 | if (residue == 0) | |
112 | return len; | |
113 | ||
114 | in += len; | |
115 | out += len; | |
116 | ||
117 | memset(tmp_in.c, 0, sizeof(tmp_in)); | |
118 | memcpy(tmp_in.c, in, residue); | |
42281f26 SL |
119 | if (!ctx->hw->cipher(ctx, out - CTS_BLOCK_SIZE + residue, tmp_in.c, |
120 | CTS_BLOCK_SIZE)) | |
7cc355c2 SL |
121 | return 0; |
122 | return len + residue; | |
123 | } | |
124 | ||
125 | static void do_xor(const unsigned char *in1, const unsigned char *in2, | |
126 | size_t len, unsigned char *out) | |
127 | { | |
128 | size_t i; | |
129 | ||
130 | for (i = 0; i < len; ++i) | |
131 | out[i] = in1[i] ^ in2[i]; | |
132 | } | |
133 | ||
134 | static size_t cts128_cs1_decrypt(PROV_CIPHER_CTX *ctx, const unsigned char *in, | |
135 | unsigned char *out, size_t len) | |
136 | { | |
46ac83ea | 137 | aligned_16bytes mid_iv, ct_mid, cn, pt_last; |
7cc355c2 SL |
138 | size_t residue; |
139 | ||
42281f26 | 140 | residue = len % CTS_BLOCK_SIZE; |
7cc355c2 SL |
141 | if (residue == 0) { |
142 | /* If there are no partial blocks then it is the same as CBC mode */ | |
143 | if (!ctx->hw->cipher(ctx, out, in, len)) | |
144 | return 0; | |
145 | return len; | |
146 | } | |
147 | /* Process blocks at the start - but leave the last 2 blocks */ | |
42281f26 | 148 | len -= CTS_BLOCK_SIZE + residue; |
7cc355c2 SL |
149 | if (len > 0) { |
150 | if (!ctx->hw->cipher(ctx, out, in, len)) | |
151 | return 0; | |
152 | in += len; | |
153 | out += len; | |
154 | } | |
155 | /* Save the iv that will be used by the second last block */ | |
42281f26 | 156 | memcpy(mid_iv.c, ctx->iv, CTS_BLOCK_SIZE); |
46ac83ea SL |
157 | /* Save the C(n) block */ |
158 | memcpy(cn.c, in + residue, CTS_BLOCK_SIZE); | |
7cc355c2 SL |
159 | |
160 | /* Decrypt the last block first using an iv of zero */ | |
42281f26 SL |
161 | memset(ctx->iv, 0, CTS_BLOCK_SIZE); |
162 | if (!ctx->hw->cipher(ctx, pt_last.c, in + residue, CTS_BLOCK_SIZE)) | |
7cc355c2 SL |
163 | return 0; |
164 | ||
165 | /* | |
166 | * Rebuild the ciphertext of the second last block as a combination of | |
167 | * the decrypted last block + replace the start with the ciphertext bytes | |
168 | * of the partial second last block. | |
169 | */ | |
170 | memcpy(ct_mid.c, in, residue); | |
42281f26 | 171 | memcpy(ct_mid.c + residue, pt_last.c + residue, CTS_BLOCK_SIZE - residue); |
7cc355c2 SL |
172 | /* |
173 | * Restore the last partial ciphertext block. | |
174 | * Now that we have the cipher text of the second last block, apply | |
175 | * that to the partial plaintext end block. We have already decrypted the | |
176 | * block using an IV of zero. For decryption the IV is just XORed after | |
42281f26 | 177 | * doing an Cipher CBC block - so just XOR in the cipher text. |
7cc355c2 | 178 | */ |
42281f26 | 179 | do_xor(ct_mid.c, pt_last.c, residue, out + CTS_BLOCK_SIZE); |
7cc355c2 SL |
180 | |
181 | /* Restore the iv needed by the second last block */ | |
42281f26 | 182 | memcpy(ctx->iv, mid_iv.c, CTS_BLOCK_SIZE); |
46ac83ea | 183 | |
7cc355c2 SL |
184 | /* |
185 | * Decrypt the second last plaintext block now that we have rebuilt the | |
186 | * ciphertext. | |
187 | */ | |
42281f26 | 188 | if (!ctx->hw->cipher(ctx, out, ct_mid.c, CTS_BLOCK_SIZE)) |
7cc355c2 SL |
189 | return 0; |
190 | ||
46ac83ea SL |
191 | /* The returned iv is the C(n) block */ |
192 | memcpy(ctx->iv, cn.c, CTS_BLOCK_SIZE); | |
42281f26 | 193 | return len + CTS_BLOCK_SIZE + residue; |
7cc355c2 SL |
194 | } |
195 | ||
7cc355c2 SL |
196 | static size_t cts128_cs3_encrypt(PROV_CIPHER_CTX *ctx, const unsigned char *in, |
197 | unsigned char *out, size_t len) | |
198 | { | |
199 | aligned_16bytes tmp_in; | |
200 | size_t residue; | |
201 | ||
7daabe78 | 202 | if (len < CTS_BLOCK_SIZE) /* CS3 requires at least one block */ |
7cc355c2 SL |
203 | return 0; |
204 | ||
7daabe78 SL |
205 | /* If we only have one block then just process the aligned block */ |
206 | if (len == CTS_BLOCK_SIZE) | |
207 | return ctx->hw->cipher(ctx, out, in, len) ? len : 0; | |
208 | ||
42281f26 | 209 | residue = len % CTS_BLOCK_SIZE; |
7cc355c2 | 210 | if (residue == 0) |
42281f26 | 211 | residue = CTS_BLOCK_SIZE; |
7cc355c2 SL |
212 | len -= residue; |
213 | ||
214 | if (!ctx->hw->cipher(ctx, out, in, len)) | |
215 | return 0; | |
216 | ||
217 | in += len; | |
218 | out += len; | |
219 | ||
220 | memset(tmp_in.c, 0, sizeof(tmp_in)); | |
221 | memcpy(tmp_in.c, in, residue); | |
42281f26 SL |
222 | memcpy(out, out - CTS_BLOCK_SIZE, residue); |
223 | if (!ctx->hw->cipher(ctx, out - CTS_BLOCK_SIZE, tmp_in.c, CTS_BLOCK_SIZE)) | |
7cc355c2 SL |
224 | return 0; |
225 | return len + residue; | |
226 | } | |
227 | ||
228 | /* | |
229 | * Note: | |
230 | * The cipher text (in) is of the form C(0), C(1), ., C(n), C(n-1)* where | |
231 | * C(n) is a full block and C(n-1)* can be a partial block | |
232 | * (but could be a full block). | |
233 | * This means that the output plaintext (out) needs to swap the plaintext of | |
234 | * the last two decoded ciphertext blocks. | |
235 | */ | |
236 | static size_t cts128_cs3_decrypt(PROV_CIPHER_CTX *ctx, const unsigned char *in, | |
237 | unsigned char *out, size_t len) | |
238 | { | |
46ac83ea | 239 | aligned_16bytes mid_iv, ct_mid, cn, pt_last; |
7cc355c2 SL |
240 | size_t residue; |
241 | ||
7daabe78 | 242 | if (len < CTS_BLOCK_SIZE) /* CS3 requires at least one block */ |
7cc355c2 SL |
243 | return 0; |
244 | ||
7daabe78 SL |
245 | /* If we only have one block then just process the aligned block */ |
246 | if (len == CTS_BLOCK_SIZE) | |
247 | return ctx->hw->cipher(ctx, out, in, len) ? len : 0; | |
248 | ||
7cc355c2 | 249 | /* Process blocks at the start - but leave the last 2 blocks */ |
42281f26 | 250 | residue = len % CTS_BLOCK_SIZE; |
7cc355c2 | 251 | if (residue == 0) |
42281f26 SL |
252 | residue = CTS_BLOCK_SIZE; |
253 | len -= CTS_BLOCK_SIZE + residue; | |
7cc355c2 SL |
254 | |
255 | if (len > 0) { | |
256 | if (!ctx->hw->cipher(ctx, out, in, len)) | |
257 | return 0; | |
258 | in += len; | |
259 | out += len; | |
260 | } | |
261 | /* Save the iv that will be used by the second last block */ | |
42281f26 | 262 | memcpy(mid_iv.c, ctx->iv, CTS_BLOCK_SIZE); |
46ac83ea SL |
263 | /* Save the C(n) block : For CS3 it is C(1)||...||C(n-2)||C(n)||C(n-1)* */ |
264 | memcpy(cn.c, in, CTS_BLOCK_SIZE); | |
7cc355c2 | 265 | |
46ac83ea | 266 | /* Decrypt the C(n) block first using an iv of zero */ |
42281f26 SL |
267 | memset(ctx->iv, 0, CTS_BLOCK_SIZE); |
268 | if (!ctx->hw->cipher(ctx, pt_last.c, in, CTS_BLOCK_SIZE)) | |
7cc355c2 SL |
269 | return 0; |
270 | ||
271 | /* | |
272 | * Rebuild the ciphertext of C(n-1) as a combination of | |
273 | * the decrypted C(n) block + replace the start with the ciphertext bytes | |
274 | * of the partial last block. | |
275 | */ | |
42281f26 SL |
276 | memcpy(ct_mid.c, in + CTS_BLOCK_SIZE, residue); |
277 | if (residue != CTS_BLOCK_SIZE) | |
278 | memcpy(ct_mid.c + residue, pt_last.c + residue, CTS_BLOCK_SIZE - residue); | |
7cc355c2 SL |
279 | /* |
280 | * Restore the last partial ciphertext block. | |
281 | * Now that we have the cipher text of the second last block, apply | |
282 | * that to the partial plaintext end block. We have already decrypted the | |
283 | * block using an IV of zero. For decryption the IV is just XORed after | |
284 | * doing an AES block - so just XOR in the ciphertext. | |
285 | */ | |
42281f26 | 286 | do_xor(ct_mid.c, pt_last.c, residue, out + CTS_BLOCK_SIZE); |
7cc355c2 SL |
287 | |
288 | /* Restore the iv needed by the second last block */ | |
42281f26 | 289 | memcpy(ctx->iv, mid_iv.c, CTS_BLOCK_SIZE); |
7cc355c2 SL |
290 | /* |
291 | * Decrypt the second last plaintext block now that we have rebuilt the | |
292 | * ciphertext. | |
293 | */ | |
42281f26 | 294 | if (!ctx->hw->cipher(ctx, out, ct_mid.c, CTS_BLOCK_SIZE)) |
7cc355c2 SL |
295 | return 0; |
296 | ||
46ac83ea SL |
297 | /* The returned iv is the C(n) block */ |
298 | memcpy(ctx->iv, cn.c, CTS_BLOCK_SIZE); | |
42281f26 | 299 | return len + CTS_BLOCK_SIZE + residue; |
7cc355c2 SL |
300 | } |
301 | ||
302 | static size_t cts128_cs2_encrypt(PROV_CIPHER_CTX *ctx, const unsigned char *in, | |
303 | unsigned char *out, size_t len) | |
304 | { | |
42281f26 | 305 | if (len % CTS_BLOCK_SIZE == 0) { |
7cc355c2 SL |
306 | /* If there are no partial blocks then it is the same as CBC mode */ |
307 | if (!ctx->hw->cipher(ctx, out, in, len)) | |
308 | return 0; | |
309 | return len; | |
310 | } | |
311 | /* For partial blocks CS2 is equivalent to CS3 */ | |
312 | return cts128_cs3_encrypt(ctx, in, out, len); | |
313 | } | |
314 | ||
315 | static size_t cts128_cs2_decrypt(PROV_CIPHER_CTX *ctx, const unsigned char *in, | |
316 | unsigned char *out, size_t len) | |
317 | { | |
42281f26 | 318 | if (len % CTS_BLOCK_SIZE == 0) { |
7cc355c2 SL |
319 | /* If there are no partial blocks then it is the same as CBC mode */ |
320 | if (!ctx->hw->cipher(ctx, out, in, len)) | |
321 | return 0; | |
322 | return len; | |
323 | } | |
324 | /* For partial blocks CS2 is equivalent to CS3 */ | |
325 | return cts128_cs3_decrypt(ctx, in, out, len); | |
326 | } | |
7cc355c2 | 327 | |
42281f26 SL |
328 | int ossl_cipher_cbc_cts_block_update(void *vctx, unsigned char *out, size_t *outl, |
329 | size_t outsize, const unsigned char *in, | |
330 | size_t inl) | |
7cc355c2 SL |
331 | { |
332 | PROV_CIPHER_CTX *ctx = (PROV_CIPHER_CTX *)vctx; | |
333 | size_t sz = 0; | |
334 | ||
42281f26 | 335 | if (inl < CTS_BLOCK_SIZE) /* There must be at least one block for CTS mode */ |
7cc355c2 SL |
336 | return 0; |
337 | if (outsize < inl) | |
338 | return 0; | |
339 | if (out == NULL) { | |
340 | *outl = inl; | |
341 | return 1; | |
342 | } | |
343 | ||
344 | /* | |
345 | * Return an error if the update is called multiple times, only one shot | |
346 | * is supported. | |
347 | */ | |
348 | if (ctx->updated == 1) | |
349 | return 0; | |
350 | ||
351 | if (ctx->enc) { | |
7cc355c2 SL |
352 | if (ctx->cts_mode == CTS_CS1) |
353 | sz = cts128_cs1_encrypt(ctx, in, out, inl); | |
354 | else if (ctx->cts_mode == CTS_CS2) | |
355 | sz = cts128_cs2_encrypt(ctx, in, out, inl); | |
356 | else if (ctx->cts_mode == CTS_CS3) | |
357 | sz = cts128_cs3_encrypt(ctx, in, out, inl); | |
7cc355c2 | 358 | } else { |
7cc355c2 SL |
359 | if (ctx->cts_mode == CTS_CS1) |
360 | sz = cts128_cs1_decrypt(ctx, in, out, inl); | |
361 | else if (ctx->cts_mode == CTS_CS2) | |
362 | sz = cts128_cs2_decrypt(ctx, in, out, inl); | |
363 | else if (ctx->cts_mode == CTS_CS3) | |
364 | sz = cts128_cs3_decrypt(ctx, in, out, inl); | |
7cc355c2 SL |
365 | } |
366 | if (sz == 0) | |
367 | return 0; | |
368 | ctx->updated = 1; /* Stop multiple updates being allowed */ | |
369 | *outl = sz; | |
370 | return 1; | |
371 | } | |
372 | ||
42281f26 SL |
373 | int ossl_cipher_cbc_cts_block_final(void *vctx, unsigned char *out, size_t *outl, |
374 | size_t outsize) | |
7cc355c2 SL |
375 | { |
376 | *outl = 0; | |
377 | return 1; | |
378 | } |