MDS v2 structures and decode/crypto utilities from Marisa-Chan's repository in preparation for MDS v2/MDX support implementation.

This commit is contained in:
OBattler
2026-01-18 03:56:57 +01:00
parent 605a1443de
commit 51effd0453
67 changed files with 21470 additions and 8 deletions

133
src/utils/common/crc.c Normal file
View File

@@ -0,0 +1,133 @@
/*
Legal Notice: Some portions of the source code contained in this file were
derived from the source code of Encryption for the Masses 2.02a, which is
Copyright (c) 1998-2000 Paul Le Roux and which is governed by the 'License
Agreement for Encryption for the Masses'. Modifications and additions to
the original source code (contained in this file) and all other portions of
this file are Copyright (c) 2003-2008 TrueCrypt Foundation and are governed
by the TrueCrypt License 2.4 the full text of which is contained in the
file License.txt included in TrueCrypt binary and source code distribution
packages. */
#include "tcdefs.h"
#include "crc.h"
#include "../common/endian.h"
#ifndef TC_MINIMIZE_CODE_SIZE
/* CRC polynomial 0x04c11db7 */
uint32_t crc_32_tab[]=
{
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
};
uint32_t GetCrc32 (unsigned char *data, int length)
{
uint32_t CRC = 0xffffffff;
while (length--)
{
CRC = (CRC >> 8) ^ crc_32_tab[ (CRC ^ *data++) & 0xFF ];
}
return CRC ^ 0xffffffff;
}
uint32_t crc32int (uint32_t *data)
{
unsigned char *d = (unsigned char *) data;
uint32_t CRC = 0xffffffff;
CRC = (CRC >> 8) ^ crc_32_tab[ (CRC ^ *d++) & 0xFF ];
CRC = (CRC >> 8) ^ crc_32_tab[ (CRC ^ *d++) & 0xFF ];
CRC = (CRC >> 8) ^ crc_32_tab[ (CRC ^ *d++) & 0xFF ];
return (CRC >> 8) ^ crc_32_tab[ (CRC ^ *d) & 0xFF ] ^ 0xffffffff;
}
#if BYTE_ORDER == LITTLE_ENDIAN
# define CRC_SELFTEST 0x6fcf9e13
#else
# define CRC_SELFTEST 0xca87914d
#endif
int crc32_selftests (void)
{
int i;
uint32_t crc = 0xffffffff;
int bSuccess = 0;
for (i = 0; i < (int)sizeof(crc_32_tab); i++)
crc = UPDC32 (((unsigned char *) crc_32_tab)[i], crc);
bSuccess = CRC_SELFTEST == (crc ^ 0xffffffff);
bSuccess &= GetCrc32 ((unsigned char *)crc_32_tab, sizeof crc_32_tab) == CRC_SELFTEST;
return bSuccess;
}
#else // TC_MINIMIZE_CODE_SIZE
uint32_t GetCrc32 (unsigned char *data, int length)
{
uint32_t r = 0xFFFFFFFFUL;
int i, b;
for (i = 0; i < length; ++i)
{
r ^= data[i];
for (b = 0; b < 8; ++b)
{
if ((unsigned __int8) r & 1)
r = (r >> 1) ^ 0xEDB88320UL;
else
r >>= 1;
}
}
return r ^ 0xFFFFFFFFUL;
}
int crc32_selftests ()
{
unsigned __int8 testData[32];
unsigned __int8 i;
for (i = 0; i < sizeof (testData); ++i)
testData[i] = i;
return GetCrc32 (testData, sizeof (testData)) == 0x91267E8AUL;
}
#endif // TC_MINIMIZE_CODE_SIZE

37
src/utils/common/crc.h Normal file
View File

@@ -0,0 +1,37 @@
/*
Legal Notice: Some portions of the source code contained in this file were
derived from the source code of Encryption for the Masses 2.02a, which is
Copyright (c) 1998-2000 Paul Le Roux and which is governed by the 'License
Agreement for Encryption for the Masses'. Modifications and additions to
the original source code (contained in this file) and all other portions of
this file are Copyright (c) 2003-2008 TrueCrypt Foundation and are governed
by the TrueCrypt License 2.4 the full text of which is contained in the
file License.txt included in TrueCrypt binary and source code distribution
packages. */
#ifndef TC_HEADER_CRC
#define TC_HEADER_CRC
#include <inttypes.h>
#include "tcdefs.h"
#if defined(__cplusplus)
extern "C"
{
#endif
#define UPDC32(octet, crc)\
(uint32_t)((crc_32_tab[(((uint32_t)(crc)) ^ ((unsigned char)(octet))) & 0xff] ^ (((uint32_t)(crc)) >> 8)))
uint32_t GetCrc32 (unsigned char *data, int length);
uint32_t crc32int (uint32_t *data);
int crc32_selftests (void);
extern uint32_t crc_32_tab[];
#if defined(__cplusplus)
}
#endif
#endif // TC_HEADER_CRC

1653
src/utils/common/crypto.c Normal file

File diff suppressed because it is too large Load Diff

304
src/utils/common/crypto.h Normal file
View File

@@ -0,0 +1,304 @@
/*
Legal Notice: Some portions of the source code contained in this file were
derived from the source code of Encryption for the Masses 2.02a, which is
Copyright (c) 1998-2000 Paul Le Roux and which is governed by the 'License
Agreement for Encryption for the Masses'. Modifications and additions to
the original source code (contained in this file) and all other portions of
this file are Copyright (c) 2003-2008 TrueCrypt Foundation and are governed
by the TrueCrypt License 2.4 the full text of which is contained in the
file License.txt included in TrueCrypt binary and source code distribution
packages. */
/* 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()
*/
#ifndef CRYPTO_H
#define CRYPTO_H
#include <inttypes.h>
#include "tcdefs.h"
#ifdef __cplusplus
extern "C" {
#endif
// Encryption data unit size, which may differ from the sector size and must always be 512
#define ENCRYPTION_DATA_UNIT_SIZE 512
// Size of the salt (in bytes)
#define PKCS5_SALT_SIZE 64
// Size of the volume header area containing concatenated master key(s) and secondary key(s) (XTS mode)
#define MASTER_KEYDATA_SIZE 256
// Size of the deprecated volume header item containing either an IV seed (CBC mode) or tweak key (LRW mode)
#define LEGACY_VOL_IV_SIZE 32
// Volume header byte offsets
#define HEADER_SALT_OFFSET 0
#define HEADER_ENCRYPTED_DATA_OFFSET PKCS5_SALT_SIZE
#define HEADER_MASTER_KEYDATA_OFFSET 256
// Volume header sizes
#define HEADER_SIZE 512
#define HEADER_ENCRYPTED_DATA_SIZE (HEADER_SIZE - HEADER_ENCRYPTED_DATA_OFFSET)
/* The offset, in bytes, of the hidden volume header position from the end of the file (a positive value).
The extra offset (SECTOR_SIZE * 2) was added because FAT file system fills the last sector with zeroes
(marked as free; observed when quick format was performed using the OS format tool). One extra sector was
added to the offset for future expandability (should the header size increase, or should header backup be
introduced). */
#define HIDDEN_VOL_HEADER_OFFSET (HEADER_SIZE + SECTOR_SIZE * 2)
// The first PRF to try when mounting
#define FIRST_PRF_ID 1
// Hash algorithms (pseudorandom functions).
enum
{
RIPEMD160 = FIRST_PRF_ID,
SHA1,
WHIRLPOOL,
SHA512,
HASH_ENUM_END_ID
};
// The last PRF to try when mounting and also the number of implemented PRFs
#define LAST_PRF_ID (HASH_ENUM_END_ID - 1)
#define RIPEMD160_BLOCKSIZE 64
#define RIPEMD160_DIGESTSIZE 20
#define SHA1_BLOCKSIZE 64
#define SHA1_DIGESTSIZE 20
#define SHA512_BLOCKSIZE 128
#define SHA512_DIGESTSIZE 64
#define WHIRLPOOL_BLOCKSIZE 64
#define WHIRLPOOL_DIGESTSIZE 64
#define MAX_DIGESTSIZE WHIRLPOOL_DIGESTSIZE
#define DEFAULT_HASH_ALGORITHM FIRST_PRF_ID
#define DEFAULT_HASH_ALGORITHM_BOOT RIPEMD160
// The mode of operation used for newly created volumes and first to try when mounting
#define FIRST_MODE_OF_OPERATION_ID 1
// Modes of operation
enum
{
/* If you add/remove a mode, update the following: GetMaxPkcs5OutSize(), EAInitMode() */
XTS = FIRST_MODE_OF_OPERATION_ID,
LRW, // Deprecated/legacy
CBC, // Deprecated/legacy
OUTER_CBC, // Deprecated/legacy
INNER_CBC, // Deprecated/legacy
MODE_ENUM_END_ID
};
// The last mode of operation to try when mounting and also the number of implemented modes
#define LAST_MODE_OF_OPERATION (MODE_ENUM_END_ID - 1)
// Ciphertext/plaintext block size for XTS mode (in bytes)
#define BYTES_PER_XTS_BLOCK 16
// Number of ciphertext/plaintext blocks per XTS data unit
#define BLOCKS_PER_XTS_DATA_UNIT (ENCRYPTION_DATA_UNIT_SIZE / BYTES_PER_XTS_BLOCK)
// Cipher IDs
enum
{
NONE = 0,
AES256,
AES192,
AES128,
BLOWFISH, // Deprecated/legacy
CAST, // Deprecated/legacy
SERPENT,
TRIPLEDES, // Deprecated/legacy
TWOFISH,
DES56 // Deprecated/legacy (used only by Triple DES)
};
typedef struct
{
int Id; // Cipher ID
char *Name; // Name
int BlockSize; // Block size (bytes)
int KeySize; // Key size (bytes)
int KeyScheduleSize; // Scheduled key size (bytes)
} Cipher;
typedef struct
{
int Ciphers[4]; // Null terminated array of ciphers used by encryption algorithm
int Modes[LAST_MODE_OF_OPERATION + 1]; // Null terminated array of modes of operation
int FormatEnabled;
} EncryptionAlgorithm;
typedef struct
{
int Id; // Hash ID
char *Name; // Name
int Deprecated;
int SystemEncryption; // Available for system encryption
} Hash;
// Maxium length of scheduled key
#define AES_KS (sizeof(aes_encrypt_ctx) + sizeof(aes_decrypt_ctx))
#define SERPENT_KS (140 * 4)
#define MAX_EXPANDED_KEY (AES_KS + SERPENT_KS + TWOFISH_KS)
#define PRAND_DISK_WIPE_PASSES 200
#if !defined (TC_WINDOWS_BOOT) || defined (TC_WINDOWS_BOOT_AES)
# include "../crypto/aes.h"
#else
# include "../crypto/aesSmall.h"
#endif
#include "../crypto/blowfish.h"
#include "../crypto/cast.h"
#include "../crypto/des.h"
#include "../crypto/serpent.h"
#include "../crypto/twofish.h"
#include "../crypto/rmd160.h"
# include "../crypto/sha1.h"
# include "../crypto/sha2.h"
# include "../crypto/whirlpool.h"
#include "gfmul.h"
#include "password.h"
typedef struct keyInfo_t
{
int noIterations; /* Number of times to iterate (PKCS-5) */
int keyLength; /* Length of the key */
int8_t userKey[MAX_PASSWORD]; /* Password (to which keyfiles may have been applied). WITHOUT +1 for the null terminator. */
int8_t salt[PKCS5_SALT_SIZE]; /* PKCS-5 salt */
int8_t master_keydata[MASTER_KEYDATA_SIZE]; /* Concatenated master primary and secondary key(s) (XTS mode). For LRW (deprecated/legacy), it contains the tweak key before the master key(s). For CBC (deprecated/legacy), it contains the IV seed before the master key(s). */
} KEY_INFO, *PKEY_INFO;
typedef struct CRYPTO_INFO_t
{
int ea; /* Encryption algorithm ID */
int mode; /* Mode of operation (e.g., XTS) */
uint8_t ks[MAX_EXPANDED_KEY]; /* Primary key schedule (if it is a cascade, it conatins multiple concatenated keys) */
uint8_t ks2[MAX_EXPANDED_KEY]; /* Secondary key schedule (if cascade, multiple concatenated) for XTS mode. */
GfCtx gf_ctx;
uint8_t master_keydata[MASTER_KEYDATA_SIZE]; /* This holds the volume header area containing concatenated master key(s) and secondary key(s) (XTS mode). For LRW (deprecated/legacy), it contains the tweak key before the master key(s). For CBC (deprecated/legacy), it contains the IV seed before the master key(s). */
uint8_t k2[MASTER_KEYDATA_SIZE]; /* For XTS, this contains the secondary key (if cascade, multiple concatenated). For LRW (deprecated/legacy), it contains the tweak key. For CBC (deprecated/legacy), it contains the IV seed. */
uint8_t salt[PKCS5_SALT_SIZE];
int noIterations;
int pkcs5;
// uint64_t volume_creation_time;
// uint64_t header_creation_time;
// // Hidden volume status & parameters
// int hiddenVolume; // Indicates whether the volume is mounted/mountable as hidden volume
// int bProtectHiddenVolume; // Indicates whether the volume contains a hidden volume to be protected against overwriting
// int bHiddenVolProtectionAction; // TRUE if a write operation has been denied by the driver in order to prevent the hidden volume from being overwritten (set to FALSE upon volume mount).
// uint64_t hiddenVolumeSize; // Size of the hidden volume excluding the header (in bytes). Set to 0 for standard volumes.
// uint64_t hiddenVolumeOffset; // Absolute position, in bytes, of the first hidden volume data sector within the host volume (provided that there is a hidden volume within). This must be set for all hidden volumes; in case of a normal volume, this variable is only used when protecting a hidden volume within it.
// uint64_t volDataAreaOffset; // Absolute position, in bytes, of the first data sector of the volume.
// int bPartitionInInactiveSysEncScope; // If TRUE, the volume is a partition located on an encrypted system drive and mounted without pre-boot authentication.
// UINT64_STRUCT FirstDataUnitNo; // First data unit number of the volume. This is 0 for file-hosted and non-system partition-hosted volumes. For partitions within key scope of system encryption this reflects real physical offset within the device (this is used e.g. when such a partition is mounted as a regular volume without pre-boot authentication).
// UINT64_STRUCT VolumeSize;
// UINT64_STRUCT EncryptedAreaStart;
// UINT64_STRUCT EncryptedAreaLength;
} CRYPTO_INFO, *PCRYPTO_INFO;
PCRYPTO_INFO crypto_open (void);
void crypto_loadkey (PKEY_INFO keyInfo, char *lpszUserKey, int nUserKeyLen);
void crypto_close (PCRYPTO_INFO cryptoInfo);
int CipherGetBlockSize (int cipher);
int CipherGetKeySize (int cipher);
int CipherGetKeyScheduleSize (int cipher);
char * CipherGetName (int cipher);
int CipherInit (int cipher, unsigned char *key, unsigned char *ks);
int EAInit (int ea, unsigned char *key, unsigned char *ks);
int EAInitMode (PCRYPTO_INFO ci);
void EncipherBlock(int cipher, void *data, void *ks);
void DecipherBlock(int cipher, void *data, void *ks);
int EAGetFirst (void);
int EAGetCount (void);
int EAGetNext (int previousEA);
char * EAGetName (char *buf, int ea);
int EAGetByName (char *name);
int EAGetKeySize (int ea);
int EAGetFirstMode (int ea);
int EAGetNextMode (int ea, int previousModeId);
char * EAGetModeName (int ea, int mode, int capitalLetters);
int EAGetKeyScheduleSize (int ea);
int EAGetLargestKey (void);
int EAGetLargestKeyForMode (int mode);
int EAGetCipherCount (int ea);
int EAGetFirstCipher (int ea);
int EAGetLastCipher (int ea);
int EAGetNextCipher (int ea, int previousCipherId);
int EAGetPreviousCipher (int ea, int previousCipherId);
int EAIsFormatEnabled (int ea);
int EAIsModeSupported (int ea, int testedMode);
char *HashGetName (int hash_algo_id);
int HashIsDeprecated (int hashId);
int GetMaxPkcs5OutSize (void);
//void EncryptDataUnits (uint8_t *buf, const UINT64_STRUCT *structUnitNo, TC_LARGEST_COMPILER_UINT nbrUnits, PCRYPTO_INFO ci);
//void DecryptDataUnits (uint8_t *buf, const UINT64_STRUCT *structUnitNo, TC_LARGEST_COMPILER_UINT nbrUnits, PCRYPTO_INFO ci);
void EncryptBuffer (uint8_t *buf, TC_LARGEST_COMPILER_UINT len, PCRYPTO_INFO cryptoInfo);
void DecryptBuffer (uint8_t *buf, TC_LARGEST_COMPILER_UINT len, uint32_t secSz, uint64_t secN, uint8_t flags, PCRYPTO_INFO cryptoInfo);
#ifndef TC_NO_COMPILER_INT64
void Xor128 (uint64_t *a, uint64_t *b);
void Xor64 (uint64_t *a, uint64_t *b);
void EncryptBufferLRW128 (uint8_t *buffer, uint64_t length, uint64_t blockIndex, PCRYPTO_INFO cryptoInfo);
void DecryptBufferLRW128 (uint8_t *buffer, uint64_t length, uint64_t blockIndex, PCRYPTO_INFO cryptoInfo);
void EncryptBufferLRW64 (uint8_t *buffer, uint64_t length, uint64_t blockIndex, PCRYPTO_INFO cryptoInfo);
void DecryptBufferLRW64 (uint8_t *buffer, uint64_t length, uint64_t blockIndex, PCRYPTO_INFO cryptoInfo);
void InitSectorIVAndWhitening (uint64_t unitNo, int blockSize, uint32_t *iv, uint64_t *ivSeed, uint32_t *whitening);
//uint64_t DataUnit2LRWIndex (uint64_t dataUnit, int blockSize, PCRYPTO_INFO ci);
#endif // #ifndef TC_NO_COMPILER_INT64
#ifdef __cplusplus
}
#endif
#endif /* CRYPTO_H */

