www.pudn.com > truecrypt-4.2-source-code.zip > Crypto.c


/* Legal Notice: The source code contained in this file has been derived from 
   the source code of Encryption for the Masses 2.02a, which is Copyright (c) 
   1998-99 Paul Le Roux and which is covered by the 'License Agreement for 
   Encryption for the Masses'. Modifications and additions to that source code 
   contained in this file are Copyright (c) 2004-2006 TrueCrypt Foundation and 
   Copyright (c) 2004 TrueCrypt Team, and are covered by TrueCrypt License 2.0 
   the full text of which is contained in the file License.txt included in 
   TrueCrypt binary and source code distribution archives.  */ 
 
#include "Tcdefs.h" 
#include "Crypto.h" 
#include "Crc.h" 
#include "Endian.h" 
 
#ifdef LINUX_DRIVER 
#include  
#include  
#endif 
 
/* Update the following when adding a new cipher or EA: 
 
   Crypto.h: 
     ID #define 
     MAX_EXPANDED_KEY #define 
 
   Crypto.c: 
     Ciphers[] 
     EncryptionAlgorithms[] 
     CipherInit() 
     EncipherBlock() 
     DecipherBlock() 
 
*/ 
 
// Cipher configuration 
static Cipher Ciphers[] = 
{ 
//								Block Size	Key Size	Key Schedule Size 
//	  ID		Name			(Bytes)		(Bytes)		(Bytes) 
	{ AES,		"AES",			16,			32,			sizeof(aes_encrypt_ctx)+sizeof(aes_decrypt_ctx)	}, 
	{ BLOWFISH,	"Blowfish",		8,			56,			4168											}, 
	{ CAST,		"CAST5",		8,			16,			128												}, 
	{ DES56,	"DES",			8,			7,			128												}, 
	{ SERPENT,	"Serpent",		16,			32,			140*4											}, 
	{ TRIPLEDES,"Triple DES",	8,			8*3,		128*3											}, 
	{ TWOFISH,	"Twofish",		16,			32,			TWOFISH_KS										}, 
	{ 0,		0,				0,			0,			0												} 
}; 
 
// Encryption algorithm configuration 
// The following modes have been deprecated (legacy):  CBC, INNER_CBC, OUTER_CBC 
static EncryptionAlgorithm EncryptionAlgorithms[] = 
{ 
	//  Cipher(s)                     Modes 
	{ { 0,						0 } , { 0, 0, 0 }			},	// Must be all-zero 
	{ { AES,					0 } , { LRW, CBC, 0 }		}, 
	{ { BLOWFISH,				0 } , { LRW, CBC, 0 }		}, 
	{ { CAST,					0 } , { LRW, CBC, 0 }		}, 
	{ { SERPENT,				0 } , { LRW, CBC, 0 }		}, 
	{ { TRIPLEDES,				0 } , { LRW, CBC, 0 }		}, 
	{ { TWOFISH,				0 } , { LRW, CBC, 0 }		}, 
	{ { TWOFISH, AES,			0 } , { LRW, OUTER_CBC, 0 }	}, 
	{ { SERPENT, TWOFISH, AES,	0 } , { LRW, OUTER_CBC, 0 }	}, 
	{ { AES, SERPENT,			0 } , { LRW, OUTER_CBC, 0 }	}, 
	{ { AES, TWOFISH, SERPENT,	0 } , { LRW, OUTER_CBC, 0 }	}, 
	{ { SERPENT, TWOFISH,		0 } , { LRW, OUTER_CBC, 0 }	}, 
	{ { BLOWFISH, AES,			0 } , { INNER_CBC, 0, 0 }	}, 
	{ { SERPENT, BLOWFISH, AES,	0 } , { INNER_CBC, 0, 0 }	}, 
	{ { 0,						0 } , { 0, 0, 0 }			}	// Must be all-zero 
}; 
 
// Hash algorithms 
static Hash Hashes[] = 
{ 
	{ RIPEMD160, "RIPEMD-160" }, 
	{ SHA1, "SHA-1" }, 
	{ WHIRLPOOL, "Whirlpool" }, 
	{ 0, 0 } 
}; 
 
