xref: /optee_os/core/crypto/aes-gcm.c (revision fcabe15c7783f14d6997a89154a8754790c648ea)
1fb7ef469SJerome Forissier // SPDX-License-Identifier: BSD-2-Clause
21fca7e26SJens Wiklander /*
3b314df1fSJens Wiklander  * Copyright (c) 2017-2020, Linaro Limited
41fca7e26SJens Wiklander  */
51fca7e26SJens Wiklander 
661b4cd9cSJens Wiklander #include <assert.h>
74f6d7160SJens Wiklander #include <crypto/crypto.h>
8f1e9b21bSJens Wiklander #include <crypto/crypto_impl.h>
94f6d7160SJens Wiklander #include <crypto/internal_aes-gcm.h>
101fca7e26SJens Wiklander #include <io.h>
111fca7e26SJens Wiklander #include <string_ext.h>
121fca7e26SJens Wiklander #include <string.h>
131fca7e26SJens Wiklander #include <tee_api_types.h>
141fca7e26SJens Wiklander #include <types_ext.h>
151fca7e26SJens Wiklander #include <utee_defines.h>
161fca7e26SJens Wiklander #include <util.h>
171fca7e26SJens Wiklander 
181fca7e26SJens Wiklander static void xor_buf(uint8_t *dst, const uint8_t *src, size_t len)
191fca7e26SJens Wiklander {
201fca7e26SJens Wiklander 	size_t n;
211fca7e26SJens Wiklander 
221fca7e26SJens Wiklander 	for (n = 0; n < len; n++)
231fca7e26SJens Wiklander 		dst[n] ^= src[n];
241fca7e26SJens Wiklander }
251fca7e26SJens Wiklander 
261fca7e26SJens Wiklander 
2754af8d67SJens Wiklander static void ghash_update_pad_zero(struct internal_aes_gcm_state *state,
281fca7e26SJens Wiklander 				  const uint8_t *data, size_t len)
291fca7e26SJens Wiklander {
301fca7e26SJens Wiklander 	size_t n = len / TEE_AES_BLOCK_SIZE;
311fca7e26SJens Wiklander 	uint64_t block[2];
321fca7e26SJens Wiklander 
331fca7e26SJens Wiklander 	if (n) {
34b8c186b5SJens Wiklander 		if (internal_aes_gcm_ptr_is_block_aligned(data)) {
3554af8d67SJens Wiklander 			internal_aes_gcm_ghash_update(state, NULL, data, n);
361fca7e26SJens Wiklander 		} else {
371fca7e26SJens Wiklander 			size_t m;
381fca7e26SJens Wiklander 
391fca7e26SJens Wiklander 			for (m = 0; m < n; m++) {
401fca7e26SJens Wiklander 
411fca7e26SJens Wiklander 				memcpy(block, data + m * sizeof(block),
421fca7e26SJens Wiklander 				       sizeof(block));
4354af8d67SJens Wiklander 				internal_aes_gcm_ghash_update(state, NULL,
441fca7e26SJens Wiklander 							      (void *)block, 1);
451fca7e26SJens Wiklander 			}
461fca7e26SJens Wiklander 		}
471fca7e26SJens Wiklander 	}
481fca7e26SJens Wiklander 
491fca7e26SJens Wiklander 	if (len - n * TEE_AES_BLOCK_SIZE) {
501fca7e26SJens Wiklander 		memset(block, 0, sizeof(block));
511fca7e26SJens Wiklander 		memcpy(block, data + n * TEE_AES_BLOCK_SIZE,
521fca7e26SJens Wiklander 		       len - n * TEE_AES_BLOCK_SIZE);
5354af8d67SJens Wiklander 		internal_aes_gcm_ghash_update(state, block, NULL, 0);
541fca7e26SJens Wiklander 	}
551fca7e26SJens Wiklander }
561fca7e26SJens Wiklander 
5754af8d67SJens Wiklander static void ghash_update_lengths(struct internal_aes_gcm_state *state,
5854af8d67SJens Wiklander 				 uint32_t l1, uint32_t l2)
591fca7e26SJens Wiklander {
601fca7e26SJens Wiklander 	uint64_t len_fields[2] = {
611fca7e26SJens Wiklander 		TEE_U64_TO_BIG_ENDIAN(l1 * 8),
621fca7e26SJens Wiklander 		TEE_U64_TO_BIG_ENDIAN(l2 * 8)
631fca7e26SJens Wiklander 	};
641fca7e26SJens Wiklander 
651fca7e26SJens Wiklander 	COMPILE_TIME_ASSERT(sizeof(len_fields) == TEE_AES_BLOCK_SIZE);
6654af8d67SJens Wiklander 	internal_aes_gcm_ghash_update(state, (uint8_t *)len_fields, NULL, 0);
671fca7e26SJens Wiklander }
681fca7e26SJens Wiklander 
6954af8d67SJens Wiklander static TEE_Result __gcm_init(struct internal_aes_gcm_state *state,
7054af8d67SJens Wiklander 			     const struct internal_aes_gcm_key *ek,
7154af8d67SJens Wiklander 			     TEE_OperationMode mode, const void *nonce,
721fca7e26SJens Wiklander 			     size_t nonce_len, size_t tag_len)
731fca7e26SJens Wiklander {
7454af8d67SJens Wiklander 	COMPILE_TIME_ASSERT(sizeof(state->ctr) == TEE_AES_BLOCK_SIZE);
751fca7e26SJens Wiklander 
7654af8d67SJens Wiklander 	if (tag_len > sizeof(state->buf_tag))
771fca7e26SJens Wiklander 		return TEE_ERROR_BAD_PARAMETERS;
781fca7e26SJens Wiklander 
7954af8d67SJens Wiklander 	memset(state, 0, sizeof(*state));
801fca7e26SJens Wiklander 
8154af8d67SJens Wiklander 	state->tag_len = tag_len;
8254af8d67SJens Wiklander 	internal_aes_gcm_set_key(state, ek);
831fca7e26SJens Wiklander 
841fca7e26SJens Wiklander 	if (nonce_len == (96 / 8)) {
8554af8d67SJens Wiklander 		memcpy(state->ctr, nonce, nonce_len);
8654af8d67SJens Wiklander 		internal_aes_gcm_inc_ctr(state);
871fca7e26SJens Wiklander 	} else {
8854af8d67SJens Wiklander 		ghash_update_pad_zero(state, nonce, nonce_len);
8954af8d67SJens Wiklander 		ghash_update_lengths(state, 0, nonce_len);
901fca7e26SJens Wiklander 
9154af8d67SJens Wiklander 		memcpy(state->ctr, state->hash_state, sizeof(state->ctr));
9254af8d67SJens Wiklander 		memset(state->hash_state, 0, sizeof(state->hash_state));
931fca7e26SJens Wiklander 	}
941fca7e26SJens Wiklander 
954f6d7160SJens Wiklander 	crypto_aes_enc_block(ek->data, sizeof(ek->data), ek->rounds,
964f6d7160SJens Wiklander 			     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 		 */
1164f6d7160SJens Wiklander 		crypto_aes_enc_block(ek->data, sizeof(ek->data), ek->rounds,
1174f6d7160SJens Wiklander 				     state->ctr, state->buf_cryp);
11854af8d67SJens Wiklander 		internal_aes_gcm_inc_ctr(state);
1191fca7e26SJens Wiklander 	}
1201fca7e26SJens Wiklander 
1211fca7e26SJens Wiklander 	return TEE_SUCCESS;
1221fca7e26SJens Wiklander }
1231fca7e26SJens Wiklander 
12454af8d67SJens Wiklander TEE_Result internal_aes_gcm_init(struct internal_aes_gcm_ctx *ctx,
12554af8d67SJens Wiklander 				 TEE_OperationMode mode, const void *key,
12654af8d67SJens Wiklander 				 size_t key_len, const void *nonce,
12754af8d67SJens Wiklander 				 size_t nonce_len, size_t tag_len)
12854af8d67SJens Wiklander {
1291df59751SJens Wiklander 	TEE_Result res = TEE_SUCCESS;
1301df59751SJens Wiklander 	struct internal_aes_gcm_key *ek = &ctx->key;
1311df59751SJens Wiklander 
1321df59751SJens Wiklander 	res = crypto_aes_expand_enc_key(key, key_len, ek->data,
1331df59751SJens Wiklander 					sizeof(ek->data), &ek->rounds);
13454af8d67SJens Wiklander 	if (res)
13554af8d67SJens Wiklander 		return res;
13654af8d67SJens Wiklander 
1371df59751SJens Wiklander 	return __gcm_init(&ctx->state, ek, mode, nonce, nonce_len, tag_len);
13854af8d67SJens Wiklander }
13954af8d67SJens Wiklander 
140043411e5SJens Wiklander static TEE_Result __gcm_update_aad(struct internal_aes_gcm_state *state,
1411fca7e26SJens Wiklander 				   const void *data, size_t len)
1421fca7e26SJens Wiklander {
1431fca7e26SJens Wiklander 	const uint8_t *d = data;
1441fca7e26SJens Wiklander 	size_t l = len;
1451fca7e26SJens Wiklander 	const uint8_t *head = NULL;
1461fca7e26SJens Wiklander 	size_t n;
1471fca7e26SJens Wiklander 
14854af8d67SJens Wiklander 	if (state->payload_bytes)
1491fca7e26SJens Wiklander 		return TEE_ERROR_BAD_PARAMETERS;
1501fca7e26SJens Wiklander 
15154af8d67SJens Wiklander 	state->aad_bytes += len;
1521fca7e26SJens Wiklander 
1531fca7e26SJens Wiklander 	while (l) {
15454af8d67SJens Wiklander 		if (state->buf_pos ||
15554af8d67SJens Wiklander 		    !internal_aes_gcm_ptr_is_block_aligned(d) ||
1561fca7e26SJens Wiklander 		    l < TEE_AES_BLOCK_SIZE) {
15754af8d67SJens Wiklander 			n = MIN(TEE_AES_BLOCK_SIZE - state->buf_pos, l);
15854af8d67SJens Wiklander 			memcpy(state->buf_hash + state->buf_pos, d, n);
15954af8d67SJens Wiklander 			state->buf_pos += n;
1601fca7e26SJens Wiklander 
16154af8d67SJens Wiklander 			if (state->buf_pos != TEE_AES_BLOCK_SIZE)
1621fca7e26SJens Wiklander 				return TEE_SUCCESS;
1631fca7e26SJens Wiklander 
16454af8d67SJens Wiklander 			state->buf_pos = 0;
16554af8d67SJens Wiklander 			head = state->buf_hash;
1661fca7e26SJens Wiklander 			d += n;
1671fca7e26SJens Wiklander 			l -= n;
1681fca7e26SJens Wiklander 		}
1691fca7e26SJens Wiklander 
170b8c186b5SJens Wiklander 		if (internal_aes_gcm_ptr_is_block_aligned(d))
1711fca7e26SJens Wiklander 			n = l / TEE_AES_BLOCK_SIZE;
1721fca7e26SJens Wiklander 		else
1731fca7e26SJens Wiklander 			n = 0;
1741fca7e26SJens Wiklander 
17554af8d67SJens Wiklander 		internal_aes_gcm_ghash_update(state, head, d, n);
1761fca7e26SJens Wiklander 		l -= n * TEE_AES_BLOCK_SIZE;
1771fca7e26SJens Wiklander 		d += n * TEE_AES_BLOCK_SIZE;
1781fca7e26SJens Wiklander 	}
1791fca7e26SJens Wiklander 
1801fca7e26SJens Wiklander 	return TEE_SUCCESS;
1811fca7e26SJens Wiklander }
1821fca7e26SJens Wiklander 
183043411e5SJens Wiklander TEE_Result internal_aes_gcm_update_aad(struct internal_aes_gcm_ctx *ctx,
184043411e5SJens Wiklander 				       const void *data, size_t len)
1851fca7e26SJens Wiklander {
186043411e5SJens Wiklander 	return __gcm_update_aad(&ctx->state, data, len);
187043411e5SJens Wiklander }
188043411e5SJens Wiklander 
189043411e5SJens Wiklander static TEE_Result
190043411e5SJens Wiklander __gcm_update_payload(struct internal_aes_gcm_state *state,
191043411e5SJens Wiklander 		     const struct internal_aes_gcm_key *ek,
192043411e5SJens Wiklander 		     TEE_OperationMode mode, const void *src,
193043411e5SJens Wiklander 		     size_t len, void *dst)
194043411e5SJens Wiklander {
1951fca7e26SJens Wiklander 	size_t n;
1961fca7e26SJens Wiklander 	const uint8_t *s = src;
1971fca7e26SJens Wiklander 	uint8_t *d = dst;
1981fca7e26SJens Wiklander 	size_t l = len;
1991fca7e26SJens Wiklander 
20054af8d67SJens Wiklander 	if (!state->payload_bytes && state->buf_pos) {
2011fca7e26SJens Wiklander 		/* AAD part done, finish up the last bits. */
20254af8d67SJens Wiklander 		memset(state->buf_hash + state->buf_pos, 0,
20354af8d67SJens Wiklander 		       TEE_AES_BLOCK_SIZE - state->buf_pos);
20454af8d67SJens Wiklander 		internal_aes_gcm_ghash_update(state, state->buf_hash, NULL, 0);
20554af8d67SJens Wiklander 		state->buf_pos = 0;
2061fca7e26SJens Wiklander 	}
2071fca7e26SJens Wiklander 
20854af8d67SJens Wiklander 	state->payload_bytes += len;
2091fca7e26SJens Wiklander 
2101fca7e26SJens Wiklander 	while (l) {
211d7fd8f87SJens Wiklander 		if (state->buf_pos || l < TEE_AES_BLOCK_SIZE) {
21254af8d67SJens Wiklander 			n = MIN(TEE_AES_BLOCK_SIZE - state->buf_pos, l);
2131fca7e26SJens Wiklander 
2144f6d7160SJens Wiklander 			if (!state->buf_pos && mode == TEE_MODE_DECRYPT)
2154f6d7160SJens Wiklander 				crypto_aes_enc_block(ek->data, sizeof(ek->data),
2164f6d7160SJens Wiklander 						     ek->rounds, state->ctr,
21754af8d67SJens Wiklander 						     state->buf_cryp);
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)
2404f6d7160SJens Wiklander 				crypto_aes_enc_block(ek->data, sizeof(ek->data),
2414f6d7160SJens Wiklander 						     ek->rounds, state->ctr,
24254af8d67SJens Wiklander 						     state->buf_cryp);
24354af8d67SJens Wiklander 			internal_aes_gcm_inc_ctr(state);
2441fca7e26SJens Wiklander 		} else {
2451fca7e26SJens Wiklander 			n = l / TEE_AES_BLOCK_SIZE;
246d7fd8f87SJens Wiklander 			internal_aes_gcm_update_payload_blocks(state, ek, 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 {
3488a15c688SJens Wiklander 	uint64_t c = 0;
349*fcabe15cSJens Wiklander 	uint32_t lower = 0;
3501fca7e26SJens Wiklander 
351*fcabe15cSJens Wiklander 	c = TEE_U64_FROM_BIG_ENDIAN(state->ctr[1]);
352*fcabe15cSJens Wiklander 	lower = c + 1;
353*fcabe15cSJens Wiklander 	c = (c & GENMASK_64(63, 32)) | lower;
35454af8d67SJens Wiklander 	state->ctr[1] = TEE_U64_TO_BIG_ENDIAN(c);
3551fca7e26SJens Wiklander }
3561fca7e26SJens Wiklander 
3578a15c688SJens Wiklander void internal_aes_gcm_dec_ctr(struct internal_aes_gcm_state *state)
3588a15c688SJens Wiklander {
3598a15c688SJens Wiklander 	uint64_t c = 0;
360*fcabe15cSJens Wiklander 	uint32_t lower = 0;
3618a15c688SJens Wiklander 
362*fcabe15cSJens Wiklander 	c = TEE_U64_FROM_BIG_ENDIAN(state->ctr[1]);
363*fcabe15cSJens Wiklander 	lower = c - 1;
364*fcabe15cSJens Wiklander 	c = (c & GENMASK_64(63, 32)) | lower;
3658a15c688SJens Wiklander 	state->ctr[1] = TEE_U64_TO_BIG_ENDIAN(c);
3668a15c688SJens Wiklander }
3678a15c688SJens Wiklander 
368043411e5SJens Wiklander TEE_Result internal_aes_gcm_enc(const struct internal_aes_gcm_key *enc_key,
369043411e5SJens Wiklander 				const void *nonce, size_t nonce_len,
370043411e5SJens Wiklander 				const void *aad, size_t aad_len,
371043411e5SJens Wiklander 				const void *src, size_t len, void *dst,
372043411e5SJens Wiklander 				void *tag, size_t *tag_len)
373043411e5SJens Wiklander {
374043411e5SJens Wiklander 	TEE_Result res;
375043411e5SJens Wiklander 	struct internal_aes_gcm_state state;
376043411e5SJens Wiklander 
377043411e5SJens Wiklander 	res = __gcm_init(&state, enc_key, TEE_MODE_ENCRYPT, nonce, nonce_len,
378043411e5SJens Wiklander 			 *tag_len);
379043411e5SJens Wiklander 	if (res)
380043411e5SJens Wiklander 		return res;
381043411e5SJens Wiklander 
382043411e5SJens Wiklander 	if (aad) {
383043411e5SJens Wiklander 		res = __gcm_update_aad(&state, aad, aad_len);
384043411e5SJens Wiklander 		if (res)
385043411e5SJens Wiklander 			return res;
386043411e5SJens Wiklander 	}
387043411e5SJens Wiklander 
388043411e5SJens Wiklander 	return __gcm_enc_final(&state, enc_key, src, len, dst, tag, tag_len);
389043411e5SJens Wiklander }
390043411e5SJens Wiklander 
391043411e5SJens Wiklander TEE_Result internal_aes_gcm_dec(const struct internal_aes_gcm_key *enc_key,
392043411e5SJens Wiklander 				const void *nonce, size_t nonce_len,
393043411e5SJens Wiklander 				const void *aad, size_t aad_len,
394043411e5SJens Wiklander 				const void *src, size_t len, void *dst,
395043411e5SJens Wiklander 				const void *tag, size_t tag_len)
396043411e5SJens Wiklander {
397043411e5SJens Wiklander 	TEE_Result res;
398043411e5SJens Wiklander 	struct internal_aes_gcm_state state;
399043411e5SJens Wiklander 
400043411e5SJens Wiklander 	res = __gcm_init(&state, enc_key, TEE_MODE_DECRYPT, nonce, nonce_len,
401043411e5SJens Wiklander 			 tag_len);
402043411e5SJens Wiklander 	if (res)
403043411e5SJens Wiklander 		return res;
404043411e5SJens Wiklander 
405043411e5SJens Wiklander 	if (aad) {
406043411e5SJens Wiklander 		res = __gcm_update_aad(&state, aad, aad_len);
407043411e5SJens Wiklander 		if (res)
408043411e5SJens Wiklander 			return res;
409043411e5SJens Wiklander 	}
410043411e5SJens Wiklander 
411043411e5SJens Wiklander 	return __gcm_dec_final(&state, enc_key, src, len, dst, tag, tag_len);
412043411e5SJens Wiklander }
413043411e5SJens Wiklander 
414043411e5SJens Wiklander 
4151fca7e26SJens Wiklander #ifndef CFG_CRYPTO_AES_GCM_FROM_CRYPTOLIB
416d7ac7d0fSJens Wiklander #include <stdlib.h>
417f1e9b21bSJens Wiklander #include <crypto/crypto.h>
4181fca7e26SJens Wiklander 
419f1e9b21bSJens Wiklander struct aes_gcm_ctx {
420f1e9b21bSJens Wiklander 	struct crypto_authenc_ctx aec;
421f1e9b21bSJens Wiklander 	struct internal_aes_gcm_ctx ctx;
422f1e9b21bSJens Wiklander };
423f1e9b21bSJens Wiklander 
424f1e9b21bSJens Wiklander static const struct crypto_authenc_ops aes_gcm_ops;
425f1e9b21bSJens Wiklander 
426f1e9b21bSJens Wiklander static struct aes_gcm_ctx *
427f1e9b21bSJens Wiklander to_aes_gcm_ctx(struct crypto_authenc_ctx *aec)
4281fca7e26SJens Wiklander {
429f1e9b21bSJens Wiklander 	assert(aec->ops == &aes_gcm_ops);
430f1e9b21bSJens Wiklander 
431f1e9b21bSJens Wiklander 	return container_of(aec, struct aes_gcm_ctx, aec);
432f1e9b21bSJens Wiklander }
433f1e9b21bSJens Wiklander 
434f1e9b21bSJens Wiklander TEE_Result crypto_aes_gcm_alloc_ctx(struct crypto_authenc_ctx **ctx_ret)
435f1e9b21bSJens Wiklander {
436f1e9b21bSJens Wiklander 	struct aes_gcm_ctx *ctx = calloc(1, sizeof(*ctx));
437d7ac7d0fSJens Wiklander 
438d7ac7d0fSJens Wiklander 	if (!ctx)
439d7ac7d0fSJens Wiklander 		return TEE_ERROR_OUT_OF_MEMORY;
440f1e9b21bSJens Wiklander 	ctx->aec.ops = &aes_gcm_ops;
441d7ac7d0fSJens Wiklander 
442f1e9b21bSJens Wiklander 	*ctx_ret = &ctx->aec;
443f1e9b21bSJens Wiklander 
444d7ac7d0fSJens Wiklander 	return TEE_SUCCESS;
445d7ac7d0fSJens Wiklander }
446d7ac7d0fSJens Wiklander 
447f1e9b21bSJens Wiklander static void aes_gcm_free_ctx(struct crypto_authenc_ctx *aec)
448d7ac7d0fSJens Wiklander {
449f1e9b21bSJens Wiklander 	free(to_aes_gcm_ctx(aec));
450d7ac7d0fSJens Wiklander }
451d7ac7d0fSJens Wiklander 
452f1e9b21bSJens Wiklander static void aes_gcm_copy_state(struct crypto_authenc_ctx *dst_ctx,
453f1e9b21bSJens Wiklander 			       struct crypto_authenc_ctx *src_ctx)
454d7ac7d0fSJens Wiklander {
455f1e9b21bSJens Wiklander 	to_aes_gcm_ctx(dst_ctx)->ctx = to_aes_gcm_ctx(src_ctx)->ctx;
4561fca7e26SJens Wiklander }
4571fca7e26SJens Wiklander 
458f1e9b21bSJens Wiklander static TEE_Result aes_gcm_init(struct crypto_authenc_ctx *aec,
459f1e9b21bSJens Wiklander 			       TEE_OperationMode mode,
4601fca7e26SJens Wiklander 			       const uint8_t *key, size_t key_len,
4611fca7e26SJens Wiklander 			       const uint8_t *nonce, size_t nonce_len,
462f1e9b21bSJens Wiklander 			       size_t tag_len, size_t aad_len __unused,
463f1e9b21bSJens Wiklander 			       size_t payload_len __unused)
4641fca7e26SJens Wiklander {
465f1e9b21bSJens Wiklander 	return internal_aes_gcm_init(&to_aes_gcm_ctx(aec)->ctx, mode, key,
466f1e9b21bSJens Wiklander 				     key_len, nonce, nonce_len, tag_len);
4671fca7e26SJens Wiklander }
4681fca7e26SJens Wiklander 
469f1e9b21bSJens Wiklander static TEE_Result aes_gcm_update_aad(struct crypto_authenc_ctx *aec,
470f1e9b21bSJens Wiklander 				     const uint8_t *data, size_t len)
4711fca7e26SJens Wiklander {
472f1e9b21bSJens Wiklander 	return internal_aes_gcm_update_aad(&to_aes_gcm_ctx(aec)->ctx, data,
473f1e9b21bSJens Wiklander 					   len);
4741fca7e26SJens Wiklander }
4751fca7e26SJens Wiklander 
476f1e9b21bSJens Wiklander static TEE_Result aes_gcm_update_payload(struct crypto_authenc_ctx *aec,
477f1e9b21bSJens Wiklander 					 TEE_OperationMode m,
4781fca7e26SJens Wiklander 					 const uint8_t *src, size_t len,
4791fca7e26SJens Wiklander 					 uint8_t *dst)
4801fca7e26SJens Wiklander {
481f1e9b21bSJens Wiklander 	return internal_aes_gcm_update_payload(&to_aes_gcm_ctx(aec)->ctx,
482f1e9b21bSJens Wiklander 					       m, src, len, dst);
4831fca7e26SJens Wiklander }
4841fca7e26SJens Wiklander 
485f1e9b21bSJens Wiklander static TEE_Result aes_gcm_enc_final(struct crypto_authenc_ctx *aec,
486f1e9b21bSJens Wiklander 				    const uint8_t *src, size_t len,
4871fca7e26SJens Wiklander 				    uint8_t *dst, uint8_t *tag, size_t *tag_len)
4881fca7e26SJens Wiklander {
489f1e9b21bSJens Wiklander 	return internal_aes_gcm_enc_final(&to_aes_gcm_ctx(aec)->ctx, src, len,
490f1e9b21bSJens Wiklander 					  dst, tag, tag_len);
4911fca7e26SJens Wiklander }
4921fca7e26SJens Wiklander 
493f1e9b21bSJens Wiklander static TEE_Result aes_gcm_dec_final(struct crypto_authenc_ctx *aec,
494f1e9b21bSJens Wiklander 				    const uint8_t *src, size_t len,
4951fca7e26SJens Wiklander 				    uint8_t *dst, const uint8_t *tag,
4961fca7e26SJens Wiklander 				    size_t tag_len)
4971fca7e26SJens Wiklander {
498f1e9b21bSJens Wiklander 	return internal_aes_gcm_dec_final(&to_aes_gcm_ctx(aec)->ctx, src, len,
499f1e9b21bSJens Wiklander 					  dst, tag, tag_len);
5001fca7e26SJens Wiklander }
5011fca7e26SJens Wiklander 
502f1e9b21bSJens Wiklander static void aes_gcm_final(struct crypto_authenc_ctx *aec __unused)
5031fca7e26SJens Wiklander {
5041fca7e26SJens Wiklander }
505f1e9b21bSJens Wiklander 
506f1e9b21bSJens Wiklander static const struct crypto_authenc_ops aes_gcm_ops = {
507f1e9b21bSJens Wiklander 	.init = aes_gcm_init,
508f1e9b21bSJens Wiklander 	.update_aad = aes_gcm_update_aad,
509f1e9b21bSJens Wiklander 	.update_payload = aes_gcm_update_payload,
510f1e9b21bSJens Wiklander 	.enc_final = aes_gcm_enc_final,
511f1e9b21bSJens Wiklander 	.dec_final = aes_gcm_dec_final,
512f1e9b21bSJens Wiklander 	.final = aes_gcm_final,
513f1e9b21bSJens Wiklander 	.free_ctx = aes_gcm_free_ctx,
514f1e9b21bSJens Wiklander 	.copy_state = aes_gcm_copy_state,
515f1e9b21bSJens Wiklander };
516b314df1fSJens Wiklander 
517b314df1fSJens Wiklander /*
518b314df1fSJens Wiklander  * internal_aes_gcm_gfmul() is based on ghash_gfmul() from
519b314df1fSJens Wiklander  * https://github.com/openbsd/src/blob/master/sys/crypto/gmac.c
520b314df1fSJens Wiklander  */
521b314df1fSJens Wiklander void internal_aes_gcm_gfmul(const uint64_t X[2], const uint64_t Y[2],
522b314df1fSJens Wiklander 			    uint64_t product[2])
523b314df1fSJens Wiklander {
524b314df1fSJens Wiklander 	uint64_t y[2] = { 0 };
525b314df1fSJens Wiklander 	uint64_t z[2] = { 0 };
526b314df1fSJens Wiklander 	const uint8_t *x = (const uint8_t *)X;
527b314df1fSJens Wiklander 	uint32_t mul = 0;
528b314df1fSJens Wiklander 	size_t n = 0;
529b314df1fSJens Wiklander 
530b314df1fSJens Wiklander 	y[0] = TEE_U64_FROM_BIG_ENDIAN(Y[0]);
531b314df1fSJens Wiklander 	y[1] = TEE_U64_FROM_BIG_ENDIAN(Y[1]);
532b314df1fSJens Wiklander 
533b314df1fSJens Wiklander 	for (n = 0; n < TEE_AES_BLOCK_SIZE * 8; n++) {
534b314df1fSJens Wiklander 		/* update Z */
535b314df1fSJens Wiklander 		if (x[n >> 3] & (1 << (~n & 7)))
536b314df1fSJens Wiklander 			internal_aes_gcm_xor_block(z, y);
537b314df1fSJens Wiklander 
538b314df1fSJens Wiklander 		/* update Y */
539b314df1fSJens Wiklander 		mul = y[1] & 1;
540b314df1fSJens Wiklander 		y[1] = (y[0] << 63) | (y[1] >> 1);
541b314df1fSJens Wiklander 		y[0] = (y[0] >> 1) ^ (0xe100000000000000 * mul);
542b314df1fSJens Wiklander 	}
543b314df1fSJens Wiklander 
544b314df1fSJens Wiklander 	product[0] = TEE_U64_TO_BIG_ENDIAN(z[0]);
545b314df1fSJens Wiklander 	product[1] = TEE_U64_TO_BIG_ENDIAN(z[1]);
546b314df1fSJens Wiklander }
5471fca7e26SJens Wiklander #endif /*!CFG_CRYPTO_AES_GCM_FROM_CRYPTOLIB*/
548