📄 twofish.c
字号:
* Function Name: makeKey
*
* Function: Initialize the Twofish key schedule
*
* Arguments: key = ptr to keyInstance to be initialized
* direction = DIR_ENCRYPT or DIR_DECRYPT
* keyLen = # bits of key text at *keyMaterial
* keyMaterial = ptr to hex ASCII chars representing key bits
*
* Return: TRUE on success
* else error code (e.g., BAD_KEY_DIR)
*
* Notes:
* This parses the key bits from keyMaterial. No crypto stuff happens here.
* The function reKey() is called to actually build the key schedule after
* the keyMaterial has been parsed.
*
-****************************************************************************/
int makeKey(keyInstance *key, BYTE direction, int keyLen,CONST char *keyMaterial)
{
int i;
#if VALIDATE_PARMS /* first, sanity check on parameters */
if (key == NULL)
return BAD_KEY_INSTANCE;/* must have a keyInstance to initialize */
if ((direction != DIR_ENCRYPT) && (direction != DIR_DECRYPT))
return BAD_KEY_DIR; /* must have valid direction */
if ((keyLen > MAX_KEY_BITS) || (keyLen < 8))
return BAD_KEY_MAT; /* length must be valid */
key->keySig = VALID_SIG; /* show that we are initialized */
#if ALIGN32
if ((((int)key) & 3) || (((int)key->key32) & 3))
return BAD_ALIGN32;
#endif
#endif
key->direction = direction; /* set our cipher direction */
key->keyLen = (keyLen+63) & ~63; /* round up to multiple of 64 */
key->numRounds = numRounds[(keyLen-1)/64];
for (i=0;i<MAX_KEY_BITS/32;i++) /* zero unused bits */
key->key32[i]=0;
key->keyMaterial[MAX_KEY_SIZE]=0; /* terminate ASCII string */
if ((keyMaterial == NULL) || (keyMaterial[0]==0))
return TRUE; /* allow a "dummy" call */
if (ParseHexDword(keyLen,keyMaterial,key->key32,key->keyMaterial))
return BAD_KEY_MAT;
return reKey(key); /* generate round subkeys */
}
/*
+*****************************************************************************
*
* Function Name: cipherInit
*
* Function: Initialize the Twofish cipher in a given mode
*
* Arguments: cipher = ptr to cipherInstance to be initialized
* mode = MODE_ECB, MODE_CBC, or MODE_CFB1
* IV = ptr to hex ASCII test representing IV bytes
*
* Return: TRUE on success
* else error code (e.g., BAD_CIPHER_MODE)
*
-****************************************************************************/
int cipherInit(cipherInstance *cipher, BYTE mode,CONST char *IV)
{
int i;
#if VALIDATE_PARMS /* first, sanity check on parameters */
if (cipher == NULL)
return BAD_PARAMS; /* must have a cipherInstance to initialize */
if ((mode != MODE_ECB) && (mode != MODE_CBC) && (mode != MODE_CFB1))
return BAD_CIPHER_MODE; /* must have valid cipher mode */
cipher->cipherSig = VALID_SIG;
#if ALIGN32
if ((((int)cipher) & 3) || (((int)cipher->IV) & 3) || (((int)cipher->iv32) & 3))
return BAD_ALIGN32;
#endif
#endif
if ((mode != MODE_ECB) && (IV)) /* parse the IV */
{
if (ParseHexDword(BLOCK_SIZE,IV,cipher->iv32,NULL))
return BAD_IV_MAT;
for (i=0;i<BLOCK_SIZE/32;i++) /* make byte-oriented copy for CFB1 */
((DWORD *)cipher->IV)[i] = Bswap(cipher->iv32[i]);
}
cipher->mode = mode;
return TRUE;
}
/*
+*****************************************************************************
*
* Function Name: blockEncrypt
*
* Function: Encrypt block(s) of data using Twofish
*
* Arguments: cipher = ptr to already initialized cipherInstance
* key = ptr to already initialized keyInstance
* input = ptr to data blocks to be encrypted
* inputLen = # bits to encrypt (multiple of blockSize)
* outBuffer = ptr to where to put encrypted blocks
*
* Return: # bits ciphered (>= 0)
* else error code (e.g., BAD_CIPHER_STATE, BAD_KEY_MATERIAL)
*
* Notes: The only supported block size for ECB/CBC modes is BLOCK_SIZE bits.
* If inputLen is not a multiple of BLOCK_SIZE bits in those modes,
* an error BAD_INPUT_LEN is returned. In CFB1 mode, all block
* sizes can be supported.
*
-****************************************************************************/
int blockEncrypt(cipherInstance *cipher, keyInstance *key,CONST BYTE *input,
int inputLen, BYTE *outBuffer)
{
int i,n,r; /* loop variables */
DWORD x[BLOCK_SIZE/32]; /* block being encrypted */
DWORD t0,t1,tmp; /* temp variables */
int rounds=key->numRounds; /* number of rounds */
BYTE bit,ctBit,carry; /* temps for CFB */
#if ALIGN32
BYTE alignDummy; /* keep 32-bit variable alignment on stack */
#endif
#if VALIDATE_PARMS
if ((cipher == NULL) || (cipher->cipherSig != VALID_SIG))
return BAD_CIPHER_STATE;
if ((key == NULL) || (key->keySig != VALID_SIG))
return BAD_KEY_INSTANCE;
if ((rounds < 2) || (rounds > MAX_ROUNDS) || (rounds&1))
return BAD_KEY_INSTANCE;
if ((cipher->mode != MODE_CFB1) && (inputLen % BLOCK_SIZE))
return BAD_INPUT_LEN;
#if ALIGN32
if ( (((int)cipher) & 3) || (((int)key ) & 3) ||
(((int)input ) & 3) || (((int)outBuffer) & 3))
return BAD_ALIGN32;
#endif
#endif
if (cipher->mode == MODE_CFB1)
{ /* use recursion here to handle CFB, one block at a time */
cipher->mode = MODE_ECB; /* do encryption in ECB */
for (n=0;n<inputLen;n++)
{
blockEncrypt(cipher,key,cipher->IV,BLOCK_SIZE,(BYTE *)x);
bit = 0x80 >> (n & 7);/* which bit position in byte */
ctBit = (input[n/8] & bit) ^ ((((BYTE *) x)[0] & 0x80) >> (n&7));
outBuffer[n/8] = (outBuffer[n/8] & ~ bit) | ctBit;
carry = ctBit >> (7 - (n&7));
for (i=BLOCK_SIZE/8-1;i>=0;i--)
{
bit = cipher->IV[i] >> 7; /* save next "carry" from shift */
cipher->IV[i] = (cipher->IV[i] << 1) ^ carry;
carry = bit;
}
}
cipher->mode = MODE_CFB1; /* restore mode for next time */
return inputLen;
}
/* here for ECB, CBC modes */
for (n=0;n<inputLen;n+=BLOCK_SIZE,input+=BLOCK_SIZE/8,outBuffer+=BLOCK_SIZE/8)
{
#ifdef DEBUG
DebugDump(input,"\n",-1,0,0,0,1);
if (cipher->mode == MODE_CBC)
DebugDump(cipher->iv32,"",IV_ROUND,0,0,0,0);
#endif
for (i=0;i<BLOCK_SIZE/32;i++) /* copy in the block, add whitening */
{
x[i]=Bswap(((DWORD *)input)[i]) ^ key->subKeys[INPUT_WHITEN+i];
if (cipher->mode == MODE_CBC)
x[i] ^= cipher->iv32[i];
}
DebugDump(x,"",0,0,0,0,0);
for (r=0;r<rounds;r++) /* main Twofish encryption loop */
{
#if FEISTEL
t0 = f32(ROR(x[0], (r+1)/2),key->sboxKeys,key->keyLen);
t1 = f32(ROL(x[1],8+(r+1)/2),key->sboxKeys,key->keyLen);
/* PHT, round keys */
x[2]^= ROL(t0 + t1 + key->subKeys[ROUND_SUBKEYS+2*r ], r /2);
x[3]^= ROR(t0 + 2*t1 + key->subKeys[ROUND_SUBKEYS+2*r+1],(r+2) /2);
DebugDump(x,"",r+1,2*(r&1),1,1,0);
#else
t0 = f32( x[0] ,key->sboxKeys,key->keyLen);
t1 = f32(ROL(x[1],8),key->sboxKeys,key->keyLen);
x[3] = ROL(x[3],1);
x[2]^= t0 + t1 + key->subKeys[ROUND_SUBKEYS+2*r ]; /* PHT, round keys */
x[3]^= t0 + 2*t1 + key->subKeys[ROUND_SUBKEYS+2*r+1];
x[2] = ROR(x[2],1);
DebugDump(x,"",r+1,2*(r&1),0,1,0);/* make format compatible with optimized code */
#endif
if (r < rounds-1) /* swap for next round */
{
tmp = x[0]; x[0]= x[2]; x[2] = tmp;
tmp = x[1]; x[1]= x[3]; x[3] = tmp;
}
}
#if FEISTEL
x[0] = ROR(x[0],8); /* "final permutation" */
x[1] = ROL(x[1],8);
x[2] = ROR(x[2],8);
x[3] = ROL(x[3],8);
#endif
for (i=0;i<BLOCK_SIZE/32;i++) /* copy out, with whitening */
{
((DWORD *)outBuffer)[i] = Bswap(x[i] ^ key->subKeys[OUTPUT_WHITEN+i]);
if (cipher->mode == MODE_CBC)
cipher->iv32[i] = Bswap(((DWORD *)outBuffer)[i]);
}
#ifdef DEBUG
DebugDump(outBuffer,"",rounds+1,0,0,0,1);
if (cipher->mode == MODE_CBC)
DebugDump(cipher->iv32,"",IV_ROUND,0,0,0,0);
#endif
}
return inputLen;
}
/*
+*****************************************************************************
*
* Function Name: blockDecrypt
*
* Function: Decrypt block(s) of data using Twofish
*
* Arguments: cipher = ptr to already initialized cipherInstance
* key = ptr to already initialized keyInstance
* input = ptr to data blocks to be decrypted
* inputLen = # bits to encrypt (multiple of blockSize)
* outBuffer = ptr to where to put decrypted blocks
*
* Return: # bits ciphered (>= 0)
* else error code (e.g., BAD_CIPHER_STATE, BAD_KEY_MATERIAL)
*
* Notes: The only supported block size for ECB/CBC modes is BLOCK_SIZE bits.
* If inputLen is not a multiple of BLOCK_SIZE bits in those modes,
* an error BAD_INPUT_LEN is returned. In CFB1 mode, all block
* sizes can be supported.
*
-****************************************************************************/
int blockDecrypt(cipherInstance *cipher, keyInstance *key,CONST BYTE *input,
int inputLen, BYTE *outBuffer)
{
int i,n,r; /* loop counters */
DWORD x[BLOCK_SIZE/32]; /* block being encrypted */
DWORD t0,t1; /* temp variables */
int rounds=key->numRounds; /* number of rounds */
BYTE bit,ctBit,carry; /* temps for CFB */
#if ALIGN32
BYTE alignDummy; /* keep 32-bit variable alignment on stack */
#endif
#if VALIDATE_PARMS
if ((cipher == NULL) || (cipher->cipherSig != VALID_SIG))
return BAD_CIPHER_STATE;
if ((key == NULL) || (key->keySig != VALID_SIG))
return BAD_KEY_INSTANCE;
if ((rounds < 2) || (rounds > MAX_ROUNDS) || (rounds&1))
return BAD_KEY_INSTANCE;
if ((cipher->mode != MODE_CFB1) && (inputLen % BLOCK_SIZE))
return BAD_INPUT_LEN;
#if ALIGN32
if ( (((int)cipher) & 3) || (((int)key ) & 3) ||
(((int)input) & 3) || (((int)outBuffer) & 3))
return BAD_ALIGN32;
#endif
#endif
if (cipher->mode == MODE_CFB1)
{ /* use blockEncrypt here to handle CFB, one block at a time */
cipher->mode = MODE_ECB; /* do encryption in ECB */
for (n=0;n<inputLen;n++)
{
blockEncrypt(cipher,key,cipher->IV,BLOCK_SIZE,(BYTE *)x);
bit = 0x80 >> (n & 7);
ctBit = input[n/8] & bit;
outBuffer[n/8] = (outBuffer[n/8] & ~ bit) |
(ctBit ^ ((((BYTE *) x)[0] & 0x80) >> (n&7)));
carry = ctBit >> (7 - (n&7));
for (i=BLOCK_SIZE/8-1;i>=0;i--)
{
bit = cipher->IV[i] >> 7; /* save next "carry" from shift */
cipher->IV[i] = (cipher->IV[i] << 1) ^ carry;
carry = bit;
}
}
cipher->mode = MODE_CFB1; /* restore mode for next time */
return inputLen;
}
/* here for ECB, CBC modes */
for (n=0;n<inputLen;n+=BLOCK_SIZE,input+=BLOCK_SIZE/8,outBuffer+=BLOCK_SIZE/8)
{
DebugDump(input,"\n",rounds+1,0,0,0,1);
for (i=0;i<BLOCK_SIZE/32;i++) /* copy in the block, add whitening */
x[i]=Bswap(((DWORD *)input)[i]) ^ key->subKeys[OUTPUT_WHITEN+i];
for (r=rounds-1;r>=0;r--) /* main Twofish decryption loop */
{
t0 = f32( x[0] ,key->sboxKeys,key->keyLen);
t1 = f32(ROL(x[1],8),key->sboxKeys,key->keyLen);
DebugDump(x,"",r+1,2*(r&1),0,1,0);/* make format compatible with optimized code */
x[2] = ROL(x[2],1);
x[2]^= t0 + t1 + key->subKeys[ROUND_SUBKEYS+2*r ]; /* PHT, round keys */
x[3]^= t0 + 2*t1 + key->subKeys[ROUND_SUBKEYS+2*r+1];
x[3] = ROR(x[3],1);
if (r) /* unswap, except for last round */
{
t0 = x[0]; x[0]= x[2]; x[2] = t0;
t1 = x[1]; x[1]= x[3]; x[3] = t1;
}
}
DebugDump(x,"",0,0,0,0,0);/* make final output match encrypt initial output */
for (i=0;i<BLOCK_SIZE/32;i++) /* copy out, with whitening */
{
x[i] ^= key->subKeys[INPUT_WHITEN+i];
if (cipher->mode == MODE_CBC)
{
x[i] ^= cipher->iv32[i];
cipher->iv32[i] = Bswap(((DWORD *)input)[i]);
}
((DWORD *)outBuffer)[i] = Bswap(x[i]);
}
DebugDump(outBuffer,"",-1,0,0,0,1);
}
return inputLen;
}
#ifdef GetCodeSize
DWORD TwofishCodeSize(void) { return Here(0)-TwofishCodeStart(); };
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -