mirror of
https://github.com/rn10950/RetroZilla.git
synced 2024-11-16 04:20:32 +01:00
30d33aa8e8
9934c8faef29, 3c3b381c4865, 5a67f6beee9a, 1b1eb6d77728, a8b668fd72f7, bug962760, bug743700, bug857304, bug972653, bug972450, bug971358, bug903885, bug977073, bug976111, bug949939, bug947653, bug947572, bug903885, bug979106, bug966596, bug979004, bug979752, bug980848, bug938369, bug981170, bug668130, bug974693, bug975056, bug979132, bug370717, bug979070, bug985070, bug900067, bug977673, bug519255, bug989558, bug557299, bug987263, bug369802, a751a5146718, bug992343, bug952572, bug979703, bug994883, bug994869, bug993489, bug984608, bug977869, bug667371, bug672828, bug793347, bug977869
230 lines
5.9 KiB
C
230 lines
5.9 KiB
C
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#ifdef FREEBL_NO_DEPEND
|
|
#include "stubs.h"
|
|
#endif
|
|
#include "prtypes.h"
|
|
#include "blapit.h"
|
|
#include "blapii.h"
|
|
#include "ctr.h"
|
|
#include "pkcs11t.h"
|
|
#include "secerr.h"
|
|
|
|
#ifdef USE_HW_AES
|
|
#include "intel-aes.h"
|
|
#include "rijndael.h"
|
|
#endif
|
|
|
|
SECStatus
|
|
CTR_InitContext(CTRContext *ctr, void *context, freeblCipherFunc cipher,
|
|
const unsigned char *param, unsigned int blocksize)
|
|
{
|
|
const CK_AES_CTR_PARAMS *ctrParams = (const CK_AES_CTR_PARAMS *)param;
|
|
|
|
if (ctrParams->ulCounterBits == 0 ||
|
|
ctrParams->ulCounterBits > blocksize * PR_BITS_PER_BYTE) {
|
|
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
|
return SECFailure;
|
|
}
|
|
|
|
/* Invariant: 0 < ctr->bufPtr <= blocksize */
|
|
ctr->bufPtr = blocksize; /* no unused data in the buffer */
|
|
ctr->cipher = cipher;
|
|
ctr->context = context;
|
|
ctr->counterBits = ctrParams->ulCounterBits;
|
|
if (blocksize > sizeof(ctr->counter) ||
|
|
blocksize > sizeof(ctrParams->cb)) {
|
|
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
|
|
return SECFailure;
|
|
}
|
|
PORT_Memcpy(ctr->counter, ctrParams->cb, blocksize);
|
|
return SECSuccess;
|
|
}
|
|
|
|
CTRContext *
|
|
CTR_CreateContext(void *context, freeblCipherFunc cipher,
|
|
const unsigned char *param, unsigned int blocksize)
|
|
{
|
|
CTRContext *ctr;
|
|
SECStatus rv;
|
|
|
|
/* first fill in the Counter context */
|
|
ctr = PORT_ZNew(CTRContext);
|
|
if (ctr == NULL) {
|
|
return NULL;
|
|
}
|
|
rv = CTR_InitContext(ctr, context, cipher, param, blocksize);
|
|
if (rv != SECSuccess) {
|
|
CTR_DestroyContext(ctr, PR_TRUE);
|
|
ctr = NULL;
|
|
}
|
|
return ctr;
|
|
}
|
|
|
|
void
|
|
CTR_DestroyContext(CTRContext *ctr, PRBool freeit)
|
|
{
|
|
PORT_Memset(ctr, 0, sizeof(CTRContext));
|
|
if (freeit) {
|
|
PORT_Free(ctr);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Used by counter mode. Increment the counter block. Not all bits in the
|
|
* counter block are part of the counter, counterBits tells how many bits
|
|
* are part of the counter. The counter block is blocksize long. It's a
|
|
* big endian value.
|
|
*
|
|
* XXX Does not handle counter rollover.
|
|
*/
|
|
static void
|
|
ctr_GetNextCtr(unsigned char *counter, unsigned int counterBits,
|
|
unsigned int blocksize)
|
|
{
|
|
unsigned char *counterPtr = counter + blocksize - 1;
|
|
unsigned char mask, count;
|
|
|
|
PORT_Assert(counterBits <= blocksize*PR_BITS_PER_BYTE);
|
|
while (counterBits >= PR_BITS_PER_BYTE) {
|
|
if (++(*(counterPtr--))) {
|
|
return;
|
|
}
|
|
counterBits -= PR_BITS_PER_BYTE;
|
|
}
|
|
if (counterBits == 0) {
|
|
return;
|
|
}
|
|
/* increment the final partial byte */
|
|
mask = (1 << counterBits)-1;
|
|
count = ++(*counterPtr) & mask;
|
|
*counterPtr = ((*counterPtr) & ~mask) | count;
|
|
return;
|
|
}
|
|
|
|
static void
|
|
ctr_xor(unsigned char *target, const unsigned char *x,
|
|
const unsigned char *y, unsigned int count)
|
|
{
|
|
unsigned int i;
|
|
for (i=0; i < count; i++) {
|
|
*target++ = *x++ ^ *y++;
|
|
}
|
|
}
|
|
|
|
SECStatus
|
|
CTR_Update(CTRContext *ctr, unsigned char *outbuf,
|
|
unsigned int *outlen, unsigned int maxout,
|
|
const unsigned char *inbuf, unsigned int inlen,
|
|
unsigned int blocksize)
|
|
{
|
|
unsigned int tmp;
|
|
SECStatus rv;
|
|
|
|
if (maxout < inlen) {
|
|
*outlen = inlen;
|
|
PORT_SetError(SEC_ERROR_OUTPUT_LEN);
|
|
return SECFailure;
|
|
}
|
|
*outlen = 0;
|
|
if (ctr->bufPtr != blocksize) {
|
|
unsigned int needed = PR_MIN(blocksize-ctr->bufPtr, inlen);
|
|
ctr_xor(outbuf, inbuf, ctr->buffer + ctr->bufPtr, needed);
|
|
ctr->bufPtr += needed;
|
|
outbuf += needed;
|
|
inbuf += needed;
|
|
*outlen += needed;
|
|
inlen -= needed;
|
|
if (inlen == 0) {
|
|
return SECSuccess;
|
|
}
|
|
PORT_Assert(ctr->bufPtr == blocksize);
|
|
}
|
|
|
|
while (inlen >= blocksize) {
|
|
rv = (*ctr->cipher)(ctr->context, ctr->buffer, &tmp, blocksize,
|
|
ctr->counter, blocksize, blocksize);
|
|
ctr_GetNextCtr(ctr->counter, ctr->counterBits, blocksize);
|
|
if (rv != SECSuccess) {
|
|
return SECFailure;
|
|
}
|
|
ctr_xor(outbuf, inbuf, ctr->buffer, blocksize);
|
|
outbuf += blocksize;
|
|
inbuf += blocksize;
|
|
*outlen += blocksize;
|
|
inlen -= blocksize;
|
|
}
|
|
if (inlen == 0) {
|
|
return SECSuccess;
|
|
}
|
|
rv = (*ctr->cipher)(ctr->context, ctr->buffer, &tmp, blocksize,
|
|
ctr->counter, blocksize, blocksize);
|
|
ctr_GetNextCtr(ctr->counter, ctr->counterBits, blocksize);
|
|
if (rv != SECSuccess) {
|
|
return SECFailure;
|
|
}
|
|
ctr_xor(outbuf, inbuf, ctr->buffer, inlen);
|
|
ctr->bufPtr = inlen;
|
|
*outlen += inlen;
|
|
return SECSuccess;
|
|
}
|
|
|
|
#if defined(USE_HW_AES) && defined(_MSC_VER)
|
|
SECStatus
|
|
CTR_Update_HW_AES(CTRContext *ctr, unsigned char *outbuf,
|
|
unsigned int *outlen, unsigned int maxout,
|
|
const unsigned char *inbuf, unsigned int inlen,
|
|
unsigned int blocksize)
|
|
{
|
|
unsigned int fullblocks;
|
|
unsigned int tmp;
|
|
SECStatus rv;
|
|
|
|
if (maxout < inlen) {
|
|
*outlen = inlen;
|
|
PORT_SetError(SEC_ERROR_OUTPUT_LEN);
|
|
return SECFailure;
|
|
}
|
|
*outlen = 0;
|
|
if (ctr->bufPtr != blocksize) {
|
|
unsigned int needed = PR_MIN(blocksize-ctr->bufPtr, inlen);
|
|
ctr_xor(outbuf, inbuf, ctr->buffer + ctr->bufPtr, needed);
|
|
ctr->bufPtr += needed;
|
|
outbuf += needed;
|
|
inbuf += needed;
|
|
*outlen += needed;
|
|
inlen -= needed;
|
|
if (inlen == 0) {
|
|
return SECSuccess;
|
|
}
|
|
PORT_Assert(ctr->bufPtr == blocksize);
|
|
}
|
|
|
|
intel_aes_ctr_worker(((AESContext*)(ctr->context))->Nr)(
|
|
ctr, outbuf, outlen, maxout, inbuf, inlen, blocksize);
|
|
/* XXX intel_aes_ctr_worker should set *outlen. */
|
|
PORT_Assert(*outlen == 0);
|
|
fullblocks = (inlen/blocksize)*blocksize;
|
|
*outlen += fullblocks;
|
|
outbuf += fullblocks;
|
|
inbuf += fullblocks;
|
|
inlen -= fullblocks;
|
|
|
|
if (inlen == 0) {
|
|
return SECSuccess;
|
|
}
|
|
rv = (*ctr->cipher)(ctr->context, ctr->buffer, &tmp, blocksize,
|
|
ctr->counter, blocksize, blocksize);
|
|
ctr_GetNextCtr(ctr->counter, ctr->counterBits, blocksize);
|
|
if (rv != SECSuccess) {
|
|
return SECFailure;
|
|
}
|
|
ctr_xor(outbuf, inbuf, ctr->buffer, inlen);
|
|
ctr->bufPtr = inlen;
|
|
*outlen += inlen;
|
|
return SECSuccess;
|
|
}
|
|
#endif
|