57
src/utils/common/endian.c Normal file
View File

@@ -0,0 +1,57 @@
/*
Legal Notice: Some portions of the source code contained in this file were
derived from the source code of Encryption for the Masses 2.02a, which is
Copyright (c) 1998-2000 Paul Le Roux and which is governed by the 'License
Agreement for Encryption for the Masses'. Modifications and additions to
the original source code (contained in this file) and all other portions of
this file are Copyright (c) 2003-2008 TrueCrypt Foundation and are governed
by the TrueCrypt License 2.4 the full text of which is contained in the
file License.txt included in TrueCrypt binary and source code distribution
packages. */
#include "tcdefs.h"
#include "../common/endian.h"
uint16_t MirrorBytes16 (uint16_t x)
{
return (x << 8) | (x >> 8);
}
uint32_t MirrorBytes32 (uint32_t x)
{
uint32_t n = (uint8_t) x;
n <<= 8; n |= (uint8_t) (x >> 8);
n <<= 8; n |= (uint8_t) (x >> 16);
return (n << 8) | (uint8_t) (x >> 24);
}
#ifndef TC_NO_COMPILER_INT64
uint64_t MirrorBytes64 (uint64_t x)
{
uint64_t n = (uint8_t) x;
n <<= 8; n |= (uint8_t) (x >> 8);
n <<= 8; n |= (uint8_t) (x >> 16);
n <<= 8; n |= (uint8_t) (x >> 24);
n <<= 8; n |= (uint8_t) (x >> 32);
n <<= 8; n |= (uint8_t) (x >> 40);
n <<= 8; n |= (uint8_t) (x >> 48);
return (n << 8) | (uint8_t) (x >> 56);
}
#endif
void
LongReverse (uint32_t *buffer, unsigned byteCount)
{
uint32_t value;
byteCount /= sizeof (uint32_t);
while (byteCount--)
{
value = *buffer;
value = ((value & 0xFF00FF00L) >> 8) | \
((value & 0x00FF00FFL) << 8);
*buffer++ = (value << 16) | (value >> 16);
}
}

138
src/utils/common/endian.h Normal file
View File

@@ -0,0 +1,138 @@
/*
Legal Notice: Some portions of the source code contained in this file were
derived from the source code of Encryption for the Masses 2.02a, which is
Copyright (c) 1998-2000 Paul Le Roux and which is governed by the 'License
Agreement for Encryption for the Masses'. Modifications and additions to
the original source code (contained in this file) and all other portions of
this file are Copyright (c) 2003-2008 TrueCrypt Foundation and are governed
by the TrueCrypt License 2.4 the full text of which is contained in the
file License.txt included in TrueCrypt binary and source code distribution
packages. */
#ifndef TC_ENDIAN_H
#define TC_ENDIAN_H
#include <inttypes.h>
#if defined(__cplusplus)
extern "C"
{
#endif
#ifdef _WIN32
# ifndef LITTLE_ENDIAN
# define LITTLE_ENDIAN 1234
# endif
# ifndef BYTE_ORDER
# define BYTE_ORDER LITTLE_ENDIAN
# endif
#elif !defined(BYTE_ORDER)
# ifdef TC_MACOSX
# include <machine/endian.h>
# elif defined (TC_BSD)
# include <sys/endian.h>
# else
# include <endian.h>
# endif
# ifndef BYTE_ORDER
# ifndef __BYTE_ORDER
# error Byte order cannot be determined (BYTE_ORDER undefined)
# endif
# define BYTE_ORDER __BYTE_ORDER
# endif
# ifndef LITTLE_ENDIAN
# define LITTLE_ENDIAN __LITTLE_ENDIAN
# endif
# ifndef BIG_ENDIAN
# define BIG_ENDIAN __BIG_ENDIAN
# endif
#endif // !BYTE_ORDER
/* Macros to read and write 16, 32, and 64-bit quantities in a portable manner.
These functions are implemented as macros rather than true functions as
the need to adjust the memory pointers makes them somewhat painful to call
in user code */
#define mputInt64(memPtr,data) \
*memPtr++ = ( unsigned char ) ( ( ( data ) >> 56 ) & 0xFF ), \
*memPtr++ = ( unsigned char ) ( ( ( data ) >> 48 ) & 0xFF ), \
*memPtr++ = ( unsigned char ) ( ( ( data ) >> 40 ) & 0xFF ), \
*memPtr++ = ( unsigned char ) ( ( ( data ) >> 32 ) & 0xFF ), \
*memPtr++ = ( unsigned char ) ( ( ( data ) >> 24 ) & 0xFF ), \
*memPtr++ = ( unsigned char ) ( ( ( data ) >> 16 ) & 0xFF ), \
*memPtr++ = ( unsigned char ) ( ( ( data ) >> 8 ) & 0xFF ), \
*memPtr++ = ( unsigned char ) ( ( data ) & 0xFF )
#define mputLong(memPtr,data) \
*memPtr++ = ( unsigned char ) ( ( ( data ) >> 24 ) & 0xFF ), \
*memPtr++ = ( unsigned char ) ( ( ( data ) >> 16 ) & 0xFF ), \
*memPtr++ = ( unsigned char ) ( ( ( data ) >> 8 ) & 0xFF ), \
*memPtr++ = ( unsigned char ) ( ( data ) & 0xFF )
#define mputWord(memPtr,data) \
*memPtr++ = ( unsigned char ) ( ( ( data ) >> 8 ) & 0xFF ), \
*memPtr++ = ( unsigned char ) ( ( data ) & 0xFF )
#define mputByte(memPtr,data) \
*memPtr++ = ( unsigned char ) data
#define mputBytes(memPtr,data,len) \
memcpy (memPtr,data,len); \
memPtr += len;
#define mgetInt64(memPtr) \
( memPtr += 8, ( ( unsigned __int64 ) memPtr[ -8 ] << 56 ) | ( ( unsigned __int64 ) memPtr[ -7 ] << 48 ) | \
( ( unsigned __int64 ) memPtr[ -6 ] << 40 ) | ( ( unsigned __int64 ) memPtr[ -5 ] << 32 ) | \
( ( unsigned __int64 ) memPtr[ -4 ] << 24 ) | ( ( unsigned __int64 ) memPtr[ -3 ] << 16 ) | \
( ( unsigned __int64 ) memPtr[ -2 ] << 8 ) | ( unsigned __int64 ) memPtr[ -1 ] )
#define mgetLong(memPtr) \
( memPtr += 4, ( ( unsigned __int32 ) memPtr[ -4 ] << 24 ) | ( ( unsigned __int32 ) memPtr[ -3 ] << 16 ) | \
( ( unsigned __int32 ) memPtr[ -2 ] << 8 ) | ( unsigned __int32 ) memPtr[ -1 ] )
#define mgetWord(memPtr) \
( memPtr += 2, ( unsigned short ) memPtr[ -2 ] << 8 ) | ( ( unsigned short ) memPtr[ -1 ] )
#define mgetByte(memPtr) \
( ( unsigned char ) *memPtr++ )
#if BYTE_ORDER == BIG_ENDIAN
# define LE16(x) MirrorBytes16(x)
# define LE32(x) MirrorBytes32(x)
# define LE64(x) MirrorBytes64(x)
#else
# define LE16(x) (x)
# define LE32(x) (x)
# define LE64(x) (x)
#endif
#if BYTE_ORDER == LITTLE_ENDIAN
# define BE16(x) MirrorBytes16(x)
# define BE32(x) MirrorBytes32(x)
# define BE64(x) MirrorBytes64(x)
#else
# define BE16(x) (x)
# define BE32(x) (x)
# define BE64(x) (x)
#endif
uint16_t MirrorBytes16 (uint16_t x);
uint32_t MirrorBytes32 (uint32_t x);
#ifndef TC_NO_COMPILER_INT64
uint64_t MirrorBytes64 (uint64_t x);
#endif
void LongReverse ( uint32_t *buffer , unsigned byteCount );
#if defined(__cplusplus)
}
#endif
#endif /* TC_ENDIAN_H */

893
src/utils/common/gfmul.c Normal file
View File

