Crypt-Loki97

 view release on metacpan or  search on metacpan

_loki97.c  view on Meta::CPAN

/*
 * loki97.h - header file for the LOKI97 AES candidate block cipher.<p>
 *
 * LOKI97 was written by Lawrie Brown (ADFA), Josef Pieprzyk, and Jennifer
 * Seberry (UOW) in 1997.<p>
 *
 * <b>Copyright</b> 1998 by <a href="mailto:Lawrie.Brown@adfa.oz.au">
 * Lawrie Brown</a> & ITRACE (UNSW).
 *
 * based on aes.h - AES Cipher header file for ANSI C Submissions
 */

/* Includes: Standard include files */
#include <stdio.h>
#include <string.h>

/* Defines: AES */

#define     DIR_ENCRYPT     0    /*  Are we encrypting?  */
#define     DIR_DECRYPT     1    /*  Are we decrypting?  */
#define     MODE_ECB        1    /*  Are we ciphering in ECB mode?   */
#define     MODE_CBC        2    /*  Are we ciphering in CBC mode?   */
#define     MODE_CFB1       3    /*  Are we ciphering in 1-bit CFB mode? */
#define     S_TRUE            1
#define     S_FALSE           0


/* Error Codes */
#define     BAD_KEY_DIR        -1  /*  Key direction is invalid, e.g.,
					unknown value */
#define     BAD_KEY_MAT        -2  /*  Key material not of correct
					length */
#define     BAD_KEY_INSTANCE   -3  /*  Key passed is not valid  */
#define     BAD_CIPHER_MODE    -4  /*  Params struct passed to
					cipherInit invalid */
#define     BAD_CIPHER_STATE   -5  /*  Cipher in wrong state (e.g., not
					initialized) */
#define     BAD_CIPHER_INPUT   -6  /*  Cipher input not BLOCK_SIZE multiple */


/* Algorithm Specific Defines  */
#define     MAX_KEY_SIZE	64  /* # of ASCII char's needed to
					represent a key */
#define     MAX_IV_SIZE		16  /* # bytes needed to represent an IV  */

/* Number of bytes in a data-block. */
#define	    BLOCK_SIZE		16

/* Number of rounds for the algorithm. */
#define     ROUNDS		16

/* Number of subkeys used by the algorithm. */
#define     NUM_SUBKEYS		3*ROUNDS

/* Typedefs: */

typedef    unsigned char    BYTE;			/* unsigned byte */

typedef    struct ULONG64 {
    unsigned long l,r;
} ULONG64;	/* 64bit unsigned int */


/*  The structure for key information */
typedef struct keyInstance {
      BYTE  direction;	/*  Key used for encrypting or decrypting? */
      int   keyLen;	/*  Length of the key  */
      unsigned char  keyMaterial[MAX_KEY_SIZE+1];  /*  Raw key data in ASCII,
                                    e.g., user input or KAT values */
      /*  The following parameters are algorithm dependent */
      ULONG64	SK[NUM_SUBKEYS];	/* LOKI97 subkeys for this key */
      } keyInstance;

/*  The structure for cipher information */
typedef struct cipherInstance {
      BYTE  mode;            /* MODE_ECB, MODE_CBC, or MODE_CFB1 */
      BYTE  IV[MAX_IV_SIZE]; /* A possible Initialization Vector for
      					ciphering */
      /*  Add any algorithm specific parameters needed here  */
      ULONG64	IVL, IVR;	/* IV packed into 64-bit L & R halves */
      int   blockSize;    	/* Sample: Handles non-128 bit block sizes
      					(if available) */
      } cipherInstance;


/*  Function protoypes  */
int makeKey(keyInstance *key, BYTE direction, int keyLen,
			unsigned char *keyMaterial);

int cipherInit(cipherInstance *cipher, BYTE mode, unsigned char *IV);

int blockEncrypt(cipherInstance *cipher, keyInstance *key, BYTE *input,
			int inputLen, BYTE *outBuffer);

int blockDecrypt(cipherInstance *cipher, keyInstance *key, BYTE *input,
			int inputLen, BYTE *outBuffer);

