--- truecrypt/common/crypto.c 2018/04/24 16:40:48 1.1.1.4 +++ truecrypt/common/crypto.c 2018/04/24 16:41:28 1.1.1.5 @@ -1,13 +1,366 @@ /* The source code contained in this file has been derived from the source code of Encryption for the Masses 2.02a by Paul Le Roux. Modifications and additions to that source code contained in this file are Copyright (c) 2004 - TrueCrypt Team and Copyright (c) 2004 TrueCrypt Foundation. Unmodified + TrueCrypt Foundation and Copyright (c) 2004 TrueCrypt Team. Unmodified parts are Copyright (c) 1998-99 Paul Le Roux. This is a TrueCrypt Foundation release. Please see the file license.txt for full license details. */ #include "TCdefs.h" #include "crypto.h" #include "random.h" +#include "crc.h" + +/* 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[] = +{ +// ID Name Block size Key size Key schedule size + { 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, 7*3, 128*3 }, + { TWOFISH, "Twofish", 16, 32, TWOFISH_KS }, + { 0, 0, 0, 0, 0 } +}; + +// Encryption algorithm configuration +static EncryptionAlgorithm EncryptionAlgorithms[] = +{ + // Cipher(s) Mode + { { 0, 0 } , 0 }, // (must be null) + { { AES, 0 } , CBC }, // AES + { { BLOWFISH, 0 } , CBC }, // Blowfish + { { CAST, 0 } , CBC }, // CAST5 + { { SERPENT, 0 } , CBC }, // Serpent + { { TRIPLEDES, 0 } , CBC }, // Triple DES + { { TWOFISH, 0 } , CBC }, // Twofish + { { BLOWFISH, AES, 0 } , INNER_CBC }, // AES-Blowfish + { { SERPENT, BLOWFISH, AES, 0 } , INNER_CBC }, // AES-Blowfish-Serpent + { { TWOFISH, AES, 0 } , OUTER_CBC }, // AES-Twofish + { { SERPENT, TWOFISH, AES, 0 } , OUTER_CBC }, // AES-Twofish-Serpent + { { AES, SERPENT, 0 } , OUTER_CBC }, // Serpent-AES + { { AES, TWOFISH, SERPENT, 0 } , OUTER_CBC }, // Serpent-Twofish-AES + { { SERPENT, TWOFISH, 0 } , OUTER_CBC }, // Twofish-Serpent + { { 0, 0 } , 0 } // (must be null) +}; + + +void CipherInit (int cipher, unsigned char *key, unsigned char *ks) +{ + switch (cipher) + { + case BLOWFISH: + BF_set_key ((BF_KEY *)ks, CipherGetKeySize(BLOWFISH), key); + break; + + case AES: + aes_encrypt_key(key, CipherGetKeySize(AES), (aes_encrypt_ctx *) ks); + aes_decrypt_key(key, CipherGetKeySize(AES), (aes_decrypt_ctx *) (ks + sizeof(aes_encrypt_ctx))); + break; + + case DES56: + des_key_sched ((des_cblock *) key, (struct des_ks_struct *) ks); + 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: + des_key_sched ((des_cblock *) key, (struct des_ks_struct *) ks); + des_key_sched ((des_cblock *) ((char*)(key)+8), (struct des_ks_struct *) (ks + CipherGetKeyScheduleSize (DES56))); + des_key_sched ((des_cblock *) ((char*)(key)+16), (struct des_ks_struct *) (ks + CipherGetKeyScheduleSize (DES56) * 2)); + break; + + case TWOFISH: + twofish_set_key ((TwofishInstance *)ks, (const u4byte *)key, CipherGetKeySize(TWOFISH) * 8); + break; + + } +} + +void EncipherBlock(int cipher, void *data, void *ks) +{ + switch (cipher) + { + case BLOWFISH: BF_encrypt (data, ks); 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_decrypt (data, ks); 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; +} + +void EAInit (int ea, unsigned char *key, unsigned char *ks) +{ + int i = 0, c; + + for (c = EAGetFirstCipher (ea); c != 0; c = EAGetNextCipher (ea, c)) + { + CipherInit (c, key, ks); + + key += CipherGetKeySize (c); + ks += CipherGetKeyScheduleSize (c); + } +} + +// 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; +} + +// 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 mode of operation of the whole EA +int EAGetMode (int ea) +{ + return (EncryptionAlgorithms[ea].Mode); +} + +// Returns the name of the mode of operation of the whole EA +char *EAGetModeName (char *name, int ea, BOOL capitalLetters) +{ + char eaName[100]; + + switch (EncryptionAlgorithms[ea].Mode) + { + case CBC: + EAGetName (eaName, ea); + + if (strcmp (eaName, "Triple DES") == 0) + sprintf (name, "%s", capitalLetters ? "Outer-CBC" : "outer-CBC"); + else + sprintf (name, "%s", "CBC"); + + break; + + case OUTER_CBC: + strcpy (name, capitalLetters ? "Outer-CBC" : "outer-CBC"); + break; + + case INNER_CBC: + strcpy (name, capitalLetters ? "Inner-CBC" : "inner-CBC"); + break; + + default: + strcpy (name, "[unknown]"); + break; + } + return name; +} + +// 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 support functions + +char * get_hash_name (int pkcs5) +{ + switch (pkcs5) + { + case SHA1: return "HMAC-SHA-1"; + case RIPEMD160: return "HMAC-RIPEMD-160"; + default: return "Unknown"; + } +} + + PCRYPTO_INFO crypto_open () @@ -21,7 +374,7 @@ crypto_open () if (cryptoInfo == NULL) return NULL; - cryptoInfo->cipher = -1; + cryptoInfo->ea = -1; return cryptoInfo; } @@ -43,59 +396,470 @@ crypto_close (PCRYPTO_INFO cryptoInfo) TCfree (cryptoInfo); } -int -get_block_size (int cipher) + +// Initializes IV and whitening values for sector encryption/decryption +static void +InitSectorIVAndWhitening (unsigned __int64 secNo, + int blockSize, + unsigned long *iv, + unsigned __int64 *ivSeed, + unsigned long *whitening) { - if (cipher == AES) - return 16; - else - return 8; -} - -int -get_key_size (int cipher) -{ - if (cipher == DES56) - return 7; - else if (cipher == BLOWFISH) - return 56; - else if (cipher == AES) - return 32; - else if (cipher == TRIPLEDES) - return 21; - else if (cipher == CAST) - return 16; - else + unsigned __int64 iv64[4]; + unsigned long *iv32 = (unsigned long *) iv64; + + iv64[0] = ivSeed[0] ^ secNo; + iv64[1] = ivSeed[1] ^ secNo; + iv64[2] = ivSeed[2] ^ secNo; + if (blockSize == 16) { - return 0; + iv64[3] = ivSeed[3] ^ 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] = crc32long ( &iv32[4] ) ^ crc32long ( &iv32[7] ); + whitening[1] = crc32long ( &iv32[5] ) ^ crc32long ( &iv32[6] ); + break; + + case 8: + + // 64-bit block + + whitening[0] = crc32long ( &iv32[2] ) ^ crc32long ( &iv32[5] ); + whitening[1] = crc32long ( &iv32[3] ) ^ crc32long ( &iv32[4] ); + break; } } -char * -get_cipher_name (int cipher) + +// EncryptBufferCBC +// +// 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 long *data, + unsigned __int64 len, + unsigned char *ks, + unsigned long *iv, + unsigned long *whitening, + int ea, + int cipher) { - if (cipher == BLOWFISH) - return "Blowfish"; - if (cipher == AES) - return "AES"; - else if (cipher == DES56) - return "DES"; - else if (cipher == TRIPLEDES) - return "Triple-DES"; - else if (cipher == CAST) - return "CAST"; - else if (cipher == NONE) - return "None"; - else - return "Unknown"; + unsigned long 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); + } } -char * get_hash_name (int pkcs5) + +// DecryptBufferCBC +// +// 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 long *data, + unsigned __int64 len, + unsigned char *ks, + unsigned long *iv, + unsigned long *whitening, + int ea, + int cipher) { - switch (pkcs5) + unsigned long bufIV[4]; + unsigned __int64 i; + unsigned long ct[4]; + int blockSize = CipherGetBlockSize (ea != 0 ? EAGetFirstCipher (ea) : cipher); + + // IV + bufIV[0] = iv[0]; + bufIV[1] = iv[1]; + if (blockSize == 16) { - case SHA1: return "HMAC-SHA-1"; - case RIPEMD160: return "HMAC-RIPEMD-160"; - default: return "Unknown"; + 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); } } + + +// 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) +// ks: scheduled key +// iv: IV +// whitening: whitening constants +// ea: encryption algorithm + +void +EncryptBuffer (unsigned long *buf, + unsigned __int64 len, + unsigned char *ks, + void *iv, + void *whitening, + int ea) +{ + unsigned __int64 *iv64 = (unsigned __int64 *) iv; + int cipher; + + switch (EAGetMode(ea)) + { + case CBC: + case INNER_CBC: + + for (cipher = EAGetFirstCipher (ea); cipher != 0; cipher = EAGetNextCipher (ea, cipher)) + { + EncryptBufferCBC (buf, + len, + ks, + (unsigned long *) iv, + (unsigned long *) whitening, + 0, + cipher); + + ks += CipherGetKeyScheduleSize (cipher); + } + + break; + + case OUTER_CBC: + + EncryptBufferCBC (buf, + len, + ks, + (unsigned long *) iv, + (unsigned long *) whitening, + ea, + 0); + + break; + } +} + +// 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 long *buf, + unsigned __int64 secNo, + unsigned __int64 noSectors, + unsigned char *ks, + void *iv, + int ea) +{ + unsigned __int64 *iv64 = (unsigned __int64 *) iv; + unsigned long sectorIV[4]; + unsigned long secWhitening[2]; + int cipher; + + switch (EAGetMode(ea)) + { + case CBC: + case INNER_CBC: + + 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: + + 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) +// ks: scheduled key +// iv: IV +// whitening: whitening constants +// ea: encryption algorithm +void +DecryptBuffer (unsigned long *buf, + unsigned __int64 len, + unsigned char *ks, + void *iv, + void *whitening, + int ea) +{ + unsigned __int64 *iv64 = (unsigned __int64 *) iv; + int cipher; + + switch (EAGetMode(ea)) + { + case CBC: + case INNER_CBC: + + ks += EAGetKeyScheduleSize (ea); + for (cipher = EAGetLastCipher (ea); cipher != 0; cipher = EAGetPreviousCipher (ea, cipher)) + { + ks -= CipherGetKeyScheduleSize (cipher); + + DecryptBufferCBC (buf, + len, + ks, + (unsigned long *) iv, + (unsigned long *) whitening, + 0, + cipher); + } + break; + + case OUTER_CBC: + + DecryptBufferCBC (buf, + len, + ks, + (unsigned long *) iv, + (unsigned long *) whitening, + 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 long *buf, + unsigned __int64 secNo, + unsigned __int64 noSectors, + unsigned char *ks, + void *iv, + int ea) +{ + unsigned __int64 *iv64 = (unsigned __int64 *) iv; + unsigned long sectorIV[4]; + unsigned long secWhitening[2]; + int cipher; + + switch (EAGetMode(ea)) + { + case CBC: + case INNER_CBC: + + 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: + + 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; + } +} +