📄 pgptwofish.c
字号:
if ((useAsm & 1) && (inputLen))
#ifdef COMPILE_KEY
if (key->keySig == VALID_SIG)
return ((CipherProc *)(key->encryptFuncPtr))(cipher,key,input,inputLen,outBuffer);
#else
return (*blockEncrypt_86)(cipher,key,input,inputLen,outBuffer);
#endif
#endif
/* make local copy of subkeys for speed */
memcpy(sk,key->subKeys,sizeof(DWORD)*(ROUND_SUBKEYS+2*rounds));
if (mode == MODE_CBC)
BlockCopy(IV,cipher->iv32)
else
IV[0]=IV[1]=IV[2]=IV[3]=0;
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
#define LoadBlockE(N) x[N]=Bswap(((DWORD *)input)[N]) ^ sk[INPUT_WHITEN+N] ^ IV[N]
LoadBlockE(0); LoadBlockE(1); LoadBlockE(2); LoadBlockE(3);
DebugDump(x,"",0,0,0,0,0);
#define EncryptRound(K,R,id) \
t0 = Fe32##id(x[K ],0); \
t1 = Fe32##id(x[K^1],3); \
x[K^3] = ROL(x[K^3],1); \
x[K^2]^= t0 + t1 + sk[ROUND_SUBKEYS+2*(R) ]; \
x[K^3]^= t0 + 2*t1 + sk[ROUND_SUBKEYS+2*(R)+1]; \
x[K^2] = ROR(x[K^2],1); \
DebugDump(x,"",rounds-(R),0,0,1,0);
#define Encrypt2(R,id) { EncryptRound(0,R+1,id); EncryptRound(2,R,id); }
#if defined(ZERO_KEY)
switch (key->keyLen)
{
case 128:
for (i=rounds-2;i>=0;i-=2)
Encrypt2(i,_128);
break;
case 192:
for (i=rounds-2;i>=0;i-=2)
Encrypt2(i,_192);
break;
case 256:
for (i=rounds-2;i>=0;i-=2)
Encrypt2(i,_256);
break;
}
#else
Encrypt2(14,_);
Encrypt2(12,_);
Encrypt2(10,_);
Encrypt2( 8,_);
Encrypt2( 6,_);
Encrypt2( 4,_);
Encrypt2( 2,_);
Encrypt2( 0,_);
#endif
/* need to do (or undo, depending on your point of view) final swap */
#if LittleEndian
#define StoreBlockE(N) ((DWORD *)outBuffer)[N]=x[N^2] ^ sk[OUTPUT_WHITEN+N]
#else
#define StoreBlockE(N) { t0=x[N^2] ^ sk[OUTPUT_WHITEN+N]; ((DWORD *)outBuffer)[N]=Bswap(t0); }
#endif
StoreBlockE(0); StoreBlockE(1); StoreBlockE(2); StoreBlockE(3);
if (mode == MODE_CBC)
{
IV[0]=Bswap(((DWORD *)outBuffer)[0]);
IV[1]=Bswap(((DWORD *)outBuffer)[1]);
IV[2]=Bswap(((DWORD *)outBuffer)[2]);
IV[3]=Bswap(((DWORD *)outBuffer)[3]);
}
#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
}
if (mode == MODE_CBC)
BlockCopy(cipher->iv32,IV);
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; /* 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 dummyAlign = 0; /* keep dword alignment on stack */
#endif
/* make local copies of things for faster access */
int mode = cipher->mode;
DWORD sk[TOTAL_SUBKEYS];
DWORD IV[BLOCK_SIZE/32];
GetSboxKey;
#if ALIGN32
(void) dummyAlign;
#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 */
if (key->direction != DIR_DECRYPT)
ReverseRoundSubkeys(key,DIR_DECRYPT); /* reverse the round subkey order */
#ifdef USE_ASM
if ((useAsm & 2) && (inputLen))
#ifdef COMPILE_KEY
if (key->keySig == VALID_SIG)
return ((CipherProc *)(key->decryptFuncPtr))(cipher,key,input,inputLen,outBuffer);
#else
return (*blockDecrypt_86)(cipher,key,input,inputLen,outBuffer);
#endif
#endif
/* make local copy of subkeys for speed */
memcpy(sk,key->subKeys,sizeof(DWORD)*(ROUND_SUBKEYS+2*rounds));
if (mode == MODE_CBC)
BlockCopy(IV,cipher->iv32)
else
IV[0]=IV[1]=IV[2]=IV[3]=0;
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);
#define LoadBlockD(N) x[N^2]=Bswap(((DWORD *)input)[N]) ^ sk[OUTPUT_WHITEN+N]
LoadBlockD(0); LoadBlockD(1); LoadBlockD(2); LoadBlockD(3);
#define DecryptRound(K,R,id) \
t0 = Fe32##id(x[K ],0); \
t1 = Fe32##id(x[K^1],3); \
DebugDump(x,"",(R)+1,0,0,1,0); \
x[K^2] = ROL (x[K^2],1); \
x[K^2]^= t0 + t1 + sk[ROUND_SUBKEYS+2*(R) ]; \
x[K^3]^= t0 + 2*t1 + sk[ROUND_SUBKEYS+2*(R)+1]; \
x[K^3] = ROR (x[K^3],1); \
#define Decrypt2(R,id) { DecryptRound(2,R+1,id); DecryptRound(0,R,id); }
#if defined(ZERO_KEY)
switch (key->keyLen)
{
case 128:
for (i=rounds-2;i>=0;i-=2)
Decrypt2(i,_128);
break;
case 192:
for (i=rounds-2;i>=0;i-=2)
Decrypt2(i,_192);
break;
case 256:
for (i=rounds-2;i>=0;i-=2)
Decrypt2(i,_256);
break;
}
#else
{
Decrypt2(14,_);
Decrypt2(12,_);
Decrypt2(10,_);
Decrypt2( 8,_);
Decrypt2( 6,_);
Decrypt2( 4,_);
Decrypt2( 2,_);
Decrypt2( 0,_);
}
#endif
DebugDump(x,"",0,0,0,0,0);
if (cipher->mode == MODE_ECB)
{
#if LittleEndian
#define StoreBlockD(N) ((DWORD *)outBuffer)[N] = x[N] ^ sk[INPUT_WHITEN+N]
#else
#define StoreBlockD(N) { t0=x[N]^sk[INPUT_WHITEN+N]; ((DWORD *)outBuffer)[N] = Bswap(t0); }
#endif
StoreBlockD(0); StoreBlockD(1); StoreBlockD(2); StoreBlockD(3);
#undef StoreBlockD
DebugDump(outBuffer,"",-1,0,0,0,1);
continue;
}
else
{
#define StoreBlockD(N) x[N] ^= sk[INPUT_WHITEN+N] ^ IV[N]; \
IV[N] = Bswap(((DWORD *)input)[N]); \
((DWORD *)outBuffer)[N] = Bswap(x[N]);
StoreBlockD(0); StoreBlockD(1); StoreBlockD(2); StoreBlockD(3);
#undef StoreBlockD
DebugDump(outBuffer,"",-1,0,0,0,1);
}
}
return inputLen;
}
#if ! PGP_OSX /* This function doesn't appear to be called */
static DWORD TwofishCodeSize(void)
{
DWORD x= Here(0);
#ifdef USE_ASM
if (useAsm & 3)
return TwofishAsmCodeSize();
#endif
return x - TwofishCodeStart();
}
#endif
/*
* Exported functions for PGP
*/
static void
twof256Key(void *priv, void const *keymaterial)
{
keyInstance *key = (keyInstance *)priv;
key->direction = DIR_ENCRYPT; /* Can be reversed later */
key->keyLen = 256;
key->numRounds = numRounds[(key->keyLen-1)/64];
memset(key->key32,0,sizeof(key->key32)); /* zero unused bits */
pgpCopyMemory (keymaterial, key->key32, key->keyLen / 8);
#if UnknownEndian
if (!EndianKnown)
setEndian();
/* key->key32 array must be properly swapped Dwords */
{ unsigned i;
for( i=0; i<sizeof(key->key32)/sizeof(DWORD); i++ )
key->key32[i] = Bswap(key->key32[i]);
}
#endif
(void) reKey(key); /* generate round subkeys */
}
/* This version replicates a bug that was present in Solaris versions
* prior to June 2002. We do the byte swapping for the key32 array the
* opposite of what they should be, i.e. we byte swap on little endian but
* not on big endian.
*/
static void
twof256KeyBad(void *priv, void const *keymaterial)
{
keyInstance *key = (keyInstance *)priv;
key->direction = DIR_ENCRYPT; /* Can be reversed later */
key->keyLen = 256;
key->numRounds = numRounds[(key->keyLen-1)/64];
memset(key->key32,0,sizeof(key->key32)); /* zero unused bits */
pgpCopyMemory (keymaterial, key->key32, key->keyLen / 8);
#if UnknownEndian
if (!EndianKnown)
setEndian();
if( ADDR_XOR == 0 ) // means little endian
{
unsigned i;
for( i=0; i<sizeof(key->key32)/sizeof(DWORD); i++ )
key->key32[i] = ((ROR(key->key32[i],8) & 0xFF00FF00)
| (ROL(key->key32[i],8) & 0x00FF00FF));
}
#elif LittleEndian
{ unsigned i;
for( i=0; i<sizeof(key->key32)/sizeof(DWORD); i++ )
key->key32[i] = ((ROR(key->key32[i],8) & 0xFF00FF00)
| (ROL(key->key32[i],8) & 0x00FF00FF));
}
#else
/* Do nothing on big endian */
#endif
(void) reKey(key); /* generate round subkeys */
}
static void
twof256Encrypt(void *priv, void const *in, void *out)
{
keyInstance *key = (keyInstance *)priv;
cipherInstance cipher;
pgpClearMemory (&cipher, sizeof(cipher));
cipher.mode = MODE_ECB;
(void)blockEncrypt (&cipher, key, (PGPByte *)in, BLOCK_SIZE,
(PGPByte *)out);
}
static void
twof256Decrypt(void *priv, void const *in, void *out)
{
keyInstance *key = (keyInstance *)priv;
cipherInstance cipher;
pgpClearMemory (&cipher, sizeof(cipher));
cipher.mode = MODE_ECB;
(void)blockDecrypt (&cipher, key, (PGPByte *)in, BLOCK_SIZE,
(PGPByte *)out);
}
/*
* Define a Cipher for the generic cipher. This is the only
* real exported thing -- everything else can be static, since everything
* is referenced through function pointers!
*/
PGPCipherVTBL const cipherTwofish256 = {
"Twofish256",
kPGPCipherAlgorithm_Twofish256,
16, /* Blocksize */
32, /* Keysize */
sizeof(keyInstance),
alignof(PGPUInt32),
twof256Key,
twof256Encrypt,
twof256Decrypt,
NULL
};
/* Buggy version of Twofish, for compatibility with a bug we had on
* big-endian machines prior to June 2002
*/
PGPCipherVTBL const cipherBadTwofish256 = {
"BadTwofish256",
kPGPCipherAlgorithm_BadTwofish256,
16, /* Blocksize */
32, /* Keysize */
sizeof(keyInstance),
alignof(PGPUInt32),
twof256KeyBad,
twof256Encrypt,
twof256Decrypt,
NULL
};
#endif /* ] PGP_TWOFISH */
#if UNITTEST
/* Test vectors */
PGPByte K1[] = {
0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF,
0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF
};
PGPByte P1[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
PGPByte C1[] = {
0x37, 0x52, 0x7B, 0xE0, 0x05, 0x23, 0x34, 0xB8,
0x9F, 0x0C, 0xFC, 0xCA, 0xE8, 0x7C, 0xFA, 0x20
};
PGPByte C1bad[] = {
0x04, 0xcf, 0xce, 0xf2, 0x75, 0xd4, 0xb4, 0x4f,
0x17, 0x95, 0xd1, 0x23, 0x22, 0x7e, 0xf4, 0xde
};
int
main(void)
{ /* Test driver for CAST cipher */
PGPByte priv[sizeof(keyInstance)];
PGPByte X[16], Y[16];
twof256Key(priv, K1);
twof256Encrypt(priv, P1, X);
if (memcmp(C1, X, sizeof(X)) == 0)
printf ("Encryption test 1 passed\n");
else
printf ("ERROR ON ENCRYPTION TEST 1\n");
twof256Decrypt(priv, C1, Y);
if (memcmp(P1, Y, sizeof(Y)) == 0)
printf ("Decryption test 1 passed\n");
else
printf ("ERROR ON DECRYPTION TEST 1\n");
/* Test "bad" version (backwards compatible with Solaris bug) */
twof256KeyBad(priv, K1);
twof256Encrypt(priv, P1, X);
if (memcmp(C1bad, X, sizeof(X)) == 0)
printf (PGPTXT_DEBUG8("Encryption test 2 passed\n"));
else
printf (PGPTXT_DEBUG8("ERROR ON ENCRYPTION TEST 2\n"));
twof256Decrypt(priv, C1bad, Y);
if (memcmp(P1, Y, sizeof(Y)) == 0)
printf (PGPTXT_DEBUG8("Decryption test 2 passed\n"));
else
printf (PGPTXT_DEBUG8("ERROR ON DECRYPTION TEST 2\n"));
return 0; /* normal exit */
} /* main */
#endif /* UNITTEST */
/*__Editor_settings____
Local Variables:
tab-width: 4
End:
vi: ts=4 sw=4
vim: si
_____________________*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -