comparison nss/lib/freebl/intel-gcm-wrap.c @ 0:1e5118fa0cb1

This is NSS with a Cmake Buildsyste To compile a static NSS library for Windows we've used the Chromium-NSS fork and added a Cmake buildsystem to compile it statically for Windows. See README.chromium for chromium changes and README.trustbridge for our modifications.
author Andre Heinecke <andre.heinecke@intevation.de>
date Mon, 28 Jul 2014 10:47:06 +0200
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:1e5118fa0cb1
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);
53 int IV_remainder_len = gcmParams->ulIvLen&0xf;
54 int AAD_whole_len = gcmParams->ulAADLen&(~0xf);
55 int AAD_remainder_len = gcmParams->ulAADLen&0xf;
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 */
82 if(gcmParams->ulIvLen == 12) {
83 _mm_storeu_si128((__m128i*)gcm->CTR, _mm_setr_epi32(((unsigned int*)gcmParams->pIv)[0], ((unsigned int*)gcmParams->pIv)[1], ((unsigned int*)gcmParams->pIv)[2], 0x01000000));
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 (
96 gcm->Htbl,
97 gcm->T,
98 gcmParams->ulIvLen,
99 0,
100 gcm->X0,
101 gcm->CTR
102 );
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_SIZE, 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 creation 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,
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);
176
177 *outlen = inlen + tagBytes;
178
179 for(j=0; j<tagBytes; j++)
180 {
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,
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_INPUT_LEN);
201 return SECFailure;
202 }
203
204 inlen -= tagBytes;
205 intag = inbuf + inlen;
206
207 if (maxout < inlen) {
208 *outlen = inlen;
209 PORT_SetError(SEC_ERROR_OUTPUT_LEN);
210 return SECFailure;
211 }
212
213 intel_aes_gcmDEC(
214 inbuf,
215 outbuf,
216 gcm,
217 inlen);
218
219 gcm->Mlen += inlen;
220 intel_aes_gcmTAG(
221 gcm->Htbl,
222 gcm->T,
223 gcm->Mlen,
224 gcm->Alen,
225 gcm->X0,
226 T);
227
228 if (NSS_SecureMemcmp(T, intag, tagBytes) != 0) {
229 memset(outbuf, 0, inlen);
230 *outlen = 0;
231 /* force a CKR_ENCRYPTED_DATA_INVALID error at in softoken */
232 PORT_SetError(SEC_ERROR_BAD_DATA);
233 return SECFailure;
234 }
235 *outlen = inlen;
236
237 return SECSuccess;
238 }
239
240 #endif
This site is hosted by Intevation GmbH (Datenschutzerklärung und Impressum | Privacy Policy and Imprint)