int self_test();
/*
 * Implements the LOKI97 block cipher.<p>
 *
 * LOKI97 is a 128-bit symmetric block cipher with a 256-bit key schedule,
 * which may be initialised from 128, 192, or 256-bit keys. It uses 16 rounds
 * of data computation using a balanced feistel network with a complex
 * function f which incorporates two S-P layers. The 256-bit key schedule
 * uses 33 rounds of an unbalanced feistel network using the same complex
 * function f to generate the subkeys.<p>
 *
 * LOKI97 was written by Lawrie Brown (ADFA), Josef Pieprzyk, and Jennifer
 * Seberry (UOW) in 1997.<p>
 *
 * <b>Copyright</b> &copy; 1998 by <a href="mailto:Lawrie.Brown@adfa.oz.au">
 * Lawrie Brown</a> & ITRACE (UNSW)
 *
 * <br>All rights reserved.<p>
 *
 * Author:  Lawrie Brown
 *
 * code derived from LOKI97 java implementation by Lawrie Brown & Raif Naffah
 */

/* include standard AES C header file */

/* Global defines and variables */

#define NAME	"LOKI97"
#define L_DEBUG	0

/*
 * Debug diagnostics. Valid values of symbolic constant L_DEBUG: <p>
 *
 * Values are:<dl compact>
 * <dt> 1 <dd> engine calls,
 * <dt> 2 <dd> enc/dec round values,
 * <dt> 3 <dd> subkeys,
 * <dt> 4 <dd> func f calls,
 * <dt> 5 <dd> func f internals,
 * <dt> 6 <dd> static init. </dl>
 */
#define debuglevel L_DEBUG 


/*  LOKI97 algorithm specific constants and tables */
/* ........................................................................... */

/* Generator polynomial for S-box S1, in GF(2<sup>13</sup>). */
#define S1_GEN 0x2911

/* Size of S-box S1, for 13-bit inputs. */
#define S1_SIZE 0x2000

/* Table of pre-computed S-box S1 values. */
static BYTE S1[S1_SIZE];

/* Generator polynomial for S-box S2, in GF(2<sup>11</sup>). */
#define S2_GEN 0xAA7

/* Size of S-box S2, for 11-bit inputs. */
#define S2_SIZE 0x800

/* Table of pre-computed S-box S2 values. */
static BYTE S2[S2_SIZE];

/* Constant value for Delta which is used in the key schedule */
static ULONG64 DELTA = {0x9E3779B9L, 0x7F4A7C15L};

/*
 * Table specifying the pre-computed permutation P.
 * nb. precompute permutations for lowest 8 bits only,
 *     value of P is a 64-bit wide (long) mask of the permuted input value.
 */
static ULONG64 P[0x100];

/* Flag specifying whether once-off init of S1, S2 and P has been done */
static int init_done = S_FALSE;

/* prototypes for local utility functions */
static int enECB(cipherInstance *cipher, keyInstance *key, BYTE *input, 
		int inputLen, BYTE *outBuffer);
static int enCBC(cipherInstance *cipher, keyInstance *key, BYTE *input, 
		int inputLen, BYTE *outBuffer);
static int enCFB1(cipherInstance *cipher, keyInstance *key, BYTE *input, 
		int inputLen, BYTE *outBuffer);
static int deECB(cipherInstance *cipher, keyInstance *key, BYTE *input,
		int inputLen, BYTE *outBuffer);
static int deCBC(cipherInstance *cipher, keyInstance *key, BYTE *input,
		int inputLen, BYTE *outBuffer);
static int deCFB1(cipherInstance *cipher, keyInstance *key, BYTE *input, 
		int inputLen, BYTE *outBuffer);
static ULONG64 f (ULONG64 A, ULONG64 B) ;
static ULONG64 add64(ULONG64 a, ULONG64 b) ;
static ULONG64 sub64(ULONG64 a, ULONG64 b) ;
static int exp3 (int b, int g, int n) ;
static int mult (int a, int b, int g, int n) ;
static ULONG64 byteToULONG64(BYTE *inp) ;
static BYTE *ULONG64ToBYTE(BYTE *buf, ULONG64 I) ;
static BYTE *charToBYTE(BYTE *buf, unsigned char *hex, int len) ;
/* static ULONG64 charToULONG64(unsigned char *hex) ; */
static int fromHex (unsigned char ch) ;
void puthex(BYTE *out, int len, FILE *f);


