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

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/security/nss/lib/freebl/intel-gcm-wrap.c	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,253 @@
     1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.7 +/* Copyright(c) 2013, Intel Corp. */
     1.8 +
     1.9 +/* Wrapper functions for Intel optimized implementation of AES-GCM */
    1.10 +
    1.11 +#ifdef USE_HW_AES
    1.12 +
    1.13 +#ifdef FREEBL_NO_DEPEND
    1.14 +#include "stubs.h"
    1.15 +#endif
    1.16 +
    1.17 +#include "blapii.h"
    1.18 +#include "blapit.h"
    1.19 +#include "gcm.h"
    1.20 +#include "ctr.h"
    1.21 +#include "secerr.h"
    1.22 +#include "prtypes.h"
    1.23 +#include "pkcs11t.h"
    1.24 +
    1.25 +#include <limits.h>
    1.26 +
    1.27 +#include "intel-gcm.h"
    1.28 +#include "rijndael.h"
    1.29 +
    1.30 +#include <emmintrin.h>
    1.31 +#include <tmmintrin.h>
    1.32 +
    1.33 +
    1.34 +struct intel_AES_GCMContextStr{
    1.35 +    unsigned char Htbl[16*AES_BLOCK_SIZE];
    1.36 +    unsigned char X0[AES_BLOCK_SIZE];
    1.37 +    unsigned char T[AES_BLOCK_SIZE];
    1.38 +    unsigned char CTR[AES_BLOCK_SIZE];
    1.39 +    AESContext *aes_context;
    1.40 +    unsigned long tagBits;
    1.41 +    unsigned long Alen;
    1.42 +    unsigned long Mlen;
    1.43 +};
    1.44 +
    1.45 +intel_AES_GCMContext *intel_AES_GCM_CreateContext(void *context,
    1.46 +               freeblCipherFunc cipher,
    1.47 +               const unsigned char *params,
    1.48 +               unsigned int blocksize)
    1.49 +{
    1.50 +    intel_AES_GCMContext *gcm = NULL;
    1.51 +    AESContext *aes = (AESContext*)context;
    1.52 +    const CK_GCM_PARAMS *gcmParams = (const CK_GCM_PARAMS *)params;
    1.53 +    unsigned char buff[AES_BLOCK_SIZE]; /* aux buffer */
    1.54 +
    1.55 +    unsigned long IV_whole_len = gcmParams->ulIvLen & (~0xful);
    1.56 +    unsigned int IV_remainder_len = gcmParams->ulIvLen & 0xful;
    1.57 +    unsigned long AAD_whole_len = gcmParams->ulAADLen & (~0xful);
    1.58 +    unsigned int AAD_remainder_len = gcmParams->ulAADLen & 0xful;
    1.59 +
    1.60 +    __m128i BSWAP_MASK = _mm_setr_epi8(15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0);
    1.61 +    __m128i ONE = _mm_set_epi32(0,0,0,1);
    1.62 +    unsigned int j;
    1.63 +    SECStatus rv;
    1.64 +
    1.65 +    if (blocksize != AES_BLOCK_SIZE) {
    1.66 +      PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
    1.67 +      return NULL;
    1.68 +    }
    1.69 +    gcm = PORT_ZNew(intel_AES_GCMContext);
    1.70 +
    1.71 +    if (gcm == NULL) {
    1.72 +        return NULL;
    1.73 +    }
    1.74 +
    1.75 +    /* initialize context fields */
    1.76 +    gcm->aes_context = aes;
    1.77 +    gcm->tagBits = gcmParams->ulTagBits;
    1.78 +    gcm->Alen = 0;
    1.79 +    gcm->Mlen = 0;
    1.80 +
    1.81 +    /* first prepare H and its derivatives for ghash */
    1.82 +    intel_aes_gcmINIT(gcm->Htbl, (unsigned char*)aes->expandedKey, aes->Nr);
    1.83 +
    1.84 +    /* Initial TAG value is zero */
    1.85 +    _mm_storeu_si128((__m128i*)gcm->T, _mm_setzero_si128());
    1.86 +    _mm_storeu_si128((__m128i*)gcm->X0, _mm_setzero_si128());
    1.87 +
    1.88 +    /* Init the counter */
    1.89 +    if (gcmParams->ulIvLen == 12) {
    1.90 +        _mm_storeu_si128((__m128i*)gcm->CTR,
    1.91 +                         _mm_setr_epi32(((unsigned int*)gcmParams->pIv)[0],
    1.92 +                                        ((unsigned int*)gcmParams->pIv)[1],
    1.93 +                                        ((unsigned int*)gcmParams->pIv)[2],
    1.94 +                                        0x01000000));
    1.95 +    } else {
    1.96 +        /* If IV size is not 96 bits, then the initial counter value is GHASH
    1.97 +         * of the IV */
    1.98 +        intel_aes_gcmAAD(gcm->Htbl, gcmParams->pIv, IV_whole_len, gcm->T);
    1.99 +
   1.100 +        /* Partial block */
   1.101 +        if (IV_remainder_len) {
   1.102 +            PORT_Memset(buff, 0, AES_BLOCK_SIZE);
   1.103 +            PORT_Memcpy(buff, gcmParams->pIv + IV_whole_len, IV_remainder_len);
   1.104 +            intel_aes_gcmAAD(gcm->Htbl, buff, AES_BLOCK_SIZE, gcm->T);
   1.105 +        }
   1.106 +
   1.107 +        intel_aes_gcmTAG(
   1.108 +            gcm->Htbl,
   1.109 +            gcm->T,
   1.110 +            gcmParams->ulIvLen,
   1.111 +            0,
   1.112 +            gcm->X0,
   1.113 +            gcm->CTR);
   1.114 +
   1.115 +        /* TAG should be zero again */
   1.116 +        _mm_storeu_si128((__m128i*)gcm->T, _mm_setzero_si128());
   1.117 +    }
   1.118 +
   1.119 +    /* Encrypt the initial counter, will be used to encrypt the GHASH value,
   1.120 +     * in the end */
   1.121 +    rv = (*cipher)(context, gcm->X0, &j, AES_BLOCK_SIZE, gcm->CTR,
   1.122 +                   AES_BLOCK_SIZE, AES_BLOCK_SIZE);
   1.123 +    if (rv != SECSuccess) {
   1.124 +        goto loser;
   1.125 +    }
   1.126 +
   1.127 +    /* Promote the counter by 1 */
   1.128 +    _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));
   1.129 +
   1.130 +    /* Now hash AAD - it would actually make sense to seperate the context
   1.131 +     * creation from the AAD, because that would allow to reuse the H, which
   1.132 +     * only changes when the AES key changes, and not every package, like the
   1.133 +     * IV and AAD */
   1.134 +    intel_aes_gcmAAD(gcm->Htbl, gcmParams->pAAD, AAD_whole_len, gcm->T);
   1.135 +    if (AAD_remainder_len) {
   1.136 +        PORT_Memset(buff, 0, AES_BLOCK_SIZE);
   1.137 +        PORT_Memcpy(buff, gcmParams->pAAD + AAD_whole_len, AAD_remainder_len);
   1.138 +        intel_aes_gcmAAD(gcm->Htbl, buff, AES_BLOCK_SIZE, gcm->T);
   1.139 +    }
   1.140 +    gcm->Alen += gcmParams->ulAADLen;
   1.141 +    return gcm;
   1.142 +
   1.143 +loser:
   1.144 +    if (gcm) {
   1.145 +        PORT_Free(gcm);
   1.146 +    }
   1.147 +    return NULL;
   1.148 +}
   1.149 +
   1.150 +void intel_AES_GCM_DestroyContext(intel_AES_GCMContext *gcm, PRBool freeit)
   1.151 +{
   1.152 +    if (freeit) {
   1.153 +        PORT_Free(gcm);
   1.154 +    }
   1.155 +}
   1.156 +
   1.157 +SECStatus intel_AES_GCM_EncryptUpdate(intel_AES_GCMContext *gcm,
   1.158 +            unsigned char *outbuf,
   1.159 +            unsigned int *outlen, unsigned int maxout,
   1.160 +            const unsigned char *inbuf, unsigned int inlen,
   1.161 +            unsigned int blocksize)
   1.162 +{
   1.163 +    unsigned int tagBytes;
   1.164 +    unsigned char T[AES_BLOCK_SIZE];
   1.165 +    unsigned int j;
   1.166 +
   1.167 +    tagBytes = (gcm->tagBits + (PR_BITS_PER_BYTE - 1)) / PR_BITS_PER_BYTE;
   1.168 +    if (UINT_MAX - inlen < tagBytes) {
   1.169 +        PORT_SetError(SEC_ERROR_INPUT_LEN);
   1.170 +        return SECFailure;
   1.171 +    }
   1.172 +    if (maxout < inlen + tagBytes) {
   1.173 +        *outlen = inlen + tagBytes;
   1.174 +        PORT_SetError(SEC_ERROR_OUTPUT_LEN);
   1.175 +        return SECFailure;
   1.176 +    }
   1.177 +
   1.178 +    intel_aes_gcmENC(
   1.179 +        inbuf,
   1.180 +        outbuf,
   1.181 +        gcm,
   1.182 +        inlen);
   1.183 +
   1.184 +    gcm->Mlen += inlen;
   1.185 +
   1.186 +    intel_aes_gcmTAG(
   1.187 +        gcm->Htbl,
   1.188 +        gcm->T,
   1.189 +        gcm->Mlen,
   1.190 +        gcm->Alen,
   1.191 +        gcm->X0,
   1.192 +        T);
   1.193 +
   1.194 +    *outlen = inlen + tagBytes;
   1.195 +
   1.196 +    for (j = 0; j < tagBytes; j++) {
   1.197 +        outbuf[inlen + j] = T[j];
   1.198 +    }
   1.199 +    return SECSuccess;
   1.200 +}
   1.201 +
   1.202 +SECStatus intel_AES_GCM_DecryptUpdate(intel_AES_GCMContext *gcm,
   1.203 +            unsigned char *outbuf,
   1.204 +            unsigned int *outlen, unsigned int maxout,
   1.205 +            const unsigned char *inbuf, unsigned int inlen,
   1.206 +            unsigned int blocksize)
   1.207 +{
   1.208 +    unsigned int tagBytes;
   1.209 +    unsigned char T[AES_BLOCK_SIZE];
   1.210 +    const unsigned char *intag;
   1.211 +
   1.212 +    tagBytes = (gcm->tagBits + (PR_BITS_PER_BYTE - 1)) / PR_BITS_PER_BYTE;
   1.213 +
   1.214 +    /* get the authentication block */
   1.215 +    if (inlen < tagBytes) {
   1.216 +        PORT_SetError(SEC_ERROR_INPUT_LEN);
   1.217 +        return SECFailure;
   1.218 +    }
   1.219 +
   1.220 +    inlen -= tagBytes;
   1.221 +    intag = inbuf + inlen;
   1.222 +
   1.223 +    if (maxout < inlen) {
   1.224 +        *outlen = inlen;
   1.225 +        PORT_SetError(SEC_ERROR_OUTPUT_LEN);
   1.226 +        return SECFailure;
   1.227 +    }
   1.228 +
   1.229 +    intel_aes_gcmDEC(
   1.230 +         inbuf,
   1.231 +         outbuf,
   1.232 +         gcm,
   1.233 +         inlen);
   1.234 +
   1.235 +    gcm->Mlen += inlen;
   1.236 +    intel_aes_gcmTAG(
   1.237 +         gcm->Htbl,
   1.238 +         gcm->T,
   1.239 +         gcm->Mlen,
   1.240 +         gcm->Alen,
   1.241 +         gcm->X0,
   1.242 +         T);
   1.243 +
   1.244 +    if (NSS_SecureMemcmp(T, intag, tagBytes) != 0) {
   1.245 +        memset(outbuf, 0, inlen);
   1.246 +        *outlen = 0;
   1.247 +        /* force a CKR_ENCRYPTED_DATA_INVALID error at in softoken */
   1.248 +        PORT_SetError(SEC_ERROR_BAD_DATA);
   1.249 +        return SECFailure;
   1.250 +    }
   1.251 +    *outlen = inlen;
   1.252 +
   1.253 +    return SECSuccess;
   1.254 +}
   1.255 +
   1.256 +#endif

mercurial