xref: /optee_os/core/crypto/cbc-mac.c (revision 5b25c76ac40f830867e3d60800120ffd7874e8dc)
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, TEE_MODE_ENCRYPT, key, len,
54 				  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, TEE_MODE_ENCRYPT,
71 					   false, mc->block, mc->block_len,
72 					   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, TEE_MODE_ENCRYPT,
81 					   false, data, mc->block_len,
82 					   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);
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);
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);
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);
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