/*  Initialise cipher, precompute S-boxes and permutation table */
/* ......................................................................... */

int cipherInit(cipherInstance *cipher, BYTE mode, unsigned char *IV)
{
    int S1_MASK = S1_SIZE - 1;	/*  mask to select S1 input bits */
    int S2_MASK = S2_SIZE - 1;	/*  mask to select S2 input bits */

    int i, j, k;		/*  index into S-box, P bit , out bit */
    int b;			/*  S-box fn input */
    long pval;			/*  perm P mask for given input value */
    BYTE *input;		/*  pointer into byte array for IV */

    if (debuglevel) fprintf(stderr,"%s: cipherInit(mode=%d, IV=%s)\n", NAME, mode, IV);

    if (!init_done) {

        /*  precompute S-box tables for S1 and S2 */
        if (debuglevel > 5) fprintf(stderr,"%s: Static init of S1, S2 & P \n", NAME);
        for (i = 0; i < S1_SIZE; i++) { /*  for all S1 inputs */
            b = i ^ S1_MASK; /*  compute input value */
            S1[i] = exp3(b, S1_GEN, S1_SIZE); /*  compute fn value */
            if (debuglevel > 5) fprintf(stderr,"%s: S1[%04x] = %02x\n", NAME, i, S1[i]);
        }
        for (i = 0; i < S2_SIZE; i++) { /*  for all S2 inputs */
            b = i ^ S2_MASK; /*  compute input value */
            S2[i] = exp3(b, S2_GEN, S2_SIZE); /*  compute fn value */
            if (debuglevel > 5) fprintf(stderr,"%s: S2[%04x] = %02x\n", NAME, i, S2[i]);
        }

        /*  initialising expanded permutation P table (for lowest BYTE only) */
        /*    Permutation P maps input bits [63..0] to outputs bits: */
        /*    [56, 48, 40, 32, 24, 16,  8, 0, */
        /*     57, 49, 41, 33, 25, 17,  9, 1, */
        /*     58, 50, 42, 34, 26, 18, 10, 2, */
        /*     59, 51, 43, 35, 27, 19, 11, 3, */
        /*     60, 52, 44, 36, 28, 20, 12, 4, */
        /*     61, 53, 45, 37, 29, 21, 13, 5, */
        /*     62, 54, 46, 38, 30, 22, 14, 6, */
        /*     63, 55, 47, 39, 31, 23, 15, 7]  <- this row only used in table */
        /*   since it is so regular, we can construct it on the fly */
        for (i = 0; i < 0x100; i++) { /*  loop over all 8-bit inputs */
            /*  for each input bit permute to specified output position */
            pval = 0L;
            for (j = 0, k = 7; j < 4; j++, k += 8)	/* do right half of P */
                pval |= (long)((i >> j) & 0x1) << k;
            P[i].r = pval;
            pval = 0L;
            for (j = 4, k = 7; j < 8; j++, k += 8)	/* do left half of P */
                pval |= (long)((i >> j) & 0x1) << k;
            P[i].l = pval;
            if (debuglevel > 5) fprintf(stderr,"%s: P[%02x] = %08lx%08lx\n", NAME, i, P[i].l, P[i].r);
        }

	/* and remember that init has been done */
	init_done = S_TRUE;
    }

    /* now fill out cipherInstance structure */
    cipher->mode = mode;				/* copy mode over */
    if (IV != NULL) {					/* IV specified */
	charToBYTE(cipher->IV,IV,sizeof(cipher->IV));	/* convert IV */
        /*  pack IV into IVL and IVR */
	input = cipher->IV;
        cipher->IVL = byteToULONG64(input); input += 8;
        cipher->IVR = byteToULONG64(input); input += 8;
    } else {						/* no IV, so set to 0 */
	memset(cipher->IV,0,sizeof(cipher->IV));
	cipher->IVL.l = cipher->IVL.r = cipher->IVR.l = cipher->IVR.r = 0L;
    }
    cipher->blockSize = BLOCK_SIZE*8;			/* BLOCK_SIZE in bits */

    /* decide correct return value */
    if ((mode == MODE_ECB)||(mode == MODE_CBC)||(mode == MODE_CFB1))
        return S_TRUE;
    else
        return BAD_CIPHER_MODE;

}


