Subject Re: [Firebird-Architect] Encryption
Author Jim Starkey
On 11/7/2010 7:50 AM, Alex Peshkoff wrote:
> On 11/05/10 03:31, Jim Starkey wrote:
>> If anyone is planning to screw around with encryption, may I recommend a
>> formalism that I developed a awhile back that may help.
> Looks like it's as designed here that transforms are objects of single
> use - in constructor initial data in some form is passed to transform,
> then we get() from transform result of it's job, and after it transform
> can be only destroyed. Does it mean that on practice transform
> constructors are so fast that we can ignore possible performance issues
> with it?
>

Not the case at all. The reset method prepares a transform for re-use.
In specific, cipher transforms retain their computed keys. Transforms
are also required to pass the reset to their source transforms, if any.
This allows, for example, to use a single pair of transform chains for a
socket for the duration of the session or a single transform chain for
private key of a server instance.

I've attached an AES transform as an example.

----------

// Copyright (C) 2010 by NimbusDB, Inc. 2010

#include "Cloud.h"
#include "AESTransform.h"
#include "TransformException.h"
#include "tomcrypt.h"

#define SETUP rijndael_setup
#define ECB_ENC rijndael_ecb_encrypt
#define ECB_DEC rijndael_ecb_decrypt
#define ECB_DONE rijndael_done
#define ECB_TEST rijndael_test
#define ECB_KS rijndael_keysize

extern int SETUP(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
extern int ECB_ENC(const unsigned char *pt, unsigned char *ct, symmetric_key *skey);
extern int ECB_DEC(const unsigned char *pt, unsigned char *ct, symmetric_key *skey);

#ifdef _DEBUG
#undef THIS_FILE
static const char THIS_FILE[]=__FILE__;
#endif

AESTransform::AESTransform(int operatingMode, Transform *src)
{
mode = operatingMode;
source = src;
schedule = new symmetric_key;
blockSize = AES_blocksize;
reset();
}

AESTransform::~AESTransform(void)
{
delete schedule;
}

unsigned int AESTransform::get(unsigned int bufferLength, UCHAR* buffer)
{
UCHAR *p = buffer;
UCHAR *endBuffer = buffer + bufferLength;
UCHAR input[AES_blocksize];

// If there is residual data from the last call, move it to output buffer

if (ptr < end)
{
int len = MIN(bufferLength, (unsigned int)(end - ptr));
memcpy (p, ptr, len);
ptr += len;
p += len;
}

// loop until output buffer is full or we run out of data

while (p < endBuffer && !done)
{
int len = source->get(sizeof(input), input);

// If we got less than a full block, we've run the input source dry

if (len < sizeof(input))
{
done = true;

if (len == 0)
break;

memset(input + len, 0, AES_blocksize - len);
}

// Encode or decode a block

switch(mode)
{
case AES_encrypt:
ECB_ENC(input, block, schedule);
break;

case AES_decrypt:
if (len < sizeof(input))
throw TransformException("partial AES block");

ECB_DEC(input, block, schedule);
break;
}

// Figure out how much of the block fits in the output buffer and more than amount of data

len = MIN(endBuffer - p, AES_blocksize);
memcpy(p, block, len);
p += len;

// If there's residual data, set up for the next call

if (len < sizeof(block))
{
ptr = block + len;

break;
}
}

return p - buffer;
}

unsigned int AESTransform::getLength(void)
{
int len = source->getLength();

//return (len + AES_blocksize - 1) / BLOCK_SIZE8 * AES_blocksize;
return ROUNDUP(len, AES_blocksize);
}

void AESTransform::reset(void)
{
end = block + sizeof(block);
ptr = end;
done = false;

if (source)
source->reset();
}

void AESTransform::setKey(int keyLength, const UCHAR* key)
{
int rounds = 0;

switch (keyLength)
{
case 16:
rounds = 10;
break;

case 24:
rounds = 12;
break;

case 32:
rounds = 14;
break;

default:
throw TransformException("Invalid AES keysize");
}

SETUP(key, keyLength, rounds, schedule);
}

----------

// Copyright (C) 2010 by NimbusDB, Inc.

#ifndef _AES_TRANSFORM_H_
#define _AES_TRANSFORM_H_

#include "Transform.h"

static const int AES_encrypt = 0;
static const int AES_decrypt = 1;
static const int AES_blocksize = 16;

union Symmetric_key;

class AESTransform : public Transform
{
public:
AESTransform(int operatingMode, Transform *src);
virtual ~AESTransform(void);

virtual unsigned int get(unsigned int bufferLength, UCHAR* buffer);
virtual unsigned int getLength(void);
virtual void reset(void);

void setKey(int keyLength, const UCHAR* key);

int mode;
uint blockSize;
bool done;
Transform *source;
UCHAR block[AES_blocksize];
UCHAR *ptr;
UCHAR *end;
Symmetric_key *schedule;
};

#endif


[Non-text portions of this message have been removed]