/* Return values: 0 = success, ERR_CIPHER_INIT_FAILURE (fatal), ERR_CIPHER_INIT_WEAK_KEY (non-fatal) */ 
int CipherInit (int cipher, unsigned char *key, unsigned __int8 *ks) 
{ 
	int retVal = 0; 
 
	switch (cipher) 
	{ 
	case BLOWFISH: 
		BF_set_key ((BF_KEY *)ks, CipherGetKeySize(BLOWFISH), key); 
		break; 
 
	case AES: 
		if (aes_encrypt_key(key, CipherGetKeySize(AES), (aes_encrypt_ctx *) ks) != EXIT_SUCCESS) 
			return ERR_CIPHER_INIT_FAILURE; 
 
		if (aes_decrypt_key(key, CipherGetKeySize(AES), (aes_decrypt_ctx *) (ks + sizeof(aes_encrypt_ctx))) != EXIT_SUCCESS) 
			return ERR_CIPHER_INIT_FAILURE; 
 
		break; 
 
	case DES56:		 
		/* Included for testing purposes only */ 
		switch (des_key_sched ((des_cblock *) key, (struct des_ks_struct *) ks)) 
		{ 
		case -1: 
			return ERR_CIPHER_INIT_FAILURE; 
		case -2: 
			retVal = ERR_CIPHER_INIT_WEAK_KEY;		// Non-fatal error 
			break; 
		} 
		break; 
 
	case CAST: 
		CAST_set_key((CAST_KEY *) ks, CipherGetKeySize(CAST), key); 
		break; 
 
	case SERPENT: 
		serpent_set_key (key, CipherGetKeySize(SERPENT) * 8, ks); 
		break; 
 
	case TRIPLEDES: 
		switch (des_key_sched ((des_cblock *) key, (struct des_ks_struct *) ks)) 
		{ 
		case -1: 
			return ERR_CIPHER_INIT_FAILURE; 
		case -2: 
			retVal = ERR_CIPHER_INIT_WEAK_KEY;		// Non-fatal error 
			break; 
		} 
		switch (des_key_sched ((des_cblock *) ((char*)(key)+8), (struct des_ks_struct *) (ks + CipherGetKeyScheduleSize (DES56)))) 
		{ 
		case -1: 
			return ERR_CIPHER_INIT_FAILURE; 
		case -2: 
			retVal = ERR_CIPHER_INIT_WEAK_KEY;		// Non-fatal error 
			break; 
		} 
		switch (des_key_sched ((des_cblock *) ((char*)(key)+16), (struct des_ks_struct *) (ks + CipherGetKeyScheduleSize (DES56) * 2))) 
		{ 
		case -1: 
			return ERR_CIPHER_INIT_FAILURE; 
		case -2: 
			retVal = ERR_CIPHER_INIT_WEAK_KEY;		// Non-fatal error 
			break; 
		} 
 
		// Verify whether all three DES keys are mutually different 
		if (((*((__int64 *) key) ^ *((__int64 *) key+1)) & 0xFEFEFEFEFEFEFEFE) == 0 
		|| ((*((__int64 *) key+1) ^ *((__int64 *) key+2)) & 0xFEFEFEFEFEFEFEFE) == 0 
		|| ((*((__int64 *) key) ^ *((__int64 *) key+2)) & 0xFEFEFEFEFEFEFEFE) == 0) 
			retVal = ERR_CIPHER_INIT_WEAK_KEY;		// Non-fatal error 
 
		break; 
 
	case TWOFISH: 
		twofish_set_key ((TwofishInstance *)ks, (const u4byte *)key, CipherGetKeySize(TWOFISH) * 8); 
		break; 
 
	} 
	return retVal; 
} 
 
void EncipherBlock(int cipher, void *data, void *ks) 
{ 
	switch (cipher) 
	{ 
	case BLOWFISH:		BF_ecb_le_encrypt (data, data, ks, 1); break; 
	case AES:			aes_encrypt (data, data, ks); break; 
	case DES56:			des_encrypt (data, ks, 1); break; 
	case CAST:			CAST_ecb_encrypt (data, data, ks, 1); break; 
	case SERPENT:		serpent_encrypt (data, data, ks); break; 
	case TRIPLEDES:		des_ecb3_encrypt (data, data, ks, 
						(void*)((char*) ks + CipherGetKeyScheduleSize (DES56)), (void*)((char*) ks + CipherGetKeyScheduleSize (DES56) * 2), 1); break; 
	case TWOFISH:		twofish_encrypt (ks, data, data); break; 
	} 
} 
 
void DecipherBlock(int cipher, void *data, void *ks) 
{ 
	switch (cipher) 
	{ 
	case BLOWFISH:	BF_ecb_le_encrypt (data, data, ks, 0); break; 
	case AES:		aes_decrypt (data, data, (void *) ((char *) ks + sizeof(aes_encrypt_ctx))); break; 
	case DES56:		des_encrypt (data, ks, 0); break; 
	case CAST:		CAST_ecb_encrypt (data, data, ks,0); break; 
	case SERPENT:	serpent_decrypt (data, data, ks); break; 
	case TRIPLEDES:	des_ecb3_encrypt (data, data, ks, 
					(void*)((char*) ks + CipherGetKeyScheduleSize (DES56)), 
					(void*)((char*) ks + CipherGetKeyScheduleSize (DES56) * 2), 0); break; 
	case TWOFISH:	twofish_decrypt (ks, data, data); break; 
	} 
} 
 
// Ciphers support 
 
Cipher *CipherGet (int id) 
{ 
	int i; 
	for (i = 0; Ciphers[i].Id != 0; i++) 
		if (Ciphers[i].Id == id) 
			return &Ciphers[i]; 
 
	return 0; 
} 
 
char *CipherGetName (int cipherId) 
{ 
	return CipherGet (cipherId) -> Name; 
} 
 
int CipherGetBlockSize (int cipherId) 
{ 
	return CipherGet (cipherId) -> BlockSize; 
} 
 
int CipherGetKeySize (int cipherId) 
{ 
	return CipherGet (cipherId) -> KeySize; 
} 
 
int CipherGetKeyScheduleSize (int cipherId) 
{ 
	return CipherGet (cipherId) -> KeyScheduleSize; 
} 
 
 
// Encryption algorithms support 
 
int EAGetFirst () 
{ 
	return 1; 
} 
 
// Returns number of EAs 
int EAGetCount (void) 
{ 
	int ea, count = 0; 
 
	for (ea = EAGetFirst (); ea != 0; ea = EAGetNext (ea)) 
	{ 
		count++; 
	} 
	return count; 
} 
 