@@ -0,0 +1,893 @@
/*
---------------------------------------------------------------------------
Copyright (c) 2003, Dr Brian Gladman, Worcester, UK. All rights reserved.
LICENSE TERMS
The free distribution and use of this software is allowed (with or without
changes) provided that:
1. source code distributions include the above copyright notice, this
list of conditions and the following disclaimer;
2. binary distributions include the above copyright notice, this list
of conditions and the following disclaimer in their documentation;
3. the name of the copyright holder is not used to endorse products
built using this software without specific written permission.
DISCLAIMER
This software is provided 'as is' with no explicit or implied warranties
in respect of its properties, including, but not limited to, correctness
and/or fitness for purpose.
---------------------------------------------------------------------------
Issue Date: 31/01/2004
My thanks to John Viega and David McGrew for their support in developing
this code and to David for testing it on a big-endain system.
*/
/*
Portions Copyright (c) 2005 TrueCrypt Foundation
TrueCrypt Foundation made the following changes:
- Added multiplication in the finite field GF(2^128) optimized for
cases involving a 64-bit operand.
- Added multiplication in the finite field GF(2^64).
- Added MSB-first mode.
- Added basic test algorithms.
- Removed GCM.
*/
#include <memory.h>
#include <stdlib.h>
#include <inttypes.h>
#include "gfmul.h"
#include "tcdefs.h"
#include "../common/endian.h"
/* BUFFER_ALIGN32 or BUFFER_ALIGN64 must be defined at this point to */
/* enable faster operation by taking advantage of memory aligned values */
/* NOTE: the BUFFER_ALIGN64 option has not been tested extensively */
#define BUFFER_ALIGN32
#define UNROLL_LOOPS /* define to unroll some loops */
#define IN_LINES /* define to use inline functions */
/* in place of macros */
#define mode(x) GM_##x
#if defined(__cplusplus)
extern "C"
{
#endif
typedef uint32_t mode(32t);
typedef uint64_t mode(64t);
#define BRG_LITTLE_ENDIAN 1234 /* byte 0 is least significant (i386) */
#define BRG_BIG_ENDIAN 4321 /* byte 0 is most significant (mc68k) */
#if BYTE_ORDER == LITTLE_ENDIAN
# define PLATFORM_BYTE_ORDER BRG_LITTLE_ENDIAN
#endif
#if BYTE_ORDER == BIG_ENDIAN
# define PLATFORM_BYTE_ORDER BRG_BIG_ENDIAN
#endif
#ifdef _MSC_VER
#pragma intrinsic(memcpy)
#define in_line __inline
#else
#define in_line
#endif
#if 0 && defined(_MSC_VER)
#define rotl32 _lrotl
#define rotr32 _lrotr
#else
#define rotl32(x,n) (((x) << n) | ((x) >> (32 - n)))
#define rotr32(x,n) (((x) >> n) | ((x) << (32 - n)))
#endif
#if !defined(bswap_32)
#define bswap_32(x) ((rotr32((x), 24) & 0x00ff00ff) | (rotr32((x), 8) & 0xff00ff00))
#endif
#if (PLATFORM_BYTE_ORDER == BRG_LITTLE_ENDIAN)
#define SWAP_BYTES
#else
#undef SWAP_BYTES
#endif
#if defined(SWAP_BYTES)
#if defined ( IN_LINES )
in_line void bsw_32(void * p, unsigned int n)
{ unsigned int i = n;
while(i--)
((mode(32t)*)p)[i] = bswap_32(((mode(32t)*)p)[i]);
}
#else
#define bsw_32(p,n) \
{ int _i = (n); while(_i--) ((mode(32t)*)p)[_i] = bswap_32(((mode(32t)*)p)[_i]); }
#endif
#else
#define bsw_32(p,n)
#endif
/* These values are used to detect long word alignment in order */
/* to speed up some GCM buffer operations. This facility may */
/* not work on some machines */
#define lp08(x) ((unsigned char*)(x))
#define lp32(x) ((mode(32t)*)(x))
#define lp64(x) ((mode(64t)*)(x))
#define A32_MASK 3
#define A64_MASK 7
#define aligned32(x) (!(((mode(32t))(x)) & A32_MASK))
#define aligned64(x) (!(((mode(32t))(x)) & A64_MASK))
#if defined( BUFFER_ALIGN32 )
#define ADR_MASK A32_MASK
#define aligned aligned32
#define lp lp32
#define lp_inc 4
#if defined( IN_LINES )
in_line void move_block_aligned( void *p, const void *q)
{
lp32(p)[0] = lp32(q)[0], lp32(p)[1] = lp32(q)[1],
lp32(p)[2] = lp32(q)[2], lp32(p)[3] = lp32(q)[3];
}
in_line void move_block_aligned64( void *p, const void *q)
{
lp32(p)[0] = lp32(q)[0], lp32(p)[1] = lp32(q)[1];
}
in_line void xor_block_aligned( void *p, const void *q)
{
lp32(p)[0] ^= lp32(q)[0], lp32(p)[1] ^= lp32(q)[1],
lp32(p)[2] ^= lp32(q)[2], lp32(p)[3] ^= lp32(q)[3];
}
in_line void xor_block_aligned64( void *p, const void *q)
{
lp32(p)[0] ^= lp32(q)[0], lp32(p)[1] ^= lp32(q)[1];
}
#else
#define move_block_aligned(p,q) \
lp32(p)[0] = lp32(q)[0], lp32(p)[1] = lp32(q)[1], \
lp32(p)[2] = lp32(q)[2], lp32(p)[3] = lp32(q)[3]
#define xor_block_aligned(p,q) \
lp32(p)[0] ^= lp32(q)[0], lp32(p)[1] ^= lp32(q)[1], \
lp32(p)[2] ^= lp32(q)[2], lp32(p)[3] ^= lp32(q)[3]
#endif
#elif defined( BUFFER_ALIGN64 )
#define ADR_MASK A64_MASK
#define aligned aligned64
#define lp lp64
#define lp_inc 8
#define move_block_aligned(p,q) \
lp64(p)[0] = lp64(q)[0], lp64(p)[1] = lp64(q)[1]
#define xor_block_aligned(p,q) \
lp64(p)[0] ^= lp64(q)[0], lp64(p)[1] ^= lp64(q)[1]
#else
#define aligned(x) 0
#endif
#define move_block(p,q) memcpy((p), (q), BLOCK_LEN)
#define xor_block(p,q) \
lp08(p)[ 0] ^= lp08(q)[ 0], lp08(p)[ 1] ^= lp08(q)[ 1], \
lp08(p)[ 2] ^= lp08(q)[ 2], lp08(p)[ 3] ^= lp08(q)[ 3], \
lp08(p)[ 4] ^= lp08(q)[ 4], lp08(p)[ 5] ^= lp08(q)[ 5], \
lp08(p)[ 6] ^= lp08(q)[ 6], lp08(p)[ 7] ^= lp08(q)[ 7], \
lp08(p)[ 8] ^= lp08(q)[ 8], lp08(p)[ 9] ^= lp08(q)[ 9], \
lp08(p)[10] ^= lp08(q)[10], lp08(p)[11] ^= lp08(q)[11], \
lp08(p)[12] ^= lp08(q)[12], lp08(p)[13] ^= lp08(q)[13], \
lp08(p)[14] ^= lp08(q)[14], lp08(p)[15] ^= lp08(q)[15]
#define gf_dat(q) {\
q(0x00), q(0x01), q(0x02), q(0x03), q(0x04), q(0x05), q(0x06), q(0x07),\
q(0x08), q(0x09), q(0x0a), q(0x0b), q(0x0c), q(0x0d), q(0x0e), q(0x0f),\
q(0x10), q(0x11), q(0x12), q(0x13), q(0x14), q(0x15), q(0x16), q(0x17),\
q(0x18), q(0x19), q(0x1a), q(0x1b), q(0x1c), q(0x1d), q(0x1e), q(0x1f),\
q(0x20), q(0x21), q(0x22), q(0x23), q(0x24), q(0x25), q(0x26), q(0x27),\
q(0x28), q(0x29), q(0x2a), q(0x2b), q(0x2c), q(0x2d), q(0x2e), q(0x2f),\
q(0x30), q(0x31), q(0x32), q(0x33), q(0x34), q(0x35), q(0x36), q(0x37),\
q(0x38), q(0x39), q(0x3a), q(0x3b), q(0x3c), q(0x3d), q(0x3e), q(0x3f),\
q(0x40), q(0x41), q(0x42), q(0x43), q(0x44), q(0x45), q(0x46), q(0x47),\
q(0x48), q(0x49), q(0x4a), q(0x4b), q(0x4c), q(0x4d), q(0x4e), q(0x4f),\
q(0x50), q(0x51), q(0x52), q(0x53), q(0x54), q(0x55), q(0x56), q(0x57),\
q(0x58), q(0x59), q(0x5a), q(0x5b), q(0x5c), q(0x5d), q(0x5e), q(0x5f),\
q(0x60), q(0x61), q(0x62), q(0x63), q(0x64), q(0x65), q(0x66), q(0x67),\
q(0x68), q(0x69), q(0x6a), q(0x6b), q(0x6c), q(0x6d), q(0x6e), q(0x6f),\
q(0x70), q(0x71), q(0x72), q(0x73), q(0x74), q(0x75), q(0x76), q(0x77),\
q(0x78), q(0x79), q(0x7a), q(0x7b), q(0x7c), q(0x7d), q(0x7e), q(0x7f),\
q(0x80), q(0x81), q(0x82), q(0x83), q(0x84), q(0x85), q(0x86), q(0x87),\
q(0x88), q(0x89), q(0x8a), q(0x8b), q(0x8c), q(0x8d), q(0x8e), q(0x8f),\
q(0x90), q(0x91), q(0x92), q(0x93), q(0x94), q(0x95), q(0x96), q(0x97),\
q(0x98), q(0x99), q(0x9a), q(0x9b), q(0x9c), q(0x9d), q(0x9e), q(0x9f),\
q(0xa0), q(0xa1), q(0xa2), q(0xa3), q(0xa4), q(0xa5), q(0xa6), q(0xa7),\
q(0xa8), q(0xa9), q(0xaa), q(0xab), q(0xac), q(0xad), q(0xae), q(0xaf),\
q(0xb0), q(0xb1), q(0xb2), q(0xb3), q(0xb4), q(0xb5), q(0xb6), q(0xb7),\
q(0xb8), q(0xb9), q(0xba), q(0xbb), q(0xbc), q(0xbd), q(0xbe), q(0xbf),\
q(0xc0), q(0xc1), q(0xc2), q(0xc3), q(0xc4), q(0xc5), q(0xc6), q(0xc7),\
q(0xc8), q(0xc9), q(0xca), q(0xcb), q(0xcc), q(0xcd), q(0xce), q(0xcf),\
q(0xd0), q(0xd1), q(0xd2), q(0xd3), q(0xd4), q(0xd5), q(0xd6), q(0xd7),\
q(0xd8), q(0xd9), q(0xda), q(0xdb), q(0xdc), q(0xdd), q(0xde), q(0xdf),\
q(0xe0), q(0xe1), q(0xe2), q(0xe3), q(0xe4), q(0xe5), q(0xe6), q(0xe7),\
q(0xe8), q(0xe9), q(0xea), q(0xeb), q(0xec), q(0xed), q(0xee), q(0xef),\
q(0xf0), q(0xf1), q(0xf2), q(0xf3), q(0xf4), q(0xf5), q(0xf6), q(0xf7),\
q(0xf8), q(0xf9), q(0xfa), q(0xfb), q(0xfc), q(0xfd), q(0xfe), q(0xff) }
/* given the value i in 0..255 as the byte overflow when a a field */
/* element in GHASH is multipled by x^8, this function will return */
/* the values that are generated in the lo 16-bit word of the field */
/* value by applying the modular polynomial. The values lo_byte and */
/* hi_byte are returned via the macro xp_fun(lo_byte, hi_byte) so */
/* that the values can be assembled into memory as required by a */
/* suitable definition of this macro operating on the table above */
#define xp(i) xp_fun( \
(i & 0x80 ? 0xe1 : 0) ^ (i & 0x40 ? 0x70 : 0) ^ \
(i & 0x20 ? 0x38 : 0) ^ (i & 0x10 ? 0x1c : 0) ^ \
(i & 0x08 ? 0x0e : 0) ^ (i & 0x04 ? 0x07 : 0) ^ \
(i & 0x02 ? 0x03 : 0) ^ (i & 0x01 ? 0x01 : 0), \
(i & 0x80 ? 0x00 : 0) ^ (i & 0x40 ? 0x80 : 0) ^ \
(i & 0x20 ? 0x40 : 0) ^ (i & 0x10 ? 0x20 : 0) ^ \
(i & 0x08 ? 0x10 : 0) ^ (i & 0x04 ? 0x08 : 0) ^ \
(i & 0x02 ? 0x84 : 0) ^ (i & 0x01 ? 0xc2 : 0) )
#define xp64(i) xp_fun( \
(i & 0x80 ? 0xd8 : 0) ^ (i & 0x40 ? 0x6c : 0) ^ \
(i & 0x20 ? 0x36 : 0) ^ (i & 0x10 ? 0x1b : 0) ^ \
(i & 0x08 ? 0x0d : 0) ^ (i & 0x04 ? 0x06 : 0) ^ \
(i & 0x02 ? 0x03 : 0) ^ (i & 0x01 ? 0x01 : 0), \
(i & 0x80 ? 0x00 : 0) ^ (i & 0x40 ? 0x00 : 0) ^ \
(i & 0x20 ? 0x00 : 0) ^ (i & 0x10 ? 0x00 : 0) ^ \
(i & 0x08 ? 0x80 : 0) ^ (i & 0x04 ? 0xc0 : 0) ^ \
(i & 0x02 ? 0x60 : 0) ^ (i & 0x01 ? 0xb0 : 0) )
static mode(32t) gf_poly[2] = { 0, 0xe1000000 };
static mode(32t) gf_poly64[2] = { 0, 0xd8000000 };
/* Multiply of a GF128 field element by x. The field element */
/* is held in an array of bytes in which field bits 8n..8n + 7 */
/* are held in byte[n], with lower indexed bits placed in the */
/* more numerically significant bit positions in bytes. */
/* This function multiples a field element x, in the polynomial */
/* field representation. It uses 32-bit word operations to gain */
/* speed but compensates for machine endianess and hence works */
/* correctly on both styles of machine */
in_line void mul_x(mode(32t) x[4])
{ mode(32t) t;
bsw_32(x, 4);
/* at this point the filed element bits 0..127 are set out */
/* as follows in 32-bit words (where the most significant */
/* (ms) numeric bits are to the left) */
/* */
/* x[0] x[1] x[2] x[3] */
/* ms ls ms ls ms ls ms ls */
/* field: 0 ... 31 32 .. 63 64 .. 95 96 .. 127 */
t = gf_poly[x[3] & 1]; /* bit 127 of the element */
x[3] = (x[3] >> 1) | (x[2] << 31); /* shift bits up by one */
x[2] = (x[2] >> 1) | (x[1] << 31); /* position */
x[1] = (x[1] >> 1) | (x[0] << 31); /* if bit 7 is 1 xor in */
x[0] = (x[0] >> 1) ^ t; /* the field polynomial */
bsw_32(x, 4);
}
in_line void mul_x64(mode(32t) x[2])
{ mode(32t) t;
bsw_32(x, 2);
/* at this point the filed element bits 0..127 are set out */
/* as follows in 32-bit words (where the most significant */
/* (ms) numeric bits are to the left) */
/* */
/* x[0] x[1] x[2] x[3] */
/* ms ls ms ls ms ls ms ls */
/* field: 0 ... 31 32 .. 63 64 .. 95 96 .. 127 */
t = gf_poly64[x[1] & 1]; /* bit 127 of the element */
/* shift bits up by one */
/* position */
x[1] = (x[1] >> 1) | (x[0] << 31); /* if bit 7 is 1 xor in */
x[0] = (x[0] >> 1) ^ t; /* the field polynomial */
bsw_32(x, 2);
}
/* Multiply of a GF128 field element by x^8 using 32-bit words */
/* for speed - machine endianess matters here */
#if (PLATFORM_BYTE_ORDER == BRG_LITTLE_ENDIAN)
#define xp_fun(x,y) ((mode(32t))(x)) | (((mode(32t))(y)) << 8)
static const uint16_t gft_le[256] = gf_dat(xp);
static const uint16_t gft_le64[256] = gf_dat(xp64);
in_line void mul_lex8(mode(32t) x[4]) /* mutiply with long words */
{ mode(32t) t = (x[3] >> 24); /* in little endian format */
x[3] = (x[3] << 8) | (x[2] >> 24);
x[2] = (x[2] << 8) | (x[1] >> 24);
x[1] = (x[1] << 8) | (x[0] >> 24);
x[0] = (x[0] << 8) ^ gft_le[t];
}
in_line void mul_lex8_64(mode(32t) x[2]) /* mutiply with long words */
{ mode(32t) t = (x[1] >> 24); /* in little endian format */
x[1] = (x[1] << 8) | (x[0] >> 24);
x[0] = (x[0] << 8) ^ gft_le64[t];
}
#endif
#if 1 || (PLATFORM_BYTE_ORDER == BRG_LITTLE_ENDIAN)
#undef xp_fun
#define xp_fun(x,y) ((mode(32t))(y)) | (((mode(32t))(x)) << 8)
static const uint16_t gft_be[256] = gf_dat(xp);
static const uint16_t gft_be64[256] = gf_dat(xp64);
in_line void mul_bex8(mode(32t) x[4]) /* mutiply with long words */
{ mode(32t) t = (x[3] & 0xff); /* in big endian format */
x[3] = (x[3] >> 8) | (x[2] << 24);
x[2] = (x[2] >> 8) | (x[1] << 24);
x[1] = (x[1] >> 8) | (x[0] << 24);
x[0] = (x[0] >> 8) ^ (((mode(32t))gft_be[t]) << 16);
}
in_line void mul_bex8_64(mode(32t) x[2]) /* mutiply with long words */
{ mode(32t) t = (x[1] & 0xff); /* in big endian format */
x[1] = (x[1] >> 8) | (x[0] << 24);
x[0] = (x[0] >> 8) ^ (((mode(32t))gft_be64[t]) << 16);
}
#endif
/* hence choose the correct version for the machine endianess */
#if PLATFORM_BYTE_ORDER == BRG_BIG_ENDIAN
#define mul_x8 mul_bex8
#define mul_x8_64 mul_bex8_64
#else
#define mul_x8 mul_lex8
#define mul_x8_64 mul_lex8_64
#endif
/* different versions of the general gf_mul function are provided */
/* here. Sadly none are very fast :-( */
void GfMul128 (void *a, const void* b)
{ mode(32t) r[CBLK_LEN >> 2], p[8][CBLK_LEN >> 2];
int i;
move_block_aligned(p[0], b);
bsw_32(p[0], 4);
for(i = 0; i < 7; ++i)
{
p[i + 1][3] = (p[i][3] >> 1) | (p[i][2] << 31);
p[i + 1][2] = (p[i][2] >> 1) | (p[i][1] << 31);
p[i + 1][1] = (p[i][1] >> 1) | (p[i][0] << 31);
p[i + 1][0] = (p[i][0] >> 1) ^ gf_poly[p[i][3] & 1];
}
memset(r, 0, CBLK_LEN);
for(i = 0; i < 16; ++i)
{
if(i) mul_bex8(r); /* order is always big endian here */
if(((unsigned char*)a)[15 - i] & 0x80)
xor_block_aligned(r, p[0]);
if(((unsigned char*)a)[15 - i] & 0x40)
xor_block_aligned(r, p[1]);
if(((unsigned char*)a)[15 - i] & 0x20)
xor_block_aligned(r, p[2]);
if(((unsigned char*)a)[15 - i] & 0x10)
xor_block_aligned(r, p[3]);
if(((unsigned char*)a)[15 - i] & 0x08)
xor_block_aligned(r, p[4]);
if(((unsigned char*)a)[15 - i] & 0x04)
xor_block_aligned(r, p[5]);
if(((unsigned char*)a)[15 - i] & 0x02)
xor_block_aligned(r, p[6]);
if(((unsigned char*)a)[15 - i] & 0x01)
xor_block_aligned(r, p[7]);
}
bsw_32(r, 4);
move_block_aligned(a, r);
}
#if defined( UNROLL_LOOPS )
#define xor_8k(i) \
xor_block_aligned(r, ctx->gf_t8k[i + i][a[i] & 15]); \
xor_block_aligned(r, ctx->gf_t8k[i + i + 1][a[i] >> 4])
void GfMul128Tab (unsigned char a[CBLK_LEN], GfCtx8k *ctx)
{ uint32_t r[CBLK_LEN >> 2];
move_block_aligned(r, ctx->gf_t8k[0][a[0] & 15]);
xor_block_aligned(r, ctx->gf_t8k[1][a[0] >> 4]);
xor_8k( 1); xor_8k( 2); xor_8k( 3);
xor_8k( 4); xor_8k( 5); xor_8k( 6); xor_8k( 7);
xor_8k( 8); xor_8k( 9); xor_8k(10); xor_8k(11);
xor_8k(12); xor_8k(13); xor_8k(14); xor_8k(15);
move_block_aligned(a, r);
}
#else
void GfMul128Tab (unsigned char a[CBLK_LEN], GfCtx8k *ctx)
{ uint32_t r[CBLK_LEN >> 2], *p;
int i;
p = ctx->gf_t8k[0][a[0] & 15];
memcpy(r, p, CBLK_LEN);
p = ctx->gf_t8k[1][a[0] >> 4];
xor_block_aligned(r, p);
for(i = 1; i < CBLK_LEN; ++i)
{
xor_block_aligned(r, ctx->gf_t8k[i + i][a[i] & 15]);
xor_block_aligned(r, ctx->gf_t8k[i + i + 1][a[i] >> 4]);
}
memcpy(a, r, CBLK_LEN);
}
#endif
void compile_8k_table(uint8_t *a, GfCtx8k *ctx)
{ int i, j, k;
memset(ctx->gf_t8k, 0, 32 * 16 * 16);
for(i = 0; i < 2 * CBLK_LEN; ++i)
{
if(i == 0)
{
memcpy(ctx->gf_t8k[1][8], a, CBLK_LEN);
for(j = 4; j > 0; j >>= 1)
{
memcpy(ctx->gf_t8k[1][j], ctx->gf_t8k[1][j + j], CBLK_LEN);
mul_x(ctx->gf_t8k[1][j]);
}
memcpy(ctx->gf_t8k[0][8], ctx->gf_t8k[1][1], CBLK_LEN);
mul_x(ctx->gf_t8k[0][8]);
for(j = 4; j > 0; j >>= 1)
{
memcpy(ctx->gf_t8k[0][j], ctx->gf_t8k[0][j + j], CBLK_LEN);
mul_x(ctx->gf_t8k[0][j]);
}
}
else if(i > 1)
for(j = 8; j > 0; j >>= 1)
{
memcpy(ctx->gf_t8k[i][j], ctx->gf_t8k[i - 2][j], CBLK_LEN);
mul_x8(ctx->gf_t8k[i][j]);
}
for(j = 2; j < 16; j += j)
{
mode(32t) *pj = ctx->gf_t8k[i][j];
mode(32t) *pk = ctx->gf_t8k[i][1];
mode(32t) *pl = ctx->gf_t8k[i][j + 1];
for(k = 1; k < j; ++k)
{
*pl++ = pj[0] ^ *pk++;
*pl++ = pj[1] ^ *pk++;
*pl++ = pj[2] ^ *pk++;
*pl++ = pj[3] ^ *pk++;
}
}
}
}
void compile_4k_table64(uint8_t *a, GfCtx4k64 *ctx)
{ int i, j, k;
memset(ctx->gf_t4k, 0, sizeof(ctx->gf_t4k));
for(i = 0; i < 2 * CBLK_LEN8; ++i)
{
if(i == 0)
{
memcpy(ctx->gf_t4k[1][8], a, CBLK_LEN8);
for(j = 4; j > 0; j >>= 1)
{
memcpy(ctx->gf_t4k[1][j], ctx->gf_t4k[1][j + j], CBLK_LEN8);
mul_x64(ctx->gf_t4k[1][j]);
}
memcpy(ctx->gf_t4k[0][8], ctx->gf_t4k[1][1], CBLK_LEN8);
mul_x64(ctx->gf_t4k[0][8]);
for(j = 4; j > 0; j >>= 1)
{
memcpy(ctx->gf_t4k[0][j], ctx->gf_t4k[0][j + j], CBLK_LEN8);
mul_x64(ctx->gf_t4k[0][j]);
}
}
else if(i > 1)
for(j = 8; j > 0; j >>= 1)
{
memcpy(ctx->gf_t4k[i][j], ctx->gf_t4k[i - 2][j], CBLK_LEN8);
mul_x8_64(ctx->gf_t4k[i][j]);
}
for(j = 2; j < 16; j += j)
{
mode(32t) *pj = ctx->gf_t4k[i][j];
mode(32t) *pk = ctx->gf_t4k[i][1];
mode(32t) *pl = ctx->gf_t4k[i][j + 1];
for(k = 1; k < j; ++k)
{
*pl++ = pj[0] ^ *pk++;
*pl++ = pj[1] ^ *pk++;
*pl++ = pj[2] ^ *pk++;
*pl++ = pj[3] ^ *pk++;
}
}
}
}
static int IsBitSet128 (unsigned int bit, uint8_t *a)
{
return a[(127 - bit) / 8] & (0x80 >> ((127 - bit) % 8));
}
static int IsBitSet64 (unsigned int bit, uint8_t *a)
{
return a[(63 - bit) / 8] & (0x80 >> ((63 - bit) % 8));
}
static void SetBit128 (unsigned int bit, uint8_t *a)
{
a[(127 - bit) / 8] |= 0x80 >> ((127 - bit) % 8);
}
static void SetBit64 (unsigned int bit, uint8_t *a)
{
a[(63 - bit) / 8] |= 0x80 >> ((63 - bit) % 8);
}
void MirrorBits128 (uint8_t *a)
{
uint8_t t[128 / 8];
int i;
memset (t,0,16);
for (i = 0; i < 128; i++)
{
if (IsBitSet128(i, a))
SetBit128 (127 - i, t);
}
memcpy (a, t, sizeof (t));
burn (t,sizeof (t));
}
void MirrorBits64 (uint8_t *a)
{
uint8_t t[64 / 8];
int i;
memset (t,0,8);
for (i = 0; i < 64; i++)
{
if (IsBitSet64(i, a))
SetBit64 (63 - i, t);
}
memcpy (a, t, sizeof (t));
burn (t,sizeof (t));
}
/* Allocate and initialize speed optimization table
for multiplication by 64-bit operand in MSB-first mode */
int Gf128Tab64Init (uint8_t *a, GfCtx *ctx)
{
GfCtx8k *ctx8k;
uint8_t am[16];
int i, j;
ctx8k = (GfCtx8k *) TCalloc (sizeof (GfCtx8k));
if (!ctx8k)
return 0;
memcpy (am, a, 16);
MirrorBits128 (am);
compile_8k_table (am, ctx8k);
/* Convert 8k LSB-first table to 4k MSB-first */
for (i = 16; i < 32; i++)
{
for (j = 0; j < 16; j++)
{
int jm = 0;
jm |= (j & 0x1) << 3;
jm |= (j & 0x2) << 1;
jm |= (j & 0x4) >> 1;
jm |= (j & 0x8) >> 3;
memcpy (&ctx->gf_t128[i-16][jm], (unsigned char *)&ctx8k->gf_t8k[31-i][j], 16);
MirrorBits128 ((unsigned char *)&ctx->gf_t128[i-16][jm]);
}
}
burn (ctx8k ,sizeof (*ctx8k));
burn (am, sizeof (am));
TCfree (ctx8k);
return 1;
}
int Gf64TabInit (uint8_t *a, GfCtx *ctx)
{
/* Deprecated/legacy */
GfCtx4k64 *ctx4k;
uint8_t am[8];
int i, j;
ctx4k = (GfCtx4k64 *) TCalloc (sizeof (GfCtx4k64));
if (!ctx4k)
return 0;
memcpy (am, a, 8);
MirrorBits64 (am);
compile_4k_table64 (am, ctx4k);
/* Convert LSB-first table to MSB-first */
for (i = 0; i < 16; i++)
{
for (j = 0; j < 16; j++)
{
int jm = 0;
jm |= (j & 0x1) << 3;
jm |= (j & 0x2) << 1;
jm |= (j & 0x4) >> 1;
jm |= (j & 0x8) >> 3;
memcpy (&ctx->gf_t64[i][jm], (unsigned char *)&ctx4k->gf_t4k[15-i][j], 8);
MirrorBits64 ((unsigned char *)&ctx->gf_t64[i][jm]);
}
}
burn (ctx4k,sizeof (*ctx4k));
burn (am, sizeof (am));
TCfree (ctx4k);
return 1;
}
#define xor_8kt64(i) \
xor_block_aligned(r, ctx->gf_t128[i + i][a[i] & 15]); \
xor_block_aligned(r, ctx->gf_t128[i + i + 1][a[i] >> 4])
/* Multiply a 128-bit number by a 64-bit number in the finite field GF(2^128) */
void Gf128MulBy64Tab (uint8_t a[8], uint8_t p[16], GfCtx *ctx)
{
uint32_t r[CBLK_LEN >> 2];
move_block_aligned(r, ctx->gf_t128[7*2][a[7] & 15]);
xor_block_aligned(r, ctx->gf_t128[7*2+1][a[7] >> 4]);
if (*(uint16_t *)a)
{
xor_8kt64(0);
xor_8kt64(1);
}
if (a[2])
{
xor_8kt64(2);
}
xor_8kt64(3);
xor_8kt64(4);
xor_8kt64(5);
xor_8kt64(6);
move_block_aligned(p, r);
}
#define xor_8k64(i) \
xor_block_aligned64(r, ctx->gf_t64[i + i][a[i] & 15]); \
xor_block_aligned64(r, ctx->gf_t64[i + i + 1][a[i] >> 4])
/* Multiply two 64-bit numbers in the finite field GF(2^64) */
void Gf64MulTab (unsigned char a[8], unsigned char p[8], GfCtx *ctx)
{
/* Deprecated/legacy */
uint32_t r[CBLK_LEN8 >> 2];
move_block_aligned64(r, ctx->gf_t64[7*2][a[7] & 15]);
xor_block_aligned64(r, ctx->gf_t64[7*2+1][a[7] >> 4]);
if (*(uint16_t *)a)
{
xor_8k64(0);
xor_8k64(1);
}
if (a[2])
{
xor_8k64(2);
}
xor_8k64(3);
xor_8k64(4);
xor_8k64(5);
xor_8k64(6);
move_block_aligned64(p, r);
}
/* Basic algorithms for testing of optimized algorithms */
static void xor128 (uint64_t *a, uint64_t *b)
{
*a++ ^= *b++;
*a ^= *b;
}
static void shl128 (uint8_t *a)
{
int i, x = 0, xx;
for (i = 15; i >= 0; i--)
{
xx = (a[i] & 0x80) >> 7;
a[i] = (a[i] << 1) | x;
x = xx;
}
}
static void GfMul128Basic (uint8_t *a, uint8_t *b, uint8_t *p)
{
int i;
uint8_t la[16];
memcpy (la, a, 16);
memset (p, 0, 16);
for (i = 0; i < 128; i++)
{
if (IsBitSet128 (i, b))
xor128 ((uint64_t *)p, (uint64_t *)la);
if (la[0] & 0x80)
{
shl128 (la);
la[15] ^= 0x87;
}
else
{
shl128 (la);
}
}
}
static void xor64 (uint64_t *a, uint64_t *b)
{
*a ^= *b;
}
static void shl64 (uint8_t *a)
{
int i, x = 0, xx;
for (i = 7; i >= 0; i--)
{
xx = (a[i] & 0x80) >> 7;
a[i] = (a[i] << 1) | x;
x = xx;
}
}
static void GfMul64Basic (uint8_t *a, uint8_t *b, uint8_t* p)
{
/* Deprecated/legacy */
int i;
uint8_t la[8];
memcpy (la, a, 8);
memset (p, 0, 8);
for (i = 0; i < 64; i++)
{
if (IsBitSet64 (i, b))
xor64 ((uint64_t *)p, (uint64_t *)la);
if (la[0] & 0x80)
{
shl64 (la);
la[7] ^= 0x1b;
}
else
{
shl64 (la);
}
}
}
int GfMulSelfTest (void)
{
int result = 1;
uint8_t a[16];
uint8_t b[16];
uint8_t p1[16];
uint8_t p2[16];
GfCtx *gfCtx = (GfCtx *) TCalloc (sizeof (GfCtx));
int i, j;
if (!gfCtx)
return 0;
/* GF(2^64) - deprecated/legacy */
for (i = 0; i < 0x100; i++)
{
for (j = 0; j < 8; j++)
{
a[j] = (uint8_t) i;
b[j] = a[j] ^ 0xff;
}
GfMul64Basic (a, b, p1);
Gf64TabInit (a, gfCtx);
Gf64MulTab (b, p2, gfCtx);
if (memcmp (p1, p2, 8) != 0)
result = 0;
}
/* GF(2^128) */
for (i = 0; i < 0x100; i++)
{
for (j = 0; j < 16; j++)
{
a[j] = (uint8_t) i;
b[j] = j < 8 ? 0 : a[j] ^ 0xff;
}
GfMul128Basic (a, b, p1);
Gf128Tab64Init (a, gfCtx);
Gf128MulBy64Tab (b + 8, p2, gfCtx);
if (memcmp (p1, p2, 16) != 0)
result = 0;
}
TCfree (gfCtx);
return result;
}
#if defined(__cplusplus)
}
#endif

