1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3 * Copyright (c) 2014-2019, Linaro Limited
4 */
5
6 #include <assert.h>
7 #include <crypto/crypto.h>
8 #include <crypto/crypto_impl.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <tee_api_types.h>
12 #include <tee/tee_cryp_utl.h>
13 #include <util.h>
14
15
16 /* From libtomcrypt doc:
17 * Ciphertext stealing is a method of dealing with messages
18 * in CBC mode which are not a multiple of the block
19 * length. This is accomplished by encrypting the last
20 * ciphertext block in ECB mode, and XOR'ing the output
21 * against the last partial block of plaintext. LibTomCrypt
22 * does not support this mode directly but it is fairly
23 * easy to emulate with a call to the cipher's
24 * ecb encrypt() callback function.
25 * The more sane way to deal with partial blocks is to pad
26 * them with zeroes, and then use CBC normally
27 */
28
29 /*
30 * From Global Platform: CTS = CBC-CS3
31 */
32
33 struct cts_ctx {
34 struct crypto_cipher_ctx ctx;
35 struct crypto_cipher_ctx *ecb;
36 struct crypto_cipher_ctx *cbc;
37 TEE_OperationMode mode;
38 };
39
40 static const struct crypto_cipher_ops cts_ops;
41
to_cts_ctx(struct crypto_cipher_ctx * ctx)42 static struct cts_ctx *to_cts_ctx(struct crypto_cipher_ctx *ctx)
43 {
44 assert(ctx && ctx->ops == &cts_ops);
45
46 return container_of(ctx, struct cts_ctx, ctx);
47 }
48
cts_init(struct crypto_cipher_ctx * ctx,TEE_OperationMode mode,const uint8_t * key1,size_t key1_len,const uint8_t * key2,size_t key2_len,const uint8_t * iv,size_t iv_len)49 static TEE_Result cts_init(struct crypto_cipher_ctx *ctx,
50 TEE_OperationMode mode, const uint8_t *key1,
51 size_t key1_len, const uint8_t *key2,
52 size_t key2_len, const uint8_t *iv, size_t iv_len)
53 {
54 TEE_Result res = TEE_SUCCESS;
55 struct cts_ctx *c = to_cts_ctx(ctx);
56
57 c->mode = mode;
58
59 res = crypto_cipher_init(c->ecb, mode, key1, key1_len, key2, key2_len,
60 iv, iv_len);
61 if (res)
62 return res;
63
64 return crypto_cipher_init(c->cbc, mode, key1, key1_len, key2, key2_len,
65 iv, iv_len);
66 }
67
68 /*
69 * From http://en.wikipedia.org/wiki/Ciphertext_stealing
70 * CBC ciphertext stealing encryption using a standard
71 * CBC interface:
72 * 1. Pad the last partial plaintext block with 0.
73 * 2. Encrypt the whole padded plaintext using the
74 * standard CBC mode.
75 * 3. Swap the last two ciphertext blocks.
76 * 4. Truncate the ciphertext to the length of the
77 * original plaintext.
78 *
79 * CBC ciphertext stealing decryption using a standard
80 * CBC interface
81 * 1. Dn = Decrypt (K, Cn-1). Decrypt the second to last
82 * ciphertext block.
83 * 2. Cn = Cn || Tail (Dn, B-M). Pad the ciphertext to the
84 * nearest multiple of the block size using the last
85 * B-M bits of block cipher decryption of the
86 * second-to-last ciphertext block.
87 * 3. Swap the last two ciphertext blocks.
88 * 4. Decrypt the (modified) ciphertext using the standard
89 * CBC mode.
90 * 5. Truncate the plaintext to the length of the original
91 * ciphertext.
92 */
cbc_cts_update(void * cbc_ctx,void * ecb_ctx,TEE_OperationMode mode,bool last_block,const uint8_t * data,size_t len,uint8_t * dst)93 static TEE_Result cbc_cts_update(void *cbc_ctx, void *ecb_ctx,
94 TEE_OperationMode mode, bool last_block,
95 const uint8_t *data, size_t len, uint8_t *dst)
96 {
97 TEE_Result res = TEE_SUCCESS;
98 uint8_t tmp2_block[64] = { 0 };
99 uint8_t tmp_block[64] = { 0 };
100 int len_last_block = 0;
101 int block_size = 16;
102 int nb_blocks = 0;
103
104 if (!last_block)
105 return tee_do_cipher_update(cbc_ctx, TEE_ALG_AES_CBC_NOPAD,
106 mode, last_block, data, len, dst);
107
108 /* Compute the last block length and check constraints */
109 nb_blocks = (len + block_size - 1) / block_size;
110 if (nb_blocks < 2)
111 return TEE_ERROR_BAD_STATE;
112 len_last_block = len % block_size;
113 if (len_last_block == 0)
114 len_last_block = block_size;
115
116 if (mode == TEE_MODE_ENCRYPT) {
117 memcpy(tmp_block,
118 data + ((nb_blocks - 1) * block_size),
119 len_last_block);
120 memset(tmp_block + len_last_block,
121 0,
122 block_size - len_last_block);
123
124 res = tee_do_cipher_update(cbc_ctx, TEE_ALG_AES_CBC_NOPAD,
125 mode, 0, data,
126 (nb_blocks - 1) * block_size, dst);
127 if (res != TEE_SUCCESS)
128 return res;
129
130 memcpy(dst + (nb_blocks - 1) * block_size,
131 dst + (nb_blocks - 2) * block_size,
132 len_last_block);
133
134 res = tee_do_cipher_update(cbc_ctx, TEE_ALG_AES_CBC_NOPAD,
135 mode, 0, tmp_block, block_size,
136 dst + (nb_blocks - 2) * block_size);
137 if (res != TEE_SUCCESS)
138 return res;
139 } else {
140 /* 1. Decrypt the second to last ciphertext block */
141 res = tee_do_cipher_update(ecb_ctx, TEE_ALG_AES_ECB_NOPAD,
142 mode, 0,
143 data + (nb_blocks - 2) * block_size,
144 block_size, tmp2_block);
145 if (res != TEE_SUCCESS)
146 return res;
147
148 /* 2. Cn = Cn || Tail (Dn, B-M) */
149 memcpy(tmp_block, data + ((nb_blocks - 1) * block_size),
150 len_last_block);
151 memcpy(tmp_block + len_last_block, tmp2_block + len_last_block,
152 block_size - len_last_block);
153
154 /* 3. Swap the last two ciphertext blocks */
155 /* done by passing the correct buffers in step 4. */
156
157 /* 4. Decrypt the (modified) ciphertext */
158 if (nb_blocks > 2) {
159 res = tee_do_cipher_update(cbc_ctx,
160 TEE_ALG_AES_CBC_NOPAD, mode,
161 0, data,
162 (nb_blocks - 2) *
163 block_size, dst);
164 if (res != TEE_SUCCESS)
165 return res;
166 }
167
168 res = tee_do_cipher_update(cbc_ctx, TEE_ALG_AES_CBC_NOPAD,
169 mode, 0, tmp_block, block_size,
170 dst +
171 ((nb_blocks - 2) * block_size));
172 if (res != TEE_SUCCESS)
173 return res;
174
175 res = tee_do_cipher_update(cbc_ctx, TEE_ALG_AES_CBC_NOPAD,
176 mode, 0, data +
177 ((nb_blocks - 2) * block_size),
178 block_size, tmp_block);
179 if (res != TEE_SUCCESS)
180 return res;
181
182 /* 5. Truncate the plaintext */
183 memcpy(dst + (nb_blocks - 1) * block_size, tmp_block,
184 len_last_block);
185 }
186 return TEE_SUCCESS;
187 }
188
cts_update(struct crypto_cipher_ctx * ctx,bool last_block,const uint8_t * data,size_t len,uint8_t * dst)189 static TEE_Result cts_update(struct crypto_cipher_ctx *ctx, bool last_block,
190 const uint8_t *data, size_t len, uint8_t *dst)
191 {
192 struct cts_ctx *c = to_cts_ctx(ctx);
193
194 return cbc_cts_update(c->cbc, c->ecb, c->mode, last_block, data, len,
195 dst);
196 }
197
cts_final(struct crypto_cipher_ctx * ctx)198 static void cts_final(struct crypto_cipher_ctx *ctx)
199 {
200 struct cts_ctx *c = to_cts_ctx(ctx);
201
202 crypto_cipher_final(c->cbc);
203 crypto_cipher_final(c->ecb);
204 }
205
cts_free_ctx(struct crypto_cipher_ctx * ctx)206 static void cts_free_ctx(struct crypto_cipher_ctx *ctx)
207 {
208 struct cts_ctx *c = to_cts_ctx(ctx);
209
210 crypto_cipher_free_ctx(c->cbc);
211 crypto_cipher_free_ctx(c->ecb);
212 free(c);
213 }
214
cts_copy_state(struct crypto_cipher_ctx * dst_ctx,struct crypto_cipher_ctx * src_ctx)215 static void cts_copy_state(struct crypto_cipher_ctx *dst_ctx,
216 struct crypto_cipher_ctx *src_ctx)
217 {
218 struct cts_ctx *src = to_cts_ctx(src_ctx);
219 struct cts_ctx *dst = to_cts_ctx(dst_ctx);
220
221 crypto_cipher_copy_state(dst->cbc, src->cbc);
222 crypto_cipher_copy_state(dst->ecb, src->ecb);
223 dst->mode = src->mode;
224 }
225
226 static const struct crypto_cipher_ops cts_ops = {
227 .init = cts_init,
228 .update = cts_update,
229 .final = cts_final,
230 .free_ctx = cts_free_ctx,
231 .copy_state = cts_copy_state,
232 };
233
crypto_aes_cts_alloc_ctx(struct crypto_cipher_ctx ** ctx)234 TEE_Result crypto_aes_cts_alloc_ctx(struct crypto_cipher_ctx **ctx)
235 {
236 TEE_Result res = TEE_SUCCESS;
237 struct cts_ctx *c = calloc(1, sizeof(*c));
238
239 if (!c)
240 return TEE_ERROR_OUT_OF_MEMORY;
241
242 res = crypto_aes_ecb_alloc_ctx(&c->ecb);
243 if (res)
244 goto err;
245 res = crypto_aes_cbc_alloc_ctx(&c->cbc);
246 if (res)
247 goto err;
248
249 c->ctx.ops = &cts_ops;
250 *ctx = &c->ctx;
251
252 return TEE_SUCCESS;
253 err:
254 crypto_cipher_free_ctx(c->ecb);
255 free(c);
256
257 return res;
258 }
259