/*
 * Returns residue of base b to power 3 mod g in GF(2^n).
 *
 * @param b  Base of exponentiation, the exponent being always 3.
 * @param g  Irreducible polynomial generating Galois Field (GF(2^n)).
 * @param n  Size of the galois field.
 * @return (b ** 3) mod g.
 */
static int exp3 (int b, int g, int n) {
    int r = b;            /*  r = b */
    if (b == 0)
        return 0;
    b = mult(r, b, g, n); /*  r = b ** 2 */
    r = mult(r, b, g, n); /*  r = b ** 3 */
    return r;
}

/*
 * Returns the product of two binary numbers a and b, using the
 * generator g as the modulus: p = (a * b) mod g. g Generates a
 * suitable Galois Field in GF(2^n).
 *
 * @param a  First multiplicand.
 * @param b  Second multiplicand.
 * @param g  Irreducible polynomial generating Galois Field.
 * @param n  Size of the galois field.
 * @return (a * b) mod g.
 */
static int mult (int a, int b, int g, int n) {
    int p = 0;
    while (b != 0) {
        if ((b & 0x01) != 0)
            p ^= a;
        a <<= 1;
        if (a >= n)
            a ^= g;
        b >>= 1;
    }
    return p;
}


/*  Basic NIST API methods for LOKI97 */
/* ......................................................................... */

/* Expand a user-supplied key material into a LOKI97 session key.  */
int makeKey(keyInstance *key, BYTE direction, int keyLen, unsigned char *keyMaterial)
{
    ULONG64 k4, k3, k2, k1;		/*  key schedule 128-bit entities */
    ULONG64 deltan = DELTA;		/*  multiples of delta */
    ULONG64 t1, t2;			/*  temps used for doing 64-bit adds */
    ULONG64 f_out;			/*  fn f output value for debug */
    int i = 0;				/*  index into key input */

_loki97.c  view on Meta::CPAN

        }

        /* k2 = charToULONG64(keyMaterial); keyMaterial += 16; */
        k2.l = tmp >> 32;
        k2.r = tmp;

        if (keyLen == 192) /*  192-bit key - call fn f once to gen 256 bits */
            k1 = f(k4, k3);
        else {              /*  256-bit key - pack k1 from key data */
            tmp = 0;
            for (i = 24; i < 32; i++) {
                tmp = (tmp << 8);
                tmp |= keyMaterial[i];
            }

            /* k1 = charToULONG64(keyMaterial); keyMaterial += 16; */
            k1.l = tmp >> 32;
            k1.r = tmp;
        }
    }

    if (debuglevel) fprintf(stderr,"%s: makeKey(k4.l=%08lx k4.r=%08lx k3.l=%08lx k3.r=%08lx k2.l=%08lx k2.r=%08lx k1.l=%08lx k1.r=%08lx,%s)\n", NAME, k4.l, k4.r, k3.l, k3.r, k2.l, k2.r, k1.l, k1.r, direction?"Dec":"Enc");

    /*  iterate over all LOKI97 rounds to generate the required subkeys */
    for (i = 0; i < NUM_SUBKEYS; i++) {
	t1 = add64(k1,k3);		/* compute f(k1+k3+n.delta,k2) */
	t2 = add64(t1,deltan);
        f_out = f(t2, k2);
        key->SK[i].l = k4.l ^ f_out.l;	/*  compute next subkey using fn f */
        key->SK[i].r = k4.r ^ f_out.r;
        k4 = k3;			/*  exchange the other words around */
        k3 = k2;
        k2 = k1;
        k1 = key->SK[i];
        deltan = add64(deltan,DELTA);	/*  next multiple of delta */
        if (debuglevel > 2) fprintf(stderr,"%s: SK[%02d]=%08lx%08lx\t", NAME, i, key->SK[i].l, key->SK[i].r);
        if (debuglevel > 2) fprintf(stderr,"f=%08lx%08lx,\tdeltan=%08lx%08lx\n", f_out.l, f_out.r, deltan.l, deltan.r);
    }

    return S_TRUE;
}


