1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4 /* Copyright(c) 2013, Intel Corp. */
5 
6 /* Wrapper functions for Intel optimized implementation of AES-GCM */
7 
8 #ifdef USE_HW_AES
9 
10 #ifdef FREEBL_NO_DEPEND
11 #include "stubs.h"
12 #endif
13 
14 #include "blapii.h"
15 #include "blapit.h"
16 #include "gcm.h"
17 #include "ctr.h"
18 #include "secerr.h"
19 #include "prtypes.h"
20 #include "pkcs11t.h"
21 
22 #include <limits.h>
23 
24 #include "intel-gcm.h"
25 #include "rijndael.h"
26 
27 #include <emmintrin.h>
28 #include <tmmintrin.h>
29 
30 struct intel_AES_GCMContextStr {
31     unsigned char Htbl[16 * AES_BLOCK_SIZE];
32     unsigned char X0[AES_BLOCK_SIZE];
33     unsigned char T[AES_BLOCK_SIZE];
34     unsigned char CTR[AES_BLOCK_SIZE];
35     AESContext *aes_context;
36     unsigned long tagBits;
37     unsigned long Alen;
38     unsigned long Mlen;
39     freeblCipherFunc cipher;
40     PRBool ctr_context_init;
41     gcmIVContext gcm_iv;
42 };
43 
44 SECStatus intel_aes_gcmInitCounter(intel_AES_GCMContext *gcm,
45                                    const unsigned char *iv,
46                                    unsigned long ivLen, unsigned long tagBits,
47                                    const unsigned char *aad, unsigned long aadLen);
48 
49 intel_AES_GCMContext *
intel_AES_GCM_CreateContext(void * context,freeblCipherFunc cipher,const unsigned char * params)50 intel_AES_GCM_CreateContext(void *context,
51                             freeblCipherFunc cipher,
52                             const unsigned char *params)
53 {
54     intel_AES_GCMContext *gcm = NULL;
55     AESContext *aes = (AESContext *)context;
56     const CK_NSS_GCM_PARAMS *gcmParams = (const CK_NSS_GCM_PARAMS *)params;
57     SECStatus rv;
58 
59     gcm = PORT_ZNew(intel_AES_GCMContext);
60     if (gcm == NULL) {
61         return NULL;
62     }
63 
64     /* initialize context fields */
65     gcm->aes_context = aes;
66     gcm->cipher = cipher;
67     gcm->Alen = 0;
68     gcm->Mlen = 0;
69     gcm->ctr_context_init = PR_FALSE;
70 
71     /* first prepare H and its derivatives for ghash */
72     intel_aes_gcmINIT(gcm->Htbl, (unsigned char *)aes->k.expandedKey, aes->Nr);
73 
74     gcm_InitIVContext(&gcm->gcm_iv);
75 
76     /* if gcmParams is NULL, then we are creating an PKCS #11 MESSAGE
77      * style context, in which we initialize the key once, then do separate
78      * iv/aad's for each message. If we are doing that kind of operation,
79      * we've finished with init here. We'll init the Counter in each AEAD
80      * call */
81     if (gcmParams == NULL) {
82         return gcm;
83     }
84 
85     rv = intel_aes_gcmInitCounter(gcm, gcmParams->pIv,
86                                   gcmParams->ulIvLen, gcmParams->ulTagBits,
87                                   gcmParams->pAAD, gcmParams->ulAADLen);
88     if (rv != SECSuccess) {
89         PORT_Free(gcm);
90         return NULL;
91     }
92     gcm->ctr_context_init = PR_TRUE;
93 
94     return gcm;
95 }
96 
97 SECStatus
intel_aes_gcmInitCounter(intel_AES_GCMContext * gcm,const unsigned char * iv,unsigned long ivLen,unsigned long tagBits,const unsigned char * aad,unsigned long aadLen)98 intel_aes_gcmInitCounter(intel_AES_GCMContext *gcm,
99                          const unsigned char *iv, unsigned long ivLen,
100                          unsigned long tagBits,
101                          const unsigned char *aad, unsigned long aadLen)
102 {
103     unsigned char buff[AES_BLOCK_SIZE]; /* aux buffer */
104     unsigned long IV_whole_len = ivLen & (~0xful);
105     unsigned int IV_remainder_len = ivLen & 0xful;
106     unsigned long AAD_whole_len = aadLen & (~0xful);
107     unsigned int AAD_remainder_len = aadLen & 0xful;
108     unsigned int j;
109     __m128i BSWAP_MASK = _mm_setr_epi8(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0);
110     __m128i ONE = _mm_set_epi32(0, 0, 0, 1);
111     SECStatus rv;
112 
113     if (ivLen == 0) {
114         PORT_SetError(SEC_ERROR_INVALID_ARGS);
115         return SECFailure;
116     }
117 
118     if (tagBits != 128 && tagBits != 120 && tagBits != 112 &&
119         tagBits != 104 && tagBits != 96 && tagBits != 64 &&
120         tagBits != 32) {
121         PORT_SetError(SEC_ERROR_INVALID_ARGS);
122         return SECFailure;
123     }
124     gcm->tagBits = tagBits;
125 
126     /* reset the aad and message length counters */
127     gcm->Alen = 0;
128     gcm->Mlen = 0;
129 
130     // Limit AADLen in accordance with SP800-38D
131     if (sizeof(AAD_whole_len) >= 8 && AAD_whole_len > (1ULL << 61) - 1) {
132         PORT_SetError(SEC_ERROR_INPUT_LEN);
133         return SECFailure;
134     }
135     /* Initial TAG value is zero */
136     _mm_storeu_si128((__m128i *)gcm->T, _mm_setzero_si128());
137     _mm_storeu_si128((__m128i *)gcm->X0, _mm_setzero_si128());
138 
139     /* Init the counter */
140     if (ivLen == 12) {
141         _mm_storeu_si128((__m128i *)gcm->CTR,
142                          _mm_setr_epi32(((unsigned int *)iv)[0],
143                                         ((unsigned int *)iv)[1],
144                                         ((unsigned int *)iv)[2],
145                                         0x01000000));
146     } else {
147         /* If IV size is not 96 bits, then the initial counter value is GHASH
148          * of the IV */
149         intel_aes_gcmAAD(gcm->Htbl, (unsigned char *)iv, IV_whole_len, gcm->T);
150 
151         /* Partial block */
152         if (IV_remainder_len) {
153             PORT_Memset(buff, 0, AES_BLOCK_SIZE);
154             PORT_Memcpy(buff, iv + IV_whole_len, IV_remainder_len);
155             intel_aes_gcmAAD(gcm->Htbl, buff, AES_BLOCK_SIZE, gcm->T);
156         }
157 
158         intel_aes_gcmTAG(
159             gcm->Htbl,
160             gcm->T,
161             ivLen,
162             0,
163             gcm->X0,
164             gcm->CTR);
165 
166         /* TAG should be zero again */
167         _mm_storeu_si128((__m128i *)gcm->T, _mm_setzero_si128());
168     }
169 
170     /* Encrypt the initial counter, will be used to encrypt the GHASH value,
171      * in the end */
172     rv = (*gcm->cipher)(gcm->aes_context, gcm->X0, &j, AES_BLOCK_SIZE, gcm->CTR,
173                         AES_BLOCK_SIZE, AES_BLOCK_SIZE);
174     if (rv != SECSuccess) {
175         return SECFailure;
176     }
177 
178     /* Promote the counter by 1 */
179     _mm_storeu_si128((__m128i *)gcm->CTR, _mm_shuffle_epi8(_mm_add_epi32(ONE, _mm_shuffle_epi8(_mm_loadu_si128((__m128i *)gcm->CTR), BSWAP_MASK)), BSWAP_MASK));
180 
181     /* Now hash AAD - it would actually make sense to seperate the context
182      * creation from the AAD, because that would allow to reuse the H, which
183      * only changes when the AES key changes, and not every package, like the
184      * IV and AAD */
185     intel_aes_gcmAAD(gcm->Htbl, (unsigned char *)aad, AAD_whole_len, gcm->T);
186     if (AAD_remainder_len) {
187         PORT_Memset(buff, 0, AES_BLOCK_SIZE);
188         PORT_Memcpy(buff, aad + AAD_whole_len, AAD_remainder_len);
189         intel_aes_gcmAAD(gcm->Htbl, buff, AES_BLOCK_SIZE, gcm->T);
190     }
191     gcm->Alen += aadLen;
192     return SECSuccess;
193 }
194 
195 void
intel_AES_GCM_DestroyContext(intel_AES_GCMContext * gcm,PRBool freeit)196 intel_AES_GCM_DestroyContext(intel_AES_GCMContext *gcm, PRBool freeit)
197 {
198     PORT_Memset(gcm, 0, sizeof(intel_AES_GCMContext));
199     if (freeit) {
200         PORT_Free(gcm);
201     }
202 }
203 
204 SECStatus
intel_AES_GCM_EncryptUpdate(intel_AES_GCMContext * gcm,unsigned char * outbuf,unsigned int * outlen,unsigned int maxout,const unsigned char * inbuf,unsigned int inlen,unsigned int blocksize)205 intel_AES_GCM_EncryptUpdate(intel_AES_GCMContext *gcm,
206                             unsigned char *outbuf,
207                             unsigned int *outlen, unsigned int maxout,
208                             const unsigned char *inbuf, unsigned int inlen,
209                             unsigned int blocksize)
210 {
211     unsigned int tagBytes;
212     unsigned char T[AES_BLOCK_SIZE];
213     unsigned int j;
214 
215     // GCM has a 16 octet block, with a 32-bit block counter
216     // Limit in accordance with SP800-38D
217     if (sizeof(inlen) > 4 &&
218         inlen >= ((1ULL << 32) - 2) * AES_BLOCK_SIZE) {
219         PORT_SetError(SEC_ERROR_INPUT_LEN);
220         return SECFailure;
221     }
222 
223     if (!gcm->ctr_context_init) {
224         PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
225         return SECFailure;
226     }
227 
228     tagBytes = (gcm->tagBits + (PR_BITS_PER_BYTE - 1)) / PR_BITS_PER_BYTE;
229     if (UINT_MAX - inlen < tagBytes) {
230         PORT_SetError(SEC_ERROR_INPUT_LEN);
231         return SECFailure;
232     }
233     if (maxout < inlen + tagBytes) {
234         *outlen = inlen + tagBytes;
235         PORT_SetError(SEC_ERROR_OUTPUT_LEN);
236         return SECFailure;
237     }
238 
239     intel_aes_gcmENC(
240         inbuf,
241         outbuf,
242         gcm,
243         inlen);
244 
245     gcm->Mlen += inlen;
246 
247     intel_aes_gcmTAG(
248         gcm->Htbl,
249         gcm->T,
250         gcm->Mlen,
251         gcm->Alen,
252         gcm->X0,
253         T);
254 
255     *outlen = inlen + tagBytes;
256 
257     for (j = 0; j < tagBytes; j++) {
258         outbuf[inlen + j] = T[j];
259     }
260     return SECSuccess;
261 }
262 
263 SECStatus
intel_AES_GCM_DecryptUpdate(intel_AES_GCMContext * gcm,unsigned char * outbuf,unsigned int * outlen,unsigned int maxout,const unsigned char * inbuf,unsigned int inlen,unsigned int blocksize)264 intel_AES_GCM_DecryptUpdate(intel_AES_GCMContext *gcm,
265                             unsigned char *outbuf,
266                             unsigned int *outlen, unsigned int maxout,
267                             const unsigned char *inbuf, unsigned int inlen,
268                             unsigned int blocksize)
269 {
270     unsigned int tagBytes;
271     unsigned char T[AES_BLOCK_SIZE];
272     const unsigned char *intag;
273 
274     if (!gcm->ctr_context_init) {
275         PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
276         return SECFailure;
277     }
278 
279     tagBytes = (gcm->tagBits + (PR_BITS_PER_BYTE - 1)) / PR_BITS_PER_BYTE;
280 
281     /* get the authentication block */
282     if (inlen < tagBytes) {
283         PORT_SetError(SEC_ERROR_INPUT_LEN);
284         return SECFailure;
285     }
286 
287     inlen -= tagBytes;
288     intag = inbuf + inlen;
289 
290     // GCM has a 16 octet block, with a 32-bit block counter
291     // Limit in accordance with SP800-38D
292     if (sizeof(inlen) > 4 &&
293         inlen >= ((1ULL << 32) - 2) * AES_BLOCK_SIZE) {
294         PORT_SetError(SEC_ERROR_INPUT_LEN);
295         return SECFailure;
296     }
297 
298     if (maxout < inlen) {
299         *outlen = inlen;
300         PORT_SetError(SEC_ERROR_OUTPUT_LEN);
301         return SECFailure;
302     }
303 
304     intel_aes_gcmDEC(
305         inbuf,
306         outbuf,
307         gcm,
308         inlen);
309 
310     gcm->Mlen += inlen;
311     intel_aes_gcmTAG(
312         gcm->Htbl,
313         gcm->T,
314         gcm->Mlen,
315         gcm->Alen,
316         gcm->X0,
317         T);
318 
319     if (NSS_SecureMemcmp(T, intag, tagBytes) != 0) {
320         memset(outbuf, 0, inlen);
321         *outlen = 0;
322         /* force a CKR_ENCRYPTED_DATA_INVALID error at in softoken */
323         PORT_SetError(SEC_ERROR_BAD_DATA);
324         return SECFailure;
325     }
326     *outlen = inlen;
327 
328     return SECSuccess;
329 }
330 
331 SECStatus
intel_AES_GCM_EncryptAEAD(intel_AES_GCMContext * gcm,unsigned char * outbuf,unsigned int * outlen,unsigned int maxout,const unsigned char * inbuf,unsigned int inlen,void * params,unsigned int paramLen,const unsigned char * aad,unsigned int aadLen,unsigned int blocksize)332 intel_AES_GCM_EncryptAEAD(intel_AES_GCMContext *gcm,
333                           unsigned char *outbuf,
334                           unsigned int *outlen, unsigned int maxout,
335                           const unsigned char *inbuf, unsigned int inlen,
336                           void *params, unsigned int paramLen,
337                           const unsigned char *aad, unsigned int aadLen,
338                           unsigned int blocksize)
339 {
340     unsigned int tagBytes;
341     unsigned char T[AES_BLOCK_SIZE];
342     const CK_GCM_MESSAGE_PARAMS *gcmParams =
343         (const CK_GCM_MESSAGE_PARAMS *)params;
344     SECStatus rv;
345 
346     // GCM has a 16 octet block, with a 32-bit block counter
347     // Limit in accordance with SP800-38D
348     if (sizeof(inlen) > 4 &&
349         inlen >= ((1ULL << 32) - 2) * AES_BLOCK_SIZE) {
350         PORT_SetError(SEC_ERROR_INPUT_LEN);
351         return SECFailure;
352     }
353     /* paramLen comes all the way from the application layer, make sure
354      * it's correct */
355     if (paramLen != sizeof(CK_GCM_MESSAGE_PARAMS)) {
356         PORT_SetError(SEC_ERROR_INVALID_ARGS);
357         return SECFailure;
358     }
359 
360     /* if we were initialized with the C_EncryptInit, we shouldn't be in this
361      * function */
362     if (gcm->ctr_context_init) {
363         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
364         return SECFailure;
365     }
366 
367     if (maxout < inlen) {
368         *outlen = inlen;
369         PORT_SetError(SEC_ERROR_OUTPUT_LEN);
370         return SECFailure;
371     }
372 
373     rv = gcm_GenerateIV(&gcm->gcm_iv, gcmParams->pIv, gcmParams->ulIvLen,
374                         gcmParams->ulIvFixedBits, gcmParams->ivGenerator);
375     if (rv != SECSuccess) {
376         return SECFailure;
377     }
378 
379     rv = intel_aes_gcmInitCounter(gcm, gcmParams->pIv, gcmParams->ulIvLen,
380                                   gcmParams->ulTagBits, aad, aadLen);
381     if (rv != SECSuccess) {
382         return SECFailure;
383     }
384 
385     tagBytes = (gcm->tagBits + (PR_BITS_PER_BYTE - 1)) / PR_BITS_PER_BYTE;
386 
387     intel_aes_gcmENC(inbuf, outbuf, gcm, inlen);
388 
389     gcm->Mlen += inlen;
390 
391     intel_aes_gcmTAG(gcm->Htbl, gcm->T, gcm->Mlen, gcm->Alen, gcm->X0, T);
392 
393     *outlen = inlen;
394     PORT_Memcpy(gcmParams->pTag, T, tagBytes);
395     return SECSuccess;
396 }
397 
398 SECStatus
intel_AES_GCM_DecryptAEAD(intel_AES_GCMContext * gcm,unsigned char * outbuf,unsigned int * outlen,unsigned int maxout,const unsigned char * inbuf,unsigned int inlen,void * params,unsigned int paramLen,const unsigned char * aad,unsigned int aadLen,unsigned int blocksize)399 intel_AES_GCM_DecryptAEAD(intel_AES_GCMContext *gcm,
400                           unsigned char *outbuf,
401                           unsigned int *outlen, unsigned int maxout,
402                           const unsigned char *inbuf, unsigned int inlen,
403                           void *params, unsigned int paramLen,
404                           const unsigned char *aad, unsigned int aadLen,
405                           unsigned int blocksize)
406 {
407     unsigned int tagBytes;
408     unsigned char T[AES_BLOCK_SIZE];
409     const unsigned char *intag;
410     const CK_GCM_MESSAGE_PARAMS *gcmParams =
411         (const CK_GCM_MESSAGE_PARAMS *)params;
412     SECStatus rv;
413 
414     /* paramLen comes all the way from the application layer, make sure
415      * it's correct */
416     if (paramLen != sizeof(CK_GCM_MESSAGE_PARAMS)) {
417         PORT_SetError(SEC_ERROR_INVALID_ARGS);
418         return SECFailure;
419     }
420     /* if we were initialized with the C_DecryptInit, we shouldn't be in this
421      * function */
422     if (gcm->ctr_context_init) {
423         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
424         return SECFailure;
425     }
426 
427     // GCM has a 16 octet block, with a 32-bit block counter
428     // Limit in accordance with SP800-38D
429     if (sizeof(inlen) > 4 &&
430         inlen >= ((1ULL << 32) - 2) * AES_BLOCK_SIZE) {
431         PORT_SetError(SEC_ERROR_INPUT_LEN);
432         return SECFailure;
433     }
434 
435     if (maxout < inlen) {
436         *outlen = inlen;
437         PORT_SetError(SEC_ERROR_OUTPUT_LEN);
438         return SECFailure;
439     }
440 
441     rv = intel_aes_gcmInitCounter(gcm, gcmParams->pIv, gcmParams->ulIvLen,
442                                   gcmParams->ulTagBits, aad, aadLen);
443     if (rv != SECSuccess) {
444         return SECFailure;
445     }
446 
447     tagBytes = (gcm->tagBits + (PR_BITS_PER_BYTE - 1)) / PR_BITS_PER_BYTE;
448     intag = gcmParams->pTag;
449     PORT_Assert(tagBytes != 0);
450 
451     intel_aes_gcmDEC(inbuf, outbuf, gcm, inlen);
452 
453     gcm->Mlen += inlen;
454     intel_aes_gcmTAG(gcm->Htbl, gcm->T, gcm->Mlen, gcm->Alen, gcm->X0, T);
455 
456     if (NSS_SecureMemcmp(T, intag, tagBytes) != 0) {
457         memset(outbuf, 0, inlen);
458         *outlen = 0;
459         /* force a CKR_ENCRYPTED_DATA_INVALID error at in softoken */
460         PORT_SetError(SEC_ERROR_BAD_DATA);
461         return SECFailure;
462     }
463     *outlen = inlen;
464 
465     return SECSuccess;
466 }
467 #endif
468