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