1fb7ef469SJerome Forissier // SPDX-License-Identifier: BSD-2-Clause 21fca7e26SJens Wiklander /* 3*b314df1fSJens Wiklander * Copyright (c) 2017-2020, Linaro Limited 41fca7e26SJens Wiklander */ 51fca7e26SJens Wiklander 661b4cd9cSJens Wiklander #include <assert.h> 71fca7e26SJens Wiklander #include <crypto/internal_aes-gcm.h> 8f1e9b21bSJens Wiklander #include <crypto/crypto_impl.h> 91fca7e26SJens Wiklander #include <io.h> 101fca7e26SJens Wiklander #include <string_ext.h> 111fca7e26SJens Wiklander #include <string.h> 121fca7e26SJens Wiklander #include <tee_api_types.h> 131fca7e26SJens Wiklander #include <types_ext.h> 141fca7e26SJens Wiklander #include <utee_defines.h> 151fca7e26SJens Wiklander #include <util.h> 161fca7e26SJens Wiklander 171fca7e26SJens Wiklander static void xor_buf(uint8_t *dst, const uint8_t *src, size_t len) 181fca7e26SJens Wiklander { 191fca7e26SJens Wiklander size_t n; 201fca7e26SJens Wiklander 211fca7e26SJens Wiklander for (n = 0; n < len; n++) 221fca7e26SJens Wiklander dst[n] ^= src[n]; 231fca7e26SJens Wiklander } 241fca7e26SJens Wiklander 251fca7e26SJens Wiklander 2654af8d67SJens Wiklander static void ghash_update_pad_zero(struct internal_aes_gcm_state *state, 271fca7e26SJens Wiklander const uint8_t *data, size_t len) 281fca7e26SJens Wiklander { 291fca7e26SJens Wiklander size_t n = len / TEE_AES_BLOCK_SIZE; 301fca7e26SJens Wiklander uint64_t block[2]; 311fca7e26SJens Wiklander 321fca7e26SJens Wiklander if (n) { 33b8c186b5SJens Wiklander if (internal_aes_gcm_ptr_is_block_aligned(data)) { 3454af8d67SJens Wiklander internal_aes_gcm_ghash_update(state, NULL, data, n); 351fca7e26SJens Wiklander } else { 361fca7e26SJens Wiklander size_t m; 371fca7e26SJens Wiklander 381fca7e26SJens Wiklander for (m = 0; m < n; m++) { 391fca7e26SJens Wiklander 401fca7e26SJens Wiklander memcpy(block, data + m * sizeof(block), 411fca7e26SJens Wiklander sizeof(block)); 4254af8d67SJens Wiklander internal_aes_gcm_ghash_update(state, NULL, 431fca7e26SJens Wiklander (void *)block, 1); 441fca7e26SJens Wiklander } 451fca7e26SJens Wiklander } 461fca7e26SJens Wiklander } 471fca7e26SJens Wiklander 481fca7e26SJens Wiklander if (len - n * TEE_AES_BLOCK_SIZE) { 491fca7e26SJens Wiklander memset(block, 0, sizeof(block)); 501fca7e26SJens Wiklander memcpy(block, data + n * TEE_AES_BLOCK_SIZE, 511fca7e26SJens Wiklander len - n * TEE_AES_BLOCK_SIZE); 5254af8d67SJens Wiklander internal_aes_gcm_ghash_update(state, block, NULL, 0); 531fca7e26SJens Wiklander } 541fca7e26SJens Wiklander } 551fca7e26SJens Wiklander 5654af8d67SJens Wiklander static void ghash_update_lengths(struct internal_aes_gcm_state *state, 5754af8d67SJens Wiklander uint32_t l1, uint32_t l2) 581fca7e26SJens Wiklander { 591fca7e26SJens Wiklander uint64_t len_fields[2] = { 601fca7e26SJens Wiklander TEE_U64_TO_BIG_ENDIAN(l1 * 8), 611fca7e26SJens Wiklander TEE_U64_TO_BIG_ENDIAN(l2 * 8) 621fca7e26SJens Wiklander }; 631fca7e26SJens Wiklander 641fca7e26SJens Wiklander COMPILE_TIME_ASSERT(sizeof(len_fields) == TEE_AES_BLOCK_SIZE); 6554af8d67SJens Wiklander internal_aes_gcm_ghash_update(state, (uint8_t *)len_fields, NULL, 0); 661fca7e26SJens Wiklander } 671fca7e26SJens Wiklander 6854af8d67SJens Wiklander static TEE_Result __gcm_init(struct internal_aes_gcm_state *state, 6954af8d67SJens Wiklander const struct internal_aes_gcm_key *ek, 7054af8d67SJens Wiklander TEE_OperationMode mode, const void *nonce, 711fca7e26SJens Wiklander size_t nonce_len, size_t tag_len) 721fca7e26SJens Wiklander { 7354af8d67SJens Wiklander COMPILE_TIME_ASSERT(sizeof(state->ctr) == TEE_AES_BLOCK_SIZE); 741fca7e26SJens Wiklander 7554af8d67SJens Wiklander if (tag_len > sizeof(state->buf_tag)) 761fca7e26SJens Wiklander return TEE_ERROR_BAD_PARAMETERS; 771fca7e26SJens Wiklander 7854af8d67SJens Wiklander memset(state, 0, sizeof(*state)); 791fca7e26SJens Wiklander 8054af8d67SJens Wiklander state->tag_len = tag_len; 8154af8d67SJens Wiklander internal_aes_gcm_set_key(state, ek); 821fca7e26SJens Wiklander 831fca7e26SJens Wiklander if (nonce_len == (96 / 8)) { 8454af8d67SJens Wiklander memcpy(state->ctr, nonce, nonce_len); 8554af8d67SJens Wiklander internal_aes_gcm_inc_ctr(state); 861fca7e26SJens Wiklander } else { 8754af8d67SJens Wiklander ghash_update_pad_zero(state, nonce, nonce_len); 8854af8d67SJens Wiklander ghash_update_lengths(state, 0, nonce_len); 891fca7e26SJens Wiklander 9054af8d67SJens Wiklander memcpy(state->ctr, state->hash_state, sizeof(state->ctr)); 9154af8d67SJens Wiklander memset(state->hash_state, 0, sizeof(state->hash_state)); 921fca7e26SJens Wiklander } 931fca7e26SJens Wiklander 9454af8d67SJens Wiklander internal_aes_gcm_encrypt_block(ek, state->ctr, state->buf_tag); 9554af8d67SJens Wiklander internal_aes_gcm_inc_ctr(state); 961fca7e26SJens Wiklander if (mode == TEE_MODE_ENCRYPT) { 971fca7e26SJens Wiklander /* 981fca7e26SJens Wiklander * Encryption uses the pre-encrypted xor-buffer to encrypt 991fca7e26SJens Wiklander * while decryption encrypts the xor-buffer when needed 1001fca7e26SJens Wiklander * instead. 1011fca7e26SJens Wiklander * 1021fca7e26SJens Wiklander * The reason for this is that the combined encryption and 1031fca7e26SJens Wiklander * ghash implementation does both operations intertwined. 1041fca7e26SJens Wiklander * In the decrypt case the xor-buffer is needed at the end 1051fca7e26SJens Wiklander * of processing each block, while the encryption case 1061fca7e26SJens Wiklander * needs xor-buffer before processing each block. 1071fca7e26SJens Wiklander * 1081fca7e26SJens Wiklander * In a pure software implementation we wouldn't have any 1091fca7e26SJens Wiklander * use for this kind of optimization, but since this 1101fca7e26SJens Wiklander * AES-GCM implementation is aimed at being combined with 1111fca7e26SJens Wiklander * accelerated routines it's more convenient to always have 1121fca7e26SJens Wiklander * this optimization activated. 1131fca7e26SJens Wiklander */ 11454af8d67SJens Wiklander internal_aes_gcm_encrypt_block(ek, state->ctr, state->buf_cryp); 11554af8d67SJens Wiklander internal_aes_gcm_inc_ctr(state); 1161fca7e26SJens Wiklander } 1171fca7e26SJens Wiklander 1181fca7e26SJens Wiklander return TEE_SUCCESS; 1191fca7e26SJens Wiklander } 1201fca7e26SJens Wiklander 12154af8d67SJens Wiklander TEE_Result internal_aes_gcm_init(struct internal_aes_gcm_ctx *ctx, 12254af8d67SJens Wiklander TEE_OperationMode mode, const void *key, 12354af8d67SJens Wiklander size_t key_len, const void *nonce, 12454af8d67SJens Wiklander size_t nonce_len, size_t tag_len) 12554af8d67SJens Wiklander { 12654af8d67SJens Wiklander TEE_Result res = internal_aes_gcm_expand_enc_key(key, key_len, 12754af8d67SJens Wiklander &ctx->key); 12854af8d67SJens Wiklander if (res) 12954af8d67SJens Wiklander return res; 13054af8d67SJens Wiklander 13154af8d67SJens Wiklander return __gcm_init(&ctx->state, &ctx->key, mode, nonce, nonce_len, 13254af8d67SJens Wiklander tag_len); 13354af8d67SJens Wiklander } 13454af8d67SJens Wiklander 135043411e5SJens Wiklander static TEE_Result __gcm_update_aad(struct internal_aes_gcm_state *state, 1361fca7e26SJens Wiklander const void *data, size_t len) 1371fca7e26SJens Wiklander { 1381fca7e26SJens Wiklander const uint8_t *d = data; 1391fca7e26SJens Wiklander size_t l = len; 1401fca7e26SJens Wiklander const uint8_t *head = NULL; 1411fca7e26SJens Wiklander size_t n; 1421fca7e26SJens Wiklander 14354af8d67SJens Wiklander if (state->payload_bytes) 1441fca7e26SJens Wiklander return TEE_ERROR_BAD_PARAMETERS; 1451fca7e26SJens Wiklander 14654af8d67SJens Wiklander state->aad_bytes += len; 1471fca7e26SJens Wiklander 1481fca7e26SJens Wiklander while (l) { 14954af8d67SJens Wiklander if (state->buf_pos || 15054af8d67SJens Wiklander !internal_aes_gcm_ptr_is_block_aligned(d) || 1511fca7e26SJens Wiklander l < TEE_AES_BLOCK_SIZE) { 15254af8d67SJens Wiklander n = MIN(TEE_AES_BLOCK_SIZE - state->buf_pos, l); 15354af8d67SJens Wiklander memcpy(state->buf_hash + state->buf_pos, d, n); 15454af8d67SJens Wiklander state->buf_pos += n; 1551fca7e26SJens Wiklander 15654af8d67SJens Wiklander if (state->buf_pos != TEE_AES_BLOCK_SIZE) 1571fca7e26SJens Wiklander return TEE_SUCCESS; 1581fca7e26SJens Wiklander 15954af8d67SJens Wiklander state->buf_pos = 0; 16054af8d67SJens Wiklander head = state->buf_hash; 1611fca7e26SJens Wiklander d += n; 1621fca7e26SJens Wiklander l -= n; 1631fca7e26SJens Wiklander } 1641fca7e26SJens Wiklander 165b8c186b5SJens Wiklander if (internal_aes_gcm_ptr_is_block_aligned(d)) 1661fca7e26SJens Wiklander n = l / TEE_AES_BLOCK_SIZE; 1671fca7e26SJens Wiklander else 1681fca7e26SJens Wiklander n = 0; 1691fca7e26SJens Wiklander 17054af8d67SJens Wiklander internal_aes_gcm_ghash_update(state, head, d, n); 1711fca7e26SJens Wiklander l -= n * TEE_AES_BLOCK_SIZE; 1721fca7e26SJens Wiklander d += n * TEE_AES_BLOCK_SIZE; 1731fca7e26SJens Wiklander } 1741fca7e26SJens Wiklander 1751fca7e26SJens Wiklander return TEE_SUCCESS; 1761fca7e26SJens Wiklander } 1771fca7e26SJens Wiklander 178043411e5SJens Wiklander TEE_Result internal_aes_gcm_update_aad(struct internal_aes_gcm_ctx *ctx, 179043411e5SJens Wiklander const void *data, size_t len) 1801fca7e26SJens Wiklander { 181043411e5SJens Wiklander return __gcm_update_aad(&ctx->state, data, len); 182043411e5SJens Wiklander } 183043411e5SJens Wiklander 184043411e5SJens Wiklander static TEE_Result 185043411e5SJens Wiklander __gcm_update_payload(struct internal_aes_gcm_state *state, 186043411e5SJens Wiklander const struct internal_aes_gcm_key *ek, 187043411e5SJens Wiklander TEE_OperationMode mode, const void *src, 188043411e5SJens Wiklander size_t len, void *dst) 189043411e5SJens Wiklander { 1901fca7e26SJens Wiklander size_t n; 1911fca7e26SJens Wiklander const uint8_t *s = src; 1921fca7e26SJens Wiklander uint8_t *d = dst; 1931fca7e26SJens Wiklander size_t l = len; 1941fca7e26SJens Wiklander 19554af8d67SJens Wiklander if (!state->payload_bytes && state->buf_pos) { 1961fca7e26SJens Wiklander /* AAD part done, finish up the last bits. */ 19754af8d67SJens Wiklander memset(state->buf_hash + state->buf_pos, 0, 19854af8d67SJens Wiklander TEE_AES_BLOCK_SIZE - state->buf_pos); 19954af8d67SJens Wiklander internal_aes_gcm_ghash_update(state, state->buf_hash, NULL, 0); 20054af8d67SJens Wiklander state->buf_pos = 0; 2011fca7e26SJens Wiklander } 2021fca7e26SJens Wiklander 20354af8d67SJens Wiklander state->payload_bytes += len; 2041fca7e26SJens Wiklander 2051fca7e26SJens Wiklander while (l) { 20654af8d67SJens Wiklander if (state->buf_pos || 20754af8d67SJens Wiklander !internal_aes_gcm_ptr_is_block_aligned(s) || 208b8c186b5SJens Wiklander !internal_aes_gcm_ptr_is_block_aligned(d) || 209b8c186b5SJens Wiklander l < TEE_AES_BLOCK_SIZE) { 21054af8d67SJens Wiklander n = MIN(TEE_AES_BLOCK_SIZE - state->buf_pos, l); 2111fca7e26SJens Wiklander 21254af8d67SJens Wiklander if (!state->buf_pos && mode == TEE_MODE_DECRYPT) { 21354af8d67SJens Wiklander internal_aes_gcm_encrypt_block(ek, state->ctr, 21454af8d67SJens Wiklander state->buf_cryp); 2151fca7e26SJens Wiklander } 2161fca7e26SJens Wiklander 21754af8d67SJens Wiklander xor_buf(state->buf_cryp + state->buf_pos, s, n); 21854af8d67SJens Wiklander memcpy(d, state->buf_cryp + state->buf_pos, n); 2191fca7e26SJens Wiklander if (mode == TEE_MODE_ENCRYPT) 22054af8d67SJens Wiklander memcpy(state->buf_hash + state->buf_pos, 22154af8d67SJens Wiklander state->buf_cryp + state->buf_pos, n); 2221fca7e26SJens Wiklander else 22354af8d67SJens Wiklander memcpy(state->buf_hash + state->buf_pos, s, n); 2241fca7e26SJens Wiklander 22554af8d67SJens Wiklander state->buf_pos += n; 2261fca7e26SJens Wiklander 22754af8d67SJens Wiklander if (state->buf_pos != TEE_AES_BLOCK_SIZE) 2281fca7e26SJens Wiklander return TEE_SUCCESS; 2291fca7e26SJens Wiklander 23054af8d67SJens Wiklander internal_aes_gcm_ghash_update(state, state->buf_hash, 2311fca7e26SJens Wiklander NULL, 0); 23254af8d67SJens Wiklander state->buf_pos = 0; 2331fca7e26SJens Wiklander d += n; 2341fca7e26SJens Wiklander s += n; 2351fca7e26SJens Wiklander l -= n; 2361fca7e26SJens Wiklander 2371fca7e26SJens Wiklander if (mode == TEE_MODE_ENCRYPT) 23854af8d67SJens Wiklander internal_aes_gcm_encrypt_block(ek, state->ctr, 23954af8d67SJens Wiklander state->buf_cryp); 24054af8d67SJens Wiklander internal_aes_gcm_inc_ctr(state); 2411fca7e26SJens Wiklander } else { 2421fca7e26SJens Wiklander n = l / TEE_AES_BLOCK_SIZE; 24354af8d67SJens Wiklander internal_aes_gcm_update_payload_block_aligned(state, ek, 24454af8d67SJens Wiklander mode, 2451fca7e26SJens Wiklander s, n, d); 2461fca7e26SJens Wiklander s += n * TEE_AES_BLOCK_SIZE; 2471fca7e26SJens Wiklander d += n * TEE_AES_BLOCK_SIZE; 2481fca7e26SJens Wiklander l -= n * TEE_AES_BLOCK_SIZE; 2491fca7e26SJens Wiklander } 2501fca7e26SJens Wiklander } 2511fca7e26SJens Wiklander 2521fca7e26SJens Wiklander return TEE_SUCCESS; 2531fca7e26SJens Wiklander } 2541fca7e26SJens Wiklander 255043411e5SJens Wiklander TEE_Result internal_aes_gcm_update_payload(struct internal_aes_gcm_ctx *ctx, 256043411e5SJens Wiklander TEE_OperationMode mode, 257043411e5SJens Wiklander const void *src, size_t len, 258043411e5SJens Wiklander void *dst) 259043411e5SJens Wiklander { 260043411e5SJens Wiklander return __gcm_update_payload(&ctx->state, &ctx->key, mode, src, len, 261043411e5SJens Wiklander dst); 262043411e5SJens Wiklander } 263043411e5SJens Wiklander 264043411e5SJens Wiklander static TEE_Result operation_final(struct internal_aes_gcm_state *state, 265043411e5SJens Wiklander const struct internal_aes_gcm_key *enc_key, 2661fca7e26SJens Wiklander TEE_OperationMode m, const uint8_t *src, 2671fca7e26SJens Wiklander size_t len, uint8_t *dst) 2681fca7e26SJens Wiklander { 2691fca7e26SJens Wiklander TEE_Result res; 2701fca7e26SJens Wiklander 271043411e5SJens Wiklander res = __gcm_update_payload(state, enc_key, m, src, len, dst); 2721fca7e26SJens Wiklander if (res) 2731fca7e26SJens Wiklander return res; 2741fca7e26SJens Wiklander 27554af8d67SJens Wiklander if (state->buf_pos) { 27654af8d67SJens Wiklander memset(state->buf_hash + state->buf_pos, 0, 27754af8d67SJens Wiklander sizeof(state->buf_hash) - state->buf_pos); 27854af8d67SJens Wiklander internal_aes_gcm_ghash_update(state, state->buf_hash, NULL, 0); 2791fca7e26SJens Wiklander } 2801fca7e26SJens Wiklander 28154af8d67SJens Wiklander ghash_update_lengths(state, state->aad_bytes, state->payload_bytes); 2821fca7e26SJens Wiklander /* buf_tag was filled in with the first counter block aes_gcm_init() */ 28354af8d67SJens Wiklander xor_buf(state->buf_tag, state->hash_state, state->tag_len); 2841fca7e26SJens Wiklander 2851fca7e26SJens Wiklander return TEE_SUCCESS; 2861fca7e26SJens Wiklander } 2871fca7e26SJens Wiklander 288043411e5SJens Wiklander static TEE_Result __gcm_enc_final(struct internal_aes_gcm_state *state, 289043411e5SJens Wiklander const struct internal_aes_gcm_key *enc_key, 2901fca7e26SJens Wiklander const void *src, size_t len, void *dst, 2911fca7e26SJens Wiklander void *tag, size_t *tag_len) 2921fca7e26SJens Wiklander { 2931fca7e26SJens Wiklander TEE_Result res; 2941fca7e26SJens Wiklander 29554af8d67SJens Wiklander if (*tag_len < state->tag_len) 2961fca7e26SJens Wiklander return TEE_ERROR_SHORT_BUFFER; 2971fca7e26SJens Wiklander 298043411e5SJens Wiklander res = operation_final(state, enc_key, TEE_MODE_ENCRYPT, src, len, dst); 2991fca7e26SJens Wiklander if (res) 3001fca7e26SJens Wiklander return res; 3011fca7e26SJens Wiklander 30254af8d67SJens Wiklander memcpy(tag, state->buf_tag, state->tag_len); 30354af8d67SJens Wiklander *tag_len = state->tag_len; 3041fca7e26SJens Wiklander 3051fca7e26SJens Wiklander return TEE_SUCCESS; 3061fca7e26SJens Wiklander } 3071fca7e26SJens Wiklander 308043411e5SJens Wiklander TEE_Result internal_aes_gcm_enc_final(struct internal_aes_gcm_ctx *ctx, 309043411e5SJens Wiklander const void *src, size_t len, void *dst, 310043411e5SJens Wiklander void *tag, size_t *tag_len) 311043411e5SJens Wiklander { 312043411e5SJens Wiklander return __gcm_enc_final(&ctx->state, &ctx->key, src, len, dst, tag, 313043411e5SJens Wiklander tag_len); 314043411e5SJens Wiklander } 315043411e5SJens Wiklander 316043411e5SJens Wiklander static TEE_Result __gcm_dec_final(struct internal_aes_gcm_state *state, 317043411e5SJens Wiklander const struct internal_aes_gcm_key *enc_key, 3181fca7e26SJens Wiklander const void *src, size_t len, void *dst, 3191fca7e26SJens Wiklander const void *tag, size_t tag_len) 3201fca7e26SJens Wiklander { 3211fca7e26SJens Wiklander TEE_Result res; 3221fca7e26SJens Wiklander 32354af8d67SJens Wiklander if (tag_len != state->tag_len) 3241fca7e26SJens Wiklander return TEE_ERROR_MAC_INVALID; 3251fca7e26SJens Wiklander 326043411e5SJens Wiklander res = operation_final(state, enc_key, TEE_MODE_DECRYPT, src, len, dst); 3271fca7e26SJens Wiklander if (res) 3281fca7e26SJens Wiklander return res; 3291fca7e26SJens Wiklander 33048e10604SJerome Forissier if (consttime_memcmp(state->buf_tag, tag, tag_len)) 3311fca7e26SJens Wiklander return TEE_ERROR_MAC_INVALID; 3321fca7e26SJens Wiklander 3331fca7e26SJens Wiklander return TEE_SUCCESS; 3341fca7e26SJens Wiklander } 3351fca7e26SJens Wiklander 336043411e5SJens Wiklander TEE_Result internal_aes_gcm_dec_final(struct internal_aes_gcm_ctx *ctx, 337043411e5SJens Wiklander const void *src, size_t len, void *dst, 338043411e5SJens Wiklander const void *tag, size_t tag_len) 339043411e5SJens Wiklander { 340043411e5SJens Wiklander return __gcm_dec_final(&ctx->state, &ctx->key, src, len, dst, tag, 341043411e5SJens Wiklander tag_len); 342043411e5SJens Wiklander } 343043411e5SJens Wiklander 34454af8d67SJens Wiklander void internal_aes_gcm_inc_ctr(struct internal_aes_gcm_state *state) 3451fca7e26SJens Wiklander { 3461fca7e26SJens Wiklander uint64_t c; 3471fca7e26SJens Wiklander 34854af8d67SJens Wiklander c = TEE_U64_FROM_BIG_ENDIAN(state->ctr[1]) + 1; 34954af8d67SJens Wiklander state->ctr[1] = TEE_U64_TO_BIG_ENDIAN(c); 3501fca7e26SJens Wiklander if (!c) { 35154af8d67SJens Wiklander c = TEE_U64_FROM_BIG_ENDIAN(state->ctr[0]) + 1; 35254af8d67SJens Wiklander state->ctr[0] = TEE_U64_TO_BIG_ENDIAN(c); 3531fca7e26SJens Wiklander } 3541fca7e26SJens Wiklander } 3551fca7e26SJens Wiklander 356043411e5SJens Wiklander TEE_Result internal_aes_gcm_enc(const struct internal_aes_gcm_key *enc_key, 357043411e5SJens Wiklander const void *nonce, size_t nonce_len, 358043411e5SJens Wiklander const void *aad, size_t aad_len, 359043411e5SJens Wiklander const void *src, size_t len, void *dst, 360043411e5SJens Wiklander void *tag, size_t *tag_len) 361043411e5SJens Wiklander { 362043411e5SJens Wiklander TEE_Result res; 363043411e5SJens Wiklander struct internal_aes_gcm_state state; 364043411e5SJens Wiklander 365043411e5SJens Wiklander res = __gcm_init(&state, enc_key, TEE_MODE_ENCRYPT, nonce, nonce_len, 366043411e5SJens Wiklander *tag_len); 367043411e5SJens Wiklander if (res) 368043411e5SJens Wiklander return res; 369043411e5SJens Wiklander 370043411e5SJens Wiklander if (aad) { 371043411e5SJens Wiklander res = __gcm_update_aad(&state, aad, aad_len); 372043411e5SJens Wiklander if (res) 373043411e5SJens Wiklander return res; 374043411e5SJens Wiklander } 375043411e5SJens Wiklander 376043411e5SJens Wiklander return __gcm_enc_final(&state, enc_key, src, len, dst, tag, tag_len); 377043411e5SJens Wiklander } 378043411e5SJens Wiklander 379043411e5SJens Wiklander TEE_Result internal_aes_gcm_dec(const struct internal_aes_gcm_key *enc_key, 380043411e5SJens Wiklander const void *nonce, size_t nonce_len, 381043411e5SJens Wiklander const void *aad, size_t aad_len, 382043411e5SJens Wiklander const void *src, size_t len, void *dst, 383043411e5SJens Wiklander const void *tag, size_t tag_len) 384043411e5SJens Wiklander { 385043411e5SJens Wiklander TEE_Result res; 386043411e5SJens Wiklander struct internal_aes_gcm_state state; 387043411e5SJens Wiklander 388043411e5SJens Wiklander res = __gcm_init(&state, enc_key, TEE_MODE_DECRYPT, nonce, nonce_len, 389043411e5SJens Wiklander tag_len); 390043411e5SJens Wiklander if (res) 391043411e5SJens Wiklander return res; 392043411e5SJens Wiklander 393043411e5SJens Wiklander if (aad) { 394043411e5SJens Wiklander res = __gcm_update_aad(&state, aad, aad_len); 395043411e5SJens Wiklander if (res) 396043411e5SJens Wiklander return res; 397043411e5SJens Wiklander } 398043411e5SJens Wiklander 399043411e5SJens Wiklander return __gcm_dec_final(&state, enc_key, src, len, dst, tag, tag_len); 400043411e5SJens Wiklander } 401043411e5SJens Wiklander 402043411e5SJens Wiklander 4031fca7e26SJens Wiklander #ifndef CFG_CRYPTO_AES_GCM_FROM_CRYPTOLIB 404d7ac7d0fSJens Wiklander #include <stdlib.h> 405f1e9b21bSJens Wiklander #include <crypto/crypto.h> 4061fca7e26SJens Wiklander 407f1e9b21bSJens Wiklander struct aes_gcm_ctx { 408f1e9b21bSJens Wiklander struct crypto_authenc_ctx aec; 409f1e9b21bSJens Wiklander struct internal_aes_gcm_ctx ctx; 410f1e9b21bSJens Wiklander }; 411f1e9b21bSJens Wiklander 412f1e9b21bSJens Wiklander static const struct crypto_authenc_ops aes_gcm_ops; 413f1e9b21bSJens Wiklander 414f1e9b21bSJens Wiklander static struct aes_gcm_ctx * 415f1e9b21bSJens Wiklander to_aes_gcm_ctx(struct crypto_authenc_ctx *aec) 4161fca7e26SJens Wiklander { 417f1e9b21bSJens Wiklander assert(aec->ops == &aes_gcm_ops); 418f1e9b21bSJens Wiklander 419f1e9b21bSJens Wiklander return container_of(aec, struct aes_gcm_ctx, aec); 420f1e9b21bSJens Wiklander } 421f1e9b21bSJens Wiklander 422f1e9b21bSJens Wiklander TEE_Result crypto_aes_gcm_alloc_ctx(struct crypto_authenc_ctx **ctx_ret) 423f1e9b21bSJens Wiklander { 424f1e9b21bSJens Wiklander struct aes_gcm_ctx *ctx = calloc(1, sizeof(*ctx)); 425d7ac7d0fSJens Wiklander 426d7ac7d0fSJens Wiklander if (!ctx) 427d7ac7d0fSJens Wiklander return TEE_ERROR_OUT_OF_MEMORY; 428f1e9b21bSJens Wiklander ctx->aec.ops = &aes_gcm_ops; 429d7ac7d0fSJens Wiklander 430f1e9b21bSJens Wiklander *ctx_ret = &ctx->aec; 431f1e9b21bSJens Wiklander 432d7ac7d0fSJens Wiklander return TEE_SUCCESS; 433d7ac7d0fSJens Wiklander } 434d7ac7d0fSJens Wiklander 435f1e9b21bSJens Wiklander static void aes_gcm_free_ctx(struct crypto_authenc_ctx *aec) 436d7ac7d0fSJens Wiklander { 437f1e9b21bSJens Wiklander free(to_aes_gcm_ctx(aec)); 438d7ac7d0fSJens Wiklander } 439d7ac7d0fSJens Wiklander 440f1e9b21bSJens Wiklander static void aes_gcm_copy_state(struct crypto_authenc_ctx *dst_ctx, 441f1e9b21bSJens Wiklander struct crypto_authenc_ctx *src_ctx) 442d7ac7d0fSJens Wiklander { 443f1e9b21bSJens Wiklander to_aes_gcm_ctx(dst_ctx)->ctx = to_aes_gcm_ctx(src_ctx)->ctx; 4441fca7e26SJens Wiklander } 4451fca7e26SJens Wiklander 446f1e9b21bSJens Wiklander static TEE_Result aes_gcm_init(struct crypto_authenc_ctx *aec, 447f1e9b21bSJens Wiklander TEE_OperationMode mode, 4481fca7e26SJens Wiklander const uint8_t *key, size_t key_len, 4491fca7e26SJens Wiklander const uint8_t *nonce, size_t nonce_len, 450f1e9b21bSJens Wiklander size_t tag_len, size_t aad_len __unused, 451f1e9b21bSJens Wiklander size_t payload_len __unused) 4521fca7e26SJens Wiklander { 453f1e9b21bSJens Wiklander return internal_aes_gcm_init(&to_aes_gcm_ctx(aec)->ctx, mode, key, 454f1e9b21bSJens Wiklander key_len, nonce, nonce_len, tag_len); 4551fca7e26SJens Wiklander } 4561fca7e26SJens Wiklander 457f1e9b21bSJens Wiklander static TEE_Result aes_gcm_update_aad(struct crypto_authenc_ctx *aec, 458f1e9b21bSJens Wiklander const uint8_t *data, size_t len) 4591fca7e26SJens Wiklander { 460f1e9b21bSJens Wiklander return internal_aes_gcm_update_aad(&to_aes_gcm_ctx(aec)->ctx, data, 461f1e9b21bSJens Wiklander len); 4621fca7e26SJens Wiklander } 4631fca7e26SJens Wiklander 464f1e9b21bSJens Wiklander static TEE_Result aes_gcm_update_payload(struct crypto_authenc_ctx *aec, 465f1e9b21bSJens Wiklander TEE_OperationMode m, 4661fca7e26SJens Wiklander const uint8_t *src, size_t len, 4671fca7e26SJens Wiklander uint8_t *dst) 4681fca7e26SJens Wiklander { 469f1e9b21bSJens Wiklander return internal_aes_gcm_update_payload(&to_aes_gcm_ctx(aec)->ctx, 470f1e9b21bSJens Wiklander m, src, len, dst); 4711fca7e26SJens Wiklander } 4721fca7e26SJens Wiklander 473f1e9b21bSJens Wiklander static TEE_Result aes_gcm_enc_final(struct crypto_authenc_ctx *aec, 474f1e9b21bSJens Wiklander const uint8_t *src, size_t len, 4751fca7e26SJens Wiklander uint8_t *dst, uint8_t *tag, size_t *tag_len) 4761fca7e26SJens Wiklander { 477f1e9b21bSJens Wiklander return internal_aes_gcm_enc_final(&to_aes_gcm_ctx(aec)->ctx, src, len, 478f1e9b21bSJens Wiklander dst, tag, tag_len); 4791fca7e26SJens Wiklander } 4801fca7e26SJens Wiklander 481f1e9b21bSJens Wiklander static TEE_Result aes_gcm_dec_final(struct crypto_authenc_ctx *aec, 482f1e9b21bSJens Wiklander const uint8_t *src, size_t len, 4831fca7e26SJens Wiklander uint8_t *dst, const uint8_t *tag, 4841fca7e26SJens Wiklander size_t tag_len) 4851fca7e26SJens Wiklander { 486f1e9b21bSJens Wiklander return internal_aes_gcm_dec_final(&to_aes_gcm_ctx(aec)->ctx, src, len, 487f1e9b21bSJens Wiklander dst, tag, tag_len); 4881fca7e26SJens Wiklander } 4891fca7e26SJens Wiklander 490f1e9b21bSJens Wiklander static void aes_gcm_final(struct crypto_authenc_ctx *aec __unused) 4911fca7e26SJens Wiklander { 4921fca7e26SJens Wiklander } 493f1e9b21bSJens Wiklander 494f1e9b21bSJens Wiklander static const struct crypto_authenc_ops aes_gcm_ops = { 495f1e9b21bSJens Wiklander .init = aes_gcm_init, 496f1e9b21bSJens Wiklander .update_aad = aes_gcm_update_aad, 497f1e9b21bSJens Wiklander .update_payload = aes_gcm_update_payload, 498f1e9b21bSJens Wiklander .enc_final = aes_gcm_enc_final, 499f1e9b21bSJens Wiklander .dec_final = aes_gcm_dec_final, 500f1e9b21bSJens Wiklander .final = aes_gcm_final, 501f1e9b21bSJens Wiklander .free_ctx = aes_gcm_free_ctx, 502f1e9b21bSJens Wiklander .copy_state = aes_gcm_copy_state, 503f1e9b21bSJens Wiklander }; 504*b314df1fSJens Wiklander 505*b314df1fSJens Wiklander /* 506*b314df1fSJens Wiklander * internal_aes_gcm_gfmul() is based on ghash_gfmul() from 507*b314df1fSJens Wiklander * https://github.com/openbsd/src/blob/master/sys/crypto/gmac.c 508*b314df1fSJens Wiklander */ 509*b314df1fSJens Wiklander void internal_aes_gcm_gfmul(const uint64_t X[2], const uint64_t Y[2], 510*b314df1fSJens Wiklander uint64_t product[2]) 511*b314df1fSJens Wiklander { 512*b314df1fSJens Wiklander uint64_t y[2] = { 0 }; 513*b314df1fSJens Wiklander uint64_t z[2] = { 0 }; 514*b314df1fSJens Wiklander const uint8_t *x = (const uint8_t *)X; 515*b314df1fSJens Wiklander uint32_t mul = 0; 516*b314df1fSJens Wiklander size_t n = 0; 517*b314df1fSJens Wiklander 518*b314df1fSJens Wiklander y[0] = TEE_U64_FROM_BIG_ENDIAN(Y[0]); 519*b314df1fSJens Wiklander y[1] = TEE_U64_FROM_BIG_ENDIAN(Y[1]); 520*b314df1fSJens Wiklander 521*b314df1fSJens Wiklander for (n = 0; n < TEE_AES_BLOCK_SIZE * 8; n++) { 522*b314df1fSJens Wiklander /* update Z */ 523*b314df1fSJens Wiklander if (x[n >> 3] & (1 << (~n & 7))) 524*b314df1fSJens Wiklander internal_aes_gcm_xor_block(z, y); 525*b314df1fSJens Wiklander 526*b314df1fSJens Wiklander /* update Y */ 527*b314df1fSJens Wiklander mul = y[1] & 1; 528*b314df1fSJens Wiklander y[1] = (y[0] << 63) | (y[1] >> 1); 529*b314df1fSJens Wiklander y[0] = (y[0] >> 1) ^ (0xe100000000000000 * mul); 530*b314df1fSJens Wiklander } 531*b314df1fSJens Wiklander 532*b314df1fSJens Wiklander product[0] = TEE_U64_TO_BIG_ENDIAN(z[0]); 533*b314df1fSJens Wiklander product[1] = TEE_U64_TO_BIG_ENDIAN(z[1]); 534*b314df1fSJens Wiklander } 535*b314df1fSJens Wiklander 536*b314df1fSJens Wiklander void __weak internal_aes_gcm_update_payload_block_aligned( 537*b314df1fSJens Wiklander struct internal_aes_gcm_state *state, 538*b314df1fSJens Wiklander const struct internal_aes_gcm_key *ek, 539*b314df1fSJens Wiklander TEE_OperationMode m, const void *src, 540*b314df1fSJens Wiklander size_t num_blocks, void *dst) 541*b314df1fSJens Wiklander { 542*b314df1fSJens Wiklander size_t n; 543*b314df1fSJens Wiklander const uint8_t *s = src; 544*b314df1fSJens Wiklander uint8_t *d = dst; 545*b314df1fSJens Wiklander void *ctr = state->ctr; 546*b314df1fSJens Wiklander void *buf_cryp = state->buf_cryp; 547*b314df1fSJens Wiklander 548*b314df1fSJens Wiklander assert(!state->buf_pos && num_blocks && 549*b314df1fSJens Wiklander internal_aes_gcm_ptr_is_block_aligned(s) && 550*b314df1fSJens Wiklander internal_aes_gcm_ptr_is_block_aligned(d)); 551*b314df1fSJens Wiklander 552*b314df1fSJens Wiklander for (n = 0; n < num_blocks; n++) { 553*b314df1fSJens Wiklander if (m == TEE_MODE_ENCRYPT) { 554*b314df1fSJens Wiklander internal_aes_gcm_xor_block(buf_cryp, s); 555*b314df1fSJens Wiklander internal_aes_gcm_ghash_update(state, buf_cryp, NULL, 0); 556*b314df1fSJens Wiklander memcpy(d, buf_cryp, sizeof(state->buf_cryp)); 557*b314df1fSJens Wiklander 558*b314df1fSJens Wiklander internal_aes_gcm_encrypt_block(ek, ctr, buf_cryp); 559*b314df1fSJens Wiklander internal_aes_gcm_inc_ctr(state); 560*b314df1fSJens Wiklander } else { 561*b314df1fSJens Wiklander internal_aes_gcm_encrypt_block(ek, ctr, buf_cryp); 562*b314df1fSJens Wiklander 563*b314df1fSJens Wiklander internal_aes_gcm_xor_block(buf_cryp, s); 564*b314df1fSJens Wiklander internal_aes_gcm_ghash_update(state, s, NULL, 0); 565*b314df1fSJens Wiklander memcpy(d, buf_cryp, sizeof(state->buf_cryp)); 566*b314df1fSJens Wiklander 567*b314df1fSJens Wiklander internal_aes_gcm_inc_ctr(state); 568*b314df1fSJens Wiklander } 569*b314df1fSJens Wiklander s += TEE_AES_BLOCK_SIZE; 570*b314df1fSJens Wiklander d += TEE_AES_BLOCK_SIZE; 571*b314df1fSJens Wiklander } 572*b314df1fSJens Wiklander } 5731fca7e26SJens Wiklander #endif /*!CFG_CRYPTO_AES_GCM_FROM_CRYPTOLIB*/ 574