15da36a24SJens Wiklander // SPDX-License-Identifier: BSD-2-Clause
25da36a24SJens Wiklander /*
35da36a24SJens Wiklander * Copyright (c) 2014-2019, Linaro Limited
45da36a24SJens Wiklander */
55da36a24SJens Wiklander
65da36a24SJens Wiklander /*
75da36a24SJens Wiklander * This is implemented here as being the plain text which is encoded with IV=0.
85da36a24SJens Wiklander * Result of the CBC-MAC is the last 16-bytes cipher.
95da36a24SJens Wiklander */
105da36a24SJens Wiklander
115da36a24SJens Wiklander #include <assert.h>
125da36a24SJens Wiklander #include <crypto/crypto.h>
135da36a24SJens Wiklander #include <crypto/crypto_impl.h>
145da36a24SJens Wiklander #include <stdlib.h>
155da36a24SJens Wiklander #include <string.h>
165da36a24SJens Wiklander #include <types_ext.h>
175da36a24SJens Wiklander #include <util.h>
185da36a24SJens Wiklander
195da36a24SJens Wiklander #define CBCMAC_MAX_BLOCK_LEN 16
205da36a24SJens Wiklander
215da36a24SJens Wiklander struct crypto_cbc_mac_ctx {
225da36a24SJens Wiklander struct crypto_mac_ctx ctx;
235da36a24SJens Wiklander void *cbc_ctx;
245da36a24SJens Wiklander uint32_t cbc_algo;
255da36a24SJens Wiklander uint8_t block[CBCMAC_MAX_BLOCK_LEN];
265da36a24SJens Wiklander uint8_t digest[CBCMAC_MAX_BLOCK_LEN];
275da36a24SJens Wiklander unsigned char current_block_len;
285da36a24SJens Wiklander unsigned char block_len;
295da36a24SJens Wiklander bool is_computed;
305da36a24SJens Wiklander bool pkcs5_pad;
315da36a24SJens Wiklander };
325da36a24SJens Wiklander
335da36a24SJens Wiklander static const struct crypto_mac_ops crypto_cbc_mac_ops;
345da36a24SJens Wiklander
to_cbc_mac_ctx(struct crypto_mac_ctx * ctx)355da36a24SJens Wiklander static struct crypto_cbc_mac_ctx *to_cbc_mac_ctx(struct crypto_mac_ctx *ctx)
365da36a24SJens Wiklander {
375da36a24SJens Wiklander assert(ctx && ctx->ops == &crypto_cbc_mac_ops);
385da36a24SJens Wiklander
395da36a24SJens Wiklander return container_of(ctx, struct crypto_cbc_mac_ctx, ctx);
405da36a24SJens Wiklander }
415da36a24SJens Wiklander
crypto_cbc_mac_init(struct crypto_mac_ctx * ctx,const uint8_t * key,size_t len)425da36a24SJens Wiklander static TEE_Result crypto_cbc_mac_init(struct crypto_mac_ctx *ctx,
435da36a24SJens Wiklander const uint8_t *key, size_t len)
445da36a24SJens Wiklander {
455da36a24SJens Wiklander struct crypto_cbc_mac_ctx *mc = to_cbc_mac_ctx(ctx);
465da36a24SJens Wiklander
475da36a24SJens Wiklander memset(mc->block, 0, sizeof(mc->block));
485da36a24SJens Wiklander memset(mc->digest, 0, sizeof(mc->digest));
495da36a24SJens Wiklander mc->current_block_len = 0;
505da36a24SJens Wiklander mc->is_computed = false;
515da36a24SJens Wiklander
525da36a24SJens Wiklander /* IV should be zero and mc->block happens to be zero at this stage */
53cbda7091SJens Wiklander return crypto_cipher_init(mc->cbc_ctx, TEE_MODE_ENCRYPT, key, len,
54cbda7091SJens Wiklander NULL, 0, mc->block, mc->block_len);
555da36a24SJens Wiklander }
565da36a24SJens Wiklander
crypto_cbc_mac_update(struct crypto_mac_ctx * ctx,const uint8_t * data,size_t len)575da36a24SJens Wiklander static TEE_Result crypto_cbc_mac_update(struct crypto_mac_ctx *ctx,
585da36a24SJens Wiklander const uint8_t *data, size_t len)
595da36a24SJens Wiklander {
6016a1c178SJerome Forissier size_t nblocks = 0;
6116a1c178SJerome Forissier size_t out_len = 0;
6216a1c178SJerome Forissier uint8_t *out_tmp = NULL;
6316a1c178SJerome Forissier uint8_t *out = NULL;
645da36a24SJens Wiklander TEE_Result res = TEE_SUCCESS;
655da36a24SJens Wiklander struct crypto_cbc_mac_ctx *mc = to_cbc_mac_ctx(ctx);
665da36a24SJens Wiklander
675da36a24SJens Wiklander if ((mc->current_block_len > 0) &&
685da36a24SJens Wiklander (len + mc->current_block_len >= mc->block_len)) {
695da36a24SJens Wiklander size_t pad_len = mc->block_len - mc->current_block_len;
705da36a24SJens Wiklander
715da36a24SJens Wiklander memcpy(mc->block + mc->current_block_len, data, pad_len);
725da36a24SJens Wiklander data += pad_len;
735da36a24SJens Wiklander len -= pad_len;
74cbda7091SJens Wiklander res = crypto_cipher_update(mc->cbc_ctx, TEE_MODE_ENCRYPT,
75cbda7091SJens Wiklander false, mc->block, mc->block_len,
76cbda7091SJens Wiklander mc->digest);
775da36a24SJens Wiklander if (res)
785da36a24SJens Wiklander return res;
795da36a24SJens Wiklander mc->is_computed = 1;
805da36a24SJens Wiklander mc->current_block_len = 0;
815da36a24SJens Wiklander }
825da36a24SJens Wiklander
8316a1c178SJerome Forissier nblocks = MIN(len / mc->block_len,
8416a1c178SJerome Forissier (size_t)CFG_CRYPTO_CBC_MAC_BUNDLE_BLOCKS);
8516a1c178SJerome Forissier if (nblocks > 1)
86*2723d625SClement Faure out_tmp = calloc(nblocks, mc->block_len);
8716a1c178SJerome Forissier
885da36a24SJens Wiklander while (len >= mc->block_len) {
8916a1c178SJerome Forissier nblocks = MIN(len / mc->block_len,
9016a1c178SJerome Forissier (size_t)CFG_CRYPTO_CBC_MAC_BUNDLE_BLOCKS);
9116a1c178SJerome Forissier
9216a1c178SJerome Forissier if (nblocks > 1 && out_tmp) {
9316a1c178SJerome Forissier out_len = nblocks * mc->block_len;
9416a1c178SJerome Forissier out = out_tmp;
9516a1c178SJerome Forissier } else {
9616a1c178SJerome Forissier out_len = mc->block_len;
9716a1c178SJerome Forissier out = mc->digest;
9816a1c178SJerome Forissier nblocks = 1;
9916a1c178SJerome Forissier }
10016a1c178SJerome Forissier
101cbda7091SJens Wiklander res = crypto_cipher_update(mc->cbc_ctx, TEE_MODE_ENCRYPT,
10216a1c178SJerome Forissier false, data, out_len, out);
1035da36a24SJens Wiklander if (res)
10416a1c178SJerome Forissier goto out;
1055da36a24SJens Wiklander mc->is_computed = 1;
10616a1c178SJerome Forissier data += out_len;
10716a1c178SJerome Forissier len -= out_len;
10816a1c178SJerome Forissier if (nblocks > 1 && len < mc->block_len) {
10916a1c178SJerome Forissier assert(out_tmp);
11016a1c178SJerome Forissier /* Copy last block of output */
11116a1c178SJerome Forissier memcpy(mc->digest, out_tmp + out_len - mc->block_len,
11216a1c178SJerome Forissier mc->block_len);
11316a1c178SJerome Forissier }
1145da36a24SJens Wiklander }
1155da36a24SJens Wiklander
1165da36a24SJens Wiklander if (len > 0) {
1175da36a24SJens Wiklander assert(mc->current_block_len + len < mc->block_len);
1185da36a24SJens Wiklander memcpy(mc->block + mc->current_block_len, data, len);
1195da36a24SJens Wiklander mc->current_block_len += len;
1205da36a24SJens Wiklander }
1215da36a24SJens Wiklander
12216a1c178SJerome Forissier out:
12316a1c178SJerome Forissier free(out_tmp);
12416a1c178SJerome Forissier return res;
1255da36a24SJens Wiklander }
1265da36a24SJens Wiklander
crypto_cbc_mac_final(struct crypto_mac_ctx * ctx,uint8_t * digest,size_t digest_len)1275da36a24SJens Wiklander static TEE_Result crypto_cbc_mac_final(struct crypto_mac_ctx *ctx,
1285da36a24SJens Wiklander uint8_t *digest, size_t digest_len)
1295da36a24SJens Wiklander {
1305da36a24SJens Wiklander struct crypto_cbc_mac_ctx *mc = to_cbc_mac_ctx(ctx);
1315da36a24SJens Wiklander
1325da36a24SJens Wiklander if (mc->pkcs5_pad) {
1335da36a24SJens Wiklander /*
1345da36a24SJens Wiklander * Padding is in whole bytes. The value of each added
1355da36a24SJens Wiklander * byte is the number of bytes that are added, i.e. N
1365da36a24SJens Wiklander * bytes, each of value N are added
1375da36a24SJens Wiklander */
1385da36a24SJens Wiklander size_t pad_len = mc->block_len - mc->current_block_len;
1395da36a24SJens Wiklander
1405da36a24SJens Wiklander memset(mc->block + mc->current_block_len, pad_len, pad_len);
1415da36a24SJens Wiklander mc->current_block_len = 0;
1425da36a24SJens Wiklander if (crypto_cbc_mac_update(ctx, mc->block, mc->block_len))
1435da36a24SJens Wiklander return TEE_ERROR_BAD_STATE;
1445da36a24SJens Wiklander }
1455da36a24SJens Wiklander
1465da36a24SJens Wiklander if (!mc->is_computed || mc->current_block_len)
1475da36a24SJens Wiklander return TEE_ERROR_BAD_STATE;
1485da36a24SJens Wiklander
1495da36a24SJens Wiklander memcpy(digest, mc->digest, MIN(digest_len, mc->block_len));
150cbda7091SJens Wiklander crypto_cipher_final(mc->cbc_ctx);
1515da36a24SJens Wiklander
1525da36a24SJens Wiklander return TEE_SUCCESS;
1535da36a24SJens Wiklander }
1545da36a24SJens Wiklander
crypto_cbc_mac_free_ctx(struct crypto_mac_ctx * ctx)1555da36a24SJens Wiklander static void crypto_cbc_mac_free_ctx(struct crypto_mac_ctx *ctx)
1565da36a24SJens Wiklander {
1575da36a24SJens Wiklander struct crypto_cbc_mac_ctx *mc = to_cbc_mac_ctx(ctx);
1585da36a24SJens Wiklander
159cbda7091SJens Wiklander crypto_cipher_free_ctx(mc->cbc_ctx);
1605da36a24SJens Wiklander free(mc);
1615da36a24SJens Wiklander }
1625da36a24SJens Wiklander
crypto_cbc_mac_copy_state(struct crypto_mac_ctx * dst_ctx,struct crypto_mac_ctx * src_ctx)1635da36a24SJens Wiklander static void crypto_cbc_mac_copy_state(struct crypto_mac_ctx *dst_ctx,
1645da36a24SJens Wiklander struct crypto_mac_ctx *src_ctx)
1655da36a24SJens Wiklander {
1665da36a24SJens Wiklander struct crypto_cbc_mac_ctx *dst = to_cbc_mac_ctx(dst_ctx);
1675da36a24SJens Wiklander struct crypto_cbc_mac_ctx *src = to_cbc_mac_ctx(src_ctx);
1685da36a24SJens Wiklander
1695da36a24SJens Wiklander assert(dst->block_len == src->block_len);
1705da36a24SJens Wiklander assert(dst->pkcs5_pad == src->pkcs5_pad);
1715da36a24SJens Wiklander assert(dst->cbc_algo == src->cbc_algo);
1725da36a24SJens Wiklander
173cbda7091SJens Wiklander crypto_cipher_copy_state(dst->cbc_ctx, src->cbc_ctx);
1745da36a24SJens Wiklander memcpy(dst->block, src->block, sizeof(dst->block));
1755da36a24SJens Wiklander memcpy(dst->digest, src->digest, sizeof(dst->digest));
1765da36a24SJens Wiklander dst->current_block_len = src->current_block_len;
1775da36a24SJens Wiklander dst->is_computed = src->is_computed;
1785da36a24SJens Wiklander }
1795da36a24SJens Wiklander
1805da36a24SJens Wiklander static const struct crypto_mac_ops crypto_cbc_mac_ops = {
1815da36a24SJens Wiklander .init = crypto_cbc_mac_init,
1825da36a24SJens Wiklander .update = crypto_cbc_mac_update,
1835da36a24SJens Wiklander .final = crypto_cbc_mac_final,
1845da36a24SJens Wiklander .free_ctx = crypto_cbc_mac_free_ctx,
1855da36a24SJens Wiklander .copy_state = crypto_cbc_mac_copy_state,
1865da36a24SJens Wiklander };
1875da36a24SJens Wiklander
crypto_cbc_mac_alloc_ctx(struct crypto_mac_ctx ** ctx_ret,uint32_t cbc_algo,bool pkcs5_pad)1885da36a24SJens Wiklander static TEE_Result crypto_cbc_mac_alloc_ctx(struct crypto_mac_ctx **ctx_ret,
1895da36a24SJens Wiklander uint32_t cbc_algo, bool pkcs5_pad)
1905da36a24SJens Wiklander {
1915da36a24SJens Wiklander TEE_Result res;
1925da36a24SJens Wiklander void *cbc_ctx = NULL;
1935da36a24SJens Wiklander struct crypto_cbc_mac_ctx *ctx = NULL;
1945da36a24SJens Wiklander size_t block_size = 0;
1955da36a24SJens Wiklander
1965da36a24SJens Wiklander res = crypto_cipher_get_block_size(cbc_algo, &block_size);
1975da36a24SJens Wiklander if (res)
1985da36a24SJens Wiklander return res;
1995da36a24SJens Wiklander
2005da36a24SJens Wiklander res = crypto_cipher_alloc_ctx(&cbc_ctx, cbc_algo);
2015da36a24SJens Wiklander if (res)
2025da36a24SJens Wiklander return res;
2035da36a24SJens Wiklander
2045da36a24SJens Wiklander ctx = calloc(1, sizeof(*ctx));
2055da36a24SJens Wiklander if (!ctx) {
206cbda7091SJens Wiklander crypto_cipher_free_ctx(cbc_ctx);
2075da36a24SJens Wiklander return TEE_ERROR_OUT_OF_MEMORY;
2085da36a24SJens Wiklander }
2095da36a24SJens Wiklander
2105da36a24SJens Wiklander ctx->cbc_ctx = cbc_ctx;
2115da36a24SJens Wiklander ctx->cbc_algo = cbc_algo;
2125da36a24SJens Wiklander ctx->pkcs5_pad = pkcs5_pad;
2135da36a24SJens Wiklander ctx->block_len = block_size;
2145da36a24SJens Wiklander ctx->ctx.ops = &crypto_cbc_mac_ops;
2155da36a24SJens Wiklander *ctx_ret = &ctx->ctx;
2165da36a24SJens Wiklander
2175da36a24SJens Wiklander return TEE_SUCCESS;
2185da36a24SJens Wiklander }
2195da36a24SJens Wiklander
crypto_aes_cbc_mac_nopad_alloc_ctx(struct crypto_mac_ctx ** ctx)2205da36a24SJens Wiklander TEE_Result crypto_aes_cbc_mac_nopad_alloc_ctx(struct crypto_mac_ctx **ctx)
2215da36a24SJens Wiklander {
2225da36a24SJens Wiklander return crypto_cbc_mac_alloc_ctx(ctx, TEE_ALG_AES_CBC_NOPAD, false);
2235da36a24SJens Wiklander }
2245da36a24SJens Wiklander
crypto_aes_cbc_mac_pkcs5_alloc_ctx(struct crypto_mac_ctx ** ctx)2255da36a24SJens Wiklander TEE_Result crypto_aes_cbc_mac_pkcs5_alloc_ctx(struct crypto_mac_ctx **ctx)
2265da36a24SJens Wiklander {
2275da36a24SJens Wiklander return crypto_cbc_mac_alloc_ctx(ctx, TEE_ALG_AES_CBC_NOPAD, true);
2285da36a24SJens Wiklander }
2295da36a24SJens Wiklander
crypto_des_cbc_mac_nopad_alloc_ctx(struct crypto_mac_ctx ** ctx)2305da36a24SJens Wiklander TEE_Result crypto_des_cbc_mac_nopad_alloc_ctx(struct crypto_mac_ctx **ctx)
2315da36a24SJens Wiklander {
2325da36a24SJens Wiklander return crypto_cbc_mac_alloc_ctx(ctx, TEE_ALG_DES_CBC_NOPAD, false);
2335da36a24SJens Wiklander }
2345da36a24SJens Wiklander
crypto_des_cbc_mac_pkcs5_alloc_ctx(struct crypto_mac_ctx ** ctx)2355da36a24SJens Wiklander TEE_Result crypto_des_cbc_mac_pkcs5_alloc_ctx(struct crypto_mac_ctx **ctx)
2365da36a24SJens Wiklander {
2375da36a24SJens Wiklander return crypto_cbc_mac_alloc_ctx(ctx, TEE_ALG_DES_CBC_NOPAD, true);
2385da36a24SJens Wiklander }
2395da36a24SJens Wiklander
crypto_des3_cbc_mac_nopad_alloc_ctx(struct crypto_mac_ctx ** ctx)2405da36a24SJens Wiklander TEE_Result crypto_des3_cbc_mac_nopad_alloc_ctx(struct crypto_mac_ctx **ctx)
2415da36a24SJens Wiklander {
2425da36a24SJens Wiklander return crypto_cbc_mac_alloc_ctx(ctx, TEE_ALG_DES3_CBC_NOPAD, false);
2435da36a24SJens Wiklander }
2445da36a24SJens Wiklander
crypto_des3_cbc_mac_pkcs5_alloc_ctx(struct crypto_mac_ctx ** ctx)2455da36a24SJens Wiklander TEE_Result crypto_des3_cbc_mac_pkcs5_alloc_ctx(struct crypto_mac_ctx **ctx)
2465da36a24SJens Wiklander {
2475da36a24SJens Wiklander return crypto_cbc_mac_alloc_ctx(ctx, TEE_ALG_DES3_CBC_NOPAD, true);
2485da36a24SJens Wiklander }
249