xref: /optee_os/core/crypto/cbc-mac.c (revision cbda709118504f8b9b6812419d14f8360c40ad27)
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 
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 
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 */
53*cbda7091SJens Wiklander 	return crypto_cipher_init(mc->cbc_ctx, TEE_MODE_ENCRYPT, key, len,
54*cbda7091SJens Wiklander 				  NULL, 0, mc->block, mc->block_len);
555da36a24SJens Wiklander }
565da36a24SJens Wiklander 
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 {
605da36a24SJens Wiklander 	TEE_Result res = TEE_SUCCESS;
615da36a24SJens Wiklander 	struct crypto_cbc_mac_ctx *mc = to_cbc_mac_ctx(ctx);
625da36a24SJens Wiklander 
635da36a24SJens Wiklander 	if ((mc->current_block_len > 0) &&
645da36a24SJens Wiklander 	    (len + mc->current_block_len >= mc->block_len)) {
655da36a24SJens Wiklander 		size_t pad_len = mc->block_len - mc->current_block_len;
665da36a24SJens Wiklander 
675da36a24SJens Wiklander 		memcpy(mc->block + mc->current_block_len, data, pad_len);
685da36a24SJens Wiklander 		data += pad_len;
695da36a24SJens Wiklander 		len -= pad_len;
70*cbda7091SJens Wiklander 		res = crypto_cipher_update(mc->cbc_ctx, TEE_MODE_ENCRYPT,
71*cbda7091SJens Wiklander 					   false, mc->block, mc->block_len,
72*cbda7091SJens Wiklander 					   mc->digest);
735da36a24SJens Wiklander 		if (res)
745da36a24SJens Wiklander 			return res;
755da36a24SJens Wiklander 		mc->is_computed = 1;
765da36a24SJens Wiklander 		mc->current_block_len = 0;
775da36a24SJens Wiklander 	}
785da36a24SJens Wiklander 
795da36a24SJens Wiklander 	while (len >= mc->block_len) {
80*cbda7091SJens Wiklander 		res = crypto_cipher_update(mc->cbc_ctx, TEE_MODE_ENCRYPT,
81*cbda7091SJens Wiklander 					   false, data, mc->block_len,
82*cbda7091SJens Wiklander 					   mc->digest);
835da36a24SJens Wiklander 		if (res)
845da36a24SJens Wiklander 			return res;
855da36a24SJens Wiklander 		mc->is_computed = 1;
865da36a24SJens Wiklander 		data += mc->block_len;
875da36a24SJens Wiklander 		len -= mc->block_len;
885da36a24SJens Wiklander 	}
895da36a24SJens Wiklander 
905da36a24SJens Wiklander 	if (len > 0) {
915da36a24SJens Wiklander 		assert(mc->current_block_len + len < mc->block_len);
925da36a24SJens Wiklander 		memcpy(mc->block + mc->current_block_len, data, len);
935da36a24SJens Wiklander 		mc->current_block_len += len;
945da36a24SJens Wiklander 	}
955da36a24SJens Wiklander 
965da36a24SJens Wiklander 	return TEE_SUCCESS;
975da36a24SJens Wiklander }
985da36a24SJens Wiklander 
995da36a24SJens Wiklander static TEE_Result crypto_cbc_mac_final(struct crypto_mac_ctx *ctx,
1005da36a24SJens Wiklander 				       uint8_t *digest, size_t digest_len)
1015da36a24SJens Wiklander {
1025da36a24SJens Wiklander 	struct crypto_cbc_mac_ctx *mc = to_cbc_mac_ctx(ctx);
1035da36a24SJens Wiklander 
1045da36a24SJens Wiklander 	if (mc->pkcs5_pad) {
1055da36a24SJens Wiklander 		/*
1065da36a24SJens Wiklander 		 * Padding is in whole bytes. The value of each added
1075da36a24SJens Wiklander 		 * byte is the number of bytes that are added, i.e. N
1085da36a24SJens Wiklander 		 * bytes, each of value N are added
1095da36a24SJens Wiklander 		 */
1105da36a24SJens Wiklander 		size_t pad_len = mc->block_len - mc->current_block_len;
1115da36a24SJens Wiklander 
1125da36a24SJens Wiklander 		memset(mc->block + mc->current_block_len, pad_len, pad_len);
1135da36a24SJens Wiklander 		mc->current_block_len = 0;
1145da36a24SJens Wiklander 		if (crypto_cbc_mac_update(ctx, mc->block, mc->block_len))
1155da36a24SJens Wiklander 			return TEE_ERROR_BAD_STATE;
1165da36a24SJens Wiklander 	}
1175da36a24SJens Wiklander 
1185da36a24SJens Wiklander 	if (!mc->is_computed || mc->current_block_len)
1195da36a24SJens Wiklander 		return TEE_ERROR_BAD_STATE;
1205da36a24SJens Wiklander 
1215da36a24SJens Wiklander 	memcpy(digest, mc->digest, MIN(digest_len, mc->block_len));
122*cbda7091SJens Wiklander 	crypto_cipher_final(mc->cbc_ctx);
1235da36a24SJens Wiklander 
1245da36a24SJens Wiklander 	return TEE_SUCCESS;
1255da36a24SJens Wiklander }
1265da36a24SJens Wiklander 
1275da36a24SJens Wiklander static void crypto_cbc_mac_free_ctx(struct crypto_mac_ctx *ctx)
1285da36a24SJens Wiklander {
1295da36a24SJens Wiklander 	struct crypto_cbc_mac_ctx *mc = to_cbc_mac_ctx(ctx);
1305da36a24SJens Wiklander 
131*cbda7091SJens Wiklander 	crypto_cipher_free_ctx(mc->cbc_ctx);
1325da36a24SJens Wiklander 	free(mc);
1335da36a24SJens Wiklander }
1345da36a24SJens Wiklander 
1355da36a24SJens Wiklander static void crypto_cbc_mac_copy_state(struct crypto_mac_ctx *dst_ctx,
1365da36a24SJens Wiklander 				      struct crypto_mac_ctx *src_ctx)
1375da36a24SJens Wiklander {
1385da36a24SJens Wiklander 	struct crypto_cbc_mac_ctx *dst = to_cbc_mac_ctx(dst_ctx);
1395da36a24SJens Wiklander 	struct crypto_cbc_mac_ctx *src = to_cbc_mac_ctx(src_ctx);
1405da36a24SJens Wiklander 
1415da36a24SJens Wiklander 	assert(dst->block_len == src->block_len);
1425da36a24SJens Wiklander 	assert(dst->pkcs5_pad == src->pkcs5_pad);
1435da36a24SJens Wiklander 	assert(dst->cbc_algo == src->cbc_algo);
1445da36a24SJens Wiklander 
145*cbda7091SJens Wiklander 	crypto_cipher_copy_state(dst->cbc_ctx, src->cbc_ctx);
1465da36a24SJens Wiklander 	memcpy(dst->block, src->block, sizeof(dst->block));
1475da36a24SJens Wiklander 	memcpy(dst->digest, src->digest, sizeof(dst->digest));
1485da36a24SJens Wiklander 	dst->current_block_len = src->current_block_len;
1495da36a24SJens Wiklander 	dst->is_computed = src->is_computed;
1505da36a24SJens Wiklander }
1515da36a24SJens Wiklander 
1525da36a24SJens Wiklander static const struct crypto_mac_ops crypto_cbc_mac_ops = {
1535da36a24SJens Wiklander 	.init = crypto_cbc_mac_init,
1545da36a24SJens Wiklander 	.update = crypto_cbc_mac_update,
1555da36a24SJens Wiklander 	.final = crypto_cbc_mac_final,
1565da36a24SJens Wiklander 	.free_ctx = crypto_cbc_mac_free_ctx,
1575da36a24SJens Wiklander 	.copy_state = crypto_cbc_mac_copy_state,
1585da36a24SJens Wiklander };
1595da36a24SJens Wiklander 
1605da36a24SJens Wiklander static TEE_Result crypto_cbc_mac_alloc_ctx(struct crypto_mac_ctx **ctx_ret,
1615da36a24SJens Wiklander 					   uint32_t cbc_algo, bool pkcs5_pad)
1625da36a24SJens Wiklander {
1635da36a24SJens Wiklander 	TEE_Result res;
1645da36a24SJens Wiklander 	void *cbc_ctx = NULL;
1655da36a24SJens Wiklander 	struct crypto_cbc_mac_ctx *ctx = NULL;
1665da36a24SJens Wiklander 	size_t block_size = 0;
1675da36a24SJens Wiklander 
1685da36a24SJens Wiklander 	res = crypto_cipher_get_block_size(cbc_algo, &block_size);
1695da36a24SJens Wiklander 	if (res)
1705da36a24SJens Wiklander 		return res;
1715da36a24SJens Wiklander 
1725da36a24SJens Wiklander 	res = crypto_cipher_alloc_ctx(&cbc_ctx, cbc_algo);
1735da36a24SJens Wiklander 	if (res)
1745da36a24SJens Wiklander 		return res;
1755da36a24SJens Wiklander 
1765da36a24SJens Wiklander 	ctx = calloc(1, sizeof(*ctx));
1775da36a24SJens Wiklander 	if (!ctx) {
178*cbda7091SJens Wiklander 		crypto_cipher_free_ctx(cbc_ctx);
1795da36a24SJens Wiklander 		return TEE_ERROR_OUT_OF_MEMORY;
1805da36a24SJens Wiklander 	}
1815da36a24SJens Wiklander 
1825da36a24SJens Wiklander 	ctx->cbc_ctx = cbc_ctx;
1835da36a24SJens Wiklander 	ctx->cbc_algo = cbc_algo;
1845da36a24SJens Wiklander 	ctx->pkcs5_pad = pkcs5_pad;
1855da36a24SJens Wiklander 	ctx->block_len = block_size;
1865da36a24SJens Wiklander 	ctx->ctx.ops = &crypto_cbc_mac_ops;
1875da36a24SJens Wiklander 	*ctx_ret = &ctx->ctx;
1885da36a24SJens Wiklander 
1895da36a24SJens Wiklander 	return TEE_SUCCESS;
1905da36a24SJens Wiklander }
1915da36a24SJens Wiklander 
1925da36a24SJens Wiklander TEE_Result crypto_aes_cbc_mac_nopad_alloc_ctx(struct crypto_mac_ctx **ctx)
1935da36a24SJens Wiklander {
1945da36a24SJens Wiklander 	return crypto_cbc_mac_alloc_ctx(ctx, TEE_ALG_AES_CBC_NOPAD, false);
1955da36a24SJens Wiklander }
1965da36a24SJens Wiklander 
1975da36a24SJens Wiklander TEE_Result crypto_aes_cbc_mac_pkcs5_alloc_ctx(struct crypto_mac_ctx **ctx)
1985da36a24SJens Wiklander {
1995da36a24SJens Wiklander 	return crypto_cbc_mac_alloc_ctx(ctx, TEE_ALG_AES_CBC_NOPAD, true);
2005da36a24SJens Wiklander }
2015da36a24SJens Wiklander 
2025da36a24SJens Wiklander TEE_Result crypto_des_cbc_mac_nopad_alloc_ctx(struct crypto_mac_ctx **ctx)
2035da36a24SJens Wiklander {
2045da36a24SJens Wiklander 	return crypto_cbc_mac_alloc_ctx(ctx, TEE_ALG_DES_CBC_NOPAD, false);
2055da36a24SJens Wiklander }
2065da36a24SJens Wiklander 
2075da36a24SJens Wiklander TEE_Result crypto_des_cbc_mac_pkcs5_alloc_ctx(struct crypto_mac_ctx **ctx)
2085da36a24SJens Wiklander {
2095da36a24SJens Wiklander 	return crypto_cbc_mac_alloc_ctx(ctx, TEE_ALG_DES_CBC_NOPAD, true);
2105da36a24SJens Wiklander }
2115da36a24SJens Wiklander 
2125da36a24SJens Wiklander TEE_Result crypto_des3_cbc_mac_nopad_alloc_ctx(struct crypto_mac_ctx **ctx)
2135da36a24SJens Wiklander {
2145da36a24SJens Wiklander 	return crypto_cbc_mac_alloc_ctx(ctx, TEE_ALG_DES3_CBC_NOPAD, false);
2155da36a24SJens Wiklander }
2165da36a24SJens Wiklander 
2175da36a24SJens Wiklander TEE_Result crypto_des3_cbc_mac_pkcs5_alloc_ctx(struct crypto_mac_ctx **ctx)
2185da36a24SJens Wiklander {
2195da36a24SJens Wiklander 	return crypto_cbc_mac_alloc_ctx(ctx, TEE_ALG_DES3_CBC_NOPAD, true);
2205da36a24SJens Wiklander }
221