]> git.ipfire.org Git - people/ms/strongswan.git/blob - src/libstrongswan/plugins/aesni/aesni_xcbc.c
aesni: Avoid loading AES/GHASH round keys into local variables
[people/ms/strongswan.git] / src / libstrongswan / plugins / aesni / aesni_xcbc.c
1 /*
2 * Copyright (C) 2008-2015 Martin Willi
3 * Copyright (C) 2012 Tobias Brunner
4 * Hochschule fuer Technik Rapperswil
5 * Copyright (C) 2015 revosec AG
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 * for more details.
16 */
17
18 #include "aesni_xcbc.h"
19 #include "aesni_key.h"
20
21 #include <crypto/prfs/mac_prf.h>
22 #include <crypto/signers/mac_signer.h>
23
24 typedef struct private_aesni_mac_t private_aesni_mac_t;
25
26 /**
27 * Private data of a mac_t object.
28 */
29 struct private_aesni_mac_t {
30
31 /**
32 * Public mac_t interface.
33 */
34 mac_t public;
35
36 /**
37 * Key schedule for K1
38 */
39 aesni_key_t *k1;
40
41 /**
42 * k2
43 */
44 __m128i k2;
45
46 /**
47 * k3
48 */
49 __m128i k3;
50
51 /**
52 * E
53 */
54 __m128i e;
55
56 /**
57 * remaining, unprocessed bytes in append mode
58 */
59 u_char rem[AES_BLOCK_SIZE];
60
61 /**
62 * number of bytes used in remaining
63 */
64 int rem_size;
65
66 /**
67 * TRUE if we have zero bytes to xcbc in final()
68 */
69 bool zero;
70 };
71
72 METHOD(mac_t, get_mac, bool,
73 private_aesni_mac_t *this, chunk_t data, u_int8_t *out)
74 {
75 __m128i *ks, e, *bi;
76 u_int blocks, rem, i;
77
78 if (!this->k1)
79 {
80 return FALSE;
81 }
82
83 ks = this->k1->schedule;
84
85 e = this->e;
86
87 if (data.len)
88 {
89 this->zero = FALSE;
90 }
91
92 if (this->rem_size + data.len > AES_BLOCK_SIZE)
93 {
94 /* (3) For each block M[i], where i = 1 ... n-1:
95 * XOR M[i] with E[i-1], then encrypt the result with Key K1,
96 * yielding E[i].
97 */
98
99 /* append data to remaining bytes, process block M[1] */
100 memcpy(this->rem + this->rem_size, data.ptr,
101 AES_BLOCK_SIZE - this->rem_size);
102 data = chunk_skip(data, AES_BLOCK_SIZE - this->rem_size);
103
104 e = _mm_xor_si128(e, _mm_loadu_si128((__m128i*)this->rem));
105
106 e = _mm_xor_si128(e, ks[0]);
107 e = _mm_aesenc_si128(e, ks[1]);
108 e = _mm_aesenc_si128(e, ks[2]);
109 e = _mm_aesenc_si128(e, ks[3]);
110 e = _mm_aesenc_si128(e, ks[4]);
111 e = _mm_aesenc_si128(e, ks[5]);
112 e = _mm_aesenc_si128(e, ks[6]);
113 e = _mm_aesenc_si128(e, ks[7]);
114 e = _mm_aesenc_si128(e, ks[8]);
115 e = _mm_aesenc_si128(e, ks[9]);
116 e = _mm_aesenclast_si128(e, ks[10]);
117
118 bi = (__m128i*)data.ptr;
119 rem = data.len % AES_BLOCK_SIZE;
120 blocks = data.len / AES_BLOCK_SIZE;
121 if (!rem && blocks)
122 { /* don't do last block */
123 rem = AES_BLOCK_SIZE;
124 blocks--;
125 }
126
127 /* process blocks M[2] ... M[n-1] */
128 for (i = 0; i < blocks; i++)
129 {
130 e = _mm_xor_si128(e, _mm_loadu_si128(bi + i));
131
132 e = _mm_xor_si128(e, ks[0]);
133 e = _mm_aesenc_si128(e, ks[1]);
134 e = _mm_aesenc_si128(e, ks[2]);
135 e = _mm_aesenc_si128(e, ks[3]);
136 e = _mm_aesenc_si128(e, ks[4]);
137 e = _mm_aesenc_si128(e, ks[5]);
138 e = _mm_aesenc_si128(e, ks[6]);
139 e = _mm_aesenc_si128(e, ks[7]);
140 e = _mm_aesenc_si128(e, ks[8]);
141 e = _mm_aesenc_si128(e, ks[9]);
142 e = _mm_aesenclast_si128(e, ks[10]);
143 }
144
145 /* store remaining bytes of block M[n] */
146 memcpy(this->rem, data.ptr + data.len - rem, rem);
147 this->rem_size = rem;
148 }
149 else
150 {
151 /* no complete block, just copy into remaining */
152 memcpy(this->rem + this->rem_size, data.ptr, data.len);
153 this->rem_size += data.len;
154 }
155
156 if (out)
157 {
158 /* (4) For block M[n]: */
159 if (this->rem_size == AES_BLOCK_SIZE && !this->zero)
160 {
161 /* a) If the blocksize of M[n] is 128 bits:
162 * XOR M[n] with E[n-1] and Key K2, then encrypt the result with
163 * Key K1, yielding E[n].
164 */
165 e = _mm_xor_si128(e, this->k2);
166 }
167 else
168 {
169 /* b) If the blocksize of M[n] is less than 128 bits:
170 *
171 * i) Pad M[n] with a single "1" bit, followed by the number of
172 * "0" bits (possibly none) required to increase M[n]'s
173 * blocksize to 128 bits.
174 */
175 if (this->rem_size < AES_BLOCK_SIZE)
176 {
177 memset(this->rem + this->rem_size, 0,
178 AES_BLOCK_SIZE - this->rem_size);
179 this->rem[this->rem_size] = 0x80;
180 }
181 /* ii) XOR M[n] with E[n-1] and Key K3, then encrypt the result
182 * with Key K1, yielding E[n].
183 */
184 e = _mm_xor_si128(e, this->k3);
185 }
186 e = _mm_xor_si128(e, _mm_loadu_si128((__m128i*)this->rem));
187
188 e = _mm_xor_si128(e, ks[0]);
189 e = _mm_aesenc_si128(e, ks[1]);
190 e = _mm_aesenc_si128(e, ks[2]);
191 e = _mm_aesenc_si128(e, ks[3]);
192 e = _mm_aesenc_si128(e, ks[4]);
193 e = _mm_aesenc_si128(e, ks[5]);
194 e = _mm_aesenc_si128(e, ks[6]);
195 e = _mm_aesenc_si128(e, ks[7]);
196 e = _mm_aesenc_si128(e, ks[8]);
197 e = _mm_aesenc_si128(e, ks[9]);
198 e = _mm_aesenclast_si128(e, ks[10]);
199 _mm_storeu_si128((__m128i*)out, e);
200
201 /* (2) Define E[0] = 0x00000000000000000000000000000000 */
202 e = _mm_setzero_si128();
203 this->rem_size = 0;
204 this->zero = TRUE;
205 }
206 this->e = e;
207 return TRUE;
208 }
209
210 METHOD(mac_t, get_mac_size, size_t,
211 private_aesni_mac_t *this)
212 {
213 return AES_BLOCK_SIZE;
214 }
215
216 METHOD(mac_t, set_key, bool,
217 private_aesni_mac_t *this, chunk_t key)
218 {
219 __m128i t1, t2, t3;
220 u_char k1[AES_BLOCK_SIZE];
221 u_int round;
222 chunk_t k;
223
224 /* reset state */
225 this->e = _mm_setzero_si128();
226 this->rem_size = 0;
227 this->zero = TRUE;
228
229 /* Create RFC4434 variable keys if required */
230 if (key.len == AES_BLOCK_SIZE)
231 {
232 k = key;
233 }
234 else if (key.len < AES_BLOCK_SIZE)
235 { /* pad short keys */
236 k = chunk_alloca(AES_BLOCK_SIZE);
237 memset(k.ptr, 0, k.len);
238 memcpy(k.ptr, key.ptr, key.len);
239 }
240 else
241 { /* shorten key using XCBC */
242 k = chunk_alloca(AES_BLOCK_SIZE);
243 memset(k.ptr, 0, k.len);
244 if (!set_key(this, k) || !get_mac(this, key, k.ptr))
245 {
246 return FALSE;
247 }
248 }
249
250 /*
251 * (1) Derive 3 128-bit keys (K1, K2 and K3) from the 128-bit secret
252 * key K, as follows:
253 * K1 = 0x01010101010101010101010101010101 encrypted with Key K
254 * K2 = 0x02020202020202020202020202020202 encrypted with Key K
255 * K3 = 0x03030303030303030303030303030303 encrypted with Key K
256 */
257
258 DESTROY_IF(this->k1);
259 this->k1 = aesni_key_create(TRUE, k);
260 if (!this->k1)
261 {
262 return FALSE;
263 }
264
265 t1 = _mm_set1_epi8(0x01);
266 t2 = _mm_set1_epi8(0x02);
267 t3 = _mm_set1_epi8(0x03);
268
269 t1 = _mm_xor_si128(t1, this->k1->schedule[0]);
270 t2 = _mm_xor_si128(t2, this->k1->schedule[0]);
271 t3 = _mm_xor_si128(t3, this->k1->schedule[0]);
272
273 for (round = 1; round < this->k1->rounds; round++)
274 {
275 t1 = _mm_aesenc_si128(t1, this->k1->schedule[round]);
276 t2 = _mm_aesenc_si128(t2, this->k1->schedule[round]);
277 t3 = _mm_aesenc_si128(t3, this->k1->schedule[round]);
278 }
279
280 t1 = _mm_aesenclast_si128(t1, this->k1->schedule[this->k1->rounds]);
281 t2 = _mm_aesenclast_si128(t2, this->k1->schedule[this->k1->rounds]);
282 t3 = _mm_aesenclast_si128(t3, this->k1->schedule[this->k1->rounds]);
283
284 _mm_storeu_si128((__m128i*)k1, t1);
285 this->k2 = t2;
286 this->k3 = t3;
287
288 this->k1->destroy(this->k1);
289 this->k1 = aesni_key_create(TRUE, chunk_from_thing(k1));
290
291 memwipe(k1, AES_BLOCK_SIZE);
292 return this->k1 != NULL;
293 }
294
295 METHOD(mac_t, destroy, void,
296 private_aesni_mac_t *this)
297 {
298 DESTROY_IF(this->k1);
299 memwipe(&this->k2, sizeof(this->k2));
300 memwipe(&this->k3, sizeof(this->k3));
301 free_align(this);
302 }
303
304 /*
305 * Described in header
306 */
307 mac_t *aesni_xcbc_create(encryption_algorithm_t algo, size_t key_size)
308 {
309 private_aesni_mac_t *this;
310
311 INIT_ALIGN(this, sizeof(__m128i),
312 .public = {
313 .get_mac = _get_mac,
314 .get_mac_size = _get_mac_size,
315 .set_key = _set_key,
316 .destroy = _destroy,
317 },
318 );
319
320 return &this->public;
321 }
322
323 /*
324 * Described in header.
325 */
326 prf_t *aesni_xcbc_prf_create(pseudo_random_function_t algo)
327 {
328 mac_t *xcbc;
329
330 switch (algo)
331 {
332 case PRF_AES128_XCBC:
333 xcbc = aesni_xcbc_create(ENCR_AES_CBC, 16);
334 break;
335 default:
336 return NULL;
337 }
338 if (xcbc)
339 {
340 return mac_prf_create(xcbc);
341 }
342 return NULL;
343 }
344
345 /*
346 * Described in header
347 */
348 signer_t *aesni_xcbc_signer_create(integrity_algorithm_t algo)
349 {
350 size_t trunc;
351 mac_t *xcbc;
352
353 switch (algo)
354 {
355 case AUTH_AES_XCBC_96:
356 xcbc = aesni_xcbc_create(ENCR_AES_CBC, 16);
357 trunc = 12;
358 break;
359 default:
360 return NULL;
361 }
362 if (xcbc)
363 {
364 return mac_signer_create(xcbc, trunc);
365 }
366 return NULL;
367 }