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