xref: /optee_os/core/crypto/aes-gcm.c (revision f1e9b21b29bdc21a51c6c1a4b8df7eb5e2bd5189)
1fb7ef469SJerome Forissier // SPDX-License-Identifier: BSD-2-Clause
21fca7e26SJens Wiklander /*
31fca7e26SJens Wiklander  * Copyright (c) 2017, Linaro Limited
41fca7e26SJens Wiklander  */
51fca7e26SJens Wiklander 
661b4cd9cSJens Wiklander #include <assert.h>
71fca7e26SJens Wiklander #include <crypto/internal_aes-gcm.h>
8*f1e9b21bSJens Wiklander #include <crypto/crypto_impl.h>
91fca7e26SJens Wiklander #include <io.h>
101fca7e26SJens Wiklander #include <string_ext.h>
111fca7e26SJens Wiklander #include <string.h>
121fca7e26SJens Wiklander #include <tee_api_types.h>
131fca7e26SJens Wiklander #include <types_ext.h>
141fca7e26SJens Wiklander #include <utee_defines.h>
151fca7e26SJens Wiklander #include <util.h>
161fca7e26SJens Wiklander 
17b8c186b5SJens Wiklander #include "aes-gcm-private.h"
18b8c186b5SJens Wiklander 
191fca7e26SJens Wiklander static void xor_buf(uint8_t *dst, const uint8_t *src, size_t len)
201fca7e26SJens Wiklander {
211fca7e26SJens Wiklander 	size_t n;
221fca7e26SJens Wiklander 
231fca7e26SJens Wiklander 	for (n = 0; n < len; n++)
241fca7e26SJens Wiklander 		dst[n] ^= src[n];
251fca7e26SJens Wiklander }
261fca7e26SJens Wiklander 
271fca7e26SJens Wiklander 
2854af8d67SJens Wiklander static void ghash_update_pad_zero(struct internal_aes_gcm_state *state,
291fca7e26SJens Wiklander 				  const uint8_t *data, size_t len)
301fca7e26SJens Wiklander {
311fca7e26SJens Wiklander 	size_t n = len / TEE_AES_BLOCK_SIZE;
321fca7e26SJens Wiklander 	uint64_t block[2];
331fca7e26SJens Wiklander 
341fca7e26SJens Wiklander 	if (n) {
35b8c186b5SJens Wiklander 		if (internal_aes_gcm_ptr_is_block_aligned(data)) {
3654af8d67SJens Wiklander 			internal_aes_gcm_ghash_update(state, NULL, data, n);
371fca7e26SJens Wiklander 		} else {
381fca7e26SJens Wiklander 			size_t m;
391fca7e26SJens Wiklander 
401fca7e26SJens Wiklander 			for (m = 0; m < n; m++) {
411fca7e26SJens Wiklander 
421fca7e26SJens Wiklander 				memcpy(block, data + m * sizeof(block),
431fca7e26SJens Wiklander 				       sizeof(block));
4454af8d67SJens Wiklander 				internal_aes_gcm_ghash_update(state, NULL,
451fca7e26SJens Wiklander 							      (void *)block, 1);
461fca7e26SJens Wiklander 			}
471fca7e26SJens Wiklander 		}
481fca7e26SJens Wiklander 	}
491fca7e26SJens Wiklander 
501fca7e26SJens Wiklander 	if (len - n * TEE_AES_BLOCK_SIZE) {
511fca7e26SJens Wiklander 		memset(block, 0, sizeof(block));
521fca7e26SJens Wiklander 		memcpy(block, data + n * TEE_AES_BLOCK_SIZE,
531fca7e26SJens Wiklander 		       len - n * TEE_AES_BLOCK_SIZE);
5454af8d67SJens Wiklander 		internal_aes_gcm_ghash_update(state, block, NULL, 0);
551fca7e26SJens Wiklander 	}
561fca7e26SJens Wiklander }
571fca7e26SJens Wiklander 
5854af8d67SJens Wiklander static void ghash_update_lengths(struct internal_aes_gcm_state *state,
5954af8d67SJens Wiklander 				 uint32_t l1, uint32_t l2)
601fca7e26SJens Wiklander {
611fca7e26SJens Wiklander 	uint64_t len_fields[2] = {
621fca7e26SJens Wiklander 		TEE_U64_TO_BIG_ENDIAN(l1 * 8),
631fca7e26SJens Wiklander 		TEE_U64_TO_BIG_ENDIAN(l2 * 8)
641fca7e26SJens Wiklander 	};
651fca7e26SJens Wiklander 
661fca7e26SJens Wiklander 	COMPILE_TIME_ASSERT(sizeof(len_fields) == TEE_AES_BLOCK_SIZE);
6754af8d67SJens Wiklander 	internal_aes_gcm_ghash_update(state, (uint8_t *)len_fields, NULL, 0);
681fca7e26SJens Wiklander }
691fca7e26SJens Wiklander 
7054af8d67SJens Wiklander static TEE_Result __gcm_init(struct internal_aes_gcm_state *state,
7154af8d67SJens Wiklander 			     const struct internal_aes_gcm_key *ek,
7254af8d67SJens Wiklander 			     TEE_OperationMode mode, const void *nonce,
731fca7e26SJens Wiklander 			     size_t nonce_len, size_t tag_len)
741fca7e26SJens Wiklander {
7554af8d67SJens Wiklander 	COMPILE_TIME_ASSERT(sizeof(state->ctr) == TEE_AES_BLOCK_SIZE);
761fca7e26SJens Wiklander 
7754af8d67SJens Wiklander 	if (tag_len > sizeof(state->buf_tag))
781fca7e26SJens Wiklander 		return TEE_ERROR_BAD_PARAMETERS;
791fca7e26SJens Wiklander 
8054af8d67SJens Wiklander 	memset(state, 0, sizeof(*state));
811fca7e26SJens Wiklander 
8254af8d67SJens Wiklander 	state->tag_len = tag_len;
8354af8d67SJens Wiklander 	internal_aes_gcm_set_key(state, ek);
841fca7e26SJens Wiklander 
851fca7e26SJens Wiklander 	if (nonce_len == (96 / 8)) {
8654af8d67SJens Wiklander 		memcpy(state->ctr, nonce, nonce_len);
8754af8d67SJens Wiklander 		internal_aes_gcm_inc_ctr(state);
881fca7e26SJens Wiklander 	} else {
8954af8d67SJens Wiklander 		ghash_update_pad_zero(state, nonce, nonce_len);
9054af8d67SJens Wiklander 		ghash_update_lengths(state, 0, nonce_len);
911fca7e26SJens Wiklander 
9254af8d67SJens Wiklander 		memcpy(state->ctr, state->hash_state, sizeof(state->ctr));
9354af8d67SJens Wiklander 		memset(state->hash_state, 0, sizeof(state->hash_state));
941fca7e26SJens Wiklander 	}
951fca7e26SJens Wiklander 
9654af8d67SJens Wiklander 	internal_aes_gcm_encrypt_block(ek, state->ctr, state->buf_tag);
9754af8d67SJens Wiklander 	internal_aes_gcm_inc_ctr(state);
981fca7e26SJens Wiklander 	if (mode == TEE_MODE_ENCRYPT) {
991fca7e26SJens Wiklander 		/*
1001fca7e26SJens Wiklander 		 * Encryption uses the pre-encrypted xor-buffer to encrypt
1011fca7e26SJens Wiklander 		 * while decryption encrypts the xor-buffer when needed
1021fca7e26SJens Wiklander 		 * instead.
1031fca7e26SJens Wiklander 		 *
1041fca7e26SJens Wiklander 		 * The reason for this is that the combined encryption and
1051fca7e26SJens Wiklander 		 * ghash implementation does both operations intertwined.
1061fca7e26SJens Wiklander 		 * In the decrypt case the xor-buffer is needed at the end
1071fca7e26SJens Wiklander 		 * of processing each block, while the encryption case
1081fca7e26SJens Wiklander 		 * needs xor-buffer before processing each block.
1091fca7e26SJens Wiklander 		 *
1101fca7e26SJens Wiklander 		 * In a pure software implementation we wouldn't have any
1111fca7e26SJens Wiklander 		 * use for this kind of optimization, but since this
1121fca7e26SJens Wiklander 		 * AES-GCM implementation is aimed at being combined with
1131fca7e26SJens Wiklander 		 * accelerated routines it's more convenient to always have
1141fca7e26SJens Wiklander 		 * this optimization activated.
1151fca7e26SJens Wiklander 		 */
11654af8d67SJens Wiklander 		internal_aes_gcm_encrypt_block(ek, state->ctr, state->buf_cryp);
11754af8d67SJens Wiklander 		internal_aes_gcm_inc_ctr(state);
1181fca7e26SJens Wiklander 	}
1191fca7e26SJens Wiklander 
1201fca7e26SJens Wiklander 	return TEE_SUCCESS;
1211fca7e26SJens Wiklander }
1221fca7e26SJens Wiklander 
12354af8d67SJens Wiklander TEE_Result internal_aes_gcm_init(struct internal_aes_gcm_ctx *ctx,
12454af8d67SJens Wiklander 				 TEE_OperationMode mode, const void *key,
12554af8d67SJens Wiklander 				 size_t key_len, const void *nonce,
12654af8d67SJens Wiklander 				 size_t nonce_len, size_t tag_len)
12754af8d67SJens Wiklander {
12854af8d67SJens Wiklander 	TEE_Result res = internal_aes_gcm_expand_enc_key(key, key_len,
12954af8d67SJens Wiklander 							 &ctx->key);
13054af8d67SJens Wiklander 	if (res)
13154af8d67SJens Wiklander 		return res;
13254af8d67SJens Wiklander 
13354af8d67SJens Wiklander 	return __gcm_init(&ctx->state, &ctx->key, mode, nonce, nonce_len,
13454af8d67SJens Wiklander 			  tag_len);
13554af8d67SJens Wiklander }
13654af8d67SJens Wiklander 
137043411e5SJens Wiklander static TEE_Result __gcm_update_aad(struct internal_aes_gcm_state *state,
1381fca7e26SJens Wiklander 				   const void *data, size_t len)
1391fca7e26SJens Wiklander {
1401fca7e26SJens Wiklander 	const uint8_t *d = data;
1411fca7e26SJens Wiklander 	size_t l = len;
1421fca7e26SJens Wiklander 	const uint8_t *head = NULL;
1431fca7e26SJens Wiklander 	size_t n;
1441fca7e26SJens Wiklander 
14554af8d67SJens Wiklander 	if (state->payload_bytes)
1461fca7e26SJens Wiklander 		return TEE_ERROR_BAD_PARAMETERS;
1471fca7e26SJens Wiklander 
14854af8d67SJens Wiklander 	state->aad_bytes += len;
1491fca7e26SJens Wiklander 
1501fca7e26SJens Wiklander 	while (l) {
15154af8d67SJens Wiklander 		if (state->buf_pos ||
15254af8d67SJens Wiklander 		    !internal_aes_gcm_ptr_is_block_aligned(d) ||
1531fca7e26SJens Wiklander 		    l < TEE_AES_BLOCK_SIZE) {
15454af8d67SJens Wiklander 			n = MIN(TEE_AES_BLOCK_SIZE - state->buf_pos, l);
15554af8d67SJens Wiklander 			memcpy(state->buf_hash + state->buf_pos, d, n);
15654af8d67SJens Wiklander 			state->buf_pos += n;
1571fca7e26SJens Wiklander 
15854af8d67SJens Wiklander 			if (state->buf_pos != TEE_AES_BLOCK_SIZE)
1591fca7e26SJens Wiklander 				return TEE_SUCCESS;
1601fca7e26SJens Wiklander 
16154af8d67SJens Wiklander 			state->buf_pos = 0;
16254af8d67SJens Wiklander 			head = state->buf_hash;
1631fca7e26SJens Wiklander 			d += n;
1641fca7e26SJens Wiklander 			l -= n;
1651fca7e26SJens Wiklander 		}
1661fca7e26SJens Wiklander 
167b8c186b5SJens Wiklander 		if (internal_aes_gcm_ptr_is_block_aligned(d))
1681fca7e26SJens Wiklander 			n = l / TEE_AES_BLOCK_SIZE;
1691fca7e26SJens Wiklander 		else
1701fca7e26SJens Wiklander 			n = 0;
1711fca7e26SJens Wiklander 
17254af8d67SJens Wiklander 		internal_aes_gcm_ghash_update(state, head, d, n);
1731fca7e26SJens Wiklander 		l -= n * TEE_AES_BLOCK_SIZE;
1741fca7e26SJens Wiklander 		d += n * TEE_AES_BLOCK_SIZE;
1751fca7e26SJens Wiklander 	}
1761fca7e26SJens Wiklander 
1771fca7e26SJens Wiklander 	return TEE_SUCCESS;
1781fca7e26SJens Wiklander }
1791fca7e26SJens Wiklander 
180043411e5SJens Wiklander TEE_Result internal_aes_gcm_update_aad(struct internal_aes_gcm_ctx *ctx,
181043411e5SJens Wiklander 				       const void *data, size_t len)
1821fca7e26SJens Wiklander {
183043411e5SJens Wiklander 	return __gcm_update_aad(&ctx->state, data, len);
184043411e5SJens Wiklander }
185043411e5SJens Wiklander 
186043411e5SJens Wiklander static TEE_Result
187043411e5SJens Wiklander __gcm_update_payload(struct internal_aes_gcm_state *state,
188043411e5SJens Wiklander 		     const struct internal_aes_gcm_key *ek,
189043411e5SJens Wiklander 		     TEE_OperationMode mode, const void *src,
190043411e5SJens Wiklander 		     size_t len, void *dst)
191043411e5SJens Wiklander {
1921fca7e26SJens Wiklander 	size_t n;
1931fca7e26SJens Wiklander 	const uint8_t *s = src;
1941fca7e26SJens Wiklander 	uint8_t *d = dst;
1951fca7e26SJens Wiklander 	size_t l = len;
1961fca7e26SJens Wiklander 
19754af8d67SJens Wiklander 	if (!state->payload_bytes && state->buf_pos) {
1981fca7e26SJens Wiklander 		/* AAD part done, finish up the last bits. */
19954af8d67SJens Wiklander 		memset(state->buf_hash + state->buf_pos, 0,
20054af8d67SJens Wiklander 		       TEE_AES_BLOCK_SIZE - state->buf_pos);
20154af8d67SJens Wiklander 		internal_aes_gcm_ghash_update(state, state->buf_hash, NULL, 0);
20254af8d67SJens Wiklander 		state->buf_pos = 0;
2031fca7e26SJens Wiklander 	}
2041fca7e26SJens Wiklander 
20554af8d67SJens Wiklander 	state->payload_bytes += len;
2061fca7e26SJens Wiklander 
2071fca7e26SJens Wiklander 	while (l) {
20854af8d67SJens Wiklander 		if (state->buf_pos ||
20954af8d67SJens Wiklander 		    !internal_aes_gcm_ptr_is_block_aligned(s) ||
210b8c186b5SJens Wiklander 		    !internal_aes_gcm_ptr_is_block_aligned(d) ||
211b8c186b5SJens Wiklander 		    l < TEE_AES_BLOCK_SIZE) {
21254af8d67SJens Wiklander 			n = MIN(TEE_AES_BLOCK_SIZE - state->buf_pos, l);
2131fca7e26SJens Wiklander 
21454af8d67SJens Wiklander 			if (!state->buf_pos && mode == TEE_MODE_DECRYPT) {
21554af8d67SJens Wiklander 				internal_aes_gcm_encrypt_block(ek, state->ctr,
21654af8d67SJens Wiklander 							       state->buf_cryp);
2171fca7e26SJens Wiklander 			}
2181fca7e26SJens Wiklander 
21954af8d67SJens Wiklander 			xor_buf(state->buf_cryp + state->buf_pos, s, n);
22054af8d67SJens Wiklander 			memcpy(d, state->buf_cryp + state->buf_pos, n);
2211fca7e26SJens Wiklander 			if (mode == TEE_MODE_ENCRYPT)
22254af8d67SJens Wiklander 				memcpy(state->buf_hash + state->buf_pos,
22354af8d67SJens Wiklander 				       state->buf_cryp + state->buf_pos, n);
2241fca7e26SJens Wiklander 			else
22554af8d67SJens Wiklander 				memcpy(state->buf_hash + state->buf_pos, s, n);
2261fca7e26SJens Wiklander 
22754af8d67SJens Wiklander 			state->buf_pos += n;
2281fca7e26SJens Wiklander 
22954af8d67SJens Wiklander 			if (state->buf_pos != TEE_AES_BLOCK_SIZE)
2301fca7e26SJens Wiklander 				return TEE_SUCCESS;
2311fca7e26SJens Wiklander 
23254af8d67SJens Wiklander 			internal_aes_gcm_ghash_update(state, state->buf_hash,
2331fca7e26SJens Wiklander 						      NULL, 0);
23454af8d67SJens Wiklander 			state->buf_pos = 0;
2351fca7e26SJens Wiklander 			d += n;
2361fca7e26SJens Wiklander 			s += n;
2371fca7e26SJens Wiklander 			l -= n;
2381fca7e26SJens Wiklander 
2391fca7e26SJens Wiklander 			if (mode == TEE_MODE_ENCRYPT)
24054af8d67SJens Wiklander 				internal_aes_gcm_encrypt_block(ek, state->ctr,
24154af8d67SJens Wiklander 							       state->buf_cryp);
24254af8d67SJens Wiklander 			internal_aes_gcm_inc_ctr(state);
2431fca7e26SJens Wiklander 		} else {
2441fca7e26SJens Wiklander 			n = l / TEE_AES_BLOCK_SIZE;
24554af8d67SJens Wiklander 			internal_aes_gcm_update_payload_block_aligned(state, ek,
24654af8d67SJens Wiklander 								      mode,
2471fca7e26SJens Wiklander 								      s, n, d);
2481fca7e26SJens Wiklander 			s += n * TEE_AES_BLOCK_SIZE;
2491fca7e26SJens Wiklander 			d += n * TEE_AES_BLOCK_SIZE;
2501fca7e26SJens Wiklander 			l -= n * TEE_AES_BLOCK_SIZE;
2511fca7e26SJens Wiklander 		}
2521fca7e26SJens Wiklander 	}
2531fca7e26SJens Wiklander 
2541fca7e26SJens Wiklander 	return TEE_SUCCESS;
2551fca7e26SJens Wiklander }
2561fca7e26SJens Wiklander 
257043411e5SJens Wiklander TEE_Result internal_aes_gcm_update_payload(struct internal_aes_gcm_ctx *ctx,
258043411e5SJens Wiklander 					   TEE_OperationMode mode,
259043411e5SJens Wiklander 					   const void *src, size_t len,
260043411e5SJens Wiklander 					   void *dst)
261043411e5SJens Wiklander {
262043411e5SJens Wiklander 	return __gcm_update_payload(&ctx->state, &ctx->key, mode, src, len,
263043411e5SJens Wiklander 				    dst);
264043411e5SJens Wiklander }
265043411e5SJens Wiklander 
266043411e5SJens Wiklander static TEE_Result operation_final(struct internal_aes_gcm_state *state,
267043411e5SJens Wiklander 				  const struct internal_aes_gcm_key *enc_key,
2681fca7e26SJens Wiklander 				  TEE_OperationMode m, const uint8_t *src,
2691fca7e26SJens Wiklander 				  size_t len, uint8_t *dst)
2701fca7e26SJens Wiklander {
2711fca7e26SJens Wiklander 	TEE_Result res;
2721fca7e26SJens Wiklander 
273043411e5SJens Wiklander 	res = __gcm_update_payload(state, enc_key, m, src, len, dst);
2741fca7e26SJens Wiklander 	if (res)
2751fca7e26SJens Wiklander 		return res;
2761fca7e26SJens Wiklander 
27754af8d67SJens Wiklander 	if (state->buf_pos) {
27854af8d67SJens Wiklander 		memset(state->buf_hash + state->buf_pos, 0,
27954af8d67SJens Wiklander 		       sizeof(state->buf_hash) - state->buf_pos);
28054af8d67SJens Wiklander 		internal_aes_gcm_ghash_update(state, state->buf_hash, NULL, 0);
2811fca7e26SJens Wiklander 	}
2821fca7e26SJens Wiklander 
28354af8d67SJens Wiklander 	ghash_update_lengths(state, state->aad_bytes, state->payload_bytes);
2841fca7e26SJens Wiklander 	/* buf_tag was filled in with the first counter block aes_gcm_init() */
28554af8d67SJens Wiklander 	xor_buf(state->buf_tag, state->hash_state, state->tag_len);
2861fca7e26SJens Wiklander 
2871fca7e26SJens Wiklander 	return TEE_SUCCESS;
2881fca7e26SJens Wiklander }
2891fca7e26SJens Wiklander 
290043411e5SJens Wiklander static TEE_Result __gcm_enc_final(struct internal_aes_gcm_state *state,
291043411e5SJens Wiklander 				  const struct internal_aes_gcm_key *enc_key,
2921fca7e26SJens Wiklander 				  const void *src, size_t len, void *dst,
2931fca7e26SJens Wiklander 				  void *tag, size_t *tag_len)
2941fca7e26SJens Wiklander {
2951fca7e26SJens Wiklander 	TEE_Result res;
2961fca7e26SJens Wiklander 
29754af8d67SJens Wiklander 	if (*tag_len < state->tag_len)
2981fca7e26SJens Wiklander 		return TEE_ERROR_SHORT_BUFFER;
2991fca7e26SJens Wiklander 
300043411e5SJens Wiklander 	res = operation_final(state, enc_key, TEE_MODE_ENCRYPT, src, len, dst);
3011fca7e26SJens Wiklander 	if (res)
3021fca7e26SJens Wiklander 		return res;
3031fca7e26SJens Wiklander 
30454af8d67SJens Wiklander 	memcpy(tag, state->buf_tag, state->tag_len);
30554af8d67SJens Wiklander 	*tag_len = state->tag_len;
3061fca7e26SJens Wiklander 
3071fca7e26SJens Wiklander 	return TEE_SUCCESS;
3081fca7e26SJens Wiklander }
3091fca7e26SJens Wiklander 
310043411e5SJens Wiklander TEE_Result internal_aes_gcm_enc_final(struct internal_aes_gcm_ctx *ctx,
311043411e5SJens Wiklander 				      const void *src, size_t len, void *dst,
312043411e5SJens Wiklander 				      void *tag, size_t *tag_len)
313043411e5SJens Wiklander {
314043411e5SJens Wiklander 	return __gcm_enc_final(&ctx->state, &ctx->key, src, len, dst, tag,
315043411e5SJens Wiklander 			       tag_len);
316043411e5SJens Wiklander }
317043411e5SJens Wiklander 
318043411e5SJens Wiklander static TEE_Result __gcm_dec_final(struct internal_aes_gcm_state *state,
319043411e5SJens Wiklander 				  const struct internal_aes_gcm_key *enc_key,
3201fca7e26SJens Wiklander 				  const void *src, size_t len, void *dst,
3211fca7e26SJens Wiklander 				  const void *tag, size_t tag_len)
3221fca7e26SJens Wiklander {
3231fca7e26SJens Wiklander 	TEE_Result res;
3241fca7e26SJens Wiklander 
32554af8d67SJens Wiklander 	if (tag_len != state->tag_len)
3261fca7e26SJens Wiklander 		return TEE_ERROR_MAC_INVALID;
3271fca7e26SJens Wiklander 
328043411e5SJens Wiklander 	res = operation_final(state, enc_key, TEE_MODE_DECRYPT, src, len, dst);
3291fca7e26SJens Wiklander 	if (res)
3301fca7e26SJens Wiklander 		return res;
3311fca7e26SJens Wiklander 
33248e10604SJerome Forissier 	if (consttime_memcmp(state->buf_tag, tag, tag_len))
3331fca7e26SJens Wiklander 		return TEE_ERROR_MAC_INVALID;
3341fca7e26SJens Wiklander 
3351fca7e26SJens Wiklander 	return TEE_SUCCESS;
3361fca7e26SJens Wiklander }
3371fca7e26SJens Wiklander 
338043411e5SJens Wiklander TEE_Result internal_aes_gcm_dec_final(struct internal_aes_gcm_ctx *ctx,
339043411e5SJens Wiklander 				      const void *src, size_t len, void *dst,
340043411e5SJens Wiklander 				      const void *tag, size_t tag_len)
341043411e5SJens Wiklander {
342043411e5SJens Wiklander 	return __gcm_dec_final(&ctx->state, &ctx->key, src, len, dst, tag,
343043411e5SJens Wiklander 			       tag_len);
344043411e5SJens Wiklander }
345043411e5SJens Wiklander 
34654af8d67SJens Wiklander void internal_aes_gcm_inc_ctr(struct internal_aes_gcm_state *state)
3471fca7e26SJens Wiklander {
3481fca7e26SJens Wiklander 	uint64_t c;
3491fca7e26SJens Wiklander 
35054af8d67SJens Wiklander 	c = TEE_U64_FROM_BIG_ENDIAN(state->ctr[1]) + 1;
35154af8d67SJens Wiklander 	state->ctr[1] = TEE_U64_TO_BIG_ENDIAN(c);
3521fca7e26SJens Wiklander 	if (!c) {
35354af8d67SJens Wiklander 		c = TEE_U64_FROM_BIG_ENDIAN(state->ctr[0]) + 1;
35454af8d67SJens Wiklander 		state->ctr[0] = TEE_U64_TO_BIG_ENDIAN(c);
3551fca7e26SJens Wiklander 	}
3561fca7e26SJens Wiklander }
3571fca7e26SJens Wiklander 
358043411e5SJens Wiklander TEE_Result internal_aes_gcm_enc(const struct internal_aes_gcm_key *enc_key,
359043411e5SJens Wiklander 				const void *nonce, size_t nonce_len,
360043411e5SJens Wiklander 				const void *aad, size_t aad_len,
361043411e5SJens Wiklander 				const void *src, size_t len, void *dst,
362043411e5SJens Wiklander 				void *tag, size_t *tag_len)
363043411e5SJens Wiklander {
364043411e5SJens Wiklander 	TEE_Result res;
365043411e5SJens Wiklander 	struct internal_aes_gcm_state state;
366043411e5SJens Wiklander 
367043411e5SJens Wiklander 	res = __gcm_init(&state, enc_key, TEE_MODE_ENCRYPT, nonce, nonce_len,
368043411e5SJens Wiklander 			 *tag_len);
369043411e5SJens Wiklander 	if (res)
370043411e5SJens Wiklander 		return res;
371043411e5SJens Wiklander 
372043411e5SJens Wiklander 	if (aad) {
373043411e5SJens Wiklander 		res = __gcm_update_aad(&state, aad, aad_len);
374043411e5SJens Wiklander 		if (res)
375043411e5SJens Wiklander 			return res;
376043411e5SJens Wiklander 	}
377043411e5SJens Wiklander 
378043411e5SJens Wiklander 	return __gcm_enc_final(&state, enc_key, src, len, dst, tag, tag_len);
379043411e5SJens Wiklander }
380043411e5SJens Wiklander 
381043411e5SJens Wiklander TEE_Result internal_aes_gcm_dec(const struct internal_aes_gcm_key *enc_key,
382043411e5SJens Wiklander 				const void *nonce, size_t nonce_len,
383043411e5SJens Wiklander 				const void *aad, size_t aad_len,
384043411e5SJens Wiklander 				const void *src, size_t len, void *dst,
385043411e5SJens Wiklander 				const void *tag, size_t tag_len)
386043411e5SJens Wiklander {
387043411e5SJens Wiklander 	TEE_Result res;
388043411e5SJens Wiklander 	struct internal_aes_gcm_state state;
389043411e5SJens Wiklander 
390043411e5SJens Wiklander 	res = __gcm_init(&state, enc_key, TEE_MODE_DECRYPT, nonce, nonce_len,
391043411e5SJens Wiklander 			 tag_len);
392043411e5SJens Wiklander 	if (res)
393043411e5SJens Wiklander 		return res;
394043411e5SJens Wiklander 
395043411e5SJens Wiklander 	if (aad) {
396043411e5SJens Wiklander 		res = __gcm_update_aad(&state, aad, aad_len);
397043411e5SJens Wiklander 		if (res)
398043411e5SJens Wiklander 			return res;
399043411e5SJens Wiklander 	}
400043411e5SJens Wiklander 
401043411e5SJens Wiklander 	return __gcm_dec_final(&state, enc_key, src, len, dst, tag, tag_len);
402043411e5SJens Wiklander }
403043411e5SJens Wiklander 
404043411e5SJens Wiklander 
4051fca7e26SJens Wiklander #ifndef CFG_CRYPTO_AES_GCM_FROM_CRYPTOLIB
406d7ac7d0fSJens Wiklander #include <stdlib.h>
407*f1e9b21bSJens Wiklander #include <crypto/crypto.h>
4081fca7e26SJens Wiklander 
409*f1e9b21bSJens Wiklander struct aes_gcm_ctx {
410*f1e9b21bSJens Wiklander 	struct crypto_authenc_ctx aec;
411*f1e9b21bSJens Wiklander 	struct internal_aes_gcm_ctx ctx;
412*f1e9b21bSJens Wiklander };
413*f1e9b21bSJens Wiklander 
414*f1e9b21bSJens Wiklander static const struct crypto_authenc_ops aes_gcm_ops;
415*f1e9b21bSJens Wiklander 
416*f1e9b21bSJens Wiklander static struct aes_gcm_ctx *
417*f1e9b21bSJens Wiklander to_aes_gcm_ctx(struct crypto_authenc_ctx *aec)
4181fca7e26SJens Wiklander {
419*f1e9b21bSJens Wiklander 	assert(aec->ops == &aes_gcm_ops);
420*f1e9b21bSJens Wiklander 
421*f1e9b21bSJens Wiklander 	return container_of(aec, struct aes_gcm_ctx, aec);
422*f1e9b21bSJens Wiklander }
423*f1e9b21bSJens Wiklander 
424*f1e9b21bSJens Wiklander TEE_Result crypto_aes_gcm_alloc_ctx(struct crypto_authenc_ctx **ctx_ret)
425*f1e9b21bSJens Wiklander {
426*f1e9b21bSJens Wiklander 	struct aes_gcm_ctx *ctx = calloc(1, sizeof(*ctx));
427d7ac7d0fSJens Wiklander 
428d7ac7d0fSJens Wiklander 	if (!ctx)
429d7ac7d0fSJens Wiklander 		return TEE_ERROR_OUT_OF_MEMORY;
430*f1e9b21bSJens Wiklander 	ctx->aec.ops = &aes_gcm_ops;
431d7ac7d0fSJens Wiklander 
432*f1e9b21bSJens Wiklander 	*ctx_ret = &ctx->aec;
433*f1e9b21bSJens Wiklander 
434d7ac7d0fSJens Wiklander 	return TEE_SUCCESS;
435d7ac7d0fSJens Wiklander }
436d7ac7d0fSJens Wiklander 
437*f1e9b21bSJens Wiklander static void aes_gcm_free_ctx(struct crypto_authenc_ctx *aec)
438d7ac7d0fSJens Wiklander {
439*f1e9b21bSJens Wiklander 	free(to_aes_gcm_ctx(aec));
440d7ac7d0fSJens Wiklander }
441d7ac7d0fSJens Wiklander 
442*f1e9b21bSJens Wiklander static void aes_gcm_copy_state(struct crypto_authenc_ctx *dst_ctx,
443*f1e9b21bSJens Wiklander 			       struct crypto_authenc_ctx *src_ctx)
444d7ac7d0fSJens Wiklander {
445*f1e9b21bSJens Wiklander 	to_aes_gcm_ctx(dst_ctx)->ctx = to_aes_gcm_ctx(src_ctx)->ctx;
4461fca7e26SJens Wiklander }
4471fca7e26SJens Wiklander 
448*f1e9b21bSJens Wiklander static TEE_Result aes_gcm_init(struct crypto_authenc_ctx *aec,
449*f1e9b21bSJens Wiklander 			       TEE_OperationMode mode,
4501fca7e26SJens Wiklander 			       const uint8_t *key, size_t key_len,
4511fca7e26SJens Wiklander 			       const uint8_t *nonce, size_t nonce_len,
452*f1e9b21bSJens Wiklander 			       size_t tag_len, size_t aad_len __unused,
453*f1e9b21bSJens Wiklander 			       size_t payload_len __unused)
4541fca7e26SJens Wiklander {
455*f1e9b21bSJens Wiklander 	return internal_aes_gcm_init(&to_aes_gcm_ctx(aec)->ctx, mode, key,
456*f1e9b21bSJens Wiklander 				     key_len, nonce, nonce_len, tag_len);
4571fca7e26SJens Wiklander }
4581fca7e26SJens Wiklander 
459*f1e9b21bSJens Wiklander static TEE_Result aes_gcm_update_aad(struct crypto_authenc_ctx *aec,
460*f1e9b21bSJens Wiklander 				     const uint8_t *data, size_t len)
4611fca7e26SJens Wiklander {
462*f1e9b21bSJens Wiklander 	return internal_aes_gcm_update_aad(&to_aes_gcm_ctx(aec)->ctx, data,
463*f1e9b21bSJens Wiklander 					   len);
4641fca7e26SJens Wiklander }
4651fca7e26SJens Wiklander 
466*f1e9b21bSJens Wiklander static TEE_Result aes_gcm_update_payload(struct crypto_authenc_ctx *aec,
467*f1e9b21bSJens Wiklander 					 TEE_OperationMode m,
4681fca7e26SJens Wiklander 					 const uint8_t *src, size_t len,
4691fca7e26SJens Wiklander 					 uint8_t *dst)
4701fca7e26SJens Wiklander {
471*f1e9b21bSJens Wiklander 	return internal_aes_gcm_update_payload(&to_aes_gcm_ctx(aec)->ctx,
472*f1e9b21bSJens Wiklander 					       m, src, len, dst);
4731fca7e26SJens Wiklander }
4741fca7e26SJens Wiklander 
475*f1e9b21bSJens Wiklander static TEE_Result aes_gcm_enc_final(struct crypto_authenc_ctx *aec,
476*f1e9b21bSJens Wiklander 				    const uint8_t *src, size_t len,
4771fca7e26SJens Wiklander 				    uint8_t *dst, uint8_t *tag, size_t *tag_len)
4781fca7e26SJens Wiklander {
479*f1e9b21bSJens Wiklander 	return internal_aes_gcm_enc_final(&to_aes_gcm_ctx(aec)->ctx, src, len,
480*f1e9b21bSJens Wiklander 					  dst, tag, tag_len);
4811fca7e26SJens Wiklander }
4821fca7e26SJens Wiklander 
483*f1e9b21bSJens Wiklander static TEE_Result aes_gcm_dec_final(struct crypto_authenc_ctx *aec,
484*f1e9b21bSJens Wiklander 				    const uint8_t *src, size_t len,
4851fca7e26SJens Wiklander 				    uint8_t *dst, const uint8_t *tag,
4861fca7e26SJens Wiklander 				    size_t tag_len)
4871fca7e26SJens Wiklander {
488*f1e9b21bSJens Wiklander 	return internal_aes_gcm_dec_final(&to_aes_gcm_ctx(aec)->ctx, src, len,
489*f1e9b21bSJens Wiklander 					  dst, tag, tag_len);
4901fca7e26SJens Wiklander }
4911fca7e26SJens Wiklander 
492*f1e9b21bSJens Wiklander static void aes_gcm_final(struct crypto_authenc_ctx *aec __unused)
4931fca7e26SJens Wiklander {
4941fca7e26SJens Wiklander }
495*f1e9b21bSJens Wiklander 
496*f1e9b21bSJens Wiklander static const struct crypto_authenc_ops aes_gcm_ops = {
497*f1e9b21bSJens Wiklander 	.init = aes_gcm_init,
498*f1e9b21bSJens Wiklander 	.update_aad = aes_gcm_update_aad,
499*f1e9b21bSJens Wiklander 	.update_payload = aes_gcm_update_payload,
500*f1e9b21bSJens Wiklander 	.enc_final = aes_gcm_enc_final,
501*f1e9b21bSJens Wiklander 	.dec_final = aes_gcm_dec_final,
502*f1e9b21bSJens Wiklander 	.final = aes_gcm_final,
503*f1e9b21bSJens Wiklander 	.free_ctx = aes_gcm_free_ctx,
504*f1e9b21bSJens Wiklander 	.copy_state = aes_gcm_copy_state,
505*f1e9b21bSJens Wiklander };
5061fca7e26SJens Wiklander #endif /*!CFG_CRYPTO_AES_GCM_FROM_CRYPTOLIB*/
507