/* ....................................................................... */
/*
 * blockEncrypt(cipher,key,input,inputLen,outBuffer) -
 *     encrypt blocks of plaintext from input to outBuffer using cipher & key.
 */
int blockEncrypt(cipherInstance *cipher, keyInstance *key, BYTE *input,
		int inputLen, BYTE *outBuffer)
{
    /*  do some basic sanity checks on params */
    if (!init_done) return BAD_CIPHER_STATE;
    if (cipher == NULL) return BAD_CIPHER_STATE;
    if (key == NULL) return BAD_KEY_INSTANCE;
    if (key->direction != DIR_ENCRYPT) return BAD_KEY_DIR;

    /* now call appropriate mode encrypt routine */
    if (cipher->mode == MODE_ECB)
	return enECB(cipher, key, input, inputLen, outBuffer);
    else if (cipher->mode == MODE_CBC)
	return enCBC(cipher, key, input, inputLen, outBuffer);
    else if (cipher->mode == MODE_CFB1)
	return enCFB1(cipher, key, input, inputLen, outBuffer);
    else
        return BAD_CIPHER_MODE;
}


/*
 * encrypt blocks in ECB mode
 */
static int enECB(cipherInstance *cipher, keyInstance *key, BYTE *input, 
		int inputLen, BYTE *outBuffer)
{
    int i,j,k;			/* assorted loop counters */
    int blocks = inputLen / (BLOCK_SIZE*8);	/* compute # input blocks */
    ULONG64 L, R;		/* left and right data blocks */
    ULONG64 nR, f_out;

    /*  do some basic sanity checks on params */
    if (inputLen % (BLOCK_SIZE*8) != 0) return BAD_CIPHER_INPUT;

    /* now loop over all blocks of input */
    for (j = 0; j < blocks; j++) {

        /*  pack input block into L and R */
        L = byteToULONG64(input); input += 8;
        R = byteToULONG64(input); input += 8;

        if (debuglevel) fprintf(stderr,"%s: enECB(%08lx%08lx%08lx%08lx) ", NAME, L.l, L.r, R.l, R.r);
        if (debuglevel > 1) fprintf(stderr,"\n");

        /*  compute all rounds for this 1 block */
        k = 0;
        for (i = 0; i < ROUNDS; i++) {
            nR = add64(R, key->SK[k++]);		/* nR = R+SK(k) */
            f_out = f(nR, key->SK[k++]);		/* f = f(nR,SK(k+1)) */
            nR = add64(nR, key->SK[k++]);		/* nR = nR+SK(k+2) */
            R.l = L.l ^ f_out.l; R.r = L.r ^ f_out.r;	/* R = L XOR f */
            L = nR;					/* L = nR */
            if (debuglevel > 1) fprintf(stderr," L[%02d]=%08lx%08lx; R[%02d]=%08lx%08lx; f(SK(%02d))=%08lx%08lx\n", i+1, L.l, L.r, i+1, R.l, R.r, k-2, f_out.l, f_out.r);
        }

        if (debuglevel > 0) fprintf(stderr,"= %08lx%08lx%08lx%08lx\n", R.l, R.r, L.l, L.r);

        /*  unpack resulting L & R into output - undoing last swap */
	ULONG64ToBYTE(outBuffer, R); outBuffer += 8;
	ULONG64ToBYTE(outBuffer, L); outBuffer += 8;
    }
    return S_TRUE;
}


/*
 * encrypt blocks in CBC mode
 */