78
src/utils/common/gfmul.h Normal file
View File

@@ -0,0 +1,78 @@
/*
---------------------------------------------------------------------------
Copyright (c) 2003, Dr Brian Gladman, Worcester, UK. All rights reserved.
LICENSE TERMS
The free distribution and use of this software is allowed (with or without
changes) provided that:
1. source code distributions include the above copyright notice, this
list of conditions and the following disclaimer;
2. binary distributions include the above copyright notice, this list
of conditions and the following disclaimer in their documentation;
3. the name of the copyright holder is not used to endorse products
built using this software without specific written permission.
DISCLAIMER
This software is provided 'as is' with no explicit or implied warranties
in respect of its properties, including, but not limited to, correctness
and/or fitness for purpose.
---------------------------------------------------------------------------
Issue Date: 31/01/2004
*/
/* Adapted for TrueCrypt by the TrueCrypt Foundation */
#ifndef _GCM_H
#define _GCM_H
#include <inttypes.h>
#include "tcdefs.h"
#if defined(__cplusplus)
extern "C"
{
#endif
#define CBLK_LEN 16 /* encryption block length */
#define CBLK_LEN8 8
typedef struct
{
uint32_t gf_t8k[CBLK_LEN * 2][16][CBLK_LEN / 4];
} GfCtx8k;
typedef struct
{
uint32_t gf_t4k[CBLK_LEN8 * 2][16][CBLK_LEN / 4];
} GfCtx4k64;
typedef struct
{
/* union not used to support faster mounting */
uint32_t gf_t128[CBLK_LEN * 2 / 2][16][CBLK_LEN / 4];
uint32_t gf_t64[CBLK_LEN8 * 2][16][CBLK_LEN8 / 4];
} GfCtx;
typedef int ret_type;
void GfMul128 (void *a, const void* b);
void GfMul128Tab(unsigned char a[16], GfCtx8k *ctx);
int Gf128Tab64Init (uint8_t *a, GfCtx *ctx);
void Gf128MulBy64Tab (uint8_t a[8], uint8_t p[16], GfCtx *ctx);
int Gf64TabInit (uint8_t *a, GfCtx *ctx);
void Gf64MulTab (unsigned char a[8], unsigned char p[8], GfCtx *ctx);
void MirrorBits128 (uint8_t *a);
void MirrorBits64 (uint8_t *a);
int GfMulSelfTest (void);
#if defined(__cplusplus)
}
#endif
#endif

