security/nss/lib/freebl/intel-gcm-wrap.c

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     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. */
     6 /* Wrapper functions for Intel optimized implementation of AES-GCM */
     8 #ifdef USE_HW_AES
    10 #ifdef FREEBL_NO_DEPEND
    11 #include "stubs.h"
    12 #endif
    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"
    22 #include <limits.h>
    24 #include "intel-gcm.h"
    25 #include "rijndael.h"
    27 #include <emmintrin.h>
    28 #include <tmmintrin.h>
    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 };
    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 */
    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;
    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;
    62     if (blocksize != AES_BLOCK_SIZE) {
    63       PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
    64       return NULL;
    65     }
    66     gcm = PORT_ZNew(intel_AES_GCMContext);
    68     if (gcm == NULL) {
    69         return NULL;
    70     }
    72     /* initialize context fields */
    73     gcm->aes_context = aes;
    74     gcm->tagBits = gcmParams->ulTagBits;
    75     gcm->Alen = 0;
    76     gcm->Mlen = 0;
    78     /* first prepare H and its derivatives for ghash */
    79     intel_aes_gcmINIT(gcm->Htbl, (unsigned char*)aes->expandedKey, aes->Nr);
    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());
    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);
    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         }
   104         intel_aes_gcmTAG(
   105             gcm->Htbl,
   106             gcm->T,
   107             gcmParams->ulIvLen,
   108             0,
   109             gcm->X0,
   110             gcm->CTR);
   112         /* TAG should be zero again */
   113         _mm_storeu_si128((__m128i*)gcm->T, _mm_setzero_si128());
   114     }
   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     }
   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));
   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;
   140 loser:
   141     if (gcm) {
   142         PORT_Free(gcm);
   143     }
   144     return NULL;
   145 }
   147 void intel_AES_GCM_DestroyContext(intel_AES_GCMContext *gcm, PRBool freeit)
   148 {
   149     if (freeit) {
   150         PORT_Free(gcm);
   151     }
   152 }
   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;
   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     }
   175     intel_aes_gcmENC(
   176         inbuf,
   177         outbuf,
   178         gcm,
   179         inlen);
   181     gcm->Mlen += inlen;
   183     intel_aes_gcmTAG(
   184         gcm->Htbl,
   185         gcm->T,
   186         gcm->Mlen,
   187         gcm->Alen,
   188         gcm->X0,
   189         T);
   191     *outlen = inlen + tagBytes;
   193     for (j = 0; j < tagBytes; j++) {
   194         outbuf[inlen + j] = T[j];
   195     }
   196     return SECSuccess;
   197 }
   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;
   209     tagBytes = (gcm->tagBits + (PR_BITS_PER_BYTE - 1)) / PR_BITS_PER_BYTE;
   211     /* get the authentication block */
   212     if (inlen < tagBytes) {
   213         PORT_SetError(SEC_ERROR_INPUT_LEN);
   214         return SECFailure;
   215     }
   217     inlen -= tagBytes;
   218     intag = inbuf + inlen;
   220     if (maxout < inlen) {
   221         *outlen = inlen;
   222         PORT_SetError(SEC_ERROR_OUTPUT_LEN);
   223         return SECFailure;
   224     }
   226     intel_aes_gcmDEC(
   227          inbuf,
   228          outbuf,
   229          gcm,
   230          inlen);
   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);
   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;
   250     return SECSuccess;
   251 }
   253 #endif

mercurial