| 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     unsigned long IV_whole_len = gcmParams->ulIvLen & (~0xful); |  | 
| 53     unsigned int IV_remainder_len = gcmParams->ulIvLen & 0xful; |  | 
| 54     unsigned long AAD_whole_len = gcmParams->ulAADLen & (~0xful); |  | 
| 55     unsigned int AAD_remainder_len = gcmParams->ulAADLen & 0xful; |  | 
| 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 |  | 
| 72     /* initialize context fields */ |  | 
| 73     gcm->aes_context = aes; |  | 
| 74     gcm->tagBits = gcmParams->ulTagBits; |  | 
| 75     gcm->Alen = 0; |  | 
| 76     gcm->Mlen = 0; |  | 
| 77 |  | 
| 78     /* first prepare H and its derivatives for ghash */ |  | 
| 79     intel_aes_gcmINIT(gcm->Htbl, (unsigned char*)aes->expandedKey, aes->Nr); |  | 
| 80 |  | 
| 81     /* Initial TAG value is zero */ |  | 
| 82     _mm_storeu_si128((__m128i*)gcm->T, _mm_setzero_si128()); |  | 
| 83     _mm_storeu_si128((__m128i*)gcm->X0, _mm_setzero_si128()); |  | 
| 84 |  | 
| 85     /* Init the counter */ |  | 
| 86     if (gcmParams->ulIvLen == 12) { |  | 
| 87         _mm_storeu_si128((__m128i*)gcm->CTR, |  | 
| 88                          _mm_setr_epi32(((unsigned int*)gcmParams->pIv)[0], |  | 
| 89                                         ((unsigned int*)gcmParams->pIv)[1], |  | 
| 90                                         ((unsigned int*)gcmParams->pIv)[2], |  | 
| 91                                         0x01000000)); |  | 
| 92     } else { |  | 
| 93         /* If IV size is not 96 bits, then the initial counter value is GHASH |  | 
| 94          * of the IV */ |  | 
| 95         intel_aes_gcmAAD(gcm->Htbl, gcmParams->pIv, IV_whole_len, gcm->T); |  | 
| 96 |  | 
| 97         /* Partial block */ |  | 
| 98         if (IV_remainder_len) { |  | 
| 99             PORT_Memset(buff, 0, AES_BLOCK_SIZE); |  | 
| 100             PORT_Memcpy(buff, gcmParams->pIv + IV_whole_len, IV_remainder_len); |  | 
| 101             intel_aes_gcmAAD(gcm->Htbl, buff, AES_BLOCK_SIZE, gcm->T); |  | 
| 102         } |  | 
| 103 |  | 
| 104         intel_aes_gcmTAG( |  | 
| 105             gcm->Htbl, |  | 
| 106             gcm->T, |  | 
| 107             gcmParams->ulIvLen, |  | 
| 108             0, |  | 
| 109             gcm->X0, |  | 
| 110             gcm->CTR); |  | 
| 111 |  | 
| 112         /* TAG should be zero again */ |  | 
| 113         _mm_storeu_si128((__m128i*)gcm->T, _mm_setzero_si128()); |  | 
| 114     } |  | 
| 115 |  | 
| 116     /* Encrypt the initial counter, will be used to encrypt the GHASH value, |  | 
| 117      * in the end */ |  | 
| 118     rv = (*cipher)(context, gcm->X0, &j, AES_BLOCK_SIZE, gcm->CTR, |  | 
| 119                    AES_BLOCK_SIZE, AES_BLOCK_SIZE); |  | 
| 120     if (rv != SECSuccess) { |  | 
| 121         goto loser; |  | 
| 122     } |  | 
| 123 |  | 
| 124     /* Promote the counter by 1 */ |  | 
| 125     _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)); |  | 
| 126 |  | 
| 127     /* Now hash AAD - it would actually make sense to seperate the context |  | 
| 128      * creation from the AAD, because that would allow to reuse the H, which |  | 
| 129      * only changes when the AES key changes, and not every package, like the |  | 
| 130      * IV and AAD */ |  | 
| 131     intel_aes_gcmAAD(gcm->Htbl, gcmParams->pAAD, AAD_whole_len, gcm->T); |  | 
| 132     if (AAD_remainder_len) { |  | 
| 133         PORT_Memset(buff, 0, AES_BLOCK_SIZE); |  | 
| 134         PORT_Memcpy(buff, gcmParams->pAAD + AAD_whole_len, AAD_remainder_len); |  | 
| 135         intel_aes_gcmAAD(gcm->Htbl, buff, AES_BLOCK_SIZE, gcm->T); |  | 
| 136     } |  | 
| 137     gcm->Alen += gcmParams->ulAADLen; |  | 
| 138     return gcm; |  | 
| 139 |  | 
| 140 loser: |  | 
| 141     if (gcm) { |  | 
| 142         PORT_Free(gcm); |  | 
| 143     } |  | 
| 144     return NULL; |  | 
| 145 } |  | 
| 146 |  | 
| 147 void intel_AES_GCM_DestroyContext(intel_AES_GCMContext *gcm, PRBool freeit) |  | 
| 148 { |  | 
| 149     if (freeit) { |  | 
| 150         PORT_Free(gcm); |  | 
| 151     } |  | 
| 152 } |  | 
| 153 |  | 
| 154 SECStatus intel_AES_GCM_EncryptUpdate(intel_AES_GCMContext *gcm, |  | 
| 155             unsigned char *outbuf, |  | 
| 156             unsigned int *outlen, unsigned int maxout, |  | 
| 157             const unsigned char *inbuf, unsigned int inlen, |  | 
| 158             unsigned int blocksize) |  | 
| 159 { |  | 
| 160     unsigned int tagBytes; |  | 
| 161     unsigned char T[AES_BLOCK_SIZE]; |  | 
| 162     unsigned int j; |  | 
| 163 |  | 
| 164     tagBytes = (gcm->tagBits + (PR_BITS_PER_BYTE - 1)) / PR_BITS_PER_BYTE; |  | 
| 165     if (UINT_MAX - inlen < tagBytes) { |  | 
| 166         PORT_SetError(SEC_ERROR_INPUT_LEN); |  | 
| 167         return SECFailure; |  | 
| 168     } |  | 
| 169     if (maxout < inlen + tagBytes) { |  | 
| 170         *outlen = inlen + tagBytes; |  | 
| 171         PORT_SetError(SEC_ERROR_OUTPUT_LEN); |  | 
| 172         return SECFailure; |  | 
| 173     } |  | 
| 174 |  | 
| 175     intel_aes_gcmENC( |  | 
| 176         inbuf, |  | 
| 177         outbuf, |  | 
| 178         gcm, |  | 
| 179         inlen); |  | 
| 180 |  | 
| 181     gcm->Mlen += inlen; |  | 
| 182 |  | 
| 183     intel_aes_gcmTAG( |  | 
| 184         gcm->Htbl, |  | 
| 185         gcm->T, |  | 
| 186         gcm->Mlen, |  | 
| 187         gcm->Alen, |  | 
| 188         gcm->X0, |  | 
| 189         T); |  | 
| 190 |  | 
| 191     *outlen = inlen + tagBytes; |  | 
| 192 |  | 
| 193     for (j = 0; j < tagBytes; j++) { |  | 
| 194         outbuf[inlen + j] = T[j]; |  | 
| 195     } |  | 
| 196     return SECSuccess; |  | 
| 197 } |  | 
| 198 |  | 
| 199 SECStatus intel_AES_GCM_DecryptUpdate(intel_AES_GCMContext *gcm, |  | 
| 200             unsigned char *outbuf, |  | 
| 201             unsigned int *outlen, unsigned int maxout, |  | 
| 202             const unsigned char *inbuf, unsigned int inlen, |  | 
| 203             unsigned int blocksize) |  | 
| 204 { |  | 
| 205     unsigned int tagBytes; |  | 
| 206     unsigned char T[AES_BLOCK_SIZE]; |  | 
| 207     const unsigned char *intag; |  | 
| 208 |  | 
| 209     tagBytes = (gcm->tagBits + (PR_BITS_PER_BYTE - 1)) / PR_BITS_PER_BYTE; |  | 
| 210 |  | 
| 211     /* get the authentication block */ |  | 
| 212     if (inlen < tagBytes) { |  | 
| 213         PORT_SetError(SEC_ERROR_INPUT_LEN); |  | 
| 214         return SECFailure; |  | 
| 215     } |  | 
| 216 |  | 
| 217     inlen -= tagBytes; |  | 
| 218     intag = inbuf + inlen; |  | 
| 219 |  | 
| 220     if (maxout < inlen) { |  | 
| 221         *outlen = inlen; |  | 
| 222         PORT_SetError(SEC_ERROR_OUTPUT_LEN); |  | 
| 223         return SECFailure; |  | 
| 224     } |  | 
| 225 |  | 
| 226     intel_aes_gcmDEC( |  | 
| 227          inbuf, |  | 
| 228          outbuf, |  | 
| 229          gcm, |  | 
| 230          inlen); |  | 
| 231 |  | 
| 232     gcm->Mlen += inlen; |  | 
| 233     intel_aes_gcmTAG( |  | 
| 234          gcm->Htbl, |  | 
| 235          gcm->T, |  | 
| 236          gcm->Mlen, |  | 
| 237          gcm->Alen, |  | 
| 238          gcm->X0, |  | 
| 239          T); |  | 
| 240 |  | 
| 241     if (NSS_SecureMemcmp(T, intag, tagBytes) != 0) { |  | 
| 242         memset(outbuf, 0, inlen); |  | 
| 243         *outlen = 0; |  | 
| 244         /* force a CKR_ENCRYPTED_DATA_INVALID error at in softoken */ |  | 
| 245         PORT_SetError(SEC_ERROR_BAD_DATA); |  | 
| 246         return SECFailure; |  | 
| 247     } |  | 
| 248     *outlen = inlen; |  | 
| 249 |  | 
| 250     return SECSuccess; |  | 
| 251 } |  | 
| 252 |  | 
| 253 #endif |  | 
| OLD | NEW | 
|---|