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 { 129*1df59751SJens Wiklander TEE_Result res = TEE_SUCCESS; 130*1df59751SJens Wiklander struct internal_aes_gcm_key *ek = &ctx->key; 131*1df59751SJens Wiklander 132*1df59751SJens Wiklander res = crypto_aes_expand_enc_key(key, key_len, ek->data, 133*1df59751SJens Wiklander sizeof(ek->data), &ek->rounds); 13454af8d67SJens Wiklander if (res) 13554af8d67SJens Wiklander return res; 13654af8d67SJens Wiklander 137*1df59751SJens 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; 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 3588a15c688SJens Wiklander void internal_aes_gcm_dec_ctr(struct internal_aes_gcm_state *state) 3598a15c688SJens Wiklander { 3608a15c688SJens Wiklander uint64_t c = 0; 3618a15c688SJens Wiklander 3628a15c688SJens Wiklander c = TEE_U64_FROM_BIG_ENDIAN(state->ctr[1]) - 1; 3638a15c688SJens Wiklander state->ctr[1] = TEE_U64_TO_BIG_ENDIAN(c); 3648a15c688SJens Wiklander if (c == UINT64_MAX) { 3658a15c688SJens Wiklander c = TEE_U64_FROM_BIG_ENDIAN(state->ctr[0]) - 1; 3668a15c688SJens Wiklander state->ctr[0] = TEE_U64_TO_BIG_ENDIAN(c); 3678a15c688SJens Wiklander } 3688a15c688SJens Wiklander } 3698a15c688SJens Wiklander 370043411e5SJens Wiklander TEE_Result internal_aes_gcm_enc(const struct internal_aes_gcm_key *enc_key, 371043411e5SJens Wiklander const void *nonce, size_t nonce_len, 372043411e5SJens Wiklander const void *aad, size_t aad_len, 373043411e5SJens Wiklander const void *src, size_t len, void *dst, 374043411e5SJens Wiklander void *tag, size_t *tag_len) 375043411e5SJens Wiklander { 376043411e5SJens Wiklander TEE_Result res; 377043411e5SJens Wiklander struct internal_aes_gcm_state state; 378043411e5SJens Wiklander 379043411e5SJens Wiklander res = __gcm_init(&state, enc_key, TEE_MODE_ENCRYPT, nonce, nonce_len, 380043411e5SJens Wiklander *tag_len); 381043411e5SJens Wiklander if (res) 382043411e5SJens Wiklander return res; 383043411e5SJens Wiklander 384043411e5SJens Wiklander if (aad) { 385043411e5SJens Wiklander res = __gcm_update_aad(&state, aad, aad_len); 386043411e5SJens Wiklander if (res) 387043411e5SJens Wiklander return res; 388043411e5SJens Wiklander } 389043411e5SJens Wiklander 390043411e5SJens Wiklander return __gcm_enc_final(&state, enc_key, src, len, dst, tag, tag_len); 391043411e5SJens Wiklander } 392043411e5SJens Wiklander 393043411e5SJens Wiklander TEE_Result internal_aes_gcm_dec(const struct internal_aes_gcm_key *enc_key, 394043411e5SJens Wiklander const void *nonce, size_t nonce_len, 395043411e5SJens Wiklander const void *aad, size_t aad_len, 396043411e5SJens Wiklander const void *src, size_t len, void *dst, 397043411e5SJens Wiklander const void *tag, size_t tag_len) 398043411e5SJens Wiklander { 399043411e5SJens Wiklander TEE_Result res; 400043411e5SJens Wiklander struct internal_aes_gcm_state state; 401043411e5SJens Wiklander 402043411e5SJens Wiklander res = __gcm_init(&state, enc_key, TEE_MODE_DECRYPT, nonce, nonce_len, 403043411e5SJens Wiklander tag_len); 404043411e5SJens Wiklander if (res) 405043411e5SJens Wiklander return res; 406043411e5SJens Wiklander 407043411e5SJens Wiklander if (aad) { 408043411e5SJens Wiklander res = __gcm_update_aad(&state, aad, aad_len); 409043411e5SJens Wiklander if (res) 410043411e5SJens Wiklander return res; 411043411e5SJens Wiklander } 412043411e5SJens Wiklander 413043411e5SJens Wiklander return __gcm_dec_final(&state, enc_key, src, len, dst, tag, tag_len); 414043411e5SJens Wiklander } 415043411e5SJens Wiklander 416043411e5SJens Wiklander 4171fca7e26SJens Wiklander #ifndef CFG_CRYPTO_AES_GCM_FROM_CRYPTOLIB 418d7ac7d0fSJens Wiklander #include <stdlib.h> 419f1e9b21bSJens Wiklander #include <crypto/crypto.h> 4201fca7e26SJens Wiklander 421f1e9b21bSJens Wiklander struct aes_gcm_ctx { 422f1e9b21bSJens Wiklander struct crypto_authenc_ctx aec; 423f1e9b21bSJens Wiklander struct internal_aes_gcm_ctx ctx; 424f1e9b21bSJens Wiklander }; 425f1e9b21bSJens Wiklander 426f1e9b21bSJens Wiklander static const struct crypto_authenc_ops aes_gcm_ops; 427f1e9b21bSJens Wiklander 428f1e9b21bSJens Wiklander static struct aes_gcm_ctx * 429f1e9b21bSJens Wiklander to_aes_gcm_ctx(struct crypto_authenc_ctx *aec) 4301fca7e26SJens Wiklander { 431f1e9b21bSJens Wiklander assert(aec->ops == &aes_gcm_ops); 432f1e9b21bSJens Wiklander 433f1e9b21bSJens Wiklander return container_of(aec, struct aes_gcm_ctx, aec); 434f1e9b21bSJens Wiklander } 435f1e9b21bSJens Wiklander 436f1e9b21bSJens Wiklander TEE_Result crypto_aes_gcm_alloc_ctx(struct crypto_authenc_ctx **ctx_ret) 437f1e9b21bSJens Wiklander { 438f1e9b21bSJens Wiklander struct aes_gcm_ctx *ctx = calloc(1, sizeof(*ctx)); 439d7ac7d0fSJens Wiklander 440d7ac7d0fSJens Wiklander if (!ctx) 441d7ac7d0fSJens Wiklander return TEE_ERROR_OUT_OF_MEMORY; 442f1e9b21bSJens Wiklander ctx->aec.ops = &aes_gcm_ops; 443d7ac7d0fSJens Wiklander 444f1e9b21bSJens Wiklander *ctx_ret = &ctx->aec; 445f1e9b21bSJens Wiklander 446d7ac7d0fSJens Wiklander return TEE_SUCCESS; 447d7ac7d0fSJens Wiklander } 448d7ac7d0fSJens Wiklander 449f1e9b21bSJens Wiklander static void aes_gcm_free_ctx(struct crypto_authenc_ctx *aec) 450d7ac7d0fSJens Wiklander { 451f1e9b21bSJens Wiklander free(to_aes_gcm_ctx(aec)); 452d7ac7d0fSJens Wiklander } 453d7ac7d0fSJens Wiklander 454f1e9b21bSJens Wiklander static void aes_gcm_copy_state(struct crypto_authenc_ctx *dst_ctx, 455f1e9b21bSJens Wiklander struct crypto_authenc_ctx *src_ctx) 456d7ac7d0fSJens Wiklander { 457f1e9b21bSJens Wiklander to_aes_gcm_ctx(dst_ctx)->ctx = to_aes_gcm_ctx(src_ctx)->ctx; 4581fca7e26SJens Wiklander } 4591fca7e26SJens Wiklander 460f1e9b21bSJens Wiklander static TEE_Result aes_gcm_init(struct crypto_authenc_ctx *aec, 461f1e9b21bSJens Wiklander TEE_OperationMode mode, 4621fca7e26SJens Wiklander const uint8_t *key, size_t key_len, 4631fca7e26SJens Wiklander const uint8_t *nonce, size_t nonce_len, 464f1e9b21bSJens Wiklander size_t tag_len, size_t aad_len __unused, 465f1e9b21bSJens Wiklander size_t payload_len __unused) 4661fca7e26SJens Wiklander { 467f1e9b21bSJens Wiklander return internal_aes_gcm_init(&to_aes_gcm_ctx(aec)->ctx, mode, key, 468f1e9b21bSJens Wiklander key_len, nonce, nonce_len, tag_len); 4691fca7e26SJens Wiklander } 4701fca7e26SJens Wiklander 471f1e9b21bSJens Wiklander static TEE_Result aes_gcm_update_aad(struct crypto_authenc_ctx *aec, 472f1e9b21bSJens Wiklander const uint8_t *data, size_t len) 4731fca7e26SJens Wiklander { 474f1e9b21bSJens Wiklander return internal_aes_gcm_update_aad(&to_aes_gcm_ctx(aec)->ctx, data, 475f1e9b21bSJens Wiklander len); 4761fca7e26SJens Wiklander } 4771fca7e26SJens Wiklander 478f1e9b21bSJens Wiklander static TEE_Result aes_gcm_update_payload(struct crypto_authenc_ctx *aec, 479f1e9b21bSJens Wiklander TEE_OperationMode m, 4801fca7e26SJens Wiklander const uint8_t *src, size_t len, 4811fca7e26SJens Wiklander uint8_t *dst) 4821fca7e26SJens Wiklander { 483f1e9b21bSJens Wiklander return internal_aes_gcm_update_payload(&to_aes_gcm_ctx(aec)->ctx, 484f1e9b21bSJens Wiklander m, src, len, dst); 4851fca7e26SJens Wiklander } 4861fca7e26SJens Wiklander 487f1e9b21bSJens Wiklander static TEE_Result aes_gcm_enc_final(struct crypto_authenc_ctx *aec, 488f1e9b21bSJens Wiklander const uint8_t *src, size_t len, 4891fca7e26SJens Wiklander uint8_t *dst, uint8_t *tag, size_t *tag_len) 4901fca7e26SJens Wiklander { 491f1e9b21bSJens Wiklander return internal_aes_gcm_enc_final(&to_aes_gcm_ctx(aec)->ctx, src, len, 492f1e9b21bSJens Wiklander dst, tag, tag_len); 4931fca7e26SJens Wiklander } 4941fca7e26SJens Wiklander 495f1e9b21bSJens Wiklander static TEE_Result aes_gcm_dec_final(struct crypto_authenc_ctx *aec, 496f1e9b21bSJens Wiklander const uint8_t *src, size_t len, 4971fca7e26SJens Wiklander uint8_t *dst, const uint8_t *tag, 4981fca7e26SJens Wiklander size_t tag_len) 4991fca7e26SJens Wiklander { 500f1e9b21bSJens Wiklander return internal_aes_gcm_dec_final(&to_aes_gcm_ctx(aec)->ctx, src, len, 501f1e9b21bSJens Wiklander dst, tag, tag_len); 5021fca7e26SJens Wiklander } 5031fca7e26SJens Wiklander 504f1e9b21bSJens Wiklander static void aes_gcm_final(struct crypto_authenc_ctx *aec __unused) 5051fca7e26SJens Wiklander { 5061fca7e26SJens Wiklander } 507f1e9b21bSJens Wiklander 508f1e9b21bSJens Wiklander static const struct crypto_authenc_ops aes_gcm_ops = { 509f1e9b21bSJens Wiklander .init = aes_gcm_init, 510f1e9b21bSJens Wiklander .update_aad = aes_gcm_update_aad, 511f1e9b21bSJens Wiklander .update_payload = aes_gcm_update_payload, 512f1e9b21bSJens Wiklander .enc_final = aes_gcm_enc_final, 513f1e9b21bSJens Wiklander .dec_final = aes_gcm_dec_final, 514f1e9b21bSJens Wiklander .final = aes_gcm_final, 515f1e9b21bSJens Wiklander .free_ctx = aes_gcm_free_ctx, 516f1e9b21bSJens Wiklander .copy_state = aes_gcm_copy_state, 517f1e9b21bSJens Wiklander }; 518b314df1fSJens Wiklander 519b314df1fSJens Wiklander /* 520b314df1fSJens Wiklander * internal_aes_gcm_gfmul() is based on ghash_gfmul() from 521b314df1fSJens Wiklander * https://github.com/openbsd/src/blob/master/sys/crypto/gmac.c 522b314df1fSJens Wiklander */ 523b314df1fSJens Wiklander void internal_aes_gcm_gfmul(const uint64_t X[2], const uint64_t Y[2], 524b314df1fSJens Wiklander uint64_t product[2]) 525b314df1fSJens Wiklander { 526b314df1fSJens Wiklander uint64_t y[2] = { 0 }; 527b314df1fSJens Wiklander uint64_t z[2] = { 0 }; 528b314df1fSJens Wiklander const uint8_t *x = (const uint8_t *)X; 529b314df1fSJens Wiklander uint32_t mul = 0; 530b314df1fSJens Wiklander size_t n = 0; 531b314df1fSJens Wiklander 532b314df1fSJens Wiklander y[0] = TEE_U64_FROM_BIG_ENDIAN(Y[0]); 533b314df1fSJens Wiklander y[1] = TEE_U64_FROM_BIG_ENDIAN(Y[1]); 534b314df1fSJens Wiklander 535b314df1fSJens Wiklander for (n = 0; n < TEE_AES_BLOCK_SIZE * 8; n++) { 536b314df1fSJens Wiklander /* update Z */ 537b314df1fSJens Wiklander if (x[n >> 3] & (1 << (~n & 7))) 538b314df1fSJens Wiklander internal_aes_gcm_xor_block(z, y); 539b314df1fSJens Wiklander 540b314df1fSJens Wiklander /* update Y */ 541b314df1fSJens Wiklander mul = y[1] & 1; 542b314df1fSJens Wiklander y[1] = (y[0] << 63) | (y[1] >> 1); 543b314df1fSJens Wiklander y[0] = (y[0] >> 1) ^ (0xe100000000000000 * mul); 544b314df1fSJens Wiklander } 545b314df1fSJens Wiklander 546b314df1fSJens Wiklander product[0] = TEE_U64_TO_BIG_ENDIAN(z[0]); 547b314df1fSJens Wiklander product[1] = TEE_U64_TO_BIG_ENDIAN(z[1]); 548b314df1fSJens Wiklander } 549b314df1fSJens Wiklander 5508f848cdbSJens Wiklander void internal_aes_gcm_encrypt_block(struct internal_aes_gcm_state *state, 5518f848cdbSJens Wiklander const struct internal_aes_gcm_key *enc_key, 5528f848cdbSJens Wiklander const uint64_t src[2], uint64_t dst[2]) 553d7fd8f87SJens Wiklander { 554d7fd8f87SJens Wiklander void *buf_cryp = state->buf_cryp; 555d7fd8f87SJens Wiklander void *ctr = state->ctr; 556d7fd8f87SJens Wiklander 557d7fd8f87SJens Wiklander internal_aes_gcm_xor_block(buf_cryp, src); 558d7fd8f87SJens Wiklander internal_aes_gcm_ghash_update(state, buf_cryp, NULL, 0); 559d7fd8f87SJens Wiklander memcpy(dst, buf_cryp, sizeof(state->buf_cryp)); 560d7fd8f87SJens Wiklander 5618f848cdbSJens Wiklander crypto_aes_enc_block(enc_key->data, sizeof(enc_key->data), 5628f848cdbSJens Wiklander enc_key->rounds, ctr, buf_cryp); 563d7fd8f87SJens Wiklander internal_aes_gcm_inc_ctr(state); 564d7fd8f87SJens Wiklander } 565d7fd8f87SJens Wiklander 566d7fd8f87SJens Wiklander static void encrypt_pl(struct internal_aes_gcm_state *state, 567d7fd8f87SJens Wiklander const struct internal_aes_gcm_key *ek, 568d7fd8f87SJens Wiklander const uint8_t *src, size_t num_blocks, uint8_t *dst) 569d7fd8f87SJens Wiklander { 570d7fd8f87SJens Wiklander size_t n = 0; 571d7fd8f87SJens Wiklander 572d7fd8f87SJens Wiklander if (ALIGNMENT_IS_OK(src, uint64_t)) { 5738f848cdbSJens Wiklander for (n = 0; n < num_blocks; n++) { 5748f848cdbSJens Wiklander const void *s = src + n * TEE_AES_BLOCK_SIZE; 5758f848cdbSJens Wiklander void *d = dst + n * TEE_AES_BLOCK_SIZE; 5768f848cdbSJens Wiklander 5778f848cdbSJens Wiklander internal_aes_gcm_encrypt_block(state, ek, s, d); 5788f848cdbSJens Wiklander } 579d7fd8f87SJens Wiklander } else { 580d7fd8f87SJens Wiklander for (n = 0; n < num_blocks; n++) { 581d7fd8f87SJens Wiklander uint64_t tmp[2] = { 0 }; 5828f848cdbSJens Wiklander void *d = dst + n * TEE_AES_BLOCK_SIZE; 583d7fd8f87SJens Wiklander 584d7fd8f87SJens Wiklander memcpy(tmp, src + n * TEE_AES_BLOCK_SIZE, sizeof(tmp)); 5858f848cdbSJens Wiklander internal_aes_gcm_encrypt_block(state, ek, tmp, d); 586d7fd8f87SJens Wiklander } 587d7fd8f87SJens Wiklander } 588d7fd8f87SJens Wiklander } 589d7fd8f87SJens Wiklander 5908f848cdbSJens Wiklander void internal_aes_gcm_decrypt_block(struct internal_aes_gcm_state *state, 5918f848cdbSJens Wiklander const struct internal_aes_gcm_key *enc_key, 5928f848cdbSJens Wiklander const uint64_t src[2], uint64_t dst[2]) 593d7fd8f87SJens Wiklander { 594d7fd8f87SJens Wiklander void *buf_cryp = state->buf_cryp; 595d7fd8f87SJens Wiklander void *ctr = state->ctr; 596d7fd8f87SJens Wiklander 5978f848cdbSJens Wiklander crypto_aes_enc_block(enc_key->data, sizeof(enc_key->data), 5988f848cdbSJens Wiklander enc_key->rounds, ctr, buf_cryp); 599d7fd8f87SJens Wiklander internal_aes_gcm_inc_ctr(state); 600d7fd8f87SJens Wiklander 601d7fd8f87SJens Wiklander internal_aes_gcm_xor_block(buf_cryp, src); 602d7fd8f87SJens Wiklander internal_aes_gcm_ghash_update(state, src, NULL, 0); 603d7fd8f87SJens Wiklander memcpy(dst, buf_cryp, sizeof(state->buf_cryp)); 604d7fd8f87SJens Wiklander } 605d7fd8f87SJens Wiklander 606d7fd8f87SJens Wiklander static void decrypt_pl(struct internal_aes_gcm_state *state, 607d7fd8f87SJens Wiklander const struct internal_aes_gcm_key *ek, 608d7fd8f87SJens Wiklander const uint8_t *src, size_t num_blocks, uint8_t *dst) 609d7fd8f87SJens Wiklander { 610d7fd8f87SJens Wiklander size_t n = 0; 611d7fd8f87SJens Wiklander 612d7fd8f87SJens Wiklander if (ALIGNMENT_IS_OK(src, uint64_t)) { 6138f848cdbSJens Wiklander for (n = 0; n < num_blocks; n++) { 6148f848cdbSJens Wiklander const void *s = src + n * TEE_AES_BLOCK_SIZE; 6158f848cdbSJens Wiklander void *d = dst + n * TEE_AES_BLOCK_SIZE; 6168f848cdbSJens Wiklander 6178f848cdbSJens Wiklander internal_aes_gcm_decrypt_block(state, ek, s, d); 6188f848cdbSJens Wiklander } 619d7fd8f87SJens Wiklander } else { 620d7fd8f87SJens Wiklander for (n = 0; n < num_blocks; n++) { 621d7fd8f87SJens Wiklander uint64_t tmp[2] = { 0 }; 6228f848cdbSJens Wiklander void *d = dst + n * TEE_AES_BLOCK_SIZE; 623d7fd8f87SJens Wiklander 624d7fd8f87SJens Wiklander memcpy(tmp, src + n * TEE_AES_BLOCK_SIZE, sizeof(tmp)); 6258f848cdbSJens Wiklander internal_aes_gcm_decrypt_block(state, ek, tmp, d); 626d7fd8f87SJens Wiklander } 627d7fd8f87SJens Wiklander } 628d7fd8f87SJens Wiklander } 629d7fd8f87SJens Wiklander 630d7fd8f87SJens Wiklander void __weak 631d7fd8f87SJens Wiklander internal_aes_gcm_update_payload_blocks(struct internal_aes_gcm_state *state, 632b314df1fSJens Wiklander const struct internal_aes_gcm_key *ek, 633b314df1fSJens Wiklander TEE_OperationMode m, const void *src, 634b314df1fSJens Wiklander size_t num_blocks, void *dst) 635b314df1fSJens Wiklander { 636d7fd8f87SJens Wiklander assert(!state->buf_pos && num_blocks); 637b314df1fSJens Wiklander 638d7fd8f87SJens Wiklander if (m == TEE_MODE_ENCRYPT) 639d7fd8f87SJens Wiklander encrypt_pl(state, ek, src, num_blocks, dst); 640d7fd8f87SJens Wiklander else 641d7fd8f87SJens Wiklander decrypt_pl(state, ek, src, num_blocks, dst); 642b314df1fSJens Wiklander } 6431fca7e26SJens Wiklander #endif /*!CFG_CRYPTO_AES_GCM_FROM_CRYPTOLIB*/ 644