int EAGetNext (int previousEA) 
{ 
	int id = previousEA + 1; 
	if (EncryptionAlgorithms[id].Ciphers[0] != 0) return id; 
	return 0; 
} 
 
 
// Return values: 0 = success, ERR_CIPHER_INIT_FAILURE (fatal), ERR_CIPHER_INIT_WEAK_KEY (non-fatal) 
int EAInit (int ea, unsigned char *key, unsigned __int8 *ks) 
{ 
	int c, retVal = 0; 
 
	for (c = EAGetFirstCipher (ea); c != 0; c = EAGetNextCipher (ea, c)) 
	{ 
		switch (CipherInit (c, key, ks)) 
		{ 
		case ERR_CIPHER_INIT_FAILURE: 
			return ERR_CIPHER_INIT_FAILURE; 
 
		case ERR_CIPHER_INIT_WEAK_KEY: 
			retVal = ERR_CIPHER_INIT_WEAK_KEY;		// Non-fatal error 
			break; 
		} 
 
		key += CipherGetKeySize (c); 
		ks += CipherGetKeyScheduleSize (c); 
	} 
	return retVal; 
} 
 
 
int EAInitMode (PCRYPTO_INFO ci) 
{ 
	switch (ci->mode) 
	{ 
	case LRW: 
		switch (CipherGetBlockSize (EAGetFirstCipher (ci->ea))) 
		{ 
		case 8: 
			return Gf64TabInit (ci->iv, &ci->gf_ctx); 
 
		case 16: 
			return Gf128Tab64Init (ci->iv, &ci->gf_ctx); 
 
		default: 
			return FALSE; 
		} 
	} 
 
	return TRUE; 
} 
 
 
// Returns name of EA, cascaded cipher names are separated by hyphens 
char *EAGetName (char *buf, int ea) 
{ 
	int i = EAGetLastCipher(ea); 
	strcpy (buf, CipherGetName (i)); 
 
	while (i = EAGetPreviousCipher(ea, i)) 
	{ 
		strcat (buf, "-"); 
		strcat (buf, CipherGetName (i)); 
	} 
 
	return buf; 
} 
 
 
int EAGetByName (char *name) 
{ 
	int ea = EAGetFirst (); 
	char n[128]; 
 
	do 
	{ 
		EAGetName (n, ea); 
		if (strcmp (n, name) == 0) 
			return ea; 
	} 
	while (ea = EAGetNext (ea)); 
 
	return 0; 
} 
 
 
// Returns sum of key sizes of all EA ciphers 
int EAGetKeySize (int ea) 
{ 
	int i = EAGetFirstCipher (ea); 
	int size = CipherGetKeySize (i); 
 
	while (i = EAGetNextCipher (ea, i)) 
	{ 
		size += CipherGetKeySize (i); 
	} 
 
	return size; 
} 
 
 
// Returns the first mode of operation of EA 
int EAGetFirstMode (int ea) 
{ 
	return (EncryptionAlgorithms[ea].Modes[0]); 
} 
 
 
int EAGetNextMode (int ea, int previousModeId) 
{ 
	int c, i = 0; 
	while (c = EncryptionAlgorithms[ea].Modes[i++]) 
	{ 
		if (c == previousModeId)  
			return EncryptionAlgorithms[ea].Modes[i]; 
	} 
 
	return 0; 
} 
 
 
// Returns the name of the mode of operation of the whole EA 
char *EAGetModeName (int ea, int mode, BOOL capitalLetters) 
{ 
	switch (mode) 
	{ 
	case LRW: 
		return "LRW"; 
 
	case CBC: 
		{ 
			/* Deprecated/legacy */ 
 
			char eaName[100]; 
			EAGetName (eaName, ea); 
 
			if (strcmp (eaName, "Triple DES") == 0) 
				return capitalLetters ? "Outer-CBC" : "outer-CBC"; 
 
			return "CBC"; 
		} 
 
	case OUTER_CBC: 
 
		/* Deprecated/legacy */ 
 
		return  capitalLetters ? "Outer-CBC" : "outer-CBC"; 
 
	case INNER_CBC: 
 
		/* Deprecated/legacy */ 
 
		return capitalLetters ? "Inner-CBC" : "inner-CBC"; 
 
	} 
	return "[unknown]"; 
} 
 
 
// Returns sum of key schedule sizes of all EA ciphers 
int EAGetKeyScheduleSize (int ea) 
{ 
	int i = EAGetFirstCipher(ea); 
	int size = CipherGetKeyScheduleSize (i); 
 
	while (i = EAGetNextCipher(ea, i)) 
	{ 
		size += CipherGetKeyScheduleSize (i); 
	} 
 
	return size; 
} 
 
 
// Returns largest key needed by all EAs 
int EAGetLargestKey () 
{ 
	int ea, key = 0; 
 
	for (ea = EAGetFirst (); ea != 0 ; ea = EAGetNext (ea)) 
	{ 
		if (EAGetKeySize (ea) >= key) 
			key = EAGetKeySize (ea); 
	} 
 
	return key; 
} 
 
 
// Returns number of ciphers in EA 
int EAGetCipherCount (int ea) 
{ 
	int i = 0; 
	while (EncryptionAlgorithms[ea].Ciphers[i++]); 
 
	return i - 1; 
} 
 
 
int EAGetFirstCipher (int ea) 
{ 
	return EncryptionAlgorithms[ea].Ciphers[0]; 
} 
 
 
int EAGetLastCipher (int ea) 
{ 
	int c, i = 0; 
	while (c = EncryptionAlgorithms[ea].Ciphers[i++]); 
 
	return EncryptionAlgorithms[ea].Ciphers[i - 2]; 
} 
 
 
int EAGetNextCipher (int ea, int previousCipherId) 
{ 
	int c, i = 0; 
	while (c = EncryptionAlgorithms[ea].Ciphers[i++]) 
	{ 
		if (c == previousCipherId)  
			return EncryptionAlgorithms[ea].Ciphers[i]; 
	} 
 
	return 0; 
} 
 
 
int EAGetPreviousCipher (int ea, int previousCipherId) 
{ 
	int c, i = 0; 
 
	if (EncryptionAlgorithms[ea].Ciphers[i++] == previousCipherId) 
		return 0; 
 
	while (c = EncryptionAlgorithms[ea].Ciphers[i++]) 
	{ 
		if (c == previousCipherId)  
			return EncryptionAlgorithms[ea].Ciphers[i - 2]; 
	} 
 
	return 0; 
} 
 
 
Hash *HashGet (int id) 
{ 
	int i; 
	for (i = 0; Hashes[i].Id != 0; i++) 
		if (Hashes[i].Id == id) 
			return &Hashes[i]; 
 
	return 0; 
} 
 
 
int HashGetIdByName (char *name) 
{ 
	int i; 
	for (i = 0; Hashes[i].Id != 0; i++) 
		if (strcmp (Hashes[i].Name, name) == 0) 
			return Hashes[i].Id; 
 
	return 0; 
} 
 
 
char *HashGetName (int hashId) 
{ 
	return HashGet (hashId) -> Name; 
} 
 
 
PCRYPTO_INFO 
crypto_open () 
{ 
	/* Do the crt allocation */ 
	PCRYPTO_INFO cryptoInfo = (PCRYPTO_INFO) TCalloc (sizeof (CRYPTO_INFO)); 
	memset (cryptoInfo, 0, sizeof (CRYPTO_INFO)); 
 
#ifndef DEVICE_DRIVER 
#ifdef _WIN32 
	VirtualLock (cryptoInfo, sizeof (CRYPTO_INFO)); 
#endif 
#endif 
 
	if (cryptoInfo == NULL) 
		return NULL; 
 
	cryptoInfo->ea = -1; 
	return cryptoInfo; 
} 
 