View File

@@ -0,0 +1,39 @@
/*
Legal Notice: Some portions of the source code contained in this file were
derived from the source code of Encryption for the Masses 2.02a, which is
Copyright (c) 1998-2000 Paul Le Roux and which is governed by the 'License
Agreement for Encryption for the Masses'. Modifications and additions to
the original source code (contained in this file) and all other portions of
this file are Copyright (c) 2003-2008 TrueCrypt Foundation and are governed
by the TrueCrypt License 2.4 the full text of which is contained in the
file License.txt included in TrueCrypt binary and source code distribution
packages. */
#ifndef PASSWORD_H
#define PASSWORD_H
#include <inttypes.h>
// User text input limits
#define MIN_PASSWORD 1 // Minimum password length
#define MAX_PASSWORD 64 // Maximum password length
#define PASSWORD_LEN_WARNING 20 // Display a warning when a password is shorter than this
#ifdef __cplusplus
extern "C" {
#endif
typedef struct
{
// Modifying this structure can introduce incompatibility with previous versions
int32_t Length;
unsigned char Text[MAX_PASSWORD + 1];
char Pad[3]; // keep 64-bit alignment
} Password;
#ifdef __cplusplus
}
#endif
#endif // PASSWORD_H

631
src/utils/common/pkcs5.c Normal file
View File

@@ -0,0 +1,631 @@
/*
Legal Notice: Some portions of the source code contained in this file were
derived from the source code of Encryption for the Masses 2.02a, which is
Copyright (c) 1998-2000 Paul Le Roux and which is governed by the 'License
Agreement for Encryption for the Masses'. Modifications and additions to
the original source code (contained in this file) and all other portions of
this file are Copyright (c) 2003-2008 TrueCrypt Foundation and are governed
by the TrueCrypt License 2.4 the full text of which is contained in the
file License.txt included in TrueCrypt binary and source code distribution
packages. */
#include "tcdefs.h"
#include <memory.h>
#include "../crypto/rmd160.h"
#include "../crypto/sha1.h"
#include "../crypto/sha2.h"
#include "../crypto/whirlpool.h"
#include "pkcs5.h"
#include "crypto.h"
void hmac_truncate
(
char *d1, /* data to be truncated */
char *d2, /* truncated data */
int len /* length in bytes to keep */
)
{
int i;
for (i = 0; i < len; i++)
d2[i] = d1[i];
}
void hmac_sha512
(
char *k, /* secret key */
int lk, /* length of the key in bytes */
char *d, /* data */
int ld, /* length of data in bytes */
char *out, /* output buffer, at least "t" bytes */
int t
)
{
sha512_ctx ictx, octx;
char isha[SHA512_DIGESTSIZE], osha[SHA512_DIGESTSIZE];
char key[SHA512_DIGESTSIZE];
char buf[SHA512_BLOCKSIZE];
int i;
/* If the key is longer than the hash algorithm block size,
let key = sha512(key), as per HMAC specifications. */
if (lk > SHA512_BLOCKSIZE)
{
sha512_ctx tctx;
sha512_begin (&tctx);
sha512_hash ((unsigned char *) k, lk, &tctx);
sha512_end ((unsigned char *) key, &tctx);
k = key;
lk = SHA512_DIGESTSIZE;
burn (&tctx, sizeof(tctx)); // Prevent leaks
}
/**** Inner Digest ****/
sha512_begin (&ictx);
/* Pad the key for inner digest */
for (i = 0; i < lk; ++i)
buf[i] = (char) (k[i] ^ 0x36);
for (i = lk; i < SHA512_BLOCKSIZE; ++i)
buf[i] = 0x36;
sha512_hash ((unsigned char *) buf, SHA512_BLOCKSIZE, &ictx);
sha512_hash ((unsigned char *) d, ld, &ictx);
sha512_end ((unsigned char *) isha, &ictx);
/**** Outer Digest ****/
sha512_begin (&octx);
for (i = 0; i < lk; ++i)
buf[i] = (char) (k[i] ^ 0x5C);
for (i = lk; i < SHA512_BLOCKSIZE; ++i)
buf[i] = 0x5C;
sha512_hash ((unsigned char *) buf, SHA512_BLOCKSIZE, &octx);
sha512_hash ((unsigned char *) isha, SHA512_DIGESTSIZE, &octx);
sha512_end ((unsigned char *) osha, &octx);
/* truncate and print the results */
t = t > SHA512_DIGESTSIZE ? SHA512_DIGESTSIZE : t;
hmac_truncate (osha, out, t);
/* Prevent leaks */
burn (&ictx, sizeof(ictx));
burn (&octx, sizeof(octx));
burn (isha, sizeof(isha));
burn (osha, sizeof(osha));
burn (buf, sizeof(buf));
burn (key, sizeof(key));
}
void derive_u_sha512 (char *pwd, int pwd_len, char *salt, int salt_len, int iterations, char *u, int b)
{
char j[SHA512_DIGESTSIZE], k[SHA512_DIGESTSIZE];
char init[128];
char counter[4];
int c, i;
/* iteration 1 */
memset (counter, 0, 4);
counter[3] = (char) b;
memcpy (init, salt, salt_len); /* salt */
memcpy (&init[salt_len], counter, 4); /* big-endian block number */
hmac_sha512 (pwd, pwd_len, init, salt_len + 4, j, SHA512_DIGESTSIZE);
memcpy (u, j, SHA512_DIGESTSIZE);
/* remaining iterations */
for (c = 1; c < iterations; c++)
{
hmac_sha512 (pwd, pwd_len, j, SHA512_DIGESTSIZE, k, SHA512_DIGESTSIZE);
for (i = 0; i < SHA512_DIGESTSIZE; i++)
{
u[i] ^= k[i];
j[i] = k[i];
}
}
/* Prevent possible leaks. */
burn (j, sizeof(j));
burn (k, sizeof(k));
}
void derive_key_sha512 (char *pwd, int pwd_len, char *salt, int salt_len, int iterations, char *dk, int dklen)
{
char u[SHA512_DIGESTSIZE];
int b, l, r;
if (dklen % SHA512_DIGESTSIZE)
{
l = 1 + dklen / SHA512_DIGESTSIZE;
}
else
{
l = dklen / SHA512_DIGESTSIZE;
}
r = dklen - (l - 1) * SHA512_DIGESTSIZE;
/* first l - 1 blocks */
for (b = 1; b < l; b++)
{
derive_u_sha512 (pwd, pwd_len, salt, salt_len, iterations, u, b);
memcpy (dk, u, SHA512_DIGESTSIZE);
dk += SHA512_DIGESTSIZE;
}
/* last block */
derive_u_sha512 (pwd, pwd_len, salt, salt_len, iterations, u, b);
memcpy (dk, u, r);
/* Prevent possible leaks. */
burn (u, sizeof(u));
}
/* Deprecated/legacy */
void hmac_sha1
(
char *k, /* secret key */
int lk, /* length of the key in bytes */
char *d, /* data */
int ld, /* length of data in bytes */
char *out, /* output buffer, at least "t" bytes */
int t
)
{
sha1_ctx ictx, octx;
char isha[SHA1_DIGESTSIZE], osha[SHA1_DIGESTSIZE];
char key[SHA1_DIGESTSIZE];
char buf[SHA1_BLOCKSIZE];
int i;
/* If the key is longer than the hash algorithm block size,
let key = sha1(key), as per HMAC specifications. */
if (lk > SHA1_BLOCKSIZE)
{
sha1_ctx tctx;
sha1_begin (&tctx);
sha1_hash ((unsigned char *) k, lk, &tctx);
sha1_end ((unsigned char *) key, &tctx);
k = key;
lk = SHA1_DIGESTSIZE;
burn (&tctx, sizeof(tctx)); // Prevent leaks
}
/**** Inner Digest ****/
sha1_begin (&ictx);
/* Pad the key for inner digest */
for (i = 0; i < lk; ++i)
buf[i] = (char) (k[i] ^ 0x36);
for (i = lk; i < SHA1_BLOCKSIZE; ++i)
buf[i] = 0x36;
sha1_hash ((unsigned char *) buf, SHA1_BLOCKSIZE, &ictx);
sha1_hash ((unsigned char *) d, ld, &ictx);
sha1_end ((unsigned char *) isha, &ictx);
/**** Outer Digest ****/
sha1_begin (&octx);
for (i = 0; i < lk; ++i)
buf[i] = (char) (k[i] ^ 0x5C);
for (i = lk; i < SHA1_BLOCKSIZE; ++i)
buf[i] = 0x5C;
sha1_hash ((unsigned char *) buf, SHA1_BLOCKSIZE, &octx);
sha1_hash ((unsigned char *) isha, SHA1_DIGESTSIZE, &octx);
sha1_end ((unsigned char *) osha, &octx);
/* truncate and print the results */
t = t > SHA1_DIGESTSIZE ? SHA1_DIGESTSIZE : t;
hmac_truncate (osha, out, t);
/* Prevent leaks */
burn (&ictx, sizeof(ictx));
burn (&octx, sizeof(octx));
burn (isha, sizeof(isha));
burn (osha, sizeof(osha));
burn (buf, sizeof(buf));
burn (key, sizeof(key));
}
/* Deprecated/legacy */
void derive_u_sha1 (char *pwd, int pwd_len, char *salt, int salt_len, int iterations, char *u, int b)
{
char j[SHA1_DIGESTSIZE], k[SHA1_DIGESTSIZE];
char init[128];
char counter[4];
int c, i;
/* iteration 1 */
memset (counter, 0, 4);
counter[3] = (char) b;
memcpy (init, salt, salt_len); /* salt */
memcpy (&init[salt_len], counter, 4); /* big-endian block number */
hmac_sha1 (pwd, pwd_len, init, salt_len + 4, j, SHA1_DIGESTSIZE);
memcpy (u, j, SHA1_DIGESTSIZE);
/* remaining iterations */
for (c = 1; c < iterations; c++)
{
hmac_sha1 (pwd, pwd_len, j, SHA1_DIGESTSIZE, k, SHA1_DIGESTSIZE);
for (i = 0; i < SHA1_DIGESTSIZE; i++)
{
u[i] ^= k[i];
j[i] = k[i];
}
}
/* Prevent possible leaks. */
burn (j, sizeof(j));
burn (k, sizeof(k));
}
/* Deprecated/legacy */
void derive_key_sha1 (char *pwd, int pwd_len, char *salt, int salt_len, int iterations, char *dk, int dklen)
{
char u[SHA1_DIGESTSIZE];
int b, l, r;
if (dklen % SHA1_DIGESTSIZE)
{
l = 1 + dklen / SHA1_DIGESTSIZE;
}
else
{
l = dklen / SHA1_DIGESTSIZE;
}
r = dklen - (l - 1) * SHA1_DIGESTSIZE;
/* first l - 1 blocks */
for (b = 1; b < l; b++)
{
derive_u_sha1 (pwd, pwd_len, salt, salt_len, iterations, u, b);
memcpy (dk, u, SHA1_DIGESTSIZE);
dk += SHA1_DIGESTSIZE;
}
/* last block */
derive_u_sha1 (pwd, pwd_len, salt, salt_len, iterations, u, b);
memcpy (dk, u, r);
/* Prevent possible leaks. */
burn (u, sizeof(u));
}
void hmac_ripemd160 (char *key, int keylen, char *input, int len, char *digest)
{
RMD160_CTX context;
unsigned char k_ipad[65]; /* inner padding - key XORd with ipad */
unsigned char k_opad[65]; /* outer padding - key XORd with opad */
unsigned char tk[RIPEMD160_DIGESTSIZE];
int i;
/* If the key is longer than the hash algorithm block size,
let key = ripemd160(key), as per HMAC specifications. */
if (keylen > RIPEMD160_BLOCKSIZE)
{
RMD160_CTX tctx;
RMD160Init(&tctx);
RMD160Update(&tctx, (const uint8_t *) key, keylen);
RMD160Final(tk, &tctx);
key = (char *) tk;
keylen = RIPEMD160_DIGESTSIZE;
burn (&tctx, sizeof(tctx)); // Prevent leaks
}
/*
RMD160(K XOR opad, RMD160(K XOR ipad, text))
where K is an n byte key
ipad is the byte 0x36 repeated RIPEMD160_BLOCKSIZE times
opad is the byte 0x5c repeated RIPEMD160_BLOCKSIZE times
and text is the data being protected */
/* start out by storing key in pads */
memset(k_ipad, 0x36, sizeof(k_ipad));
memset(k_opad, 0x5c, sizeof(k_opad));
/* XOR key with ipad and opad values */
for (i=0; i<keylen; i++)
{
k_ipad[i] ^= key[i];
k_opad[i] ^= key[i];
}
/* perform inner RIPEMD-160 */
RMD160Init(&context); /* init context for 1st pass */
RMD160Update(&context, k_ipad, RIPEMD160_BLOCKSIZE); /* start with inner pad */
RMD160Update(&context, (uint8_t *) input, len); /* then text of datagram */
RMD160Final((uint8_t *) digest, &context); /* finish up 1st pass */
/* perform outer RIPEMD-160 */
RMD160Init(&context); /* init context for 2nd pass */
RMD160Update(&context, k_opad, RIPEMD160_BLOCKSIZE); /* start with outer pad */
/* results of 1st hash */
RMD160Update(&context, (uint8_t *) digest, RIPEMD160_DIGESTSIZE);
RMD160Final((uint8_t *) digest, &context); /* finish up 2nd pass */
/* Prevent possible leaks. */
burn (k_ipad, sizeof(k_ipad));
burn (k_opad, sizeof(k_opad));
burn (tk, sizeof(tk));
burn (&context, sizeof(context));
}
void derive_u_ripemd160 (char *pwd, int pwd_len, char *salt, int salt_len, int iterations, char *u, int b)
{
char j[RIPEMD160_DIGESTSIZE], k[RIPEMD160_DIGESTSIZE];
char init[128];
char counter[4];
int c, i;
/* iteration 1 */
memset (counter, 0, 4);
counter[3] = (char) b;
memcpy (init, salt, salt_len); /* salt */
memcpy (&init[salt_len], counter, 4); /* big-endian block number */
hmac_ripemd160 (pwd, pwd_len, init, salt_len + 4, j);
memcpy (u, j, RIPEMD160_DIGESTSIZE);
/* remaining iterations */
for (c = 1; c < iterations; c++)
{
hmac_ripemd160 (pwd, pwd_len, j, RIPEMD160_DIGESTSIZE, k);
for (i = 0; i < RIPEMD160_DIGESTSIZE; i++)
{
u[i] ^= k[i];
j[i] = k[i];
}
}
/* Prevent possible leaks. */
burn (j, sizeof(j));
burn (k, sizeof(k));
}
void derive_key_ripemd160 (char *pwd, int pwd_len, char *salt, int salt_len, int iterations, char *dk, int dklen)
{
char u[RIPEMD160_DIGESTSIZE];
int b, l, r;
if (dklen % RIPEMD160_DIGESTSIZE)
{
l = 1 + dklen / RIPEMD160_DIGESTSIZE;
}
else
{
l = dklen / RIPEMD160_DIGESTSIZE;
}
r = dklen - (l - 1) * RIPEMD160_DIGESTSIZE;
/* first l - 1 blocks */
for (b = 1; b < l; b++)
{
derive_u_ripemd160 (pwd, pwd_len, salt, salt_len, iterations, u, b);
memcpy (dk, u, RIPEMD160_DIGESTSIZE);
dk += RIPEMD160_DIGESTSIZE;
}
/* last block */
derive_u_ripemd160 (pwd, pwd_len, salt, salt_len, iterations, u, b);
memcpy (dk, u, r);
/* Prevent possible leaks. */
burn (u, sizeof(u));
}
void hmac_whirlpool
(
char *k, /* secret key */
int lk, /* length of the key in bytes */
char *d, /* data */
int ld, /* length of data in bytes */
char *out, /* output buffer, at least "t" bytes */
int t
)
{
WHIRLPOOL_CTX ictx, octx;
char iwhi[WHIRLPOOL_DIGESTSIZE], owhi[WHIRLPOOL_DIGESTSIZE];
char key[WHIRLPOOL_DIGESTSIZE];
char buf[WHIRLPOOL_BLOCKSIZE];
int i;
/* If the key is longer than the hash algorithm block size,
let key = whirlpool(key), as per HMAC specifications. */
if (lk > WHIRLPOOL_BLOCKSIZE)
{
WHIRLPOOL_CTX tctx;
WHIRLPOOL_init (&tctx);
WHIRLPOOL_add ((unsigned char *) k, lk * 8, &tctx);
WHIRLPOOL_finalize (&tctx, (unsigned char *) key);
k = key;
lk = WHIRLPOOL_DIGESTSIZE;
burn (&tctx, sizeof(tctx)); // Prevent leaks
}
/**** Inner Digest ****/
WHIRLPOOL_init (&ictx);
/* Pad the key for inner digest */
for (i = 0; i < lk; ++i)
buf[i] = (char) (k[i] ^ 0x36);
for (i = lk; i < WHIRLPOOL_BLOCKSIZE; ++i)
buf[i] = 0x36;
WHIRLPOOL_add ((unsigned char *) buf, WHIRLPOOL_BLOCKSIZE * 8, &ictx);
WHIRLPOOL_add ((unsigned char *) d, ld * 8, &ictx);
WHIRLPOOL_finalize (&ictx, (unsigned char *) iwhi);
/**** Outer Digest ****/
WHIRLPOOL_init (&octx);
for (i = 0; i < lk; ++i)
buf[i] = (char) (k[i] ^ 0x5C);
for (i = lk; i < WHIRLPOOL_BLOCKSIZE; ++i)
buf[i] = 0x5C;
WHIRLPOOL_add ((unsigned char *) buf, WHIRLPOOL_BLOCKSIZE * 8, &octx);
WHIRLPOOL_add ((unsigned char *) iwhi, WHIRLPOOL_DIGESTSIZE * 8, &octx);
WHIRLPOOL_finalize (&octx, (unsigned char *) owhi);
/* truncate and print the results */
t = t > WHIRLPOOL_DIGESTSIZE ? WHIRLPOOL_DIGESTSIZE : t;
hmac_truncate (owhi, out, t);
/* Prevent possible leaks. */
burn (&ictx, sizeof(ictx));
burn (&octx, sizeof(octx));
burn (owhi, sizeof(owhi));
burn (iwhi, sizeof(iwhi));
burn (buf, sizeof(buf));
burn (key, sizeof(key));
}
void derive_u_whirlpool (char *pwd, int pwd_len, char *salt, int salt_len, int iterations, char *u, int b)
{
char j[WHIRLPOOL_DIGESTSIZE], k[WHIRLPOOL_DIGESTSIZE];
char init[128];
char counter[4];
int c, i;
/* iteration 1 */
memset (counter, 0, 4);
counter[3] = (char) b;
memcpy (init, salt, salt_len); /* salt */
memcpy (&init[salt_len], counter, 4); /* big-endian block number */
hmac_whirlpool (pwd, pwd_len, init, salt_len + 4, j, WHIRLPOOL_DIGESTSIZE);
memcpy (u, j, WHIRLPOOL_DIGESTSIZE);
/* remaining iterations */
for (c = 1; c < iterations; c++)
{
hmac_whirlpool (pwd, pwd_len, j, WHIRLPOOL_DIGESTSIZE, k, WHIRLPOOL_DIGESTSIZE);
for (i = 0; i < WHIRLPOOL_DIGESTSIZE; i++)
{
u[i] ^= k[i];
j[i] = k[i];
}
}
/* Prevent possible leaks. */
burn (j, sizeof(j));
burn (k, sizeof(k));
}
void derive_key_whirlpool (char *pwd, int pwd_len, char *salt, int salt_len, int iterations, char *dk, int dklen)
{
char u[WHIRLPOOL_DIGESTSIZE];
int b, l, r;
if (dklen % WHIRLPOOL_DIGESTSIZE)
{
l = 1 + dklen / WHIRLPOOL_DIGESTSIZE;
}
else
{
l = dklen / WHIRLPOOL_DIGESTSIZE;
}
r = dklen - (l - 1) * WHIRLPOOL_DIGESTSIZE;
/* first l - 1 blocks */
for (b = 1; b < l; b++)
{
derive_u_whirlpool (pwd, pwd_len, salt, salt_len, iterations, u, b);
memcpy (dk, u, WHIRLPOOL_DIGESTSIZE);
dk += WHIRLPOOL_DIGESTSIZE;
}
/* last block */
derive_u_whirlpool (pwd, pwd_len, salt, salt_len, iterations, u, b);
memcpy (dk, u, r);
/* Prevent possible leaks. */
burn (u, sizeof(u));
}
char *get_pkcs5_prf_name (int pkcs5_prf_id)
{
switch (pkcs5_prf_id)
{
case SHA512:
return "HMAC-SHA-512";
case SHA1: // Deprecated/legacy
return "HMAC-SHA-1";
case RIPEMD160:
return "HMAC-RIPEMD-160";
case WHIRLPOOL:
return "HMAC-Whirlpool";
default:
return "(Unknown)";
}
}
int get_pkcs5_iteration_count (int pkcs5_prf_id, int bBoot)
{
switch (pkcs5_prf_id)
{
case RIPEMD160:
return (bBoot ? 1000 : 2000);
case SHA512:
return 1000;
case SHA1: // Deprecated/legacy
return 2000;
case WHIRLPOOL:
return 1000;
default:
TC_THROW_FATAL_EXCEPTION; // Unknown/wrong ID
}
return 0;
}

