1 // SPDX-License-Identifier: BSD-2-Clause 2 /* 3 * Copyright (c) 2014-2019, Linaro Limited 4 */ 5 6 /* 7 * This is implemented here as being the plain text which is encoded with IV=0. 8 * Result of the CBC-MAC is the last 16-bytes cipher. 9 */ 10 11 #include <assert.h> 12 #include <crypto/crypto.h> 13 #include <crypto/crypto_impl.h> 14 #include <stdlib.h> 15 #include <string.h> 16 #include <types_ext.h> 17 #include <util.h> 18 19 #define CBCMAC_MAX_BLOCK_LEN 16 20 21 struct crypto_cbc_mac_ctx { 22 struct crypto_mac_ctx ctx; 23 void *cbc_ctx; 24 uint32_t cbc_algo; 25 uint8_t block[CBCMAC_MAX_BLOCK_LEN]; 26 uint8_t digest[CBCMAC_MAX_BLOCK_LEN]; 27 unsigned char current_block_len; 28 unsigned char block_len; 29 bool is_computed; 30 bool pkcs5_pad; 31 }; 32 33 static const struct crypto_mac_ops crypto_cbc_mac_ops; 34 35 static struct crypto_cbc_mac_ctx *to_cbc_mac_ctx(struct crypto_mac_ctx *ctx) 36 { 37 assert(ctx && ctx->ops == &crypto_cbc_mac_ops); 38 39 return container_of(ctx, struct crypto_cbc_mac_ctx, ctx); 40 } 41 42 static TEE_Result crypto_cbc_mac_init(struct crypto_mac_ctx *ctx, 43 const uint8_t *key, size_t len) 44 { 45 struct crypto_cbc_mac_ctx *mc = to_cbc_mac_ctx(ctx); 46 47 memset(mc->block, 0, sizeof(mc->block)); 48 memset(mc->digest, 0, sizeof(mc->digest)); 49 mc->current_block_len = 0; 50 mc->is_computed = false; 51 52 /* IV should be zero and mc->block happens to be zero at this stage */ 53 return crypto_cipher_init(mc->cbc_ctx, mc->cbc_algo, TEE_MODE_ENCRYPT, 54 key, len, NULL, 0, mc->block, mc->block_len); 55 } 56 57 static TEE_Result crypto_cbc_mac_update(struct crypto_mac_ctx *ctx, 58 const uint8_t *data, size_t len) 59 { 60 TEE_Result res = TEE_SUCCESS; 61 struct crypto_cbc_mac_ctx *mc = to_cbc_mac_ctx(ctx); 62 63 if ((mc->current_block_len > 0) && 64 (len + mc->current_block_len >= mc->block_len)) { 65 size_t pad_len = mc->block_len - mc->current_block_len; 66 67 memcpy(mc->block + mc->current_block_len, data, pad_len); 68 data += pad_len; 69 len -= pad_len; 70 res = crypto_cipher_update(mc->cbc_ctx, mc->cbc_algo, 71 TEE_MODE_ENCRYPT, false, mc->block, 72 mc->block_len, mc->digest); 73 if (res) 74 return res; 75 mc->is_computed = 1; 76 mc->current_block_len = 0; 77 } 78 79 while (len >= mc->block_len) { 80 res = crypto_cipher_update(mc->cbc_ctx, mc->cbc_algo, 81 TEE_MODE_ENCRYPT, false, data, 82 mc->block_len, mc->digest); 83 if (res) 84 return res; 85 mc->is_computed = 1; 86 data += mc->block_len; 87 len -= mc->block_len; 88 } 89 90 if (len > 0) { 91 assert(mc->current_block_len + len < mc->block_len); 92 memcpy(mc->block + mc->current_block_len, data, len); 93 mc->current_block_len += len; 94 } 95 96 return TEE_SUCCESS; 97 } 98 99 static TEE_Result crypto_cbc_mac_final(struct crypto_mac_ctx *ctx, 100 uint8_t *digest, size_t digest_len) 101 { 102 struct crypto_cbc_mac_ctx *mc = to_cbc_mac_ctx(ctx); 103 104 if (mc->pkcs5_pad) { 105 /* 106 * Padding is in whole bytes. The value of each added 107 * byte is the number of bytes that are added, i.e. N 108 * bytes, each of value N are added 109 */ 110 size_t pad_len = mc->block_len - mc->current_block_len; 111 112 memset(mc->block + mc->current_block_len, pad_len, pad_len); 113 mc->current_block_len = 0; 114 if (crypto_cbc_mac_update(ctx, mc->block, mc->block_len)) 115 return TEE_ERROR_BAD_STATE; 116 } 117 118 if (!mc->is_computed || mc->current_block_len) 119 return TEE_ERROR_BAD_STATE; 120 121 memcpy(digest, mc->digest, MIN(digest_len, mc->block_len)); 122 crypto_cipher_final(mc->cbc_ctx, mc->cbc_algo); 123 124 return TEE_SUCCESS; 125 } 126 127 static void crypto_cbc_mac_free_ctx(struct crypto_mac_ctx *ctx) 128 { 129 struct crypto_cbc_mac_ctx *mc = to_cbc_mac_ctx(ctx); 130 131 crypto_cipher_free_ctx(mc->cbc_ctx, mc->cbc_algo); 132 free(mc); 133 } 134 135 static void crypto_cbc_mac_copy_state(struct crypto_mac_ctx *dst_ctx, 136 struct crypto_mac_ctx *src_ctx) 137 { 138 struct crypto_cbc_mac_ctx *dst = to_cbc_mac_ctx(dst_ctx); 139 struct crypto_cbc_mac_ctx *src = to_cbc_mac_ctx(src_ctx); 140 141 assert(dst->block_len == src->block_len); 142 assert(dst->pkcs5_pad == src->pkcs5_pad); 143 assert(dst->cbc_algo == src->cbc_algo); 144 145 crypto_cipher_copy_state(dst->cbc_ctx, src->cbc_ctx, src->cbc_algo); 146 memcpy(dst->block, src->block, sizeof(dst->block)); 147 memcpy(dst->digest, src->digest, sizeof(dst->digest)); 148 dst->current_block_len = src->current_block_len; 149 dst->is_computed = src->is_computed; 150 } 151 152 static const struct crypto_mac_ops crypto_cbc_mac_ops = { 153 .init = crypto_cbc_mac_init, 154 .update = crypto_cbc_mac_update, 155 .final = crypto_cbc_mac_final, 156 .free_ctx = crypto_cbc_mac_free_ctx, 157 .copy_state = crypto_cbc_mac_copy_state, 158 }; 159 160 static TEE_Result crypto_cbc_mac_alloc_ctx(struct crypto_mac_ctx **ctx_ret, 161 uint32_t cbc_algo, bool pkcs5_pad) 162 { 163 TEE_Result res; 164 void *cbc_ctx = NULL; 165 struct crypto_cbc_mac_ctx *ctx = NULL; 166 size_t block_size = 0; 167 168 res = crypto_cipher_get_block_size(cbc_algo, &block_size); 169 if (res) 170 return res; 171 172 res = crypto_cipher_alloc_ctx(&cbc_ctx, cbc_algo); 173 if (res) 174 return res; 175 176 ctx = calloc(1, sizeof(*ctx)); 177 if (!ctx) { 178 crypto_cipher_free_ctx(cbc_ctx, cbc_algo); 179 return TEE_ERROR_OUT_OF_MEMORY; 180 } 181 182 ctx->cbc_ctx = cbc_ctx; 183 ctx->cbc_algo = cbc_algo; 184 ctx->pkcs5_pad = pkcs5_pad; 185 ctx->block_len = block_size; 186 ctx->ctx.ops = &crypto_cbc_mac_ops; 187 *ctx_ret = &ctx->ctx; 188 189 return TEE_SUCCESS; 190 } 191 192 TEE_Result crypto_aes_cbc_mac_nopad_alloc_ctx(struct crypto_mac_ctx **ctx) 193 { 194 return crypto_cbc_mac_alloc_ctx(ctx, TEE_ALG_AES_CBC_NOPAD, false); 195 } 196 197 TEE_Result crypto_aes_cbc_mac_pkcs5_alloc_ctx(struct crypto_mac_ctx **ctx) 198 { 199 return crypto_cbc_mac_alloc_ctx(ctx, TEE_ALG_AES_CBC_NOPAD, true); 200 } 201 202 TEE_Result crypto_des_cbc_mac_nopad_alloc_ctx(struct crypto_mac_ctx **ctx) 203 { 204 return crypto_cbc_mac_alloc_ctx(ctx, TEE_ALG_DES_CBC_NOPAD, false); 205 } 206 207 TEE_Result crypto_des_cbc_mac_pkcs5_alloc_ctx(struct crypto_mac_ctx **ctx) 208 { 209 return crypto_cbc_mac_alloc_ctx(ctx, TEE_ALG_DES_CBC_NOPAD, true); 210 } 211 212 TEE_Result crypto_des3_cbc_mac_nopad_alloc_ctx(struct crypto_mac_ctx **ctx) 213 { 214 return crypto_cbc_mac_alloc_ctx(ctx, TEE_ALG_DES3_CBC_NOPAD, false); 215 } 216 217 TEE_Result crypto_des3_cbc_mac_pkcs5_alloc_ctx(struct crypto_mac_ctx **ctx) 218 { 219 return crypto_cbc_mac_alloc_ctx(ctx, TEE_ALG_DES3_CBC_NOPAD, true); 220 } 221