void 
crypto_loadkey (PKEY_INFO keyInfo, char *lpszUserKey, int nUserKeyLen) 
{ 
	keyInfo->keyLength = nUserKeyLen; 
	burn (keyInfo->userKey, sizeof (keyInfo->userKey)); 
	memcpy (keyInfo->userKey, lpszUserKey, nUserKeyLen); 
} 
 
void 
crypto_close (PCRYPTO_INFO cryptoInfo) 
{ 
	if (cryptoInfo != NULL) 
	{ 
		burn (cryptoInfo, sizeof (CRYPTO_INFO)); 
#ifndef DEVICE_DRIVER 
#ifdef _WIN32 
		VirtualUnlock (cryptoInfo, sizeof (CRYPTO_INFO)); 
#endif 
#endif 
		TCfree (cryptoInfo); 
	} 
} 
 
 
// Detect weak and potentially weak secondary LRW keys. 
// Remark: These tests reduce the key search space by approximately 0.001% 
BOOL DetectWeakSecondaryKey (unsigned char *key, int len) 
{ 
#define LRW_MAX_SUCCESSIVE_IDENTICAL_BITS	24 
#define LRW_MIN_HAMMING_WEIGHT_16			39 
#define LRW_MIN_HAMMING_WEIGHT_8			15 
 
	int minWeight = (len == 16 ? LRW_MIN_HAMMING_WEIGHT_16 : LRW_MIN_HAMMING_WEIGHT_8); 
	int i, b, zero = 0, one = 0, zeroTotal = 0, oneTotal = 0; 
 
	for (i = 0; i < len; i++) 
	{ 
		for (b = 7; b >= 0; b--) 
		{ 
			if ((key[i] & (1 << b)) == 0) 
			{ 
				zeroTotal++; 
				zero++; 
				one = 0; 
			} 
			else 
			{ 
				oneTotal++; 
				one++; 
				zero = 0; 
			} 
 
			// Maximum number of consecutive identical bit values 
			if (one >= LRW_MAX_SUCCESSIVE_IDENTICAL_BITS || zero >= LRW_MAX_SUCCESSIVE_IDENTICAL_BITS) 
				return TRUE; 
		} 
	} 
 
	// Minimum and maximum Hamming weight 
	if (zeroTotal < minWeight || oneTotal < minWeight) 
		return TRUE; 
 
	return FALSE; 
} 
 
 
// Initializes IV and whitening values for sector encryption/decryption in CBC mode. 
// IMPORTANT: This function has been deprecated (legacy). 
static void  
InitSectorIVAndWhitening (unsigned __int64 secNo, 
	int blockSize, 
	unsigned __int32 *iv, 
	unsigned __int64 *ivSeed, 
	unsigned __int32 *whitening) 
{ 
 
	/* IMPORTANT: This function has been deprecated (legacy) */ 
 
	unsigned __int64 iv64[4]; 
	unsigned __int32 *iv32 = (unsigned __int32 *) iv64; 
 
	iv64[0] = ivSeed[0] ^ LE64(secNo); 
	iv64[1] = ivSeed[1] ^ LE64(secNo); 
	iv64[2] = ivSeed[2] ^ LE64(secNo); 
	if (blockSize == 16) 
	{ 
		iv64[3] = ivSeed[3] ^ LE64(secNo); 
	} 
 
	iv[0] = iv32[0]; 
	iv[1] = iv32[1]; 
 
	switch (blockSize) 
	{ 
	case 16: 
 
		// 128-bit block 
 
		iv[2] = iv32[2]; 
		iv[3] = iv32[3]; 
 
		whitening[0] = LE32( crc32int ( &iv32[4] ) ^ crc32int ( &iv32[7] ) ); 
		whitening[1] = LE32( crc32int ( &iv32[5] ) ^ crc32int ( &iv32[6] ) ); 
		break; 
 
	case 8: 
 
		// 64-bit block 
 
		whitening[0] = LE32( crc32int ( &iv32[2] ) ^ crc32int ( &iv32[5] ) ); 
		whitening[1] = LE32( crc32int ( &iv32[3] ) ^ crc32int ( &iv32[4] ) ); 
		break; 
	} 
} 
 
 
// EncryptBufferCBC    (deprecated/legacy) 
// 
// data:		data to be encrypted 
// len:			number of bytes to encrypt (must be divisible by the largest cipher block size) 
// ks:			scheduled key 
// iv:			IV 
// whitening:	whitening constants 
// ea:			outer-CBC cascade ID (0 = CBC/inner-CBC) 
// cipher:		CBC/inner-CBC cipher ID (0 = outer-CBC) 
 
static void 
EncryptBufferCBC (unsigned __int32 *data,  
		 unsigned int len, 
		 unsigned __int8 *ks, 
		 unsigned __int32 *iv, 
		 unsigned __int32 *whitening, 
		 int ea, 
		 int cipher) 
{ 
	/* IMPORTANT: This function has been deprecated (legacy) */ 
 
	unsigned __int32 bufIV[4]; 
	unsigned __int64 i; 
	int blockSize = CipherGetBlockSize (ea != 0 ? EAGetFirstCipher (ea) : cipher); 
 
	//  IV 
	bufIV[0] = iv[0]; 
	bufIV[1] = iv[1]; 
	if (blockSize == 16) 
	{ 
		bufIV[2] = iv[2]; 
		bufIV[3] = iv[3]; 
	} 
 
	// Encrypt each block 
	for (i = 0; i < len/blockSize; i++) 
	{ 
		// CBC 
		data[0] ^= bufIV[0]; 
		data[1] ^= bufIV[1]; 
		if (blockSize == 16) 
		{ 
			data[2] ^= bufIV[2]; 
			data[3] ^= bufIV[3]; 
		} 
 
		if (ea != 0) 
		{ 
			// Outer-CBC 
			for (cipher = EAGetFirstCipher (ea); cipher != 0; cipher = EAGetNextCipher (ea, cipher)) 
			{ 
				EncipherBlock (cipher, data, ks); 
				ks += CipherGetKeyScheduleSize (cipher); 
			} 
			ks -= EAGetKeyScheduleSize (ea); 
		} 
		else 
		{ 
			// CBC/inner-CBC 
			EncipherBlock (cipher, data, ks); 
		} 
 
		// CBC 
		bufIV[0] = data[0]; 
		bufIV[1] = data[1]; 
		if (blockSize == 16) 
		{ 
			bufIV[2] = data[2]; 
			bufIV[3] = data[3]; 
		} 
 
		// Whitening 
		data[0] ^= whitening[0]; 
		data[1] ^= whitening[1]; 
		if (blockSize == 16) 
		{ 
			data[2] ^= whitening[0]; 
			data[3] ^= whitening[1]; 
		} 
 
		data += blockSize / sizeof(*data); 
	} 
} 
 
 
// DecryptBufferCBC  (deprecated/legacy) 
// 
// data:		data to be decrypted 
// len:			number of bytes to decrypt (must be divisible by the largest cipher block size) 
// ks:			scheduled key 
// iv:			IV 
// whitening:	whitening constants 
// ea:			outer-CBC cascade ID (0 = CBC/inner-CBC) 
// cipher:		CBC/inner-CBC cipher ID (0 = outer-CBC) 
 
static void 
DecryptBufferCBC (unsigned __int32 *data, 
		 unsigned int len, 
		 unsigned __int8 *ks, 
		 unsigned __int32 *iv, 
 		 unsigned __int32 *whitening, 
		 int ea, 
		 int cipher) 
{ 
 
	/* IMPORTANT: This function has been deprecated (legacy) */ 
 
	unsigned __int32 bufIV[4]; 
	unsigned __int64 i; 
	unsigned __int32 ct[4]; 
	int blockSize = CipherGetBlockSize (ea != 0 ? EAGetFirstCipher (ea) : cipher); 
 
	//  IV 
	bufIV[0] = iv[0]; 
	bufIV[1] = iv[1]; 
	if (blockSize == 16) 
	{ 
		bufIV[2] = iv[2]; 
		bufIV[3] = iv[3]; 
	} 
 
	// Decrypt each block 
	for (i = 0; i < len/blockSize; i++) 
	{ 
		// Dewhitening 
		data[0] ^= whitening[0]; 
		data[1] ^= whitening[1]; 
		if (blockSize == 16) 
		{ 
			data[2] ^= whitening[0]; 
			data[3] ^= whitening[1]; 
		} 
 
		// CBC 
		ct[0] = data[0]; 
		ct[1] = data[1]; 
		if (blockSize == 16) 
		{ 
			ct[2] = data[2]; 
			ct[3] = data[3]; 
		} 
 
		if (ea != 0) 
		{ 
			// Outer-CBC 
			ks += EAGetKeyScheduleSize (ea); 
			for (cipher = EAGetLastCipher (ea); cipher != 0; cipher = EAGetPreviousCipher (ea, cipher)) 
			{ 
				ks -= CipherGetKeyScheduleSize (cipher); 
				DecipherBlock (cipher, data, ks); 
			} 
		} 
		else 
		{ 
			// CBC/inner-CBC 
			DecipherBlock (cipher, data, ks); 
		} 
 
		// CBC 
		data[0] ^= bufIV[0]; 
		data[1] ^= bufIV[1]; 
		bufIV[0] = ct[0]; 
		bufIV[1] = ct[1]; 
		if (blockSize == 16) 
		{ 
			data[2] ^= bufIV[2]; 
			data[3] ^= bufIV[3]; 
			bufIV[2] = ct[2]; 
			bufIV[3] = ct[3]; 
		} 
 
		data += blockSize / sizeof(*data); 
	} 
} 
 
 
void Xor128 (unsigned __int64 *a, unsigned __int64 *b) 
{ 
	*a++ ^= *b++; 
	*a ^= *b; 
} 
 
 
void Xor64 (unsigned __int64 *a, unsigned __int64 *b) 
{ 
	*a ^= *b; 
} 
 
 
void EncryptBufferLRW128 (unsigned __int8 *plainText, unsigned int length, unsigned __int64 blockIndex, PCRYPTO_INFO cryptoInfo) 
{ 
	int cipher = EAGetFirstCipher (cryptoInfo->ea); 
	int cipherCount = EAGetCipherCount (cryptoInfo->ea); 
	unsigned __int8 *p = plainText; 
	unsigned __int8 *ks = cryptoInfo->ks; 
	unsigned __int8 i[8]; 
	unsigned __int8 t[16]; 
	unsigned int b; 
 
	*(unsigned __int64 *)i = BE64(blockIndex); 
 
	// Note that the maximum supported volume size is 8589934592 GB  (i.e., 2^63 bytes). 
 
	for (b = 0; b < length >> 4; b++) 
	{ 
		Gf128MulBy64Tab (i, t, &cryptoInfo->gf_ctx); 
		Xor128 ((unsigned __int64 *)p, (unsigned __int64 *)t); 
 
		if (cipherCount > 1) 
		{ 
			// Cipher cascade 
			for (cipher = EAGetFirstCipher (cryptoInfo->ea); 
				cipher != 0; 
				cipher = EAGetNextCipher (cryptoInfo->ea, cipher)) 
			{ 
				EncipherBlock (cipher, p, ks); 
				ks += CipherGetKeyScheduleSize (cipher); 
			} 
			ks = cryptoInfo->ks; 
		} 
		else 
		{ 
			EncipherBlock (cipher, p, ks); 
		} 
 
		Xor128 ((unsigned __int64 *)p, (unsigned __int64 *)t); 
 
		p += 16; 
 
		if (i[7] != 0xff) 
			i[7]++; 
		else 
			*(unsigned __int64 *)i = BE64 ( BE64(*(unsigned __int64 *)i) + 1 ); 
	} 
 
	memset (t, 0, sizeof (t)); 
} 
 
 
void EncryptBufferLRW64 (unsigned __int8 *plainText, unsigned int length, unsigned __int64 blockIndex, PCRYPTO_INFO cryptoInfo) 
{ 
	int cipher = EAGetFirstCipher (cryptoInfo->ea); 
	unsigned __int8 *p = plainText; 
	unsigned __int8 *ks = cryptoInfo->ks; 
	unsigned __int8 i[8]; 
	unsigned __int8 t[8]; 
	unsigned int b; 
 
	*(unsigned __int64 *)i = BE64(blockIndex); 
 
	for (b = 0; b < length >> 3; b++) 
	{ 
		Gf64MulTab (i, t, &cryptoInfo->gf_ctx); 
		Xor64 ((unsigned __int64 *)p, (unsigned __int64 *)t); 
 
		EncipherBlock (cipher, p, ks); 
 
		Xor64 ((unsigned __int64 *)p, (unsigned __int64 *)t); 
 
		p += 8; 
 
		if (i[7] != 0xff) 
			i[7]++; 
		else 
			*(unsigned __int64 *)i = BE64 ( BE64(*(unsigned __int64 *)i) + 1 ); 
	} 
 
	memset (t, 0, sizeof (t)); 
} 
 
 
void DecryptBufferLRW128 (unsigned __int8 *plainText, int length, unsigned __int64 blockIndex, PCRYPTO_INFO cryptoInfo) 
{ 
	int cipher = EAGetFirstCipher (cryptoInfo->ea); 
	int cipherCount = EAGetCipherCount (cryptoInfo->ea); 
	unsigned __int8 *p = plainText; 
	unsigned __int8 *ks = cryptoInfo->ks; 
	unsigned __int8 i[8]; 
	unsigned __int8 t[16]; 
	int b; 
 
	*(unsigned __int64 *)i = BE64(blockIndex); 
 
	// Note that the maximum supported volume size is 8589934592 GB  (i.e., 2^63 bytes). 
 
	for (b = 0; b < length >> 4; b++) 
	{ 
		Gf128MulBy64Tab (i, t, &cryptoInfo->gf_ctx); 
		Xor128 ((unsigned __int64 *)p, (unsigned __int64 *)t); 
 
		if (cipherCount > 1) 
		{ 
			// Cipher cascade 
			ks = cryptoInfo->ks + EAGetKeyScheduleSize (cryptoInfo->ea); 
 
			for (cipher = EAGetLastCipher (cryptoInfo->ea); 
				cipher != 0; 
				cipher = EAGetPreviousCipher (cryptoInfo->ea, cipher)) 
			{ 
				ks -= CipherGetKeyScheduleSize (cipher); 
				DecipherBlock (cipher, p, ks); 
			} 
		} 
		else 
		{ 
			DecipherBlock (cipher, p, ks); 
		} 
 
		Xor128 ((unsigned __int64 *)p, (unsigned __int64 *)t); 
 
		p += 16; 
 
		if (i[7] != 0xff) 
			i[7]++; 
		else 
			*(unsigned __int64 *)i = BE64 ( BE64(*(unsigned __int64 *)i) + 1 ); 
	} 
 
	memset (t, 0, sizeof (t)); 
} 
 
 
 
