security/nss/lib/freebl/ctr.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

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4
michael@0 5 #ifdef FREEBL_NO_DEPEND
michael@0 6 #include "stubs.h"
michael@0 7 #endif
michael@0 8 #include "prtypes.h"
michael@0 9 #include "blapit.h"
michael@0 10 #include "blapii.h"
michael@0 11 #include "ctr.h"
michael@0 12 #include "pkcs11t.h"
michael@0 13 #include "secerr.h"
michael@0 14
michael@0 15 #ifdef USE_HW_AES
michael@0 16 #include "intel-aes.h"
michael@0 17 #include "rijndael.h"
michael@0 18 #endif
michael@0 19
michael@0 20 SECStatus
michael@0 21 CTR_InitContext(CTRContext *ctr, void *context, freeblCipherFunc cipher,
michael@0 22 const unsigned char *param, unsigned int blocksize)
michael@0 23 {
michael@0 24 const CK_AES_CTR_PARAMS *ctrParams = (const CK_AES_CTR_PARAMS *)param;
michael@0 25
michael@0 26 if (ctrParams->ulCounterBits == 0 ||
michael@0 27 ctrParams->ulCounterBits > blocksize * PR_BITS_PER_BYTE) {
michael@0 28 PORT_SetError(SEC_ERROR_INVALID_ARGS);
michael@0 29 return SECFailure;
michael@0 30 }
michael@0 31
michael@0 32 /* Invariant: 0 < ctr->bufPtr <= blocksize */
michael@0 33 ctr->bufPtr = blocksize; /* no unused data in the buffer */
michael@0 34 ctr->cipher = cipher;
michael@0 35 ctr->context = context;
michael@0 36 ctr->counterBits = ctrParams->ulCounterBits;
michael@0 37 if (blocksize > sizeof(ctr->counter) ||
michael@0 38 blocksize > sizeof(ctrParams->cb)) {
michael@0 39 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
michael@0 40 return SECFailure;
michael@0 41 }
michael@0 42 PORT_Memcpy(ctr->counter, ctrParams->cb, blocksize);
michael@0 43 return SECSuccess;
michael@0 44 }
michael@0 45
michael@0 46 CTRContext *
michael@0 47 CTR_CreateContext(void *context, freeblCipherFunc cipher,
michael@0 48 const unsigned char *param, unsigned int blocksize)
michael@0 49 {
michael@0 50 CTRContext *ctr;
michael@0 51 SECStatus rv;
michael@0 52
michael@0 53 /* first fill in the Counter context */
michael@0 54 ctr = PORT_ZNew(CTRContext);
michael@0 55 if (ctr == NULL) {
michael@0 56 return NULL;
michael@0 57 }
michael@0 58 rv = CTR_InitContext(ctr, context, cipher, param, blocksize);
michael@0 59 if (rv != SECSuccess) {
michael@0 60 CTR_DestroyContext(ctr, PR_TRUE);
michael@0 61 ctr = NULL;
michael@0 62 }
michael@0 63 return ctr;
michael@0 64 }
michael@0 65
michael@0 66 void
michael@0 67 CTR_DestroyContext(CTRContext *ctr, PRBool freeit)
michael@0 68 {
michael@0 69 PORT_Memset(ctr, 0, sizeof(CTRContext));
michael@0 70 if (freeit) {
michael@0 71 PORT_Free(ctr);
michael@0 72 }
michael@0 73 }
michael@0 74
michael@0 75 /*
michael@0 76 * Used by counter mode. Increment the counter block. Not all bits in the
michael@0 77 * counter block are part of the counter, counterBits tells how many bits
michael@0 78 * are part of the counter. The counter block is blocksize long. It's a
michael@0 79 * big endian value.
michael@0 80 *
michael@0 81 * XXX Does not handle counter rollover.
michael@0 82 */
michael@0 83 static void
michael@0 84 ctr_GetNextCtr(unsigned char *counter, unsigned int counterBits,
michael@0 85 unsigned int blocksize)
michael@0 86 {
michael@0 87 unsigned char *counterPtr = counter + blocksize - 1;
michael@0 88 unsigned char mask, count;
michael@0 89
michael@0 90 PORT_Assert(counterBits <= blocksize*PR_BITS_PER_BYTE);
michael@0 91 while (counterBits >= PR_BITS_PER_BYTE) {
michael@0 92 if (++(*(counterPtr--))) {
michael@0 93 return;
michael@0 94 }
michael@0 95 counterBits -= PR_BITS_PER_BYTE;
michael@0 96 }
michael@0 97 if (counterBits == 0) {
michael@0 98 return;
michael@0 99 }
michael@0 100 /* increment the final partial byte */
michael@0 101 mask = (1 << counterBits)-1;
michael@0 102 count = ++(*counterPtr) & mask;
michael@0 103 *counterPtr = ((*counterPtr) & ~mask) | count;
michael@0 104 return;
michael@0 105 }
michael@0 106
michael@0 107 static void
michael@0 108 ctr_xor(unsigned char *target, const unsigned char *x,
michael@0 109 const unsigned char *y, unsigned int count)
michael@0 110 {
michael@0 111 unsigned int i;
michael@0 112 for (i=0; i < count; i++) {
michael@0 113 *target++ = *x++ ^ *y++;
michael@0 114 }
michael@0 115 }
michael@0 116
michael@0 117 SECStatus
michael@0 118 CTR_Update(CTRContext *ctr, unsigned char *outbuf,
michael@0 119 unsigned int *outlen, unsigned int maxout,
michael@0 120 const unsigned char *inbuf, unsigned int inlen,
michael@0 121 unsigned int blocksize)
michael@0 122 {
michael@0 123 unsigned int tmp;
michael@0 124 SECStatus rv;
michael@0 125
michael@0 126 if (maxout < inlen) {
michael@0 127 *outlen = inlen;
michael@0 128 PORT_SetError(SEC_ERROR_OUTPUT_LEN);
michael@0 129 return SECFailure;
michael@0 130 }
michael@0 131 *outlen = 0;
michael@0 132 if (ctr->bufPtr != blocksize) {
michael@0 133 unsigned int needed = PR_MIN(blocksize-ctr->bufPtr, inlen);
michael@0 134 ctr_xor(outbuf, inbuf, ctr->buffer + ctr->bufPtr, needed);
michael@0 135 ctr->bufPtr += needed;
michael@0 136 outbuf += needed;
michael@0 137 inbuf += needed;
michael@0 138 *outlen += needed;
michael@0 139 inlen -= needed;
michael@0 140 if (inlen == 0) {
michael@0 141 return SECSuccess;
michael@0 142 }
michael@0 143 PORT_Assert(ctr->bufPtr == blocksize);
michael@0 144 }
michael@0 145
michael@0 146 while (inlen >= blocksize) {
michael@0 147 rv = (*ctr->cipher)(ctr->context, ctr->buffer, &tmp, blocksize,
michael@0 148 ctr->counter, blocksize, blocksize);
michael@0 149 ctr_GetNextCtr(ctr->counter, ctr->counterBits, blocksize);
michael@0 150 if (rv != SECSuccess) {
michael@0 151 return SECFailure;
michael@0 152 }
michael@0 153 ctr_xor(outbuf, inbuf, ctr->buffer, blocksize);
michael@0 154 outbuf += blocksize;
michael@0 155 inbuf += blocksize;
michael@0 156 *outlen += blocksize;
michael@0 157 inlen -= blocksize;
michael@0 158 }
michael@0 159 if (inlen == 0) {
michael@0 160 return SECSuccess;
michael@0 161 }
michael@0 162 rv = (*ctr->cipher)(ctr->context, ctr->buffer, &tmp, blocksize,
michael@0 163 ctr->counter, blocksize, blocksize);
michael@0 164 ctr_GetNextCtr(ctr->counter, ctr->counterBits, blocksize);
michael@0 165 if (rv != SECSuccess) {
michael@0 166 return SECFailure;
michael@0 167 }
michael@0 168 ctr_xor(outbuf, inbuf, ctr->buffer, inlen);
michael@0 169 ctr->bufPtr = inlen;
michael@0 170 *outlen += inlen;
michael@0 171 return SECSuccess;
michael@0 172 }
michael@0 173
michael@0 174 #if defined(USE_HW_AES) && defined(_MSC_VER)
michael@0 175 SECStatus
michael@0 176 CTR_Update_HW_AES(CTRContext *ctr, unsigned char *outbuf,
michael@0 177 unsigned int *outlen, unsigned int maxout,
michael@0 178 const unsigned char *inbuf, unsigned int inlen,
michael@0 179 unsigned int blocksize)
michael@0 180 {
michael@0 181 unsigned int fullblocks;
michael@0 182 unsigned int tmp;
michael@0 183 SECStatus rv;
michael@0 184
michael@0 185 if (maxout < inlen) {
michael@0 186 *outlen = inlen;
michael@0 187 PORT_SetError(SEC_ERROR_OUTPUT_LEN);
michael@0 188 return SECFailure;
michael@0 189 }
michael@0 190 *outlen = 0;
michael@0 191 if (ctr->bufPtr != blocksize) {
michael@0 192 unsigned int needed = PR_MIN(blocksize-ctr->bufPtr, inlen);
michael@0 193 ctr_xor(outbuf, inbuf, ctr->buffer + ctr->bufPtr, needed);
michael@0 194 ctr->bufPtr += needed;
michael@0 195 outbuf += needed;
michael@0 196 inbuf += needed;
michael@0 197 *outlen += needed;
michael@0 198 inlen -= needed;
michael@0 199 if (inlen == 0) {
michael@0 200 return SECSuccess;
michael@0 201 }
michael@0 202 PORT_Assert(ctr->bufPtr == blocksize);
michael@0 203 }
michael@0 204
michael@0 205 intel_aes_ctr_worker(((AESContext*)(ctr->context))->Nr)(
michael@0 206 ctr, outbuf, outlen, maxout, inbuf, inlen, blocksize);
michael@0 207 /* XXX intel_aes_ctr_worker should set *outlen. */
michael@0 208 PORT_Assert(*outlen == 0);
michael@0 209 fullblocks = (inlen/blocksize)*blocksize;
michael@0 210 *outlen += fullblocks;
michael@0 211 outbuf += fullblocks;
michael@0 212 inbuf += fullblocks;
michael@0 213 inlen -= fullblocks;
michael@0 214
michael@0 215 if (inlen == 0) {
michael@0 216 return SECSuccess;
michael@0 217 }
michael@0 218 rv = (*ctr->cipher)(ctr->context, ctr->buffer, &tmp, blocksize,
michael@0 219 ctr->counter, blocksize, blocksize);
michael@0 220 ctr_GetNextCtr(ctr->counter, ctr->counterBits, blocksize);
michael@0 221 if (rv != SECSuccess) {
michael@0 222 return SECFailure;
michael@0 223 }
michael@0 224 ctr_xor(outbuf, inbuf, ctr->buffer, inlen);
michael@0 225 ctr->bufPtr = inlen;
michael@0 226 *outlen += inlen;
michael@0 227 return SECSuccess;
michael@0 228 }
michael@0 229 #endif

mercurial