41
src/utils/common/pkcs5.h Normal file
View File

@@ -0,0 +1,41 @@
/*
Legal Notice: Some portions of the source code contained in this file were
derived from the source code of Encryption for the Masses 2.02a, which is
Copyright (c) 1998-2000 Paul Le Roux and which is governed by the 'License
Agreement for Encryption for the Masses'. Modifications and additions to
the original source code (contained in this file) and all other portions of
this file are Copyright (c) 2003-2008 TrueCrypt Foundation and are governed
by the TrueCrypt License 2.4 the full text of which is contained in the
file License.txt included in TrueCrypt binary and source code distribution
packages. */
#ifndef TC_HEADER_PKCS5
#define TC_HEADER_PKCS5
#include "tcdefs.h"
#if defined(__cplusplus)
extern "C"
{
#endif
void hmac_sha512 (char *k, int lk, char *d, int ld, char *out, int t);
void derive_u_sha512 (char *pwd, int pwd_len, char *salt, int salt_len, int iterations, char *u, int b);
void derive_key_sha512 (char *pwd, int pwd_len, char *salt, int salt_len, int iterations, char *dk, int dklen);
void hmac_sha1 (char *k, int lk, char *d, int ld, char *out, int t);
void derive_u_sha1 (char *pwd, int pwd_len, char *salt, int salt_len, int iterations, char *u, int b);
void derive_key_sha1 (char *pwd, int pwd_len, char *salt, int salt_len, int iterations, char *dk, int dklen);
void hmac_ripemd160 (char *key, int keylen, char *input, int len, char *digest);
void derive_u_ripemd160 (char *pwd, int pwd_len, char *salt, int salt_len, int iterations, char *u, int b);
void derive_key_ripemd160 (char *pwd, int pwd_len, char *salt, int salt_len, int iterations, char *dk, int dklen);
void hmac_whirlpool (char *k, int lk, char *d, int ld, char *out, int t);
void derive_u_whirlpool (char *pwd, int pwd_len, char *salt, int salt_len, int iterations, char *u, int b);
void derive_key_whirlpool (char *pwd, int pwd_len, char *salt, int salt_len, int iterations, char *dk, int dklen);
int get_pkcs5_iteration_count (int pkcs5_prf_id, int bBoot);
char *get_pkcs5_prf_name (int pkcs5_prf_id);
#if defined(__cplusplus)
}
#endif
#endif // TC_HEADER_PKCS5

167
src/utils/common/tcdefs.h Normal file
View File