void DecryptBufferLRW64 (unsigned __int8 *plainText, int length, unsigned __int64 blockIndex, PCRYPTO_INFO cryptoInfo) 
{ 
	int cipher = EAGetFirstCipher (cryptoInfo->ea); 
	unsigned __int8 *p = plainText; 
	unsigned __int8 *ks = cryptoInfo->ks; 
	unsigned __int8 i[8]; 
	unsigned __int8 t[8]; 
	int b; 
 
	*(unsigned __int64 *)i = BE64(blockIndex); 
 
	for (b = 0; b < length >> 3; b++) 
	{ 
		Gf64MulTab (i, t, &cryptoInfo->gf_ctx); 
		Xor64 ((unsigned __int64 *)p, (unsigned __int64 *)t); 
 
		DecipherBlock (cipher, p, ks); 
 
		Xor64 ((unsigned __int64 *)p, (unsigned __int64 *)t); 
 
		p += 8; 
 
		if (i[7] != 0xff) 
			i[7]++; 
		else 
			*(unsigned __int64 *)i = BE64 ( BE64(*(unsigned __int64 *)i) + 1 ); 
	} 
 
	memset (t, 0, sizeof (t)); 
} 
 
 
// EncryptBuffer 
// 
// buf:			data to be encrypted 
// len:			number of bytes to encrypt; must be divisible by the block size (for cascaded 
//              ciphers divisible by the largest block size used within the cascade) 
 
void  
EncryptBuffer (unsigned __int32 *buf, 
			   unsigned __int64 len, 
			   PCRYPTO_INFO cryptoInfo) 
{ 
 
	switch (cryptoInfo->mode) 
	{ 
	case LRW: 
		switch (CipherGetBlockSize (EAGetFirstCipher (cryptoInfo->ea))) 
		{ 
		case 8: 
			EncryptBufferLRW64 ((unsigned __int8 *)buf, (unsigned int) len, 1, cryptoInfo); 
			break; 
 
		case 16: 
			EncryptBufferLRW128 ((unsigned __int8 *)buf, (unsigned int) len, 1, cryptoInfo); 
			break; 
		} 
		break; 
 
	case CBC: 
	case INNER_CBC: 
		{ 
			/* Deprecated/legacy */ 
 
			unsigned __int8 *ks = cryptoInfo->ks; 
			int cipher; 
			for (cipher = EAGetFirstCipher (cryptoInfo->ea); 
				cipher != 0; 
				cipher = EAGetNextCipher (cryptoInfo->ea, cipher)) 
			{ 
				EncryptBufferCBC (buf, 
					(unsigned int) len, 
					ks, 
					(unsigned __int32 *) cryptoInfo->iv, 
					(unsigned __int32 *) &cryptoInfo->iv[8], 
					0, 
					cipher); 
 
				ks += CipherGetKeyScheduleSize (cipher); 
			} 
		} 
		break; 
 
	case OUTER_CBC: 
 
		/* Deprecated/legacy */ 
 
		EncryptBufferCBC (buf, 
			(unsigned int) len, 
			cryptoInfo->ks, 
			(unsigned __int32 *) cryptoInfo->iv, 
			(unsigned __int32 *) &cryptoInfo->iv[8], 
			cryptoInfo->ea, 
			0); 
 
		break; 
	} 
} 
 
// Convert sector number to the index of the first LRW block in the sector. 
// Note that the maximum supported volume size is 8589934592 GB  (i.e., 2^63 bytes). 
unsigned __int64 LRWSector2Index (unsigned __int64 sector, int blockSize, PCRYPTO_INFO ci) 
{ 
	if (ci->hiddenVolume) 
		sector -= ci->hiddenVolumeOffset / SECTOR_SIZE; 
	else 
		sector -= HEADER_SIZE / SECTOR_SIZE;	// Compensate for the volume header size 
 
	switch (blockSize) 
	{ 
	case 8: 
		return (sector << 6) | 1; 
 
	case 16: 
		return (sector << 5) | 1; 
	} 
 
	return 0; 
} 
 
 
// EncryptSectors 
// 
// buf:			data to be encrypted 
// secNo:		sector number relative to volume start 
// noSectors:	number of sectors in buffer 
// ks:			scheduled key 
// iv:			IV 
// ea:			encryption algorithm 
 
void _cdecl  
EncryptSectors (unsigned __int32 *buf, 
		unsigned __int64 secNo, 
		unsigned __int64 noSectors, 
		PCRYPTO_INFO ci) 
{ 
	int ea = ci->ea; 
	void *iv = ci->iv;					// Deprecated/legacy 
	unsigned __int8 *ks = ci->ks; 
	unsigned __int64 *iv64 = (unsigned __int64 *) iv;	// Deprecated/legacy 
	unsigned __int32 sectorIV[4];		// Deprecated/legacy 
	unsigned __int32 secWhitening[2];	// Deprecated/legacy 
	int cipher; 
 
	switch (ci->mode) 
	{ 
	case LRW: 
		{ 
			switch (CipherGetBlockSize (EAGetFirstCipher (ea))) 
			{ 
			case 8: 
				EncryptBufferLRW64 ((unsigned __int8 *)buf, 
					(unsigned int) noSectors * SECTOR_SIZE, 
					LRWSector2Index (secNo, 8, ci), 
					ci); 
				break; 
 
			case 16: 
				EncryptBufferLRW128 ((unsigned __int8 *)buf, 
					(unsigned int) noSectors * SECTOR_SIZE, 
					LRWSector2Index (secNo, 16, ci), 
					ci); 
				break; 
			} 
		} 
		break; 
 
	case CBC: 
	case INNER_CBC: 
 
		/* Deprecated/legacy */ 
 
		while (noSectors--) 
		{ 
			for (cipher = EAGetFirstCipher (ea); cipher != 0; cipher = EAGetNextCipher (ea, cipher)) 
			{ 
				InitSectorIVAndWhitening (secNo, CipherGetBlockSize (cipher), sectorIV, iv64, secWhitening); 
 
				EncryptBufferCBC (buf, 
					SECTOR_SIZE, 
					ks, 
					sectorIV, 
					secWhitening, 
					0, 
					cipher); 
 
				ks += CipherGetKeyScheduleSize (cipher); 
			} 
			ks -= EAGetKeyScheduleSize (ea); 
			buf += SECTOR_SIZE / sizeof(*buf); 
			secNo++; 
		} 
		break; 
 
	case OUTER_CBC: 
 
		/* Deprecated/legacy */ 
 
		while (noSectors--) 
		{ 
			InitSectorIVAndWhitening (secNo, CipherGetBlockSize (EAGetFirstCipher (ea)), sectorIV, iv64, secWhitening); 
 
			EncryptBufferCBC (buf, 
				SECTOR_SIZE, 
				ks, 
				sectorIV, 
				secWhitening, 
				ea, 
				0); 
 
			buf += SECTOR_SIZE / sizeof(*buf); 
			secNo++; 
		} 
		break; 
	} 
} 
 
