OLD | NEW |
---|---|
(Empty) | |
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 | |
31 struct intel_AES_GCMContextStr{ | |
32 unsigned char Htbl[16*AES_BLOCK_SIZE]; | |
33 unsigned char X0[AES_BLOCK_SIZE]; | |
34 unsigned char T[AES_BLOCK_SIZE]; | |
35 unsigned char CTR[AES_BLOCK_SIZE]; | |
36 AESContext *aes_context; | |
37 unsigned long tagBits; | |
38 unsigned long Alen; | |
39 unsigned long Mlen; | |
40 }; | |
41 | |
42 intel_AES_GCMContext *intel_AES_GCM_CreateContext(void *context, | |
43 freeblCipherFunc cipher, | |
44 const unsigned char *params, | |
45 unsigned int blocksize) | |
46 { | |
47 intel_AES_GCMContext *gcm = NULL; | |
48 AESContext *aes = (AESContext*)context; | |
49 const CK_GCM_PARAMS *gcmParams = (const CK_GCM_PARAMS *)params; | |
50 unsigned char buff[AES_BLOCK_SIZE]; /* aux buffer */ | |
51 | |
52 int IV_whole_len = gcmParams->ulIvLen&(~0xf); | |
Ryan Sleevi
2014/04/23 19:53:34
type conversion warning - ulIvLen is ulong, but th
wtc
2014/04/24 01:04:10
I will fix this in the NSS upstream.
| |
53 int IV_remainder_len = gcmParams->ulIvLen&0xf; | |
54 int AAD_whole_len = gcmParams->ulAADLen&(~0xf); | |
55 int AAD_remainder_len = gcmParams->ulAADLen&0xf; | |
Ryan Sleevi
2014/04/23 19:53:34
spaces between operators for readability?
wtc
2014/04/24 01:04:10
I will fix these in the NSS upstream.
| |
56 | |
57 __m128i BSWAP_MASK = _mm_setr_epi8(15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0); | |
58 __m128i ONE = _mm_set_epi32(0,0,0,1); | |
59 unsigned int j; | |
60 SECStatus rv; | |
61 | |
62 if (blocksize != AES_BLOCK_SIZE) { | |
63 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); | |
64 return NULL; | |
65 } | |
66 gcm = PORT_ZNew(intel_AES_GCMContext); | |
67 | |
68 if (gcm == NULL) { | |
69 return NULL; | |
70 } | |
71 /* initialize context fields */ | |
72 gcm->aes_context = aes; | |
73 gcm->tagBits = gcmParams->ulTagBits; | |
74 gcm->Alen = 0; | |
75 gcm->Mlen = 0; | |
76 /* first prepare H and its derivatives for ghash */ | |
77 intel_aes_gcmINIT(gcm->Htbl, (unsigned char*)aes->expandedKey, aes->Nr); | |
78 /* Initial TAG value is zero*/ | |
79 _mm_storeu_si128((__m128i*)gcm->T, _mm_setzero_si128()); | |
80 _mm_storeu_si128((__m128i*)gcm->X0, _mm_setzero_si128()); | |
81 /* Init the counter */ | |
Ryan Sleevi
2014/04/23 19:53:34
line breaks for readability between these logical
wtc
2014/04/24 01:04:10
I will fix these in the NSS upstream.
| |
82 if(gcmParams->ulIvLen == 12) { | |
83 _mm_storeu_si128((__m128i*)gcm->CTR, _mm_setr_epi32(((unsigned int*)gcmP arams->pIv)[0], ((unsigned int*)gcmParams->pIv)[1], ((unsigned int*)gcmParams->p Iv)[2], 0x01000000)); | |
Ryan Sleevi
2014/04/23 19:53:34
Undefined aliasing behaviour (the "unsigned int*"
wtc
2014/04/24 01:04:10
Acknowledged. Any suggestion on how to fix this? I
| |
84 } else { | |
85 /* If IV size is not 96 bits, then the initial counter value is GHASH of the IV */ | |
86 intel_aes_gcmAAD(gcm->Htbl, gcmParams->pIv, IV_whole_len, gcm->T); | |
87 /* Partial block */ | |
88 if(IV_remainder_len) { | |
89 PORT_Memset(buff, 0, AES_BLOCK_SIZE); | |
90 PORT_Memcpy(buff, gcmParams->pIv + IV_whole_len, IV_remainder_len); | |
91 intel_aes_gcmAAD(gcm->Htbl, buff, AES_BLOCK_SIZE, gcm->T); | |
92 } | |
93 | |
94 intel_aes_gcmTAG | |
95 ( | |
Ryan Sleevi
2014/04/23 19:53:34
NSS style (eg: libpkix) has tended to keep the ope
wtc
2014/04/24 01:04:10
I will fix this in the NSS upstream.
| |
96 gcm->Htbl, | |
97 gcm->T, | |
98 gcmParams->ulIvLen, | |
99 0, | |
100 gcm->X0, | |
101 gcm->CTR | |
102 ); | |
Ryan Sleevi
2014/04/23 19:53:34
indent off by one from lines 92 through 102
wtc
2014/04/24 01:04:10
I will fix this in the NSS upstream.
| |
103 /* TAG should be zero again */ | |
104 _mm_storeu_si128((__m128i*)gcm->T, _mm_setzero_si128()); | |
105 } | |
106 /* Encrypt the initial counter, will be used to encrypt the GHASH value, in the end */ | |
107 rv = (*cipher)(context, gcm->X0, &j, AES_BLOCK_SIZE, gcm->CTR, AES_BLOCK_SIZ E, AES_BLOCK_SIZE); | |
108 if (rv != SECSuccess) { | |
109 goto loser; | |
110 } | |
111 /* Promote the counter by 1 */ | |
112 _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)); | |
113 | |
114 /* Now hash AAD - it would actually make sense to seperate the context creat ion from the AAD, | |
115 * because that would allow to reuse the H, which only changes when the AES key changes, | |
116 * and not every package, like the IV and AAD */ | |
117 intel_aes_gcmAAD(gcm->Htbl, gcmParams->pAAD, AAD_whole_len, gcm->T); | |
118 if(AAD_remainder_len) { | |
119 PORT_Memset(buff, 0, AES_BLOCK_SIZE); | |
120 PORT_Memcpy(buff, gcmParams->pAAD + AAD_whole_len, AAD_remainder_len); | |
121 intel_aes_gcmAAD(gcm->Htbl, buff, AES_BLOCK_SIZE, gcm->T); | |
122 } | |
123 gcm->Alen += gcmParams->ulAADLen; | |
124 return gcm; | |
125 | |
126 loser: | |
127 if (gcm) { | |
128 PORT_Free(gcm); | |
129 } | |
130 return NULL; | |
131 } | |
132 | |
133 void intel_AES_GCM_DestroyContext(intel_AES_GCMContext *gcm, PRBool freeit) | |
134 { | |
135 if (freeit) { | |
136 PORT_Free(gcm); | |
137 } | |
138 } | |
139 | |
140 SECStatus intel_AES_GCM_EncryptUpdate(intel_AES_GCMContext *gcm, | |
141 unsigned char *outbuf, | |
Ryan Sleevi
2014/04/23 19:53:34
indent style
wtc
2014/04/24 01:04:10
Done.
| |
142 unsigned int *outlen, unsigned int maxout, | |
143 const unsigned char *inbuf, unsigned int inlen, | |
144 unsigned int blocksize) | |
145 { | |
146 unsigned int tagBytes; | |
147 unsigned char T[AES_BLOCK_SIZE]; | |
148 int j; | |
149 | |
150 tagBytes = (gcm->tagBits + (PR_BITS_PER_BYTE-1)) / PR_BITS_PER_BYTE; | |
151 if (UINT_MAX - inlen < tagBytes) { | |
152 PORT_SetError(SEC_ERROR_INPUT_LEN); | |
153 return SECFailure; | |
154 } | |
155 if (maxout < inlen + tagBytes) { | |
156 *outlen = inlen + tagBytes; | |
157 PORT_SetError(SEC_ERROR_OUTPUT_LEN); | |
158 return SECFailure; | |
159 } | |
160 | |
161 intel_aes_gcmENC( | |
162 inbuf, | |
163 outbuf, | |
164 gcm, | |
165 inlen); | |
166 | |
167 gcm->Mlen += inlen; | |
168 | |
169 intel_aes_gcmTAG( | |
170 gcm->Htbl, | |
171 gcm->T, | |
172 gcm->Mlen, | |
173 gcm->Alen, | |
174 gcm->X0, | |
175 T); | |
Ryan Sleevi
2014/04/23 19:53:34
Inconsistent wrapping behaviour here and on line 1
wtc
2014/04/24 01:04:10
In the NSS upstream, I will change line 94 to matc
| |
176 | |
177 *outlen = inlen + tagBytes; | |
178 | |
179 for(j=0; j<tagBytes; j++) | |
180 { | |
Ryan Sleevi
2014/04/23 19:53:34
inconsistent brace style compared with lines 155,
wtc
2014/04/24 01:04:10
I will fix this in the NSS upstream.
| |
181 outbuf[inlen+j] = T[j]; | |
182 } | |
183 return SECSuccess; | |
184 } | |
185 | |
186 SECStatus intel_AES_GCM_DecryptUpdate(intel_AES_GCMContext *gcm, | |
187 unsigned char *outbuf, | |
Ryan Sleevi
2014/04/23 19:53:34
indent
wtc
2014/04/24 01:04:10
Done.
| |
188 unsigned int *outlen, unsigned int maxout, | |
189 const unsigned char *inbuf, unsigned int inlen, | |
190 unsigned int blocksize) | |
191 { | |
192 unsigned int tagBytes; | |
193 unsigned char T[AES_BLOCK_SIZE]; | |
194 const unsigned char *intag; | |
195 | |
196 tagBytes = (gcm->tagBits + (PR_BITS_PER_BYTE-1)) / PR_BITS_PER_BYTE; | |
197 | |
198 /* get the authentication block */ | |
199 if (inlen < tagBytes) { | |
200 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
201 return SECFailure; | |
202 } | |
203 | |
204 inlen -= tagBytes; | |
205 intag = inbuf + inlen; | |
206 | |
207 intel_aes_gcmDEC( | |
208 inbuf, | |
209 outbuf, | |
210 gcm, | |
211 inlen); | |
212 | |
213 gcm->Mlen += inlen; | |
214 intel_aes_gcmTAG( | |
215 gcm->Htbl, | |
216 gcm->T, | |
217 gcm->Mlen, | |
218 gcm->Alen, | |
219 gcm->X0, | |
220 T); | |
221 | |
222 if (NSS_SecureMemcmp(T, intag, tagBytes) != 0) { | |
223 /* force a CKR_ENCRYPTED_DATA_INVALID error at in softoken */ | |
224 PORT_SetError(SEC_ERROR_BAD_DATA); | |
225 return SECFailure; | |
Ryan Sleevi
2014/04/23 19:53:34
You should set *outlen to zero here - you still le
wtc
2014/04/24 01:04:10
Done.
| |
226 } | |
227 *outlen = inlen; | |
228 | |
229 return SECSuccess; | |
230 } | |
231 | |
232 #endif | |
OLD | NEW |