@@ -0,0 +1,167 @@
/*
Legal Notice: Some portions of the source code contained in this file were
derived from the source code of Encryption for the Masses 2.02a, which is
Copyright (c) 1998-2000 Paul Le Roux and which is governed by the 'License
Agreement for Encryption for the Masses'. Modifications and additions to
the original source code (contained in this file) and all other portions of
this file are Copyright (c) 2003-2008 TrueCrypt Foundation and are governed
by the TrueCrypt License 2.4 the full text of which is contained in the
file License.txt included in TrueCrypt binary and source code distribution
packages. */
#ifndef TCDEFS_H
#define TCDEFS_H
#include <inttypes.h>
#include <stdlib.h>
#define TC_APP_NAME "TrueCrypt"
// Version displayed to user
#define VERSION_STRING "5.1a"
// Version number to compare against driver
#define VERSION_NUM 0x051a
// Version number written to volume header during format,
// specifies the minimum program version required to mount the volume
#define VOL_REQ_PROG_VERSION 0x0500
// Volume header version
#define VOLUME_HEADER_VERSION 0x0003
// Sector size of encrypted filesystem, which may differ from sector size
// of host filesystem/device (this is fully supported since v4.3).
#define SECTOR_SIZE 512
#define BYTES_PER_KB 1024LL
#define BYTES_PER_MB 1048576LL
#define BYTES_PER_GB 1073741824LL
#define BYTES_PER_TB 1099511627776LL
#define BYTES_PER_PB 1125899906842624LL
/* GUI/driver errors */
#define MAX_128BIT_BLOCK_VOLUME_SIZE BYTES_PER_PB // Security bound (128-bit block XTS mode)
#define MAX_VOLUME_SIZE_GENERAL 0x7fffFFFFffffFFFFLL // Signed 64-bit integer file offset values
#define MAX_VOLUME_SIZE MAX_128BIT_BLOCK_VOLUME_SIZE
#define MIN_FAT_VOLUME_SIZE 19456
#define MAX_FAT_VOLUME_SIZE 0x20000000000LL
#define MIN_NTFS_VOLUME_SIZE 2634752
#define OPTIMAL_MIN_NTFS_VOLUME_SIZE (4 * BYTES_PER_GB)
#define MAX_NTFS_VOLUME_SIZE (128LL * BYTES_PER_TB) // NTFS volume can theoretically be up to 16 exabytes, but Windows XP and 2003 limit the size to that addressable with 32-bit clusters, i.e. max size is 128 TB (if 64-KB clusters are used).
#define MAX_HIDDEN_VOLUME_HOST_SIZE MAX_NTFS_VOLUME_SIZE
#define MAX_HIDDEN_VOLUME_SIZE ( MAX_HIDDEN_VOLUME_HOST_SIZE - HIDDEN_VOL_HEADER_OFFSET - HEADER_SIZE )
#define MIN_VOLUME_SIZE MIN_FAT_VOLUME_SIZE
#define MIN_HIDDEN_VOLUME_HOST_SIZE ( MIN_VOLUME_SIZE * 2 + HIDDEN_VOL_HEADER_OFFSET + HEADER_SIZE )
#ifndef TC_NO_COMPILER_INT64
#if MAX_VOLUME_SIZE > MAX_VOLUME_SIZE_GENERAL
#error MAX_VOLUME_SIZE must be less than or equal to MAX_VOLUME_SIZE_GENERAL
#endif
#endif
#define TCalloc(X) calloc(1, X)
#define TCfree free
#define WIDE(x) (LPWSTR)L##x
typedef int8_t int8;
typedef int16_t int16;
typedef int32_t int32;
typedef uint8_t byte;
typedef uint16_t uint16;
typedef uint32_t uint32;
#ifdef TC_NO_COMPILER_INT64
typedef uint32_t TC_LARGEST_COMPILER_UINT;
#else
typedef uint64_t TC_LARGEST_COMPILER_UINT;
typedef int64_t int64;
typedef uint64_t uint64;
#endif
// Needed by Cryptolib
typedef uint8_t uint_8t;
typedef uint16_t uint_16t;
typedef uint32_t uint_32t;
#ifndef TC_NO_COMPILER_INT64
typedef uint64_t uint_64t;
#endif
typedef union
{
struct
{
uint32_t LowPart;
uint32_t HighPart;
};
#ifndef TC_NO_COMPILER_INT64
uint64_t Value;
#endif
} UINT64_STRUCT;
#define TC_THROW_FATAL_EXCEPTION *(char *) 0 = 0
#define burn(mem,size) do { volatile char *burnm = (volatile char *)(mem); int burnc = size; while (burnc--) *burnm++ = 0; } while (0)
// The size of the memory area to wipe is in bytes amd it must be a multiple of 8.
#ifndef TC_NO_COMPILER_INT64
# define FAST_ERASE64(mem,size) do { volatile uint64_t *burnm = (volatile uint64_t *)(mem); int burnc = size >> 3; while (burnc--) *burnm++ = 0; } while (0)
#else
# define FAST_ERASE64(mem,size) do { volatile uint32_t *burnm = (volatile uint32_t *)(mem); int burnc = size >> 2; while (burnc--) *burnm++ = 0; } while (0)
#endif
#ifdef MAX_PATH
#define TC_MAX_PATH MAX_PATH
#else
#define TC_MAX_PATH 260 /* Includes the null terminator */
#endif
#define MAX_URL_LENGTH 2084 /* Internet Explorer limit. Includes the terminating null character. */
enum
{
/* WARNING: Add any new codes at the end (do NOT insert them between existing). Do NOT delete any
existing codes. Changing these values or their meanings may cause incompatibility with other
versions (for example, if a new version of the TrueCrypt installer receives an error code from
an installed driver whose version is lower, it will interpret the error incorrectly). */
ERR_SUCCESS = 0,
ERR_OS_ERROR = 1,
ERR_OUTOFMEMORY,
ERR_PASSWORD_WRONG,
ERR_VOL_FORMAT_BAD,
ERR_DRIVE_NOT_FOUND,
ERR_FILES_OPEN,
ERR_VOL_SIZE_WRONG,
ERR_COMPRESSION_NOT_SUPPORTED,
ERR_PASSWORD_CHANGE_VOL_TYPE,
ERR_PASSWORD_CHANGE_VOL_VERSION,
ERR_VOL_SEEKING,
ERR_VOL_WRITING,
ERR_FILES_OPEN_LOCK,
ERR_VOL_READING,
ERR_DRIVER_VERSION,
ERR_NEW_VERSION_REQUIRED,
ERR_CIPHER_INIT_FAILURE,
ERR_CIPHER_INIT_WEAK_KEY,
ERR_SELF_TESTS_FAILED,
ERR_SECTOR_SIZE_INCOMPATIBLE,
ERR_VOL_ALREADY_MOUNTED,
ERR_NO_FREE_DRIVES,
ERR_FILE_OPEN_FAILED,
ERR_VOL_MOUNT_FAILED,
ERR_INVALID_DEVICE,
ERR_ACCESS_DENIED,
ERR_MODE_INIT_FAILED,
ERR_DONT_REPORT,
ERR_ENCRYPTION_NOT_COMPLETED,
ERR_PARAMETER_INCORRECT
};
#endif // #ifndef TCDEFS_H

627
src/utils/common/xts.c Normal file
View File