// DecryptBuffer 
// 
// buf:			data to be decrypted 
// len:			number of bytes to decrypt; must be divisible by the block size (for cascaded 
//              ciphers divisible by the largest block size used within the cascade) 
void  
DecryptBuffer (unsigned __int32 *buf, 
		unsigned __int64 len, 
		PCRYPTO_INFO cryptoInfo) 
{ 
	switch (cryptoInfo->mode) 
	{ 
	case LRW: 
		switch (CipherGetBlockSize (EAGetFirstCipher (cryptoInfo->ea))) 
		{ 
		case 8: 
			DecryptBufferLRW64 ((unsigned __int8 *)buf, (unsigned int) len, 1, cryptoInfo); 
			break; 
 
		case 16: 
			DecryptBufferLRW128 ((unsigned __int8 *)buf, (unsigned int) len, 1, cryptoInfo); 
			break; 
		} 
		break; 
 
	case CBC: 
	case INNER_CBC: 
		{ 
 
			/* Deprecated/legacy */ 
 
			unsigned __int8 *ks = cryptoInfo->ks + EAGetKeyScheduleSize (cryptoInfo->ea); 
			int cipher; 
			for (cipher = EAGetLastCipher (cryptoInfo->ea); 
				cipher != 0; 
				cipher = EAGetPreviousCipher (cryptoInfo->ea, cipher)) 
			{ 
				ks -= CipherGetKeyScheduleSize (cipher); 
 
				DecryptBufferCBC (buf, 
					(unsigned int) len, 
					ks, 
					(unsigned __int32 *) cryptoInfo->iv, 
					(unsigned __int32 *) &cryptoInfo->iv[8], 
					0, 
					cipher); 
			} 
		} 
		break; 
 
	case OUTER_CBC: 
 
		/* Deprecated/legacy */ 
 
		DecryptBufferCBC (buf, 
			(unsigned int) len, 
			cryptoInfo->ks, 
			(unsigned __int32 *) cryptoInfo->iv, 
			(unsigned __int32 *) &cryptoInfo->iv[8], 
			cryptoInfo->ea, 
			0); 
 
		break; 
	} 
} 
 
// DecryptSectors 
// 
// buf:			data to be decrypted 
// secNo:		sector number relative to volume start 
// noSectors:	number of sectors in buffer 
// ks:			scheduled key 
// iv:			IV 
// ea:			encryption algorithm 
 
void _cdecl  
DecryptSectors (unsigned __int32 *buf, 
		unsigned __int64 secNo, 
		unsigned __int64 noSectors, 
		PCRYPTO_INFO ci 
) 
{ 
	int ea = ci->ea; 
	void *iv = ci->iv;						// Deprecated/legacy 
	unsigned __int8 *ks = ci->ks; 
	unsigned __int64 *iv64 = (unsigned __int64 *) iv;	// Deprecated/legacy 
	unsigned __int32 sectorIV[4];			// Deprecated/legacy 
	unsigned __int32 secWhitening[2];		// Deprecated/legacy 
	int cipher; 
 
	switch (ci->mode) 
	{ 
	case LRW: 
		{ 
			switch (CipherGetBlockSize (EAGetFirstCipher (ea))) 
			{ 
			case 8: 
				DecryptBufferLRW64 ((unsigned __int8 *)buf, 
					(unsigned int) noSectors * SECTOR_SIZE, 
					LRWSector2Index (secNo, 8, ci), 
					ci); 
				break; 
 
			case 16: 
				DecryptBufferLRW128 ((unsigned __int8 *)buf, 
					(unsigned int) noSectors * SECTOR_SIZE, 
					LRWSector2Index (secNo, 16, ci), 
					ci); 
				break; 
			} 
		} 
		break; 
 
	case CBC: 
	case INNER_CBC: 
 
		/* Deprecated/legacy */ 
 
		while (noSectors--) 
		{ 
			ks += EAGetKeyScheduleSize (ea); 
			for (cipher = EAGetLastCipher (ea); cipher != 0; cipher = EAGetPreviousCipher (ea, cipher)) 
			{ 
				InitSectorIVAndWhitening (secNo, CipherGetBlockSize (cipher), sectorIV, iv64, secWhitening); 
 
				ks -= CipherGetKeyScheduleSize (cipher); 
 
				DecryptBufferCBC (buf, 
					SECTOR_SIZE, 
					ks, 
					sectorIV, 
					secWhitening, 
					0, 
					cipher); 
			} 
			buf += SECTOR_SIZE / sizeof(*buf); 
			secNo++; 
		} 
		break; 
 
	case OUTER_CBC: 
 
		/* Deprecated/legacy */ 
 
		while (noSectors--) 
		{ 
			InitSectorIVAndWhitening (secNo, CipherGetBlockSize (EAGetFirstCipher (ea)), sectorIV, iv64, secWhitening); 
 
			DecryptBufferCBC (buf, 
				SECTOR_SIZE, 
				ks, 
				sectorIV, 
				secWhitening, 
				ea, 
				0); 
 
			buf += SECTOR_SIZE / sizeof(*buf); 
			secNo++; 
		} 
		break; 
	} 
}