static int enCBC(cipherInstance *cipher, keyInstance *key, BYTE *input, 
		int inputLen, BYTE *outBuffer)
{
    int i,j,k;			/* assorted loop counters */
    int blocks = inputLen / (BLOCK_SIZE*8);	/* compute # input blocks */
    ULONG64 L, R;		/* left and right data blocks */
    ULONG64 nR, f_out;

    /*  do some basic sanity checks on params */
    if (inputLen % (BLOCK_SIZE*8) != 0) return BAD_CIPHER_INPUT;

    /* now loop over all blocks of input */
    for (j = 0; j < blocks; j++) {

        /*  pack input block into L and R */
        L = byteToULONG64(input); input += 8;
        R = byteToULONG64(input); input += 8;

        /* XOR with IV value */
	L.l ^= cipher->IVL.l; L.r ^= cipher->IVL.r;
	R.l ^= cipher->IVR.l; R.r ^= cipher->IVR.r;

        if (debuglevel) fprintf(stderr,"%s: enCBC(%08lx%08lx%08lx%08lx) ", NAME, L.l, L.r, R.l, R.r);
        if (debuglevel > 1) fprintf(stderr,"\n");

        /*  compute all rounds for this 1 block */
        k = 0;
        for (i = 0; i < ROUNDS; i++) {
            nR = add64(R, key->SK[k++]);		/* nR = R+SK(k) */
            f_out = f(nR, key->SK[k++]);		/* f = f(nR,SK(k+1)) */
            nR = add64(nR, key->SK[k++]);		/* nR = nR+SK(k+2) */
            R.l = L.l ^ f_out.l; R.r = L.r ^ f_out.r;	/* R = L XOR f */
            L = nR;					/* L = nR */
            if (debuglevel > 1) fprintf(stderr," L[%02d]=%08lx%08lx; R[%02d]=%08lx%08lx; f(SK(%02d))=%08lx%08lx\n", i+1, L.l, L.r, i+1, R.l, R.r, k-2, f_out.l, f_out.r);
        }

        /* save new IV value (nb. undo last swap, as per output transform */
	cipher->IVL = R; cipher->IVR = L;

        if (debuglevel > 0) fprintf(stderr,"= %08lx%08lx%08lx%08lx\n", R.l, R.r, L.l, L.r);

        /*  unpack resulting L & R into output - undoing last swap */
	ULONG64ToBYTE(outBuffer, R); outBuffer += 8;
	ULONG64ToBYTE(outBuffer, L); outBuffer += 8;
    }
    return S_TRUE;
}


/*
 * encrypt blocks in CFB1 mode
 */
static int enCFB1(cipherInstance *cipher, keyInstance *key, BYTE *input, 
		int inputLen, BYTE *outBuffer)
{
    int i,j,k;			/* assorted loop counters */
    int b;			/* bit number being processed in byte */
    BYTE msgbit, keybit;	/* current message and stream key bits */
    ULONG64 L, R;		/* left and right data blocks */
    ULONG64 nR, f_out;

    /* get CFB1 input buffer from IV */
    L = cipher->IVL; R = cipher->IVR;

    /* get ready to process first byte */
    b = 7;			/* start with top bit in byte */
    *outBuffer = 0;		/* and zero byte in outBuffer */

    /* now loop over all bits of input */
    for (j = 0; j < inputLen; j++) {
        msgbit = (*input >> b) & 01;			/* get next msg bit */

        if (debuglevel) fprintf(stderr,"%s: enCFB1(%01x,%08lx%08lx%08lx%08lx) ", NAME, msgbit, L.l, L.r, R.l, R.r);
        if (debuglevel > 1) fprintf(stderr,"\n");

        /*  compute all rounds to encrypt current CFB1 buffer */
        k = 0;
        for (i = 0; i < ROUNDS; i++) {
            nR = add64(R, key->SK[k++]);		/* nR = R+SK(k) */
            f_out = f(nR, key->SK[k++]);		/* f = f(nR,SK(k+1)) */
            nR = add64(nR, key->SK[k++]);		/* nR = nR+SK(k+2) */
            R.l = L.l ^ f_out.l; R.r = L.r ^ f_out.r;	/* R = L XOR f */
            L = nR;					/* L = nR */
            if (debuglevel > 1) fprintf(stderr," L[%02d]=%08lx%08lx; R[%02d]=%08lx%08lx; f(SK(%02d))=%08lx%08lx\n", i+1, L.l, L.r, i+1, R.l, R.r, k-2, f_out.l, f_out.r);
        }
	/* undo last swap */
	L = R; R = nR;

	/* now process msgbit by getting stream key bit, XOR in and or to out */
	keybit = L.l >> 31;
	msgbit ^= keybit;
	*outBuffer |= (msgbit << b);

        if (debuglevel > 0) fprintf(stderr,"= %01x,%08lx%08lx%08lx%08lx\n", msgbit, L.l, L.r, R.l, R.r);

	/* and update the CFB1 shift register (input buffer L,R) */
	L.l = (L.l << 1) | (L.r >> 31); L.r = (L.r << 1) | (R.l >> 31);
	R.l = (R.l << 1) | (R.r >> 31); R.r = (R.r << 1) | msgbit;

	/* and update bit position counter */
	b--;
	/* and move to next input/output byte if necessary */
	if (b<0) { b = 7; input++; outBuffer++; *outBuffer = 0; }
    }

    /* save new IV value */
    cipher->IVL = L; cipher->IVR = R;
    return S_TRUE;
}