@@ -0,0 +1,627 @@
/*
Copyright (c) 2008 TrueCrypt Foundation. All rights reserved.
Governed by the TrueCrypt License 2.4 the full text of which is contained
in the file License.txt included in TrueCrypt binary and source code
distribution packages.
*/
/* For low-memory environments, define XTS_LOW_RESOURCE_VERSION, which will save
0.5 KB of RAM, but the speed will be 15-20% lower. However, on multi-core CPUs,
the XTS_LOW_RESOURCE_VERSION code might eventually be faster when parallelized,
because it processes the buffer continuously as a whole -- it does not divide the
buffer into data units (nevertheless, note that GenerateWhiteningValues supports
more than one data unit).
Note that when TC_NO_COMPILER_INT64 is defined, XTS_LOW_RESOURCE_VERSION is implicitly
defined as well (because the non-low-resource version needs 64-bit types).
For big-endian platforms (PowerPC, SPARC, etc.) define BYTE_ORDER as BIG_ENDIAN. */
#ifdef TC_MINIMIZE_CODE_SIZE
# define XTS_LOW_RESOURCE_VERSION
# pragma optimize ("tl", on)
#endif
#ifdef TC_NO_COMPILER_INT64
# ifndef XTS_LOW_RESOURCE_VERSION
# define XTS_LOW_RESOURCE_VERSION
# endif
#endif
#include "xts.h"
#ifndef XTS_LOW_RESOURCE_VERSION
// length: number of bytes to encrypt; may be larger than one data unit and must be divisible by the cipher block size
// ks: the primary key schedule
// ks2: the secondary key schedule
// startDataUnitNo: The sequential number of the data unit with which the buffer starts.
// startCipherBlockNo: The sequential number of the first plaintext block to encrypt inside the data unit startDataUnitNo.
// When encrypting the data unit from its first block, startCipherBlockNo is 0.
// The startCipherBlockNo value applies only to the first data unit in the buffer; each successive
// data unit is encrypted from its first block. The start of the buffer does not have to be
// aligned with the start of a data unit. If it is aligned, startCipherBlockNo must be 0; if it
// is not aligned, startCipherBlockNo must reflect the misalignment accordingly.
void EncryptBufferXTS (uint8_t *buffer,
TC_LARGEST_COMPILER_UINT length,
const UINT64_STRUCT *startDataUnitNo,
unsigned int startCipherBlockNo,
uint8_t *ks,
uint8_t *ks2,
int cipher)
{
uint8_t finalCarry;
uint8_t whiteningValues [ENCRYPTION_DATA_UNIT_SIZE];
uint8_t whiteningValue [BYTES_PER_XTS_BLOCK];
uint8_t byteBufUnitNo [BYTES_PER_XTS_BLOCK];
uint64_t *whiteningValuesPtr64 = (uint64_t *) whiteningValues;
uint64_t *whiteningValuePtr64 = (uint64_t *) whiteningValue;
uint64_t *bufPtr = (uint64_t *) buffer;
unsigned int startBlock = startCipherBlockNo, endBlock, block;
uint64_t *const finalInt64WhiteningValuesPtr = whiteningValuesPtr64 + sizeof (whiteningValues) / sizeof (*whiteningValuesPtr64) - 1;
TC_LARGEST_COMPILER_UINT blockCount, dataUnitNo;
/* The encrypted data unit number (i.e. the resultant ciphertext block) is to be multiplied in the
finite field GF(2^128) by j-th power of n, where j is the sequential plaintext/ciphertext block
number and n is 2, a primitive element of GF(2^128). This can be (and is) simplified and implemented
as a left shift of the preceding whitening value by one bit (with carry propagating). In addition, if
the shift of the highest byte results in a carry, 135 is XORed into the lowest byte. The value 135 is
derived from the modulus of the Galois Field (x^128+x^7+x^2+x+1). */
// Convert the 64-bit data unit number into a little-endian 16-byte array.
// Note that as we are converting a 64-bit number into a 16-byte array we can always zero the last 8 bytes.
dataUnitNo = startDataUnitNo->Value;
*((uint64_t *) byteBufUnitNo) = LE64 (dataUnitNo);
*((uint64_t *) byteBufUnitNo + 1) = 0;
if (length % BYTES_PER_XTS_BLOCK)
TC_THROW_FATAL_EXCEPTION;
blockCount = length / BYTES_PER_XTS_BLOCK;
// Process all blocks in the buffer
// When length > ENCRYPTION_DATA_UNIT_SIZE, this can be parallelized (one data unit per core)
while (blockCount > 0)
{
if (blockCount < BLOCKS_PER_XTS_DATA_UNIT)
endBlock = startBlock + (unsigned int) blockCount;
else
endBlock = BLOCKS_PER_XTS_DATA_UNIT;
whiteningValuesPtr64 = finalInt64WhiteningValuesPtr;
whiteningValuePtr64 = (uint64_t *) whiteningValue;
// Encrypt the data unit number using the secondary key (in order to generate the first
// whitening value for this data unit)
*whiteningValuePtr64 = *((uint64_t *) byteBufUnitNo);
*(whiteningValuePtr64 + 1) = 0;
EncipherBlock (cipher, whiteningValue, ks2);
// Generate subsequent whitening values for blocks in this data unit. Note that all generated 128-bit
// whitening values are stored in memory as a sequence of 64-bit integers in reverse order.
for (block = 0; block < endBlock; block++)
{
if (block >= startBlock)
{
*whiteningValuesPtr64-- = *whiteningValuePtr64++;
*whiteningValuesPtr64-- = *whiteningValuePtr64;
}
else
whiteningValuePtr64++;
// Derive the next whitening value
#if BYTE_ORDER == LITTLE_ENDIAN
// Little-endian platforms (Intel, AMD, etc.)
finalCarry =
(*whiteningValuePtr64 & 0x8000000000000000) ?
135 : 0;
*whiteningValuePtr64-- <<= 1;
if (*whiteningValuePtr64 & 0x8000000000000000)
*(whiteningValuePtr64 + 1) |= 1;
*whiteningValuePtr64 <<= 1;
#else
// Big-endian platforms (PowerPC, Motorola, etc.)
finalCarry =
(*whiteningValuePtr64 & 0x80) ?
135 : 0;
*whiteningValuePtr64 = LE64 (LE64 (*whiteningValuePtr64) << 1);
whiteningValuePtr64--;
if (*whiteningValuePtr64 & 0x80)
*(whiteningValuePtr64 + 1) |= 0x0100000000000000;
*whiteningValuePtr64 = LE64 (LE64 (*whiteningValuePtr64) << 1);
#endif
whiteningValue[0] ^= finalCarry;
}
whiteningValuesPtr64 = finalInt64WhiteningValuesPtr;
// Encrypt all blocks in this data unit
// TO DO: This should be parallelized (one block per core)
for (block = startBlock; block < endBlock; block++)
{
// Pre-whitening
*bufPtr++ ^= *whiteningValuesPtr64--;
*bufPtr-- ^= *whiteningValuesPtr64++;
// Actual encryption
EncipherBlock (cipher, bufPtr, ks);
// Post-whitening
*bufPtr++ ^= *whiteningValuesPtr64--;
*bufPtr++ ^= *whiteningValuesPtr64--;
blockCount--;
}
startBlock = 0;
dataUnitNo++;
*((uint64_t *) byteBufUnitNo) = LE64 (dataUnitNo);
}
FAST_ERASE64 (whiteningValue, sizeof(whiteningValue));
FAST_ERASE64 (whiteningValues, sizeof(whiteningValues));
}
// For descriptions of the input parameters, see EncryptBufferXTS().
void DecryptBufferXTS (uint8_t *buffer,
TC_LARGEST_COMPILER_UINT length,
const UINT64_STRUCT *startDataUnitNo,
unsigned int startCipherBlockNo,
uint8_t *ks,
uint8_t *ks2,
int cipher)
{
uint8_t finalCarry;
uint8_t whiteningValues [ENCRYPTION_DATA_UNIT_SIZE];
uint8_t whiteningValue [BYTES_PER_XTS_BLOCK];
uint8_t byteBufUnitNo [BYTES_PER_XTS_BLOCK];
uint64_t *whiteningValuesPtr64 = (uint64_t *) whiteningValues;
uint64_t *whiteningValuePtr64 = (uint64_t *) whiteningValue;
uint64_t *bufPtr = (uint64_t *) buffer;
unsigned int startBlock = startCipherBlockNo, endBlock, block;
uint64_t *const finalInt64WhiteningValuesPtr = whiteningValuesPtr64 + sizeof (whiteningValues) / sizeof (*whiteningValuesPtr64) - 1;
TC_LARGEST_COMPILER_UINT blockCount, dataUnitNo;
// Convert the 64-bit data unit number into a little-endian 16-byte array.
// Note that as we are converting a 64-bit number into a 16-byte array we can always zero the last 8 bytes.
dataUnitNo = startDataUnitNo->Value;
*((uint64_t *) byteBufUnitNo) = LE64 (dataUnitNo);
*((uint64_t *) byteBufUnitNo + 1) = 0;
if (length % BYTES_PER_XTS_BLOCK)
TC_THROW_FATAL_EXCEPTION;
blockCount = length / BYTES_PER_XTS_BLOCK;
// Process all blocks in the buffer
// When length > ENCRYPTION_DATA_UNIT_SIZE, this can be parallelized (one data unit per core)
while (blockCount > 0)
{
if (blockCount < BLOCKS_PER_XTS_DATA_UNIT)
endBlock = startBlock + (unsigned int) blockCount;
else
endBlock = BLOCKS_PER_XTS_DATA_UNIT;
whiteningValuesPtr64 = finalInt64WhiteningValuesPtr;
whiteningValuePtr64 = (uint64_t *) whiteningValue;
// Encrypt the data unit number using the secondary key (in order to generate the first
// whitening value for this data unit)
*whiteningValuePtr64 = *((uint64_t *) byteBufUnitNo);
*(whiteningValuePtr64 + 1) = 0;
EncipherBlock (cipher, whiteningValue, ks2);
// Generate subsequent whitening values for blocks in this data unit. Note that all generated 128-bit
// whitening values are stored in memory as a sequence of 64-bit integers in reverse order.
for (block = 0; block < endBlock; block++)
{
if (block >= startBlock)
{
*whiteningValuesPtr64-- = *whiteningValuePtr64++;
*whiteningValuesPtr64-- = *whiteningValuePtr64;
}
else
whiteningValuePtr64++;
// Derive the next whitening value
#if BYTE_ORDER == LITTLE_ENDIAN
// Little-endian platforms (Intel, AMD, etc.)
finalCarry =
(*whiteningValuePtr64 & 0x8000000000000000) ?
135 : 0;
*whiteningValuePtr64-- <<= 1;
if (*whiteningValuePtr64 & 0x8000000000000000)
*(whiteningValuePtr64 + 1) |= 1;
*whiteningValuePtr64 <<= 1;
#else
// Big-endian platforms (PowerPC, Motorola, etc.)
finalCarry =
(*whiteningValuePtr64 & 0x80) ?
135 : 0;
*whiteningValuePtr64 = LE64 (LE64 (*whiteningValuePtr64) << 1);
whiteningValuePtr64--;
if (*whiteningValuePtr64 & 0x80)
*(whiteningValuePtr64 + 1) |= 0x0100000000000000;
*whiteningValuePtr64 = LE64 (LE64 (*whiteningValuePtr64) << 1);
#endif
whiteningValue[0] ^= finalCarry;
}
whiteningValuesPtr64 = finalInt64WhiteningValuesPtr;
// Decrypt blocks in this data unit
// TO DO: This should be parallelized (one block per core)
for (block = startBlock; block < endBlock; block++)
{
*bufPtr++ ^= *whiteningValuesPtr64--;
*bufPtr-- ^= *whiteningValuesPtr64++;
DecipherBlock (cipher, bufPtr, ks);
*bufPtr++ ^= *whiteningValuesPtr64--;
*bufPtr++ ^= *whiteningValuesPtr64--;
blockCount--;
}
startBlock = 0;
dataUnitNo++;
*((uint64_t *) byteBufUnitNo) = LE64 (dataUnitNo);
}
FAST_ERASE64 (whiteningValue, sizeof(whiteningValue));
FAST_ERASE64 (whiteningValues, sizeof(whiteningValues));
}
#if 0 // The following function is currently unused but may be useful in future
// Generates XTS whitening values. Use this function if you need to generate whitening values for more than
// one data unit in one pass (the value 'length' may be greater than the data unit size). 'buffer' must point
// to the LAST 8 bytes of the buffer for the whitening values. Note that the generated 128-bit whitening values
// are stored in memory as a sequence of 64-bit integers in reverse order. For descriptions of the input
// parameters, see EncryptBufferXTS().
static void GenerateWhiteningValues (uint64_t *bufPtr64,
TC_LARGEST_COMPILER_UINT length,
const UINT64_STRUCT *startDataUnitNo,
unsigned int startBlock,
uint8_t *ks2,
int cipher)
{
unsigned int block;
unsigned int endBlock;
uint8_t byteBufUnitNo [BYTES_PER_XTS_BLOCK];
uint8_t whiteningValue [BYTES_PER_XTS_BLOCK];
uint64_t *whiteningValuePtr64 = (uint64_t *) whiteningValue;
uint8_t finalCarry;
uint64_t *const finalInt64WhiteningValuePtr = whiteningValuePtr64 + sizeof (whiteningValue) / sizeof (*whiteningValuePtr64) - 1;
TC_LARGEST_COMPILER_UINT blockCount, dataUnitNo;
dataUnitNo = startDataUnitNo->Value;
blockCount = length / BYTES_PER_XTS_BLOCK;
// Convert the 64-bit data unit number into a little-endian 16-byte array.
// Note that as we are converting a 64-bit number into a 16-byte array we can always zero the last 8 bytes.
*((uint64_t *) byteBufUnitNo) = LE64 (dataUnitNo);
*((uint64_t *) byteBufUnitNo + 1) = 0;
// Generate the whitening values.
// When length > ENCRYPTION_DATA_UNIT_SIZE, this can be parallelized (one data unit per core)
while (blockCount > 0)
{
if (blockCount < BLOCKS_PER_XTS_DATA_UNIT)
endBlock = startBlock + (unsigned int) blockCount;
else
endBlock = BLOCKS_PER_XTS_DATA_UNIT;
// Encrypt the data unit number using the secondary key (in order to generate the first
// whitening value for this data unit)
memcpy (whiteningValue, byteBufUnitNo, BYTES_PER_XTS_BLOCK);
EncipherBlock (cipher, whiteningValue, ks2);
// Process all blocks in this data unit
for (block = 0; block < endBlock; block++)
{
if (block >= startBlock)
{
whiteningValuePtr64 = (uint64_t *) whiteningValue;
*bufPtr64-- = *whiteningValuePtr64++;
*bufPtr64-- = *whiteningValuePtr64;
blockCount--;
}
// Derive the next whitening value
whiteningValuePtr64 = finalInt64WhiteningValuePtr;
#if BYTE_ORDER == LITTLE_ENDIAN
// Little-endian platforms (Intel, AMD, etc.)
finalCarry =
(*whiteningValuePtr64 & 0x8000000000000000) ?
135 : 0;
*whiteningValuePtr64-- <<= 1;
if (*whiteningValuePtr64 & 0x8000000000000000)
*(whiteningValuePtr64 + 1) |= 1;
*whiteningValuePtr64 <<= 1;
#else
// Big-endian platforms (PowerPC, Motorola, etc.)
finalCarry =
(*whiteningValuePtr64 & 0x80) ?
135 : 0;
*whiteningValuePtr64 = LE64 (LE64 (*whiteningValuePtr64) << 1);
whiteningValuePtr64--;
if (*whiteningValuePtr64 & 0x80)
*(whiteningValuePtr64 + 1) |= 0x0100000000000000;
*whiteningValuePtr64 = LE64 (LE64 (*whiteningValuePtr64) << 1);
#endif
whiteningValue[0] ^= finalCarry;
}
startBlock = 0;
dataUnitNo++;
// Convert the 64-bit data unit number into a little-endian 16-byte array.
*((uint64_t *) byteBufUnitNo) = LE64 (dataUnitNo);
}
FAST_ERASE64 (whiteningValue, sizeof(whiteningValue));
}
#endif // #if 0
#else // XTS_LOW_RESOURCE_VERSION
#if BYTE_ORDER == BIG_ENDIAN
#error XTS_LOW_RESOURCE_VERSION is not compatible with big-endian platforms
#endif
// Increases a 64-bit value by one in a way compatible with non-64-bit environments/platforms
static void IncUint64Struct (UINT64_STRUCT *uint64Struct)
{
#ifdef TC_NO_COMPILER_INT64
if (!++uint64Struct->LowPart)
{
uint64Struct->HighPart++;
}
#else
uint64Struct->Value++;
#endif
}
// Converts a 64-bit unsigned integer (passed as two 32-bit integers for compatibility with non-64-bit
// environments/platforms) into a little-endian 16-byte array.
static void Uint64ToLE16ByteArray (uint8_t *byteBuf, unsigned __int32 highInt32, unsigned __int32 lowInt32)
{
unsigned __int32 *bufPtr32 = (unsigned __int32 *) byteBuf;
*bufPtr32++ = lowInt32;
*bufPtr32++ = highInt32;
// We're converting a 64-bit number into a little-endian 16-byte array so we can zero the last 8 bytes
*bufPtr32++ = 0;
*bufPtr32 = 0;
}
// Generates and XORs XTS whitening values into blocks in the buffer.
// For descriptions of the input parameters, see EncryptBufferXTS().
static void WhiteningPass (uint8_t *buffer,
TC_LARGEST_COMPILER_UINT length,
const UINT64_STRUCT *startDataUnitNo,
unsigned int startBlock,
uint8_t *ks2,
int cipher)
{
TC_LARGEST_COMPILER_UINT blockCount;
UINT64_STRUCT dataUnitNo;
unsigned int block;
unsigned int endBlock;
uint8_t byteBufUnitNo [BYTES_PER_XTS_BLOCK];
uint8_t whiteningValue [BYTES_PER_XTS_BLOCK];
unsigned __int32 *bufPtr32 = (unsigned __int32 *) buffer;
unsigned __int32 *whiteningValuePtr32 = (unsigned __int32 *) whiteningValue;
uint8_t finalCarry;
unsigned __int32 *const finalDwordWhiteningValuePtr = whiteningValuePtr32 + sizeof (whiteningValue) / sizeof (*whiteningValuePtr32) - 1;
// Store the 64-bit data unit number in a way compatible with non-64-bit environments/platforms
dataUnitNo.HighPart = startDataUnitNo->HighPart;
dataUnitNo.LowPart = startDataUnitNo->LowPart;
blockCount = length / BYTES_PER_XTS_BLOCK;
// Convert the 64-bit data unit number into a little-endian 16-byte array.
// (Passed as two 32-bit integers for compatibility with non-64-bit environments/platforms.)
Uint64ToLE16ByteArray (byteBufUnitNo, dataUnitNo.HighPart, dataUnitNo.LowPart);
// Generate whitening values for all blocks in the buffer
while (blockCount > 0)
{
if (blockCount < BLOCKS_PER_XTS_DATA_UNIT)
endBlock = startBlock + (unsigned int) blockCount;
else
endBlock = BLOCKS_PER_XTS_DATA_UNIT;
// Encrypt the data unit number using the secondary key (in order to generate the first
// whitening value for this data unit)
memcpy (whiteningValue, byteBufUnitNo, BYTES_PER_XTS_BLOCK);
EncipherBlock (cipher, whiteningValue, ks2);
// Generate subsequent whitening values and XOR each whitening value into corresponding
// ciphertext/plaintext block
for (block = 0; block < endBlock; block++)
{
if (block >= startBlock)
{
whiteningValuePtr32 = (unsigned __int32 *) whiteningValue;
// XOR the whitening value into this ciphertext/plaintext block
*bufPtr32++ ^= *whiteningValuePtr32++;
*bufPtr32++ ^= *whiteningValuePtr32++;
*bufPtr32++ ^= *whiteningValuePtr32++;
*bufPtr32++ ^= *whiteningValuePtr32;
blockCount--;
}
// Derive the next whitening value
finalCarry = 0;
for (whiteningValuePtr32 = finalDwordWhiteningValuePtr;
whiteningValuePtr32 >= (unsigned __int32 *) whiteningValue;
whiteningValuePtr32--)
{
if (*whiteningValuePtr32 & 0x80000000) // If the following shift results in a carry
{
if (whiteningValuePtr32 != finalDwordWhiteningValuePtr) // If not processing the highest double word
{
// A regular carry
*(whiteningValuePtr32 + 1) |= 1;
}
else
{
// The highest byte shift will result in a carry
finalCarry = 135;
}
}
*whiteningValuePtr32 <<= 1;
}
whiteningValue[0] ^= finalCarry;
}
startBlock = 0;
// Increase the data unit number by one
IncUint64Struct (&dataUnitNo);
// Convert the 64-bit data unit number into a little-endian 16-byte array.
Uint64ToLE16ByteArray (byteBufUnitNo, dataUnitNo.HighPart, dataUnitNo.LowPart);
}
FAST_ERASE64 (whiteningValue, sizeof(whiteningValue));
}
// length: number of bytes to encrypt; may be larger than one data unit and must be divisible by the cipher block size
// ks: the primary key schedule
// ks2: the secondary key schedule
// dataUnitNo: The sequential number of the data unit with which the buffer starts.
// startCipherBlockNo: The sequential number of the first plaintext block to encrypt inside the data unit dataUnitNo.
// When encrypting the data unit from its first block, startCipherBlockNo is 0.
// The startCipherBlockNo value applies only to the first data unit in the buffer; each successive
// data unit is encrypted from its first block. The start of the buffer does not have to be
// aligned with the start of a data unit. If it is aligned, startCipherBlockNo must be 0; if it
// is not aligned, startCipherBlockNo must reflect the misalignment accordingly.
void EncryptBufferXTS (uint8_t *buffer,
TC_LARGEST_COMPILER_UINT length,
const UINT64_STRUCT *dataUnitNo,
unsigned int startCipherBlockNo,
uint8_t *ks,
uint8_t *ks2,
int cipher)
{
TC_LARGEST_COMPILER_UINT blockCount;
uint8_t *bufPtr = buffer;
if (length % BYTES_PER_XTS_BLOCK)
TC_THROW_FATAL_EXCEPTION;
// Pre-whitening (all plaintext blocks in the buffer)
WhiteningPass (buffer, length, dataUnitNo, startCipherBlockNo, ks2, cipher);
// Encrypt all plaintext blocks in the buffer
for (blockCount = 0; blockCount < length / BYTES_PER_XTS_BLOCK; blockCount++)
{
EncipherBlock (cipher, bufPtr, ks);
bufPtr += BYTES_PER_XTS_BLOCK;
}
// Post-whitening (all ciphertext blocks in the buffer)
WhiteningPass (buffer, length, dataUnitNo, startCipherBlockNo, ks2, cipher);
}
// For descriptions of the input parameters, see EncryptBufferXTS().
void DecryptBufferXTS (uint8_t *buffer,
TC_LARGEST_COMPILER_UINT length,
const UINT64_STRUCT *dataUnitNo,
unsigned int startCipherBlockNo,
uint8_t *ks,
uint8_t *ks2,
int cipher)
{
TC_LARGEST_COMPILER_UINT blockCount;
uint8_t *bufPtr = buffer;
if (length % BYTES_PER_XTS_BLOCK)
TC_THROW_FATAL_EXCEPTION;
WhiteningPass (buffer, length, dataUnitNo, startCipherBlockNo, ks2, cipher);
for (blockCount = 0; blockCount < length / BYTES_PER_XTS_BLOCK; blockCount++)
{
DecipherBlock (cipher, bufPtr, ks);
bufPtr += BYTES_PER_XTS_BLOCK;
}
WhiteningPass (buffer, length, dataUnitNo, startCipherBlockNo, ks2, cipher);
}
#endif // XTS_LOW_RESOURCE_VERSION

79
src/utils/common/xts.h Normal file
View File

@@ -0,0 +1,79 @@
/*
Copyright (c) 2008 TrueCrypt Foundation. All rights reserved.
Governed by the TrueCrypt License 2.4 the full text of which is contained
in the file License.txt included in TrueCrypt binary and source code
distribution packages.
*/
#ifndef XTS_H
#define XTS_H
// Header files (optional)
#include <inttypes.h>
#include "tcdefs.h"
#include "../common/endian.h"
#include "crypto.h"
#ifdef __cplusplus
extern "C" {
#endif
// Macros
#ifndef LITTLE_ENDIAN
# define LITTLE_ENDIAN 1
#endif
#ifndef BIG_ENDIAN
# define BIG_ENDIAN 2
#endif
#ifndef BYTE_ORDER
# define BYTE_ORDER LITTLE_ENDIAN
#endif
#ifndef LE64
# if BYTE_ORDER == LITTLE_ENDIAN
# define LE64(x) (x)
# endif
#endif
// Custom data types
#ifndef TC_LARGEST_COMPILER_UINT
# ifdef TC_NO_COMPILER_INT64
typedef uint32_t TC_LARGEST_COMPILER_UINT;
# else
typedef uint64_t TC_LARGEST_COMPILER_UINT;
# endif
#endif
#ifndef TCDEFS_H
typedef union
{
struct
{
uint32_t LowPart;
uint32_t HighPart;
};
# ifndef TC_NO_COMPILER_INT64
uint64_t Value;
# endif
} UINT64_STRUCT;
#endif
// Public function prototypes
void EncryptBufferXTS (uint8_t *buffer, TC_LARGEST_COMPILER_UINT length, const UINT64_STRUCT *startDataUnitNo, unsigned int startCipherBlockNo, uint8_t *ks, uint8_t *ks2, int cipher);
void DecryptBufferXTS (uint8_t *buffer, TC_LARGEST_COMPILER_UINT length, const UINT64_STRUCT *startDataUnitNo, unsigned int startCipherBlockNo, uint8_t *ks, uint8_t *ks2, int cipher);
#ifdef __cplusplus
}
#endif
#endif // #ifndef XTS_H