xref: /optee_os/core/crypto/aes-gcm-ghash-tbl.c (revision 817466cb476de705a8e3dabe1ef165fe27a18c2f)
1 // SPDX-License-Identifier: Apache-2.0
2 /*
3  *  NIST SP800-38D compliant GCM implementation
4  *
5  *  Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
6  *
7  *  Licensed under the Apache License, Version 2.0 (the "License"); you may
8  *  not use this file except in compliance with the License.
9  *  You may obtain a copy of the License at
10  *
11  *  http://www.apache.org/licenses/LICENSE-2.0
12  *
13  *  Unless required by applicable law or agreed to in writing, software
14  *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15  *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  *  See the License for the specific language governing permissions and
17  *  limitations under the License.
18  */
19 
20 #include <crypto/aes-gcm.h>
21 #include <io.h>
22 #include <kernel/panic.h>
23 #include <string.h>
24 #include <tee_api_types.h>
25 #include <types_ext.h>
26 
27 #include "aes-gcm-private.h"
28 
29 /*
30  * http://csrc.nist.gov/publications/nistpubs/800-38D/SP-800-38D.pdf
31  *
32  * See also:
33  * [MGV] http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/gcm/
34 gcm-revised-spec.pdf
35  *
36  * We use the algorithm described as Shoup's method with 4-bit tables in
37  * [MGV] 4.1, pp. 12-13, to enhance speed without using too much memory.
38  */
39 
40 /*
41  * Precompute small multiples of H, that is set
42  *      HH[i] || HL[i] = H times i,
43  * where i is seen as a field element as in [MGV], ie high-order bits
44  * correspond to low powers of P. The result is stored in the same way, that
45  * is the high-order bit of HH corresponds to P^0 and the low-order bit of HL
46  * corresponds to P^127.
47  */
48 void internal_aes_gcm_ghash_gen_tbl(struct internal_aes_gcm_state *state,
49 				    const struct internal_aes_gcm_key *ek)
50 {
51 	int i, j;
52 	uint64_t vl, vh;
53 	unsigned char h[16];
54 
55 	memset(h, 0, 16);
56 	internal_aes_gcm_encrypt_block(ek, h, h);
57 
58 	vh = get_be64(h);
59 	vl = get_be64(h + 8);
60 
61 	/* 8 = 1000 corresponds to 1 in GF(2^128) */
62 	state->HL[8] = vl;
63 	state->HH[8] = vh;
64 
65 	/* 0 corresponds to 0 in GF(2^128) */
66 	state->HH[0] = 0;
67 	state->HL[0] = 0;
68 
69 	for (i = 4; i > 0; i >>= 1) {
70 		uint32_t T = (vl & 1) * 0xe1000000U;
71 
72 		vl  = (vh << 63) | (vl >> 1);
73 		vh  = (vh >> 1) ^ ((uint64_t)T << 32);
74 
75 		state->HL[i] = vl;
76 		state->HH[i] = vh;
77 	}
78 
79 	for (i = 2; i <= 8; i *= 2) {
80 		uint64_t *HiL = state->HL + i, *HiH = state->HH + i;
81 
82 		vh = *HiH;
83 		vl = *HiL;
84 		for (j = 1; j < i; j++) {
85 			HiH[j] = vh ^ state->HH[j];
86 			HiL[j] = vl ^ state->HL[j];
87 		}
88 	}
89 }
90 
91 /*
92  * Shoup's method for multiplication use this table with
93  *      last4[x] = x times P^128
94  * where x and last4[x] are seen as elements of GF(2^128) as in [MGV]
95  */
96 static const uint64_t last4[16] = {
97 	0x0000, 0x1c20, 0x3840, 0x2460,
98 	0x7080, 0x6ca0, 0x48c0, 0x54e0,
99 	0xe100, 0xfd20, 0xd940, 0xc560,
100 	0x9180, 0x8da0, 0xa9c0, 0xb5e0
101 };
102 
103 /*
104  * Sets output to x times H using the precomputed tables.
105  * x and output are seen as elements of GF(2^128) as in [MGV].
106  */
107 static void gcm_mult(struct internal_aes_gcm_state *state,
108 		     const unsigned char x[16], unsigned char output[16])
109 {
110 	int i = 0;
111 	unsigned char lo, hi, rem;
112 	uint64_t zh, zl;
113 
114 	lo = x[15] & 0xf;
115 
116 	zh = state->HH[lo];
117 	zl = state->HL[lo];
118 
119 	for (i = 15; i >= 0; i--) {
120 		lo = x[i] & 0xf;
121 		hi = x[i] >> 4;
122 
123 		if (i != 15) {
124 			rem = (unsigned char)zl & 0xf;
125 			zl = (zh << 60) | (zl >> 4);
126 			zh = (zh >> 4);
127 			zh ^= (uint64_t)last4[rem] << 48;
128 			zh ^= state->HH[lo];
129 			zl ^= state->HL[lo];
130 		}
131 
132 		rem = (unsigned char)zl & 0xf;
133 		zl = (zh << 60) | (zl >> 4);
134 		zh = (zh >> 4);
135 		zh ^= (uint64_t)last4[rem] << 48;
136 		zh ^= state->HH[hi];
137 		zl ^= state->HL[hi];
138 	}
139 
140 	put_be64(output, zh);
141 	put_be64(output + 8, zl);
142 }
143 
144 void internal_aes_gcm_ghash_update_block(struct internal_aes_gcm_state *state,
145 					 const void *data)
146 {
147 	void *y = state->hash_state;
148 
149 	internal_aes_gcm_xor_block(y, data);
150 	gcm_mult(state, y, y);
151 }
152