/* ....................................................................... */
/*
 * blockDecrypt(cipher,key,input,inputLen,outBuffer) -
 *     decrypt blocks of plaintext from input to outBuffer using cipher & key.
 */
int blockDecrypt(cipherInstance *cipher, keyInstance *key, BYTE *input,
		int inputLen, BYTE *outBuffer)
{
    /*  do some basic sanity checks on params */
    if (!init_done) return BAD_CIPHER_STATE;
    if (cipher == NULL) return BAD_CIPHER_STATE;
    if (key == NULL) return BAD_KEY_INSTANCE;
    if (key->direction != DIR_DECRYPT) return BAD_KEY_DIR;

    /* now call appropriate mode decrypt routine */
    if (cipher->mode == MODE_ECB)
	return deECB(cipher, key, input, inputLen, outBuffer);
    else if (cipher->mode == MODE_CBC)
	return deCBC(cipher, key, input, inputLen, outBuffer);
    else if (cipher->mode == MODE_CFB1)
	return deCFB1(cipher, key, input, inputLen, outBuffer);
    else
        return BAD_CIPHER_MODE;
}


/*
 * decrypt blocks in ECB mode
 */
static int deECB(cipherInstance *cipher, keyInstance *key, BYTE *input,
		int inputLen, BYTE *outBuffer)
{
    int i,j,k;			/* assorted loop counters */
    int blocks = inputLen / (BLOCK_SIZE*8);	/* compute # input blocks */
    ULONG64 L, R;		/* left and right data blocks */
    ULONG64 nR, f_out;

    /*  do some basic sanity checks on params */
    if (inputLen % (BLOCK_SIZE*8) != 0) return BAD_CIPHER_INPUT;

    /* now loop over all blocks of input */
    for (j = 0; j < blocks; j++) {

        /*  pack input block into L and R */
        L = byteToULONG64(input); input += 8;
        R = byteToULONG64(input); input += 8;

        if (debuglevel) fprintf(stderr,"%s: deECB(%08lx%08lx%08lx%08lx) ", NAME, L.l, L.r, R.l, R.r);
        if (debuglevel > 1) fprintf(stderr,"\n");

        /*  compute all rounds for this 1 block */
        k = NUM_SUBKEYS - 1;
        for (i = 0; i < ROUNDS; i++) {
            nR = sub64(R, key->SK[k--]);		/* nR = R+SK(k) */
            f_out = f(nR, key->SK[k--]);		/* f = f(nR,SK(k+1)) */
            nR = sub64(nR, key->SK[k--]);		/* nR = nR+SK(k+2) */
            R.l = L.l ^ f_out.l; R.r = L.r ^ f_out.r;	/* R = L XOR f */
            L = nR;					/* L = nR */
            if (debuglevel > 1) fprintf(stderr," L[%02d]=%08lx%08lx; R[%02d]=%08lx%08lx; f(SK(%02d))=%08lx%08lx\n", i+1, L.l, L.r, i+1, R.l, R.r, k+2, f_out.l, f_out.r);
        }

        if (debuglevel > 0) fprintf(stderr,"= %08lx%08lx%08lx%08lx\n", R.l, R.r, L.l, L.r);

        /*  unpack resulting L & R into output - undoing last swap */
	ULONG64ToBYTE(outBuffer, R); outBuffer += 8;
	ULONG64ToBYTE(outBuffer, L); outBuffer += 8;
    }
    return S_TRUE;
}


