1 /* 2 * Copyright (c) 2017, Linaro Limited 3 * All rights reserved. 4 * 5 * SPDX-License-Identifier: BSD-2-Clause 6 */ 7 8 #include <crypto/internal_aes-gcm.h> 9 #include <crypto/ghash-ce-core.h> 10 #include <io.h> 11 #include <kernel/panic.h> 12 #include <kernel/thread.h> 13 #include <tomcrypt.h> 14 #include <types_ext.h> 15 16 TEE_Result internal_aes_gcm_set_key(struct internal_aes_gcm_ctx *ctx, 17 const void *key, size_t key_len) 18 { 19 uint64_t k[2]; 20 uint64_t a; 21 uint64_t b; 22 23 if (aes_setup(key, key_len, 0, &ctx->skey)) 24 return TEE_ERROR_BAD_PARAMETERS; 25 26 internal_aes_gcm_encrypt_block(ctx, ctx->ctr, ctx->hash_subkey); 27 28 /* Store hash key in little endian and multiply by 'x' */ 29 b = get_be64(ctx->hash_subkey); 30 a = get_be64(ctx->hash_subkey + 8); 31 k[0] = (a << 1) | (b >> 63); 32 k[1] = (b << 1) | (a >> 63); 33 if (b >> 63) 34 k[1] ^= 0xc200000000000000UL; 35 36 memcpy(ctx->hash_subkey, k, TEE_AES_BLOCK_SIZE); 37 return TEE_SUCCESS; 38 } 39 40 static void get_dg(uint64_t dg[2], struct internal_aes_gcm_ctx *ctx) 41 { 42 dg[1] = get_be64(ctx->hash_state); 43 dg[0] = get_be64(ctx->hash_state + 8); 44 } 45 46 static void put_dg(struct internal_aes_gcm_ctx *ctx, uint64_t dg[2]) 47 { 48 put_be64(ctx->hash_state, dg[1]); 49 put_be64(ctx->hash_state + 8, dg[0]); 50 } 51 52 void internal_aes_gcm_ghash_update(struct internal_aes_gcm_ctx *ctx, 53 const void *head, const void *data, 54 size_t num_blocks) 55 { 56 uint32_t vfp_state; 57 uint64_t dg[2]; 58 uint64_t *k; 59 60 get_dg(dg, ctx); 61 62 k = (void *)ctx->hash_subkey; 63 64 vfp_state = thread_kernel_enable_vfp(); 65 66 #ifdef CFG_HWSUPP_PMULL 67 pmull_ghash_update_p64(num_blocks, dg, data, k, head); 68 #else 69 pmull_ghash_update_p8(num_blocks, dg, data, k, head); 70 #endif 71 thread_kernel_disable_vfp(vfp_state); 72 73 put_dg(ctx, dg); 74 } 75 76 #ifdef ARM64 77 void internal_aes_gcm_encrypt_block(struct internal_aes_gcm_ctx *ctx, 78 const void *src, void *dst) 79 { 80 uint32_t vfp_state; 81 void *enc_key = ctx->skey.rijndael.eK; 82 size_t rounds = ctx->skey.rijndael.Nr; 83 84 vfp_state = thread_kernel_enable_vfp(); 85 86 pmull_gcm_load_round_keys(enc_key, rounds); 87 pmull_gcm_encrypt_block(dst, src, rounds); 88 89 thread_kernel_disable_vfp(vfp_state); 90 } 91 92 void 93 internal_aes_gcm_update_payload_block_aligned(struct internal_aes_gcm_ctx *ctx, 94 TEE_OperationMode m, 95 const void *src, 96 size_t num_blocks, void *dst) 97 { 98 uint32_t vfp_state; 99 uint64_t dg[2]; 100 uint64_t *k; 101 void *ctr = ctx->ctr; 102 void *enc_key = ctx->skey.rijndael.eK; 103 size_t rounds = ctx->skey.rijndael.Nr; 104 105 get_dg(dg, ctx); 106 k = (void *)ctx->hash_subkey; 107 108 vfp_state = thread_kernel_enable_vfp(); 109 110 pmull_gcm_load_round_keys(enc_key, rounds); 111 112 if (m == TEE_MODE_ENCRYPT) 113 pmull_gcm_encrypt(num_blocks, dg, dst, src, k, ctr, rounds, 114 ctx->buf_cryp); 115 else 116 pmull_gcm_decrypt(num_blocks, dg, dst, src, k, ctr, rounds); 117 118 thread_kernel_disable_vfp(vfp_state); 119 120 put_dg(ctx, dg); 121 } 122 #endif /*ARM64*/ 123