xref: /optee_os/core/arch/arm/crypto/aes-gcm-ce.c (revision 102986213c9fb99b332df89c1670e00fa337c5c8)
1fb7ef469SJerome Forissier // SPDX-License-Identifier: BSD-2-Clause
21fca7e26SJens Wiklander /*
3b314df1fSJens Wiklander  * Copyright (c) 2017-2020, Linaro Limited
41fca7e26SJens Wiklander  */
51fca7e26SJens Wiklander 
68a15c688SJens Wiklander #include <assert.h>
7b314df1fSJens Wiklander #include <crypto/crypto_accel.h>
84f6d7160SJens Wiklander #include <crypto/crypto.h>
91fca7e26SJens Wiklander #include <crypto/ghash-ce-core.h>
10b314df1fSJens Wiklander #include <crypto/internal_aes-gcm.h>
111fca7e26SJens Wiklander #include <io.h>
121fca7e26SJens Wiklander #include <kernel/panic.h>
131fca7e26SJens Wiklander #include <kernel/thread.h>
14d1f66029SEdison Ai #include <string.h>
151fca7e26SJens Wiklander #include <types_ext.h>
161fca7e26SJens Wiklander 
179cd2e73bSJens Wiklander #include "aes_armv8a_ce.h"
189cd2e73bSJens Wiklander 
get_be_block(void * dst,const void * src)19f6cbe5daSJens Wiklander static void get_be_block(void *dst, const void *src)
20f6cbe5daSJens Wiklander {
21f6cbe5daSJens Wiklander 	uint64_t *d = dst;
22f6cbe5daSJens Wiklander 
23f6cbe5daSJens Wiklander 	d[1] = get_be64(src);
24f6cbe5daSJens Wiklander 	d[0] = get_be64((const uint8_t *)src + 8);
25f6cbe5daSJens Wiklander }
26f6cbe5daSJens Wiklander 
put_be_block(void * dst,const void * src)27f6cbe5daSJens Wiklander static void put_be_block(void *dst, const void *src)
28f6cbe5daSJens Wiklander {
29f6cbe5daSJens Wiklander 	const uint64_t *s = src;
30f6cbe5daSJens Wiklander 
31f6cbe5daSJens Wiklander 	put_be64(dst, s[1]);
32f6cbe5daSJens Wiklander 	put_be64((uint8_t *)dst + 8, s[0]);
33f6cbe5daSJens Wiklander }
34f6cbe5daSJens Wiklander 
ghash_reflect(uint64_t h[2],const uint64_t k[2])358a15c688SJens Wiklander static void ghash_reflect(uint64_t h[2], const uint64_t k[2])
368a15c688SJens Wiklander {
378a15c688SJens Wiklander 	uint64_t b = get_be64(k);
388a15c688SJens Wiklander 	uint64_t a = get_be64(k + 1);
398a15c688SJens Wiklander 
408a15c688SJens Wiklander 	h[0] = (a << 1) | (b >> 63);
418a15c688SJens Wiklander 	h[1] = (b << 1) | (a >> 63);
428a15c688SJens Wiklander 	if (b >> 63)
438a15c688SJens Wiklander 		h[1] ^= 0xc200000000000000UL;
448a15c688SJens Wiklander }
458a15c688SJens Wiklander 
internal_aes_gcm_set_key(struct internal_aes_gcm_state * state,const struct internal_aes_gcm_key * enc_key)4654af8d67SJens Wiklander void internal_aes_gcm_set_key(struct internal_aes_gcm_state *state,
4754af8d67SJens Wiklander 			      const struct internal_aes_gcm_key *enc_key)
481fca7e26SJens Wiklander {
498a15c688SJens Wiklander 	uint64_t k[2] = { 0 };
508a15c688SJens Wiklander 	uint64_t h[2] = { 0 };
511fca7e26SJens Wiklander 
524f6d7160SJens Wiklander 	crypto_aes_enc_block(enc_key->data, sizeof(enc_key->data),
534f6d7160SJens Wiklander 			     enc_key->rounds, state->ctr, k);
541fca7e26SJens Wiklander 
558a15c688SJens Wiklander 	ghash_reflect(state->ghash_key.h, k);
568a15c688SJens Wiklander 
578a15c688SJens Wiklander 	internal_aes_gcm_gfmul(k, k, h);
588a15c688SJens Wiklander 	ghash_reflect(state->ghash_key.h2, h);
598a15c688SJens Wiklander 
608a15c688SJens Wiklander 	internal_aes_gcm_gfmul(k, h, h);
618a15c688SJens Wiklander 	ghash_reflect(state->ghash_key.h3, h);
628a15c688SJens Wiklander 
638a15c688SJens Wiklander 	internal_aes_gcm_gfmul(k, h, h);
648a15c688SJens Wiklander 	ghash_reflect(state->ghash_key.h4, h);
651fca7e26SJens Wiklander }
661fca7e26SJens Wiklander 
pmull_ghash_update(int num_blocks,uint64_t dg[2],const uint8_t * src,const struct internal_ghash_key * ghash_key,const uint8_t * head)679cd2e73bSJens Wiklander static void pmull_ghash_update(int num_blocks, uint64_t dg[2],
689cd2e73bSJens Wiklander 			       const uint8_t *src,
699cd2e73bSJens Wiklander 			       const struct internal_ghash_key *ghash_key,
709cd2e73bSJens Wiklander 			       const uint8_t *head)
719cd2e73bSJens Wiklander {
729cd2e73bSJens Wiklander #ifdef CFG_HWSUPP_PMULT_64
739cd2e73bSJens Wiklander 	pmull_ghash_update_p64(num_blocks, dg, src, ghash_key, head);
749cd2e73bSJens Wiklander #else
759cd2e73bSJens Wiklander 	pmull_ghash_update_p8(num_blocks, dg, src, ghash_key, head);
769cd2e73bSJens Wiklander #endif
779cd2e73bSJens Wiklander }
789cd2e73bSJens Wiklander 
internal_aes_gcm_ghash_update(struct internal_aes_gcm_state * state,const void * head,const void * data,size_t num_blocks)7954af8d67SJens Wiklander void internal_aes_gcm_ghash_update(struct internal_aes_gcm_state *state,
801fca7e26SJens Wiklander 				   const void *head, const void *data,
811fca7e26SJens Wiklander 				   size_t num_blocks)
821fca7e26SJens Wiklander {
831fca7e26SJens Wiklander 	uint32_t vfp_state;
841fca7e26SJens Wiklander 	uint64_t dg[2];
851fca7e26SJens Wiklander 
8654af8d67SJens Wiklander 	get_be_block(dg, state->hash_state);
871fca7e26SJens Wiklander 
881fca7e26SJens Wiklander 	vfp_state = thread_kernel_enable_vfp();
891fca7e26SJens Wiklander 
909cd2e73bSJens Wiklander 	pmull_ghash_update(num_blocks, dg, data, &state->ghash_key, head);
919cd2e73bSJens Wiklander 
921fca7e26SJens Wiklander 	thread_kernel_disable_vfp(vfp_state);
931fca7e26SJens Wiklander 
9454af8d67SJens Wiklander 	put_be_block(state->hash_state, dg);
951fca7e26SJens Wiklander }
961fca7e26SJens Wiklander 
encrypt_pl(struct internal_aes_gcm_state * state,const struct internal_aes_gcm_key * ek,uint64_t dg[2],const uint8_t * src,size_t num_blocks,uint8_t * dst)979cd2e73bSJens Wiklander static void encrypt_pl(struct internal_aes_gcm_state *state,
989cd2e73bSJens Wiklander 		       const struct internal_aes_gcm_key *ek, uint64_t dg[2],
999cd2e73bSJens Wiklander 		       const uint8_t *src, size_t num_blocks, uint8_t *dst)
1009cd2e73bSJens Wiklander {
1019cd2e73bSJens Wiklander 	void *buf_cryp = state->buf_cryp;
1029cd2e73bSJens Wiklander 
1039cd2e73bSJens Wiklander 	while (num_blocks) {
1049cd2e73bSJens Wiklander 		ce_aes_xor_block(buf_cryp, buf_cryp, src);
1059cd2e73bSJens Wiklander 
1069cd2e73bSJens Wiklander 		pmull_ghash_update(1, dg, buf_cryp, &state->ghash_key, NULL);
1079cd2e73bSJens Wiklander 		memcpy(dst, buf_cryp, TEE_AES_BLOCK_SIZE);
1089cd2e73bSJens Wiklander 
1099cd2e73bSJens Wiklander 		ce_aes_ecb_encrypt(buf_cryp, (const uint8_t *)state->ctr,
1109cd2e73bSJens Wiklander 				   (const uint8_t *)ek->data, ek->rounds,
1119cd2e73bSJens Wiklander 				   1, 1);
1129cd2e73bSJens Wiklander 		internal_aes_gcm_inc_ctr(state);
1139cd2e73bSJens Wiklander 
1149cd2e73bSJens Wiklander 		src += TEE_AES_BLOCK_SIZE;
1159cd2e73bSJens Wiklander 		dst += TEE_AES_BLOCK_SIZE;
1169cd2e73bSJens Wiklander 		num_blocks--;
1179cd2e73bSJens Wiklander 	}
1189cd2e73bSJens Wiklander }
1199cd2e73bSJens Wiklander 
decrypt_pl(struct internal_aes_gcm_state * state,const struct internal_aes_gcm_key * ek,uint64_t dg[2],const uint8_t * src,size_t num_blocks,uint8_t * dst)1209cd2e73bSJens Wiklander static void decrypt_pl(struct internal_aes_gcm_state *state,
1219cd2e73bSJens Wiklander 		       const struct internal_aes_gcm_key *ek, uint64_t dg[2],
1229cd2e73bSJens Wiklander 		       const uint8_t *src, size_t num_blocks, uint8_t *dst)
1239cd2e73bSJens Wiklander {
1249cd2e73bSJens Wiklander 	while (num_blocks) {
125*10298621SRayan Hu 		pmull_ghash_update(1, dg, src, &state->ghash_key, NULL);
1269cd2e73bSJens Wiklander 		ce_aes_ctr_encrypt(dst, src, (const uint8_t *)ek->data,
1279cd2e73bSJens Wiklander 				   ek->rounds, 1, (uint8_t *)state->ctr, 1);
1289cd2e73bSJens Wiklander 
1299cd2e73bSJens Wiklander 		src += TEE_AES_BLOCK_SIZE;
1309cd2e73bSJens Wiklander 		dst += TEE_AES_BLOCK_SIZE;
1319cd2e73bSJens Wiklander 		num_blocks--;
1329cd2e73bSJens Wiklander 	}
1339cd2e73bSJens Wiklander }
1349cd2e73bSJens Wiklander 
13576dd08edSJens Wiklander #ifdef ARM64
update_payload_2block(struct internal_aes_gcm_state * state,const struct internal_aes_gcm_key * ek,uint64_t dg[2],TEE_OperationMode mode,const void * src,size_t num_blocks,void * dst)13676dd08edSJens Wiklander static void update_payload_2block(struct internal_aes_gcm_state *state,
13776dd08edSJens Wiklander 				  const struct internal_aes_gcm_key *ek,
13876dd08edSJens Wiklander 				  uint64_t dg[2], TEE_OperationMode mode,
13976dd08edSJens Wiklander 				  const void *src, size_t num_blocks, void *dst)
14076dd08edSJens Wiklander {
14176dd08edSJens Wiklander 	assert(num_blocks && !(num_blocks % 2));
14276dd08edSJens Wiklander 
14376dd08edSJens Wiklander 	if (mode == TEE_MODE_ENCRYPT) {
14476dd08edSJens Wiklander 		uint8_t ks[sizeof(state->buf_cryp) * 2] = { 0 };
14576dd08edSJens Wiklander 
14676dd08edSJens Wiklander 		/*
14776dd08edSJens Wiklander 		 * ks holds the encrypted counters of the next two blocks.
14876dd08edSJens Wiklander 		 * pmull_gcm_encrypt() uses this to encrypt the first two
14976dd08edSJens Wiklander 		 * blocks. When pmull_gcm_encrypt() returns is ks updated
15076dd08edSJens Wiklander 		 * with the encrypted counters of the next two blocks. As
15176dd08edSJens Wiklander 		 * we're only keeping one of these blocks we throw away
15276dd08edSJens Wiklander 		 * block number two consequently decreases the counter by
15376dd08edSJens Wiklander 		 * one.
15476dd08edSJens Wiklander 		 */
15576dd08edSJens Wiklander 		memcpy(ks, state->buf_cryp, sizeof(state->buf_cryp));
15676dd08edSJens Wiklander 
15776dd08edSJens Wiklander 		pmull_gcm_load_round_keys(ek->data, ek->rounds);
15876dd08edSJens Wiklander 		pmull_gcm_encrypt_block(ks + sizeof(state->buf_cryp),
15976dd08edSJens Wiklander 					(uint8_t *)state->ctr, ek->rounds);
16076dd08edSJens Wiklander 		internal_aes_gcm_inc_ctr(state);
16176dd08edSJens Wiklander 		pmull_gcm_encrypt(num_blocks, dg, dst, src, &state->ghash_key,
16276dd08edSJens Wiklander 				  state->ctr, NULL, ek->rounds, ks);
16376dd08edSJens Wiklander 		memcpy(state->buf_cryp, ks, TEE_AES_BLOCK_SIZE);
16476dd08edSJens Wiklander 		internal_aes_gcm_dec_ctr(state);
16576dd08edSJens Wiklander 	} else {
16676dd08edSJens Wiklander 		pmull_gcm_decrypt(num_blocks, dg, dst, src, &state->ghash_key,
16776dd08edSJens Wiklander 				  state->ctr, ek->data, ek->rounds);
16876dd08edSJens Wiklander 	}
16976dd08edSJens Wiklander }
17076dd08edSJens Wiklander 
17176dd08edSJens Wiklander /* Overriding the __weak function */
17276dd08edSJens Wiklander void
internal_aes_gcm_update_payload_blocks(struct internal_aes_gcm_state * state,const struct internal_aes_gcm_key * ek,TEE_OperationMode mode,const void * src,size_t num_blocks,void * dst)17376dd08edSJens Wiklander internal_aes_gcm_update_payload_blocks(struct internal_aes_gcm_state *state,
17476dd08edSJens Wiklander 				       const struct internal_aes_gcm_key *ek,
17576dd08edSJens Wiklander 				       TEE_OperationMode mode, const void *src,
17676dd08edSJens Wiklander 				       size_t num_blocks, void *dst)
17776dd08edSJens Wiklander {
17876dd08edSJens Wiklander 	size_t nb = ROUNDDOWN(num_blocks, 2);
17976dd08edSJens Wiklander 	uint32_t vfp_state = 0;
18076dd08edSJens Wiklander 	uint64_t dg[2] = { 0 };
18176dd08edSJens Wiklander 
18276dd08edSJens Wiklander 	get_be_block(dg, state->hash_state);
18376dd08edSJens Wiklander 	vfp_state = thread_kernel_enable_vfp();
18476dd08edSJens Wiklander 
18576dd08edSJens Wiklander 	/*
18676dd08edSJens Wiklander 	 * pmull_gcm_encrypt() and pmull_gcm_decrypt() can only handle
18776dd08edSJens Wiklander 	 * blocks in multiples of two.
18876dd08edSJens Wiklander 	 */
18976dd08edSJens Wiklander 	if (nb)
19076dd08edSJens Wiklander 		update_payload_2block(state, ek, dg, mode, src, nb, dst);
19176dd08edSJens Wiklander 
19276dd08edSJens Wiklander 	if (nb != num_blocks) {
19376dd08edSJens Wiklander 		/* There's a final block */
19476dd08edSJens Wiklander 		const void *s = (const uint8_t *)src + nb * TEE_AES_BLOCK_SIZE;
19576dd08edSJens Wiklander 		void *d = (uint8_t *)dst + nb * TEE_AES_BLOCK_SIZE;
19676dd08edSJens Wiklander 
19776dd08edSJens Wiklander 		if (mode == TEE_MODE_ENCRYPT)
19876dd08edSJens Wiklander 			encrypt_pl(state, ek, dg, s, 1, d);
19976dd08edSJens Wiklander 		else
20076dd08edSJens Wiklander 			decrypt_pl(state, ek, dg, s, 1, d);
20176dd08edSJens Wiklander 	}
20276dd08edSJens Wiklander 
20376dd08edSJens Wiklander 	thread_kernel_disable_vfp(vfp_state);
20476dd08edSJens Wiklander 	put_be_block(state->hash_state, dg);
20576dd08edSJens Wiklander }
20676dd08edSJens Wiklander #endif /*ARM64*/
20776dd08edSJens Wiklander 
20876dd08edSJens Wiklander #ifdef ARM32
2099cd2e73bSJens Wiklander /* Overriding the __weak function */
2109cd2e73bSJens Wiklander void
internal_aes_gcm_update_payload_blocks(struct internal_aes_gcm_state * state,const struct internal_aes_gcm_key * ek,TEE_OperationMode mode,const void * src,size_t num_blocks,void * dst)2119cd2e73bSJens Wiklander internal_aes_gcm_update_payload_blocks(struct internal_aes_gcm_state *state,
2129cd2e73bSJens Wiklander 				       const struct internal_aes_gcm_key *ek,
2139cd2e73bSJens Wiklander 				       TEE_OperationMode mode, const void *src,
2149cd2e73bSJens Wiklander 				       size_t num_blocks, void *dst)
2159cd2e73bSJens Wiklander {
2169cd2e73bSJens Wiklander 	uint64_t dg[2] = { 0 };
2179cd2e73bSJens Wiklander 	uint32_t vfp_state = 0;
2189cd2e73bSJens Wiklander 
2199cd2e73bSJens Wiklander 	assert(!state->buf_pos && num_blocks);
2209cd2e73bSJens Wiklander 	get_be_block(dg, state->hash_state);
2219cd2e73bSJens Wiklander 	vfp_state = thread_kernel_enable_vfp();
2229cd2e73bSJens Wiklander 
2239cd2e73bSJens Wiklander 	if (mode == TEE_MODE_ENCRYPT)
2249cd2e73bSJens Wiklander 		encrypt_pl(state, ek, dg, src, num_blocks, dst);
2259cd2e73bSJens Wiklander 	else
2269cd2e73bSJens Wiklander 		decrypt_pl(state, ek, dg, src, num_blocks, dst);
2279cd2e73bSJens Wiklander 
2289cd2e73bSJens Wiklander 	thread_kernel_disable_vfp(vfp_state);
2299cd2e73bSJens Wiklander 	put_be_block(state->hash_state, dg);
2309cd2e73bSJens Wiklander }
2319cd2e73bSJens Wiklander #endif
232