xref: /optee_os/core/crypto/aes-cts.c (revision cbda709118504f8b9b6812419d14f8360c40ad27)
117c68af4SJens Wiklander // SPDX-License-Identifier: BSD-2-Clause
217c68af4SJens Wiklander /*
317c68af4SJens Wiklander  * Copyright (c) 2014-2019, Linaro Limited
417c68af4SJens Wiklander  */
517c68af4SJens Wiklander 
617c68af4SJens Wiklander #include <assert.h>
717c68af4SJens Wiklander #include <crypto/crypto.h>
817c68af4SJens Wiklander #include <crypto/crypto_impl.h>
917c68af4SJens Wiklander #include <stdlib.h>
10*cbda7091SJens Wiklander #include <string.h>
1117c68af4SJens Wiklander #include <tee_api_types.h>
1217c68af4SJens Wiklander #include <tee/tee_cryp_utl.h>
1317c68af4SJens Wiklander #include <util.h>
1417c68af4SJens Wiklander 
1517c68af4SJens Wiklander 
1617c68af4SJens Wiklander /* From libtomcrypt doc:
1717c68af4SJens Wiklander  *	Ciphertext stealing is a method of dealing with messages
1817c68af4SJens Wiklander  *	in CBC mode which are not a multiple of the block
1917c68af4SJens Wiklander  *	length.  This is accomplished by encrypting the last
2017c68af4SJens Wiklander  *	ciphertext block in ECB mode, and XOR'ing the output
2117c68af4SJens Wiklander  *	against the last partial block of plaintext. LibTomCrypt
2217c68af4SJens Wiklander  *	does not support this mode directly but it is fairly
2317c68af4SJens Wiklander  *	easy to emulate with a call to the cipher's
2417c68af4SJens Wiklander  *	ecb encrypt() callback function.
2517c68af4SJens Wiklander  *	The more sane way to deal with partial blocks is to pad
2617c68af4SJens Wiklander  *	them with zeroes, and then use CBC normally
2717c68af4SJens Wiklander  */
2817c68af4SJens Wiklander 
2917c68af4SJens Wiklander /*
3017c68af4SJens Wiklander  * From Global Platform: CTS = CBC-CS3
3117c68af4SJens Wiklander  */
3217c68af4SJens Wiklander 
3317c68af4SJens Wiklander struct cts_ctx {
3417c68af4SJens Wiklander 	struct crypto_cipher_ctx ctx;
3517c68af4SJens Wiklander 	struct crypto_cipher_ctx *ecb;
3617c68af4SJens Wiklander 	struct crypto_cipher_ctx *cbc;
3717c68af4SJens Wiklander 	TEE_OperationMode mode;
3817c68af4SJens Wiklander };
3917c68af4SJens Wiklander 
4017c68af4SJens Wiklander static const struct crypto_cipher_ops cts_ops;
4117c68af4SJens Wiklander 
4217c68af4SJens Wiklander static struct cts_ctx *to_cts_ctx(struct crypto_cipher_ctx *ctx)
4317c68af4SJens Wiklander {
4417c68af4SJens Wiklander 	assert(ctx && ctx->ops == &cts_ops);
4517c68af4SJens Wiklander 
4617c68af4SJens Wiklander 	return container_of(ctx, struct cts_ctx, ctx);
4717c68af4SJens Wiklander }
4817c68af4SJens Wiklander 
4917c68af4SJens Wiklander static TEE_Result cts_init(struct crypto_cipher_ctx *ctx,
5017c68af4SJens Wiklander 			   TEE_OperationMode mode, const uint8_t *key1,
5117c68af4SJens Wiklander 			   size_t key1_len, const uint8_t *key2,
5217c68af4SJens Wiklander 			   size_t key2_len, const uint8_t *iv, size_t iv_len)
5317c68af4SJens Wiklander {
5417c68af4SJens Wiklander 	TEE_Result res = TEE_SUCCESS;
5517c68af4SJens Wiklander 	struct cts_ctx *c = to_cts_ctx(ctx);
5617c68af4SJens Wiklander 
5717c68af4SJens Wiklander 	c->mode = mode;
5817c68af4SJens Wiklander 
59*cbda7091SJens Wiklander 	res = crypto_cipher_init(c->ecb, mode, key1, key1_len, key2, key2_len,
60*cbda7091SJens Wiklander 				 iv, iv_len);
6117c68af4SJens Wiklander 	if (res)
6217c68af4SJens Wiklander 		return res;
6317c68af4SJens Wiklander 
64*cbda7091SJens Wiklander 	return crypto_cipher_init(c->cbc, mode, key1, key1_len, key2, key2_len,
65*cbda7091SJens Wiklander 				  iv, iv_len);
66*cbda7091SJens Wiklander }
67*cbda7091SJens Wiklander 
68*cbda7091SJens Wiklander /*
69*cbda7091SJens Wiklander  * From http://en.wikipedia.org/wiki/Ciphertext_stealing
70*cbda7091SJens Wiklander  * CBC ciphertext stealing encryption using a standard
71*cbda7091SJens Wiklander  * CBC interface:
72*cbda7091SJens Wiklander  *	1. Pad the last partial plaintext block with 0.
73*cbda7091SJens Wiklander  *	2. Encrypt the whole padded plaintext using the
74*cbda7091SJens Wiklander  *	   standard CBC mode.
75*cbda7091SJens Wiklander  *	3. Swap the last two ciphertext blocks.
76*cbda7091SJens Wiklander  *	4. Truncate the ciphertext to the length of the
77*cbda7091SJens Wiklander  *	   original plaintext.
78*cbda7091SJens Wiklander  *
79*cbda7091SJens Wiklander  * CBC ciphertext stealing decryption using a standard
80*cbda7091SJens Wiklander  * CBC interface
81*cbda7091SJens Wiklander  *	1. Dn = Decrypt (K, Cn-1). Decrypt the second to last
82*cbda7091SJens Wiklander  *	   ciphertext block.
83*cbda7091SJens Wiklander  *	2. Cn = Cn || Tail (Dn, B-M). Pad the ciphertext to the
84*cbda7091SJens Wiklander  *	   nearest multiple of the block size using the last
85*cbda7091SJens Wiklander  *	   B-M bits of block cipher decryption of the
86*cbda7091SJens Wiklander  *	   second-to-last ciphertext block.
87*cbda7091SJens Wiklander  *	3. Swap the last two ciphertext blocks.
88*cbda7091SJens Wiklander  *	4. Decrypt the (modified) ciphertext using the standard
89*cbda7091SJens Wiklander  *	   CBC mode.
90*cbda7091SJens Wiklander  *	5. Truncate the plaintext to the length of the original
91*cbda7091SJens Wiklander  *	   ciphertext.
92*cbda7091SJens Wiklander  */
93*cbda7091SJens Wiklander static TEE_Result cbc_cts_update(void *cbc_ctx, void *ecb_ctx,
94*cbda7091SJens Wiklander 				 TEE_OperationMode mode, bool last_block,
95*cbda7091SJens Wiklander 				 const uint8_t *data, size_t len, uint8_t *dst)
96*cbda7091SJens Wiklander {
97*cbda7091SJens Wiklander 	TEE_Result res;
98*cbda7091SJens Wiklander 	int nb_blocks, len_last_block, block_size = 16;
99*cbda7091SJens Wiklander 	uint8_t tmp_block[64], tmp2_block[64];
100*cbda7091SJens Wiklander 
101*cbda7091SJens Wiklander 	if (!last_block)
102*cbda7091SJens Wiklander 		return tee_do_cipher_update(cbc_ctx, TEE_ALG_AES_CBC_NOPAD,
103*cbda7091SJens Wiklander 					     mode, last_block, data, len, dst);
104*cbda7091SJens Wiklander 
105*cbda7091SJens Wiklander 	/* Compute the last block length and check constraints */
106*cbda7091SJens Wiklander 	nb_blocks = ((len + block_size - 1) / block_size);
107*cbda7091SJens Wiklander 	if (nb_blocks < 2)
108*cbda7091SJens Wiklander 		return TEE_ERROR_BAD_STATE;
109*cbda7091SJens Wiklander 	len_last_block = len % block_size;
110*cbda7091SJens Wiklander 	if (len_last_block == 0)
111*cbda7091SJens Wiklander 		len_last_block = block_size;
112*cbda7091SJens Wiklander 
113*cbda7091SJens Wiklander 	if (mode == TEE_MODE_ENCRYPT) {
114*cbda7091SJens Wiklander 		memcpy(tmp_block,
115*cbda7091SJens Wiklander 		       data + ((nb_blocks - 1) * block_size),
116*cbda7091SJens Wiklander 		       len_last_block);
117*cbda7091SJens Wiklander 		memset(tmp_block + len_last_block,
118*cbda7091SJens Wiklander 		       0,
119*cbda7091SJens Wiklander 		       block_size - len_last_block);
120*cbda7091SJens Wiklander 
121*cbda7091SJens Wiklander 		res = tee_do_cipher_update(cbc_ctx, TEE_ALG_AES_CBC_NOPAD,
122*cbda7091SJens Wiklander 					   mode, 0, data,
123*cbda7091SJens Wiklander 					   (nb_blocks - 1) * block_size, dst);
124*cbda7091SJens Wiklander 		if (res != TEE_SUCCESS)
125*cbda7091SJens Wiklander 			return res;
126*cbda7091SJens Wiklander 
127*cbda7091SJens Wiklander 		memcpy(dst + (nb_blocks - 1) * block_size,
128*cbda7091SJens Wiklander 		       dst + (nb_blocks - 2) * block_size,
129*cbda7091SJens Wiklander 		       len_last_block);
130*cbda7091SJens Wiklander 
131*cbda7091SJens Wiklander 		res = tee_do_cipher_update(cbc_ctx, TEE_ALG_AES_CBC_NOPAD,
132*cbda7091SJens Wiklander 					   mode, 0, tmp_block, block_size,
133*cbda7091SJens Wiklander 					   dst + (nb_blocks - 2) * block_size);
134*cbda7091SJens Wiklander 		if (res != TEE_SUCCESS)
135*cbda7091SJens Wiklander 			return res;
136*cbda7091SJens Wiklander 	} else {
137*cbda7091SJens Wiklander 		/* 1. Decrypt the second to last ciphertext block */
138*cbda7091SJens Wiklander 		res = tee_do_cipher_update(ecb_ctx, TEE_ALG_AES_ECB_NOPAD,
139*cbda7091SJens Wiklander 					   mode, 0,
140*cbda7091SJens Wiklander 					   data + (nb_blocks - 2) * block_size,
141*cbda7091SJens Wiklander 					   block_size, tmp2_block);
142*cbda7091SJens Wiklander 		if (res != TEE_SUCCESS)
143*cbda7091SJens Wiklander 			return res;
144*cbda7091SJens Wiklander 
145*cbda7091SJens Wiklander 		/* 2. Cn = Cn || Tail (Dn, B-M) */
146*cbda7091SJens Wiklander 		memcpy(tmp_block, data + ((nb_blocks - 1) * block_size),
147*cbda7091SJens Wiklander 		       len_last_block);
148*cbda7091SJens Wiklander 		memcpy(tmp_block + len_last_block, tmp2_block + len_last_block,
149*cbda7091SJens Wiklander 		       block_size - len_last_block);
150*cbda7091SJens Wiklander 
151*cbda7091SJens Wiklander 		/* 3. Swap the last two ciphertext blocks */
152*cbda7091SJens Wiklander 		/* done by passing the correct buffers in step 4. */
153*cbda7091SJens Wiklander 
154*cbda7091SJens Wiklander 		/* 4. Decrypt the (modified) ciphertext */
155*cbda7091SJens Wiklander 		if (nb_blocks > 2) {
156*cbda7091SJens Wiklander 			res = tee_do_cipher_update(cbc_ctx,
157*cbda7091SJens Wiklander 						   TEE_ALG_AES_CBC_NOPAD, mode,
158*cbda7091SJens Wiklander 						   0, data,
159*cbda7091SJens Wiklander 						   (nb_blocks - 2) *
160*cbda7091SJens Wiklander 						   block_size, dst);
161*cbda7091SJens Wiklander 			if (res != TEE_SUCCESS)
162*cbda7091SJens Wiklander 				return res;
163*cbda7091SJens Wiklander 		}
164*cbda7091SJens Wiklander 
165*cbda7091SJens Wiklander 		res = tee_do_cipher_update(cbc_ctx, TEE_ALG_AES_CBC_NOPAD,
166*cbda7091SJens Wiklander 					   mode, 0, tmp_block, block_size,
167*cbda7091SJens Wiklander 					   dst +
168*cbda7091SJens Wiklander 					   ((nb_blocks - 2) * block_size));
169*cbda7091SJens Wiklander 		if (res != TEE_SUCCESS)
170*cbda7091SJens Wiklander 			return res;
171*cbda7091SJens Wiklander 
172*cbda7091SJens Wiklander 		res = tee_do_cipher_update(cbc_ctx, TEE_ALG_AES_CBC_NOPAD,
173*cbda7091SJens Wiklander 					   mode, 0, data +
174*cbda7091SJens Wiklander 					   ((nb_blocks - 2) * block_size),
175*cbda7091SJens Wiklander 					   block_size, tmp_block);
176*cbda7091SJens Wiklander 		if (res != TEE_SUCCESS)
177*cbda7091SJens Wiklander 			return res;
178*cbda7091SJens Wiklander 
179*cbda7091SJens Wiklander 		/* 5. Truncate the plaintext */
180*cbda7091SJens Wiklander 		memcpy(dst + (nb_blocks - 1) * block_size, tmp_block,
181*cbda7091SJens Wiklander 		       len_last_block);
182*cbda7091SJens Wiklander 	}
183*cbda7091SJens Wiklander 	return TEE_SUCCESS;
18417c68af4SJens Wiklander }
18517c68af4SJens Wiklander 
18617c68af4SJens Wiklander static TEE_Result cts_update(struct crypto_cipher_ctx *ctx, bool last_block,
18717c68af4SJens Wiklander 			     const uint8_t *data, size_t len, uint8_t *dst)
18817c68af4SJens Wiklander {
18917c68af4SJens Wiklander 	struct cts_ctx *c = to_cts_ctx(ctx);
19017c68af4SJens Wiklander 
191*cbda7091SJens Wiklander 	return cbc_cts_update(c->cbc, c->ecb, c->mode, last_block, data, len,
192*cbda7091SJens Wiklander 			      dst);
19317c68af4SJens Wiklander }
19417c68af4SJens Wiklander 
19517c68af4SJens Wiklander static void cts_final(struct crypto_cipher_ctx *ctx)
19617c68af4SJens Wiklander {
19717c68af4SJens Wiklander 	struct cts_ctx *c = to_cts_ctx(ctx);
19817c68af4SJens Wiklander 
199*cbda7091SJens Wiklander 	crypto_cipher_final(c->cbc);
200*cbda7091SJens Wiklander 	crypto_cipher_final(c->ecb);
20117c68af4SJens Wiklander }
20217c68af4SJens Wiklander 
20317c68af4SJens Wiklander static void cts_free_ctx(struct crypto_cipher_ctx *ctx)
20417c68af4SJens Wiklander {
20517c68af4SJens Wiklander 	struct cts_ctx *c = to_cts_ctx(ctx);
20617c68af4SJens Wiklander 
207*cbda7091SJens Wiklander 	crypto_cipher_free_ctx(c->cbc);
208*cbda7091SJens Wiklander 	crypto_cipher_free_ctx(c->ecb);
20917c68af4SJens Wiklander 	free(c);
21017c68af4SJens Wiklander }
21117c68af4SJens Wiklander 
21217c68af4SJens Wiklander static void cts_copy_state(struct crypto_cipher_ctx *dst_ctx,
21317c68af4SJens Wiklander 			   struct crypto_cipher_ctx *src_ctx)
21417c68af4SJens Wiklander {
21517c68af4SJens Wiklander 	struct cts_ctx *src = to_cts_ctx(src_ctx);
21617c68af4SJens Wiklander 	struct cts_ctx *dst = to_cts_ctx(dst_ctx);
21717c68af4SJens Wiklander 
218*cbda7091SJens Wiklander 	crypto_cipher_copy_state(dst->cbc, src->cbc);
219*cbda7091SJens Wiklander 	crypto_cipher_copy_state(dst->ecb, src->ecb);
22017c68af4SJens Wiklander }
22117c68af4SJens Wiklander 
22217c68af4SJens Wiklander static const struct crypto_cipher_ops cts_ops = {
22317c68af4SJens Wiklander 	.init = cts_init,
22417c68af4SJens Wiklander 	.update = cts_update,
22517c68af4SJens Wiklander 	.final = cts_final,
22617c68af4SJens Wiklander 	.free_ctx = cts_free_ctx,
22717c68af4SJens Wiklander 	.copy_state = cts_copy_state,
22817c68af4SJens Wiklander };
22917c68af4SJens Wiklander 
23017c68af4SJens Wiklander TEE_Result crypto_aes_cts_alloc_ctx(struct crypto_cipher_ctx **ctx)
23117c68af4SJens Wiklander {
23217c68af4SJens Wiklander 	TEE_Result res = TEE_SUCCESS;
23317c68af4SJens Wiklander 	struct cts_ctx *c = calloc(1, sizeof(*c));
23417c68af4SJens Wiklander 
23517c68af4SJens Wiklander 	if (!c)
23617c68af4SJens Wiklander 		return TEE_ERROR_OUT_OF_MEMORY;
23717c68af4SJens Wiklander 
23817c68af4SJens Wiklander 	res = crypto_aes_ecb_alloc_ctx(&c->ecb);
23917c68af4SJens Wiklander 	if (res)
24017c68af4SJens Wiklander 		goto err;
24117c68af4SJens Wiklander 	res = crypto_aes_cbc_alloc_ctx(&c->cbc);
24217c68af4SJens Wiklander 	if (res)
24317c68af4SJens Wiklander 		goto err;
24417c68af4SJens Wiklander 
24517c68af4SJens Wiklander 	c->ctx.ops = &cts_ops;
24617c68af4SJens Wiklander 	*ctx = &c->ctx;
24717c68af4SJens Wiklander 
24817c68af4SJens Wiklander 	return TEE_SUCCESS;
24917c68af4SJens Wiklander err:
250*cbda7091SJens Wiklander 	crypto_cipher_free_ctx(c->ecb);
25117c68af4SJens Wiklander 	free(c);
25217c68af4SJens Wiklander 
25317c68af4SJens Wiklander 	return res;
25417c68af4SJens Wiklander }
255