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
xor_buf(uint8_t * dst,const uint8_t * src,size_t len)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
ghash_update_pad_zero(struct internal_aes_gcm_state * state,const uint8_t * data,size_t len)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
ghash_update_lengths(struct internal_aes_gcm_state * state,uint32_t l1,uint32_t l2)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
__gcm_init(struct internal_aes_gcm_state * state,const struct internal_aes_gcm_key * ek,TEE_OperationMode mode,const void * nonce,size_t nonce_len,size_t tag_len)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
internal_aes_gcm_init(struct internal_aes_gcm_ctx * ctx,TEE_OperationMode mode,const void * key,size_t key_len,const void * nonce,size_t nonce_len,size_t tag_len)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
__gcm_update_aad(struct internal_aes_gcm_state * state,const void * data,size_t len)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
internal_aes_gcm_update_aad(struct internal_aes_gcm_ctx * ctx,const void * data,size_t len)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
__gcm_update_payload(struct internal_aes_gcm_state * state,const struct internal_aes_gcm_key * ek,TEE_OperationMode mode,const void * src,size_t len,void * dst)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);
2201fca7e26SJens Wiklander if (mode == TEE_MODE_ENCRYPT)
22154af8d67SJens Wiklander memcpy(state->buf_hash + state->buf_pos,
22254af8d67SJens Wiklander state->buf_cryp + state->buf_pos, n);
2231fca7e26SJens Wiklander else
22454af8d67SJens Wiklander memcpy(state->buf_hash + state->buf_pos, s, n);
225*10298621SRayan Hu memcpy(d, state->buf_cryp + state->buf_pos, 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
internal_aes_gcm_update_payload(struct internal_aes_gcm_ctx * ctx,TEE_OperationMode mode,const void * src,size_t len,void * dst)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
operation_final(struct internal_aes_gcm_state * state,const struct internal_aes_gcm_key * enc_key,TEE_OperationMode m,const uint8_t * src,size_t len,uint8_t * dst)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
__gcm_enc_final(struct internal_aes_gcm_state * state,const struct internal_aes_gcm_key * enc_key,const void * src,size_t len,void * dst,void * tag,size_t * tag_len)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
internal_aes_gcm_enc_final(struct internal_aes_gcm_ctx * ctx,const void * src,size_t len,void * dst,void * tag,size_t * tag_len)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
__gcm_dec_final(struct internal_aes_gcm_state * state,const struct internal_aes_gcm_key * enc_key,const void * src,size_t len,void * dst,const void * tag,size_t tag_len)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
internal_aes_gcm_dec_final(struct internal_aes_gcm_ctx * ctx,const void * src,size_t len,void * dst,const void * tag,size_t tag_len)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
internal_aes_gcm_inc_ctr(struct internal_aes_gcm_state * state)34654af8d67SJens Wiklander void internal_aes_gcm_inc_ctr(struct internal_aes_gcm_state *state)
3471fca7e26SJens Wiklander {
3488a15c688SJens Wiklander uint64_t c = 0;
349fcabe15cSJens Wiklander uint32_t lower = 0;
3501fca7e26SJens Wiklander
351fcabe15cSJens Wiklander c = TEE_U64_FROM_BIG_ENDIAN(state->ctr[1]);
352fcabe15cSJens Wiklander lower = c + 1;
353fcabe15cSJens Wiklander c = (c & GENMASK_64(63, 32)) | lower;
35454af8d67SJens Wiklander state->ctr[1] = TEE_U64_TO_BIG_ENDIAN(c);
3551fca7e26SJens Wiklander }
3561fca7e26SJens Wiklander
internal_aes_gcm_dec_ctr(struct internal_aes_gcm_state * state)3578a15c688SJens Wiklander void internal_aes_gcm_dec_ctr(struct internal_aes_gcm_state *state)
3588a15c688SJens Wiklander {
3598a15c688SJens Wiklander uint64_t c = 0;
360fcabe15cSJens Wiklander uint32_t lower = 0;
3618a15c688SJens Wiklander
362fcabe15cSJens Wiklander c = TEE_U64_FROM_BIG_ENDIAN(state->ctr[1]);
363fcabe15cSJens Wiklander lower = c - 1;
364fcabe15cSJens Wiklander c = (c & GENMASK_64(63, 32)) | lower;
3658a15c688SJens Wiklander state->ctr[1] = TEE_U64_TO_BIG_ENDIAN(c);
3668a15c688SJens Wiklander }
3678a15c688SJens Wiklander
internal_aes_gcm_enc(const struct internal_aes_gcm_key * enc_key,const void * nonce,size_t nonce_len,const void * aad,size_t aad_len,const void * src,size_t len,void * dst,void * tag,size_t * tag_len)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
internal_aes_gcm_dec(const struct internal_aes_gcm_key * enc_key,const void * nonce,size_t nonce_len,const void * aad,size_t aad_len,const void * src,size_t len,void * dst,const void * tag,size_t tag_len)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 *
to_aes_gcm_ctx(struct crypto_authenc_ctx * aec)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
crypto_aes_gcm_alloc_ctx(struct crypto_authenc_ctx ** ctx_ret)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
aes_gcm_free_ctx(struct crypto_authenc_ctx * aec)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
aes_gcm_copy_state(struct crypto_authenc_ctx * dst_ctx,struct crypto_authenc_ctx * src_ctx)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
aes_gcm_init(struct crypto_authenc_ctx * aec,TEE_OperationMode mode,const uint8_t * key,size_t key_len,const uint8_t * nonce,size_t nonce_len,size_t tag_len,size_t aad_len __unused,size_t payload_len __unused)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
aes_gcm_update_aad(struct crypto_authenc_ctx * aec,const uint8_t * data,size_t len)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
aes_gcm_update_payload(struct crypto_authenc_ctx * aec,TEE_OperationMode m,const uint8_t * src,size_t len,uint8_t * dst)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
aes_gcm_enc_final(struct crypto_authenc_ctx * aec,const uint8_t * src,size_t len,uint8_t * dst,uint8_t * tag,size_t * tag_len)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
aes_gcm_dec_final(struct crypto_authenc_ctx * aec,const uint8_t * src,size_t len,uint8_t * dst,const uint8_t * tag,size_t tag_len)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
aes_gcm_final(struct crypto_authenc_ctx * aec __unused)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 */
internal_aes_gcm_gfmul(const uint64_t X[2],const uint64_t Y[2],uint64_t product[2])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