/*
 * Dncrypt blocks in CBC mode
 */
static int deCBC(cipherInstance *cipher, keyInstance *key, BYTE *input,
		int inputLen, BYTE *outBuffer)
{
    int i,j,k;			/* assorted loop counters */
    int blocks = inputLen / (BLOCK_SIZE*8);	/* compute # input blocks */
    ULONG64 L, R;		/* left and right data blocks */
    ULONG64 newIVL, newIVR;	/* next IV L & R halves */
    ULONG64 nR, f_out;

    /*  do some basic sanity checks on params */
    if (inputLen % (BLOCK_SIZE*8) != 0) return BAD_CIPHER_INPUT;

    /* now loop over all blocks of input */
    for (j = 0; j < blocks; j++) {

        /*  pack input block into L and R */
        L = byteToULONG64(input); input += 8;
        R = byteToULONG64(input); input += 8;

        /* save new IV value */
	newIVL = L; newIVR = R;

        if (debuglevel) fprintf(stderr,"%s: deCBC(%08lx%08lx%08lx%08lx) ", NAME, L.l, L.r, R.l, R.r);
        if (debuglevel > 1) fprintf(stderr,"\n");

        /*  compute all rounds for this 1 block */
        k = NUM_SUBKEYS - 1;
        for (i = 0; i < ROUNDS; i++) {
            nR = sub64(R, key->SK[k--]);		/* nR = R+SK(k) */
            f_out = f(nR, key->SK[k--]);		/* f = f(nR,SK(k+1)) */
            nR = sub64(nR, key->SK[k--]);		/* nR = nR+SK(k+2) */
            R.l = L.l ^ f_out.l; R.r = L.r ^ f_out.r;	/* R = L XOR f */
            L = nR;					/* L = nR */
            if (debuglevel > 1) fprintf(stderr," L[%02d]=%08lx%08lx; R[%02d]=%08lx%08lx; f(SK(%02d))=%08lx%08lx\n", i+1, L.l, L.r, i+1, R.l, R.r, k+2, f_out.l, f_out.r);
        }

        /* XOR with IV value (undoing last swap) */
	R.l ^= cipher->IVL.l; R.r ^= cipher->IVL.r;
	L.l ^= cipher->IVR.l; L.r ^= cipher->IVR.r;

        /* save IV value */
	cipher->IVL = newIVL; cipher->IVR = newIVR;

        if (debuglevel > 0) fprintf(stderr,"= %08lx%08lx%08lx%08lx\n", R.l, R.r, L.l, L.r);

        /*  unpack resulting L & R into output - undoing last swap */
	ULONG64ToBYTE(outBuffer, R); outBuffer += 8;
	ULONG64ToBYTE(outBuffer, L); outBuffer += 8;
    }
    return S_TRUE;
}


/*
 * decrypt blocks in CFB1 mode
 */
static int deCFB1(cipherInstance *cipher, keyInstance *key, BYTE *input, 
		int inputLen, BYTE *outBuffer)
{
    int i,j,k;			/* assorted loop counters */
    int b;			/* bit number being processed in byte */
    BYTE msgbit, prev, keybit;	/* current & prev message and stream key bits */
    ULONG64 L, R;		/* left and right data blocks */
    ULONG64 nR, f_out;

    /* get CFB1 input buffer from IV */
    L = cipher->IVL; R = cipher->IVR;

    /* get ready to process first byte */
    b = 7;			/* start with top bit in byte */
    *outBuffer = 0;		/* and zero byte in outBuffer */

    /* now loop over all bits of input */
    for (j = 0; j < inputLen; j++) {
        msgbit = (*input >> b) & 01;	/* get next msg bit */
	prev = msgbit;			/* and save for shift register update */

        if (debuglevel) fprintf(stderr,"%s: deCFB1(%01x,%08lx%08lx%08lx%08lx) ", NAME, msgbit, L.l, L.r, R.l, R.r);
        if (debuglevel > 1) fprintf(stderr,"\n");

        /*  compute all rounds to encrypt current CFB1 buffer */
        k = 0;
        for (i = 0; i < ROUNDS; i++) {



( run in 0.878 second using v1.01-cache-2.11-cpan-e1769b4cff6 )