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