1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/nss/lib/freebl/ctr.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,229 @@ 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 + 1.8 +#ifdef FREEBL_NO_DEPEND 1.9 +#include "stubs.h" 1.10 +#endif 1.11 +#include "prtypes.h" 1.12 +#include "blapit.h" 1.13 +#include "blapii.h" 1.14 +#include "ctr.h" 1.15 +#include "pkcs11t.h" 1.16 +#include "secerr.h" 1.17 + 1.18 +#ifdef USE_HW_AES 1.19 +#include "intel-aes.h" 1.20 +#include "rijndael.h" 1.21 +#endif 1.22 + 1.23 +SECStatus 1.24 +CTR_InitContext(CTRContext *ctr, void *context, freeblCipherFunc cipher, 1.25 + const unsigned char *param, unsigned int blocksize) 1.26 +{ 1.27 + const CK_AES_CTR_PARAMS *ctrParams = (const CK_AES_CTR_PARAMS *)param; 1.28 + 1.29 + if (ctrParams->ulCounterBits == 0 || 1.30 + ctrParams->ulCounterBits > blocksize * PR_BITS_PER_BYTE) { 1.31 + PORT_SetError(SEC_ERROR_INVALID_ARGS); 1.32 + return SECFailure; 1.33 + } 1.34 + 1.35 + /* Invariant: 0 < ctr->bufPtr <= blocksize */ 1.36 + ctr->bufPtr = blocksize; /* no unused data in the buffer */ 1.37 + ctr->cipher = cipher; 1.38 + ctr->context = context; 1.39 + ctr->counterBits = ctrParams->ulCounterBits; 1.40 + if (blocksize > sizeof(ctr->counter) || 1.41 + blocksize > sizeof(ctrParams->cb)) { 1.42 + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); 1.43 + return SECFailure; 1.44 + } 1.45 + PORT_Memcpy(ctr->counter, ctrParams->cb, blocksize); 1.46 + return SECSuccess; 1.47 +} 1.48 + 1.49 +CTRContext * 1.50 +CTR_CreateContext(void *context, freeblCipherFunc cipher, 1.51 + const unsigned char *param, unsigned int blocksize) 1.52 +{ 1.53 + CTRContext *ctr; 1.54 + SECStatus rv; 1.55 + 1.56 + /* first fill in the Counter context */ 1.57 + ctr = PORT_ZNew(CTRContext); 1.58 + if (ctr == NULL) { 1.59 + return NULL; 1.60 + } 1.61 + rv = CTR_InitContext(ctr, context, cipher, param, blocksize); 1.62 + if (rv != SECSuccess) { 1.63 + CTR_DestroyContext(ctr, PR_TRUE); 1.64 + ctr = NULL; 1.65 + } 1.66 + return ctr; 1.67 +} 1.68 + 1.69 +void 1.70 +CTR_DestroyContext(CTRContext *ctr, PRBool freeit) 1.71 +{ 1.72 + PORT_Memset(ctr, 0, sizeof(CTRContext)); 1.73 + if (freeit) { 1.74 + PORT_Free(ctr); 1.75 + } 1.76 +} 1.77 + 1.78 +/* 1.79 + * Used by counter mode. Increment the counter block. Not all bits in the 1.80 + * counter block are part of the counter, counterBits tells how many bits 1.81 + * are part of the counter. The counter block is blocksize long. It's a 1.82 + * big endian value. 1.83 + * 1.84 + * XXX Does not handle counter rollover. 1.85 + */ 1.86 +static void 1.87 +ctr_GetNextCtr(unsigned char *counter, unsigned int counterBits, 1.88 + unsigned int blocksize) 1.89 +{ 1.90 + unsigned char *counterPtr = counter + blocksize - 1; 1.91 + unsigned char mask, count; 1.92 + 1.93 + PORT_Assert(counterBits <= blocksize*PR_BITS_PER_BYTE); 1.94 + while (counterBits >= PR_BITS_PER_BYTE) { 1.95 + if (++(*(counterPtr--))) { 1.96 + return; 1.97 + } 1.98 + counterBits -= PR_BITS_PER_BYTE; 1.99 + } 1.100 + if (counterBits == 0) { 1.101 + return; 1.102 + } 1.103 + /* increment the final partial byte */ 1.104 + mask = (1 << counterBits)-1; 1.105 + count = ++(*counterPtr) & mask; 1.106 + *counterPtr = ((*counterPtr) & ~mask) | count; 1.107 + return; 1.108 +} 1.109 + 1.110 +static void 1.111 +ctr_xor(unsigned char *target, const unsigned char *x, 1.112 + const unsigned char *y, unsigned int count) 1.113 +{ 1.114 + unsigned int i; 1.115 + for (i=0; i < count; i++) { 1.116 + *target++ = *x++ ^ *y++; 1.117 + } 1.118 +} 1.119 + 1.120 +SECStatus 1.121 +CTR_Update(CTRContext *ctr, unsigned char *outbuf, 1.122 + unsigned int *outlen, unsigned int maxout, 1.123 + const unsigned char *inbuf, unsigned int inlen, 1.124 + unsigned int blocksize) 1.125 +{ 1.126 + unsigned int tmp; 1.127 + SECStatus rv; 1.128 + 1.129 + if (maxout < inlen) { 1.130 + *outlen = inlen; 1.131 + PORT_SetError(SEC_ERROR_OUTPUT_LEN); 1.132 + return SECFailure; 1.133 + } 1.134 + *outlen = 0; 1.135 + if (ctr->bufPtr != blocksize) { 1.136 + unsigned int needed = PR_MIN(blocksize-ctr->bufPtr, inlen); 1.137 + ctr_xor(outbuf, inbuf, ctr->buffer + ctr->bufPtr, needed); 1.138 + ctr->bufPtr += needed; 1.139 + outbuf += needed; 1.140 + inbuf += needed; 1.141 + *outlen += needed; 1.142 + inlen -= needed; 1.143 + if (inlen == 0) { 1.144 + return SECSuccess; 1.145 + } 1.146 + PORT_Assert(ctr->bufPtr == blocksize); 1.147 + } 1.148 + 1.149 + while (inlen >= blocksize) { 1.150 + rv = (*ctr->cipher)(ctr->context, ctr->buffer, &tmp, blocksize, 1.151 + ctr->counter, blocksize, blocksize); 1.152 + ctr_GetNextCtr(ctr->counter, ctr->counterBits, blocksize); 1.153 + if (rv != SECSuccess) { 1.154 + return SECFailure; 1.155 + } 1.156 + ctr_xor(outbuf, inbuf, ctr->buffer, blocksize); 1.157 + outbuf += blocksize; 1.158 + inbuf += blocksize; 1.159 + *outlen += blocksize; 1.160 + inlen -= blocksize; 1.161 + } 1.162 + if (inlen == 0) { 1.163 + return SECSuccess; 1.164 + } 1.165 + rv = (*ctr->cipher)(ctr->context, ctr->buffer, &tmp, blocksize, 1.166 + ctr->counter, blocksize, blocksize); 1.167 + ctr_GetNextCtr(ctr->counter, ctr->counterBits, blocksize); 1.168 + if (rv != SECSuccess) { 1.169 + return SECFailure; 1.170 + } 1.171 + ctr_xor(outbuf, inbuf, ctr->buffer, inlen); 1.172 + ctr->bufPtr = inlen; 1.173 + *outlen += inlen; 1.174 + return SECSuccess; 1.175 +} 1.176 + 1.177 +#if defined(USE_HW_AES) && defined(_MSC_VER) 1.178 +SECStatus 1.179 +CTR_Update_HW_AES(CTRContext *ctr, unsigned char *outbuf, 1.180 + unsigned int *outlen, unsigned int maxout, 1.181 + const unsigned char *inbuf, unsigned int inlen, 1.182 + unsigned int blocksize) 1.183 +{ 1.184 + unsigned int fullblocks; 1.185 + unsigned int tmp; 1.186 + SECStatus rv; 1.187 + 1.188 + if (maxout < inlen) { 1.189 + *outlen = inlen; 1.190 + PORT_SetError(SEC_ERROR_OUTPUT_LEN); 1.191 + return SECFailure; 1.192 + } 1.193 + *outlen = 0; 1.194 + if (ctr->bufPtr != blocksize) { 1.195 + unsigned int needed = PR_MIN(blocksize-ctr->bufPtr, inlen); 1.196 + ctr_xor(outbuf, inbuf, ctr->buffer + ctr->bufPtr, needed); 1.197 + ctr->bufPtr += needed; 1.198 + outbuf += needed; 1.199 + inbuf += needed; 1.200 + *outlen += needed; 1.201 + inlen -= needed; 1.202 + if (inlen == 0) { 1.203 + return SECSuccess; 1.204 + } 1.205 + PORT_Assert(ctr->bufPtr == blocksize); 1.206 + } 1.207 + 1.208 + intel_aes_ctr_worker(((AESContext*)(ctr->context))->Nr)( 1.209 + ctr, outbuf, outlen, maxout, inbuf, inlen, blocksize); 1.210 + /* XXX intel_aes_ctr_worker should set *outlen. */ 1.211 + PORT_Assert(*outlen == 0); 1.212 + fullblocks = (inlen/blocksize)*blocksize; 1.213 + *outlen += fullblocks; 1.214 + outbuf += fullblocks; 1.215 + inbuf += fullblocks; 1.216 + inlen -= fullblocks; 1.217 + 1.218 + if (inlen == 0) { 1.219 + return SECSuccess; 1.220 + } 1.221 + rv = (*ctr->cipher)(ctr->context, ctr->buffer, &tmp, blocksize, 1.222 + ctr->counter, blocksize, blocksize); 1.223 + ctr_GetNextCtr(ctr->counter, ctr->counterBits, blocksize); 1.224 + if (rv != SECSuccess) { 1.225 + return SECFailure; 1.226 + } 1.227 + ctr_xor(outbuf, inbuf, ctr->buffer, inlen); 1.228 + ctr->bufPtr = inlen; 1.229 + *outlen += inlen; 1.230 + return SECSuccess; 1.231 +} 1.232 +#endif