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 */ 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 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 { 60*16a1c178SJerome Forissier size_t nblocks = 0; 61*16a1c178SJerome Forissier size_t out_len = 0; 62*16a1c178SJerome Forissier uint8_t *out_tmp = NULL; 63*16a1c178SJerome 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 83*16a1c178SJerome Forissier nblocks = MIN(len / mc->block_len, 84*16a1c178SJerome Forissier (size_t)CFG_CRYPTO_CBC_MAC_BUNDLE_BLOCKS); 85*16a1c178SJerome Forissier if (nblocks > 1) 86*16a1c178SJerome Forissier out_tmp = malloc(nblocks * mc->block_len); 87*16a1c178SJerome Forissier 885da36a24SJens Wiklander while (len >= mc->block_len) { 89*16a1c178SJerome Forissier nblocks = MIN(len / mc->block_len, 90*16a1c178SJerome Forissier (size_t)CFG_CRYPTO_CBC_MAC_BUNDLE_BLOCKS); 91*16a1c178SJerome Forissier 92*16a1c178SJerome Forissier if (nblocks > 1 && out_tmp) { 93*16a1c178SJerome Forissier out_len = nblocks * mc->block_len; 94*16a1c178SJerome Forissier out = out_tmp; 95*16a1c178SJerome Forissier } else { 96*16a1c178SJerome Forissier out_len = mc->block_len; 97*16a1c178SJerome Forissier out = mc->digest; 98*16a1c178SJerome Forissier nblocks = 1; 99*16a1c178SJerome Forissier } 100*16a1c178SJerome Forissier 101cbda7091SJens Wiklander res = crypto_cipher_update(mc->cbc_ctx, TEE_MODE_ENCRYPT, 102*16a1c178SJerome Forissier false, data, out_len, out); 1035da36a24SJens Wiklander if (res) 104*16a1c178SJerome Forissier goto out; 1055da36a24SJens Wiklander mc->is_computed = 1; 106*16a1c178SJerome Forissier data += out_len; 107*16a1c178SJerome Forissier len -= out_len; 108*16a1c178SJerome Forissier if (nblocks > 1 && len < mc->block_len) { 109*16a1c178SJerome Forissier assert(out_tmp); 110*16a1c178SJerome Forissier /* Copy last block of output */ 111*16a1c178SJerome Forissier memcpy(mc->digest, out_tmp + out_len - mc->block_len, 112*16a1c178SJerome Forissier mc->block_len); 113*16a1c178SJerome 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 122*16a1c178SJerome Forissier out: 123*16a1c178SJerome Forissier free(out_tmp); 124*16a1c178SJerome Forissier return res; 1255da36a24SJens Wiklander } 1265da36a24SJens Wiklander 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 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 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 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 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 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 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 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 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 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