Crypt-Loki97
view release on metacpan or search on metacpan
/*
* 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> © 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 */
}
/* 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 )