📄 twofish.c
字号:
/***************************************************************************
TWOFISH.C -- C API calls for TWOFISH AES submission
Submitters:
Bruce Schneier, Counterpane Systems
Doug Whiting, Hi/fn
John Kelsey, Counterpane Systems
Chris Hall, Counterpane Systems
David Wagner, UC Berkeley
Code Author: Doug Whiting, Hi/fn
Version 1.00 April 1998
Copyright 1998, Hi/fn and Counterpane Systems. All rights reserved.
Notes:
* Pedagogical version (non-optimized)
* Tab size is set to 4 characters in this file
***************************************************************************/
#include "aes.h"
#include "table.h"
/*
+*****************************************************************************
* Constants/Macros/Tables
-****************************************************************************/
#define VALIDATE_PARMS 1 /* nonzero --> check all parameters */
#define FEISTEL 0 /* nonzero --> use Feistel version (slow) */
int tabEnable=0; /* are we gathering stats? */
BYTE tabUsed[256]; /* one bit per table */
#if FEISTEL
CONST char *moduleDescription="Pedagogical C code (Feistel)";
#else
CONST char *moduleDescription="Pedagogical C code";
#endif
CONST char *modeString = "";
#define P0_USED 0x01
#define P1_USED 0x02
#define B0_USED 0x04
#define B1_USED 0x08
#define B2_USED 0x10
#define B3_USED 0x20
#define ALL_USED 0x3F
/* number of rounds for various key sizes: 128, 192, 256 */
int numRounds[4]= {0,ROUNDS_128,ROUNDS_192,ROUNDS_256};
#ifndef DEBUG
#ifdef GetCodeSize
#define DEBUG 1 /* force debug */
#endif
#endif
#include "debug.h" /* debug display macros */
#ifdef GetCodeSize
extern DWORD Here(DWORD x); /* return caller's address! */
DWORD TwofishCodeStart(void) { return Here(0); };
#endif
/*
+*****************************************************************************
*
* Function Name: TableOp
*
* Function: Handle table use checking
*
* Arguments: op = what to do (see TAB_* defns in AES.H)
*
* Return: TRUE --> done (for TAB_QUERY)
*
* Notes: This routine is for use in generating the tables KAT file.
*
-****************************************************************************/
int TableOp(int op)
{
static int queryCnt=0;
int i;
switch (op)
{
case TAB_DISABLE:
tabEnable=0;
break;
case TAB_ENABLE:
tabEnable=1;
break;
case TAB_RESET:
queryCnt=0;
for (i=0;i<256;i++)
tabUsed[i]=0;
break;
case TAB_QUERY:
queryCnt++;
for (i=0;i<256;i++)
if (tabUsed[i] != ALL_USED)
return FALSE;
if (queryCnt < TAB_MIN_QUERY) /* do a certain minimum number */
return FALSE;
break;
}
return TRUE;
}
/*
+*****************************************************************************
*
* Function Name: ParseHexDword
*
* Function: Parse ASCII hex nibbles and fill in key/iv dwords
*
* Arguments: bit = # bits to read
* srcTxt = ASCII source
* d = ptr to dwords to fill in
* dstTxt = where to make a copy of ASCII source
* (NULL ok)
*
* Return: Zero if no error. Nonzero --> invalid hex or length
*
* Notes: Note that the parameter d is a DWORD array, not a byte array.
* This routine is coded to work both for little-endian and big-endian
* architectures. The character stream is interpreted as a LITTLE-ENDIAN
* byte stream, since that is how the Pentium works, but the conversion
* happens automatically below.
*
-****************************************************************************/
int ParseHexDword(int bits,CONST char *srcTxt,DWORD *d,char *dstTxt)
{
int i;
DWORD b;
char c;
#if ALIGN32
char alignDummy[3]; /* keep dword alignment */
#endif
union /* make sure LittleEndian is defined correctly */
{
BYTE b[4];
DWORD d[1];
} v;
v.d[0]=1;
if (v.b[0 ^ ADDR_XOR] != 1) /* sanity check on compile-time switch */
return BAD_ENDIAN;
#if VALIDATE_PARMS
#if ALIGN32
if (((int)d) & 3)
return BAD_ALIGN32;
#endif
#endif
for (i=0;i*32<bits;i++)
d[i]=0; /* first, zero the field */
for (i=0;i*4<bits;i++) /* parse one nibble at a time */
{ /* case out the hexadecimal characters */
c=srcTxt[i];
if (dstTxt) dstTxt[i]=c;
if ((c >= '0') && (c <= '9'))
b=c-'0';
else if ((c >= 'a') && (c <= 'f'))
b=c-'a'+10;
else if ((c >= 'A') && (c <= 'F'))
b=c-'A'+10;
else
return BAD_KEY_MAT; /* invalid hex character */
/* works for big and little endian! */
d[i/8] |= b << (4*((i^1)&7));
}
return 0; /* no error */
}
/*
+*****************************************************************************
*
* Function Name: f32
*
* Function: Run four bytes through keyed S-boxes and apply MDS matrix
*
* Arguments: x = input to f function
* k32 = pointer to key dwords
* keyLen = total key length (k32 --> keyLey/2 bits)
*
* Return: The output of the keyed permutation applied to x.
*
* Notes:
* This function is a keyed 32-bit permutation. It is the major building
* block for the Twofish round function, including the four keyed 8x8
* permutations and the 4x4 MDS matrix multiply. This function is used
* both for generating round subkeys and within the round function on the
* block being encrypted.
*
* This version is fairly slow and pedagogical, although a smartcard would
* probably perform the operation exactly this way in firmware. For
* ultimate performance, the entire operation can be completed with four
* lookups into four 256x32-bit tables, with three dword xors.
*
* The MDS matrix is defined in TABLE.H. To multiply by Mij, just use the
* macro Mij(x).
*
-****************************************************************************/
DWORD f32(DWORD x,CONST DWORD *k32,int keyLen)
{
BYTE b[4];
/* Run each byte thru 8x8 S-boxes, xoring with key byte at each stage. */
/* Note that each byte goes through a different combination of S-boxes.*/
*((DWORD *)b) = Bswap(x); /* make b[0] = LSB, b[3] = MSB */
switch (((keyLen + 63)/64) & 3)
{
case 0: /* 256 bits of key */
b[0] = p8(04)[b[0]] ^ b0(k32[3]);
b[1] = p8(14)[b[1]] ^ b1(k32[3]);
b[2] = p8(24)[b[2]] ^ b2(k32[3]);
b[3] = p8(34)[b[3]] ^ b3(k32[3]);
/* fall thru, having pre-processed b[0]..b[3] with k32[3] */
case 3: /* 192 bits of key */
b[0] = p8(03)[b[0]] ^ b0(k32[2]);
b[1] = p8(13)[b[1]] ^ b1(k32[2]);
b[2] = p8(23)[b[2]] ^ b2(k32[2]);
b[3] = p8(33)[b[3]] ^ b3(k32[2]);
/* fall thru, having pre-processed b[0]..b[3] with k32[2] */
case 2: /* 128 bits of key */
b[0] = p8(00)[p8(01)[p8(02)[b[0]] ^ b0(k32[1])] ^ b0(k32[0])];
b[1] = p8(10)[p8(11)[p8(12)[b[1]] ^ b1(k32[1])] ^ b1(k32[0])];
b[2] = p8(20)[p8(21)[p8(22)[b[2]] ^ b2(k32[1])] ^ b2(k32[0])];
b[3] = p8(30)[p8(31)[p8(32)[b[3]] ^ b3(k32[1])] ^ b3(k32[0])];
}
if (tabEnable)
{ /* we could give a "tighter" bound, but this works acceptably well */
tabUsed[b0(x)] |= (P_00 == 0) ? P0_USED : P1_USED;
tabUsed[b1(x)] |= (P_10 == 0) ? P0_USED : P1_USED;
tabUsed[b2(x)] |= (P_20 == 0) ? P0_USED : P1_USED;
tabUsed[b3(x)] |= (P_30 == 0) ? P0_USED : P1_USED;
tabUsed[b[0] ] |= B0_USED;
tabUsed[b[1] ] |= B1_USED;
tabUsed[b[2] ] |= B2_USED;
tabUsed[b[3] ] |= B3_USED;
}
/* Now perform the MDS matrix multiply inline. */
return ((M00(b[0]) ^ M01(b[1]) ^ M02(b[2]) ^ M03(b[3])) ) ^
((M10(b[0]) ^ M11(b[1]) ^ M12(b[2]) ^ M13(b[3])) << 8) ^
((M20(b[0]) ^ M21(b[1]) ^ M22(b[2]) ^ M23(b[3])) << 16) ^
((M30(b[0]) ^ M31(b[1]) ^ M32(b[2]) ^ M33(b[3])) << 24) ;
}
/*
+*****************************************************************************
*
* Function Name: RS_MDS_Encode
*
* Function: Use (12,8) Reed-Solomon code over GF(256) to produce
* a key S-box dword from two key material dwords.
*
* Arguments: k0 = 1st dword
* k1 = 2nd dword
*
* Return: Remainder polynomial generated using RS code
*
* Notes:
* Since this computation is done only once per reKey per 64 bits of key,
* the performance impact of this routine is imperceptible. The RS code
* chosen has "simple" coefficients to allow smartcard/hardware implementation
* without lookup tables.
*
-****************************************************************************/
DWORD RS_MDS_Encode(DWORD k0,DWORD k1)
{
int i,j;
DWORD r;
for (i=r=0;i<2;i++)
{
r ^= (i) ? k0 : k1; /* merge in 32 more key bits */
for (j=0;j<4;j++) /* shift one byte at a time */
RS_rem(r);
}
return r;
}
/*
+*****************************************************************************
*
* Function Name: reKey
*
* Function: Initialize the Twofish key schedule from key32
*
* Arguments: key = ptr to keyInstance to be initialized
*
* Return: TRUE on success
*
* Notes:
* Here we precompute all the round subkeys, although that is not actually
* required. For example, on a smartcard, the round subkeys can
* be generated on-the-fly using f32()
*
-****************************************************************************/
int reKey(keyInstance *key)
{
int i,k64Cnt;
int keyLen = key->keyLen;
int subkeyCnt = ROUND_SUBKEYS + 2*key->numRounds;
DWORD A,B;
DWORD k32e[MAX_KEY_BITS/64],k32o[MAX_KEY_BITS/64]; /* even/odd key dwords */
#if VALIDATE_PARMS
#if ALIGN32
if ((((int)key) & 3) || (((int)key->key32) & 3))
return BAD_ALIGN32;
#endif
if ((key->keyLen % 64) || (key->keyLen < MIN_KEY_BITS))
return BAD_KEY_INSTANCE;
if (subkeyCnt > TOTAL_SUBKEYS)
return BAD_KEY_INSTANCE;
#endif
k64Cnt=(keyLen+63)/64; /* round up to next multiple of 64 bits */
for (i=0;i<k64Cnt;i++)
{ /* split into even/odd key dwords */
k32e[i]=key->key32[2*i ];
k32o[i]=key->key32[2*i+1];
/* compute S-box keys using (12,8) Reed-Solomon code over GF(256) */
key->sboxKeys[k64Cnt-1-i]=RS_MDS_Encode(k32e[i],k32o[i]); /* reverse order */
}
for (i=0;i<subkeyCnt/2;i++) /* compute round subkeys for PHT */
{
A = f32(i*SK_STEP ,k32e,keyLen); /* A uses even key dwords */
B = f32(i*SK_STEP+SK_BUMP,k32o,keyLen); /* B uses odd key dwords */
B = ROL(B,8);
key->subKeys[2*i ] = A+ B; /* combine with a PHT */
key->subKeys[2*i+1] = ROL(A+2*B,SK_ROTL);
}
DebugDumpKey(key);
return TRUE;
}
/*
+*****************************************************************************
*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -