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>
10cbda7091SJens 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
to_cts_ctx(struct crypto_cipher_ctx * ctx)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
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)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
59cbda7091SJens Wiklander res = crypto_cipher_init(c->ecb, mode, key1, key1_len, key2, key2_len,
60cbda7091SJens Wiklander iv, iv_len);
6117c68af4SJens Wiklander if (res)
6217c68af4SJens Wiklander return res;
6317c68af4SJens Wiklander
64cbda7091SJens Wiklander return crypto_cipher_init(c->cbc, mode, key1, key1_len, key2, key2_len,
65cbda7091SJens Wiklander iv, iv_len);
66cbda7091SJens Wiklander }
67cbda7091SJens Wiklander
68cbda7091SJens Wiklander /*
69cbda7091SJens Wiklander * From http://en.wikipedia.org/wiki/Ciphertext_stealing
70cbda7091SJens Wiklander * CBC ciphertext stealing encryption using a standard
71cbda7091SJens Wiklander * CBC interface:
72cbda7091SJens Wiklander * 1. Pad the last partial plaintext block with 0.
73cbda7091SJens Wiklander * 2. Encrypt the whole padded plaintext using the
74cbda7091SJens Wiklander * standard CBC mode.
75cbda7091SJens Wiklander * 3. Swap the last two ciphertext blocks.
76cbda7091SJens Wiklander * 4. Truncate the ciphertext to the length of the
77cbda7091SJens Wiklander * original plaintext.
78cbda7091SJens Wiklander *
79cbda7091SJens Wiklander * CBC ciphertext stealing decryption using a standard
80cbda7091SJens Wiklander * CBC interface
81cbda7091SJens Wiklander * 1. Dn = Decrypt (K, Cn-1). Decrypt the second to last
82cbda7091SJens Wiklander * ciphertext block.
83cbda7091SJens Wiklander * 2. Cn = Cn || Tail (Dn, B-M). Pad the ciphertext to the
84cbda7091SJens Wiklander * nearest multiple of the block size using the last
85cbda7091SJens Wiklander * B-M bits of block cipher decryption of the
86cbda7091SJens Wiklander * second-to-last ciphertext block.
87cbda7091SJens Wiklander * 3. Swap the last two ciphertext blocks.
88cbda7091SJens Wiklander * 4. Decrypt the (modified) ciphertext using the standard
89cbda7091SJens Wiklander * CBC mode.
90cbda7091SJens Wiklander * 5. Truncate the plaintext to the length of the original
91cbda7091SJens Wiklander * ciphertext.
92cbda7091SJens Wiklander */
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)93cbda7091SJens Wiklander static TEE_Result cbc_cts_update(void *cbc_ctx, void *ecb_ctx,
94cbda7091SJens Wiklander TEE_OperationMode mode, bool last_block,
95cbda7091SJens Wiklander const uint8_t *data, size_t len, uint8_t *dst)
96cbda7091SJens Wiklander {
97abd18a27SJens Wiklander TEE_Result res = TEE_SUCCESS;
98abd18a27SJens Wiklander uint8_t tmp2_block[64] = { 0 };
99abd18a27SJens Wiklander uint8_t tmp_block[64] = { 0 };
100abd18a27SJens Wiklander int len_last_block = 0;
101abd18a27SJens Wiklander int block_size = 16;
102abd18a27SJens Wiklander int nb_blocks = 0;
103cbda7091SJens Wiklander
104cbda7091SJens Wiklander if (!last_block)
105cbda7091SJens Wiklander return tee_do_cipher_update(cbc_ctx, TEE_ALG_AES_CBC_NOPAD,
106cbda7091SJens Wiklander mode, last_block, data, len, dst);
107cbda7091SJens Wiklander
108cbda7091SJens Wiklander /* Compute the last block length and check constraints */
109abd18a27SJens Wiklander nb_blocks = (len + block_size - 1) / block_size;
110cbda7091SJens Wiklander if (nb_blocks < 2)
111cbda7091SJens Wiklander return TEE_ERROR_BAD_STATE;
112cbda7091SJens Wiklander len_last_block = len % block_size;
113cbda7091SJens Wiklander if (len_last_block == 0)
114cbda7091SJens Wiklander len_last_block = block_size;
115cbda7091SJens Wiklander
116cbda7091SJens Wiklander if (mode == TEE_MODE_ENCRYPT) {
117cbda7091SJens Wiklander memcpy(tmp_block,
118cbda7091SJens Wiklander data + ((nb_blocks - 1) * block_size),
119cbda7091SJens Wiklander len_last_block);
120cbda7091SJens Wiklander memset(tmp_block + len_last_block,
121cbda7091SJens Wiklander 0,
122cbda7091SJens Wiklander block_size - len_last_block);
123cbda7091SJens Wiklander
124cbda7091SJens Wiklander res = tee_do_cipher_update(cbc_ctx, TEE_ALG_AES_CBC_NOPAD,
125cbda7091SJens Wiklander mode, 0, data,
126cbda7091SJens Wiklander (nb_blocks - 1) * block_size, dst);
127cbda7091SJens Wiklander if (res != TEE_SUCCESS)
128cbda7091SJens Wiklander return res;
129cbda7091SJens Wiklander
130cbda7091SJens Wiklander memcpy(dst + (nb_blocks - 1) * block_size,
131cbda7091SJens Wiklander dst + (nb_blocks - 2) * block_size,
132cbda7091SJens Wiklander len_last_block);
133cbda7091SJens Wiklander
134cbda7091SJens Wiklander res = tee_do_cipher_update(cbc_ctx, TEE_ALG_AES_CBC_NOPAD,
135cbda7091SJens Wiklander mode, 0, tmp_block, block_size,
136cbda7091SJens Wiklander dst + (nb_blocks - 2) * block_size);
137cbda7091SJens Wiklander if (res != TEE_SUCCESS)
138cbda7091SJens Wiklander return res;
139cbda7091SJens Wiklander } else {
140cbda7091SJens Wiklander /* 1. Decrypt the second to last ciphertext block */
141cbda7091SJens Wiklander res = tee_do_cipher_update(ecb_ctx, TEE_ALG_AES_ECB_NOPAD,
142cbda7091SJens Wiklander mode, 0,
143cbda7091SJens Wiklander data + (nb_blocks - 2) * block_size,
144cbda7091SJens Wiklander block_size, tmp2_block);
145cbda7091SJens Wiklander if (res != TEE_SUCCESS)
146cbda7091SJens Wiklander return res;
147cbda7091SJens Wiklander
148cbda7091SJens Wiklander /* 2. Cn = Cn || Tail (Dn, B-M) */
149cbda7091SJens Wiklander memcpy(tmp_block, data + ((nb_blocks - 1) * block_size),
150cbda7091SJens Wiklander len_last_block);
151cbda7091SJens Wiklander memcpy(tmp_block + len_last_block, tmp2_block + len_last_block,
152cbda7091SJens Wiklander block_size - len_last_block);
153cbda7091SJens Wiklander
154cbda7091SJens Wiklander /* 3. Swap the last two ciphertext blocks */
155cbda7091SJens Wiklander /* done by passing the correct buffers in step 4. */
156cbda7091SJens Wiklander
157cbda7091SJens Wiklander /* 4. Decrypt the (modified) ciphertext */
158cbda7091SJens Wiklander if (nb_blocks > 2) {
159cbda7091SJens Wiklander res = tee_do_cipher_update(cbc_ctx,
160cbda7091SJens Wiklander TEE_ALG_AES_CBC_NOPAD, mode,
161cbda7091SJens Wiklander 0, data,
162cbda7091SJens Wiklander (nb_blocks - 2) *
163cbda7091SJens Wiklander block_size, dst);
164cbda7091SJens Wiklander if (res != TEE_SUCCESS)
165cbda7091SJens Wiklander return res;
166cbda7091SJens Wiklander }
167cbda7091SJens Wiklander
168cbda7091SJens Wiklander res = tee_do_cipher_update(cbc_ctx, TEE_ALG_AES_CBC_NOPAD,
169cbda7091SJens Wiklander mode, 0, tmp_block, block_size,
170cbda7091SJens Wiklander dst +
171cbda7091SJens Wiklander ((nb_blocks - 2) * block_size));
172cbda7091SJens Wiklander if (res != TEE_SUCCESS)
173cbda7091SJens Wiklander return res;
174cbda7091SJens Wiklander
175cbda7091SJens Wiklander res = tee_do_cipher_update(cbc_ctx, TEE_ALG_AES_CBC_NOPAD,
176cbda7091SJens Wiklander mode, 0, data +
177cbda7091SJens Wiklander ((nb_blocks - 2) * block_size),
178cbda7091SJens Wiklander block_size, tmp_block);
179cbda7091SJens Wiklander if (res != TEE_SUCCESS)
180cbda7091SJens Wiklander return res;
181cbda7091SJens Wiklander
182cbda7091SJens Wiklander /* 5. Truncate the plaintext */
183cbda7091SJens Wiklander memcpy(dst + (nb_blocks - 1) * block_size, tmp_block,
184cbda7091SJens Wiklander len_last_block);
185cbda7091SJens Wiklander }
186cbda7091SJens Wiklander return TEE_SUCCESS;
18717c68af4SJens Wiklander }
18817c68af4SJens Wiklander
cts_update(struct crypto_cipher_ctx * ctx,bool last_block,const uint8_t * data,size_t len,uint8_t * dst)18917c68af4SJens Wiklander static TEE_Result cts_update(struct crypto_cipher_ctx *ctx, bool last_block,
19017c68af4SJens Wiklander const uint8_t *data, size_t len, uint8_t *dst)
19117c68af4SJens Wiklander {
19217c68af4SJens Wiklander struct cts_ctx *c = to_cts_ctx(ctx);
19317c68af4SJens Wiklander
194cbda7091SJens Wiklander return cbc_cts_update(c->cbc, c->ecb, c->mode, last_block, data, len,
195cbda7091SJens Wiklander dst);
19617c68af4SJens Wiklander }
19717c68af4SJens Wiklander
cts_final(struct crypto_cipher_ctx * ctx)19817c68af4SJens Wiklander static void cts_final(struct crypto_cipher_ctx *ctx)
19917c68af4SJens Wiklander {
20017c68af4SJens Wiklander struct cts_ctx *c = to_cts_ctx(ctx);
20117c68af4SJens Wiklander
202cbda7091SJens Wiklander crypto_cipher_final(c->cbc);
203cbda7091SJens Wiklander crypto_cipher_final(c->ecb);
20417c68af4SJens Wiklander }
20517c68af4SJens Wiklander
cts_free_ctx(struct crypto_cipher_ctx * ctx)20617c68af4SJens Wiklander static void cts_free_ctx(struct crypto_cipher_ctx *ctx)
20717c68af4SJens Wiklander {
20817c68af4SJens Wiklander struct cts_ctx *c = to_cts_ctx(ctx);
20917c68af4SJens Wiklander
210cbda7091SJens Wiklander crypto_cipher_free_ctx(c->cbc);
211cbda7091SJens Wiklander crypto_cipher_free_ctx(c->ecb);
21217c68af4SJens Wiklander free(c);
21317c68af4SJens Wiklander }
21417c68af4SJens Wiklander
cts_copy_state(struct crypto_cipher_ctx * dst_ctx,struct crypto_cipher_ctx * src_ctx)21517c68af4SJens Wiklander static void cts_copy_state(struct crypto_cipher_ctx *dst_ctx,
21617c68af4SJens Wiklander struct crypto_cipher_ctx *src_ctx)
21717c68af4SJens Wiklander {
21817c68af4SJens Wiklander struct cts_ctx *src = to_cts_ctx(src_ctx);
21917c68af4SJens Wiklander struct cts_ctx *dst = to_cts_ctx(dst_ctx);
22017c68af4SJens Wiklander
221cbda7091SJens Wiklander crypto_cipher_copy_state(dst->cbc, src->cbc);
222cbda7091SJens Wiklander crypto_cipher_copy_state(dst->ecb, src->ecb);
223*4cfcf345SJens Wiklander dst->mode = src->mode;
22417c68af4SJens Wiklander }
22517c68af4SJens Wiklander
22617c68af4SJens Wiklander static const struct crypto_cipher_ops cts_ops = {
22717c68af4SJens Wiklander .init = cts_init,
22817c68af4SJens Wiklander .update = cts_update,
22917c68af4SJens Wiklander .final = cts_final,
23017c68af4SJens Wiklander .free_ctx = cts_free_ctx,
23117c68af4SJens Wiklander .copy_state = cts_copy_state,
23217c68af4SJens Wiklander };
23317c68af4SJens Wiklander
crypto_aes_cts_alloc_ctx(struct crypto_cipher_ctx ** ctx)23417c68af4SJens Wiklander TEE_Result crypto_aes_cts_alloc_ctx(struct crypto_cipher_ctx **ctx)
23517c68af4SJens Wiklander {
23617c68af4SJens Wiklander TEE_Result res = TEE_SUCCESS;
23717c68af4SJens Wiklander struct cts_ctx *c = calloc(1, sizeof(*c));
23817c68af4SJens Wiklander
23917c68af4SJens Wiklander if (!c)
24017c68af4SJens Wiklander return TEE_ERROR_OUT_OF_MEMORY;
24117c68af4SJens Wiklander
24217c68af4SJens Wiklander res = crypto_aes_ecb_alloc_ctx(&c->ecb);
24317c68af4SJens Wiklander if (res)
24417c68af4SJens Wiklander goto err;
24517c68af4SJens Wiklander res = crypto_aes_cbc_alloc_ctx(&c->cbc);
24617c68af4SJens Wiklander if (res)
24717c68af4SJens Wiklander goto err;
24817c68af4SJens Wiklander
24917c68af4SJens Wiklander c->ctx.ops = &cts_ops;
25017c68af4SJens Wiklander *ctx = &c->ctx;
25117c68af4SJens Wiklander
25217c68af4SJens Wiklander return TEE_SUCCESS;
25317c68af4SJens Wiklander err:
254cbda7091SJens Wiklander crypto_cipher_free_ctx(c->ecb);
25517c68af4SJens Wiklander free(c);
25617c68af4SJens Wiklander
25717c68af4SJens Wiklander return res;
25817c68af4SJens Wiklander }
259