VeraCrypt
aboutsummaryrefslogtreecommitdiff
path: root/src/Common/Xts.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/Common/Xts.c')
-rw-r--r--src/Common/Xts.c1500
1 files changed, 750 insertions, 750 deletions
diff --git a/src/Common/Xts.c b/src/Common/Xts.c
index c2fe125c..02977887 100644
--- a/src/Common/Xts.c
+++ b/src/Common/Xts.c
@@ -1,750 +1,750 @@
-/*
- Derived from source code of TrueCrypt 7.1a, which is
- Copyright (c) 2008-2012 TrueCrypt Developers Association and which is governed
- by the TrueCrypt License 3.0.
-
- Modifications and additions to the original source code (contained in this file)
- and all other portions of this file are Copyright (c) 2013-2016 IDRIX
- and are governed by the Apache License 2.0 the full text of which is
- contained in the file License.txt included in VeraCrypt binary and source
- code distribution packages.
-*/
-
-/* If native 64-bit data types are not available, define TC_NO_COMPILER_INT64.
-
-For big-endian platforms define BYTE_ORDER as BIG_ENDIAN. */
-
-
-#ifdef TC_MINIMIZE_CODE_SIZE
-// Preboot/boot version
-# ifndef TC_NO_COMPILER_INT64
-# define TC_NO_COMPILER_INT64
-# endif
-# pragma optimize ("tl", on)
-#endif
-
-#ifdef TC_NO_COMPILER_INT64
-# include <memory.h>
-#endif
-
-#include "Xts.h"
-
-
-#ifndef TC_NO_COMPILER_INT64
-
-// 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 (unsigned __int8 *buffer,
- TC_LARGEST_COMPILER_UINT length,
- const UINT64_STRUCT *startDataUnitNo,
- unsigned int startCipherBlockNo,
- unsigned __int8 *ks,
- unsigned __int8 *ks2,
- int cipher)
-{
- if (CipherSupportsIntraDataUnitParallelization (cipher))
- EncryptBufferXTSParallel (buffer, length, startDataUnitNo, startCipherBlockNo, ks, ks2, cipher);
- else
- EncryptBufferXTSNonParallel (buffer, length, startDataUnitNo, startCipherBlockNo, ks, ks2, cipher);
-}
-
-
-// Optimized for encryption algorithms supporting intra-data-unit parallelization
-static void EncryptBufferXTSParallel (unsigned __int8 *buffer,
- TC_LARGEST_COMPILER_UINT length,
- const UINT64_STRUCT *startDataUnitNo,
- unsigned int startCipherBlockNo,
- unsigned __int8 *ks,
- unsigned __int8 *ks2,
- int cipher)
-{
- unsigned __int8 finalCarry;
- unsigned __int8 whiteningValues [ENCRYPTION_DATA_UNIT_SIZE];
- unsigned __int8 whiteningValue [BYTES_PER_XTS_BLOCK];
- unsigned __int8 byteBufUnitNo [BYTES_PER_XTS_BLOCK];
- unsigned __int64 *whiteningValuesPtr64 = (unsigned __int64 *) whiteningValues;
- unsigned __int64 *whiteningValuePtr64 = (unsigned __int64 *) whiteningValue;
- unsigned __int64 *bufPtr = (unsigned __int64 *) buffer;
- unsigned __int64 *dataUnitBufPtr;
- unsigned int startBlock = startCipherBlockNo, endBlock, block;
- unsigned __int64 *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;
- *((unsigned __int64 *) byteBufUnitNo) = LE64 (dataUnitNo);
- *((unsigned __int64 *) 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
- 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 = (unsigned __int64 *) whiteningValue;
-
- // Encrypt the data unit number using the secondary key (in order to generate the first
- // whitening value for this data unit)
- *whiteningValuePtr64 = *((unsigned __int64 *) 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
-
- finalCarry =
- (*whiteningValuePtr64 & 0x8000000000000000) ?
- 135 : 0;
-
- *whiteningValuePtr64-- <<= 1;
-
- if (*whiteningValuePtr64 & 0x8000000000000000)
- *(whiteningValuePtr64 + 1) |= 1;
-
- *whiteningValuePtr64 <<= 1;
-#else
-
- // Big-endian platforms
-
- 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;
- }
-
- dataUnitBufPtr = bufPtr;
- whiteningValuesPtr64 = finalInt64WhiteningValuesPtr;
-
- // Encrypt all blocks in this data unit
-
- for (block = startBlock; block < endBlock; block++)
- {
- // Pre-whitening
- *bufPtr++ ^= *whiteningValuesPtr64--;
- *bufPtr++ ^= *whiteningValuesPtr64--;
- }
-
- // Actual encryption
- EncipherBlocks (cipher, dataUnitBufPtr, ks, endBlock - startBlock);
-
- bufPtr = dataUnitBufPtr;
- whiteningValuesPtr64 = finalInt64WhiteningValuesPtr;
-
- for (block = startBlock; block < endBlock; block++)
- {
- // Post-whitening
- *bufPtr++ ^= *whiteningValuesPtr64--;
- *bufPtr++ ^= *whiteningValuesPtr64--;
- }
-
- blockCount -= endBlock - startBlock;
- startBlock = 0;
- dataUnitNo++;
- *((unsigned __int64 *) byteBufUnitNo) = LE64 (dataUnitNo);
- }
-
- FAST_ERASE64 (whiteningValue, sizeof (whiteningValue));
- FAST_ERASE64 (whiteningValues, sizeof (whiteningValues));
-}
-
-
-// Optimized for encryption algorithms not supporting intra-data-unit parallelization
-static void EncryptBufferXTSNonParallel (unsigned __int8 *buffer,
- TC_LARGEST_COMPILER_UINT length,
- const UINT64_STRUCT *startDataUnitNo,
- unsigned int startCipherBlockNo,
- unsigned __int8 *ks,
- unsigned __int8 *ks2,
- int cipher)
-{
- unsigned __int8 finalCarry;
- unsigned __int8 whiteningValue [BYTES_PER_XTS_BLOCK];
- unsigned __int8 byteBufUnitNo [BYTES_PER_XTS_BLOCK];
- unsigned __int64 *whiteningValuePtr64 = (unsigned __int64 *) whiteningValue;
- unsigned __int64 *bufPtr = (unsigned __int64 *) buffer;
- unsigned int startBlock = startCipherBlockNo, endBlock, block;
- 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;
- *((unsigned __int64 *) byteBufUnitNo) = LE64 (dataUnitNo);
- *((unsigned __int64 *) 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
- while (blockCount > 0)
- {
- if (blockCount < BLOCKS_PER_XTS_DATA_UNIT)
- endBlock = startBlock + (unsigned int) blockCount;
- else
- endBlock = BLOCKS_PER_XTS_DATA_UNIT;
-
- whiteningValuePtr64 = (unsigned __int64 *) whiteningValue;
-
- // Encrypt the data unit number using the secondary key (in order to generate the first
- // whitening value for this data unit)
- *whiteningValuePtr64 = *((unsigned __int64 *) byteBufUnitNo);
- *(whiteningValuePtr64 + 1) = 0;
- EncipherBlock (cipher, whiteningValue, ks2);
-
- // Generate (and apply) subsequent whitening values for blocks in this data unit and
- // encrypt all relevant blocks in this data unit
- for (block = 0; block < endBlock; block++)
- {
- if (block >= startBlock)
- {
- // Pre-whitening
- *bufPtr++ ^= *whiteningValuePtr64++;
- *bufPtr-- ^= *whiteningValuePtr64--;
-
- // Actual encryption
- EncipherBlock (cipher, bufPtr, ks);
-
- // Post-whitening
- *bufPtr++ ^= *whiteningValuePtr64++;
- *bufPtr++ ^= *whiteningValuePtr64;
- }
- else
- whiteningValuePtr64++;
-
- // Derive the next whitening value
-
-#if BYTE_ORDER == LITTLE_ENDIAN
-
- // Little-endian platforms
-
- finalCarry =
- (*whiteningValuePtr64 & 0x8000000000000000) ?
- 135 : 0;
-
- *whiteningValuePtr64-- <<= 1;
-
- if (*whiteningValuePtr64 & 0x8000000000000000)
- *(whiteningValuePtr64 + 1) |= 1;
-
- *whiteningValuePtr64 <<= 1;
-#else
-
- // Big-endian platforms
-
- 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;
- }
-
- blockCount -= endBlock - startBlock;
- startBlock = 0;
- dataUnitNo++;
- *((unsigned __int64 *) byteBufUnitNo) = LE64 (dataUnitNo);
- }
-
- FAST_ERASE64 (whiteningValue, sizeof (whiteningValue));
-}
-
-
-// For descriptions of the input parameters, see EncryptBufferXTS().
-void DecryptBufferXTS (unsigned __int8 *buffer,
- TC_LARGEST_COMPILER_UINT length,
- const UINT64_STRUCT *startDataUnitNo,
- unsigned int startCipherBlockNo,
- unsigned __int8 *ks,
- unsigned __int8 *ks2,
- int cipher)
-{
- if (CipherSupportsIntraDataUnitParallelization (cipher))
- DecryptBufferXTSParallel (buffer, length, startDataUnitNo, startCipherBlockNo, ks, ks2, cipher);
- else
- DecryptBufferXTSNonParallel (buffer, length, startDataUnitNo, startCipherBlockNo, ks, ks2, cipher);
-}
-
-
-// Optimized for encryption algorithms supporting intra-data-unit parallelization
-static void DecryptBufferXTSParallel (unsigned __int8 *buffer,
- TC_LARGEST_COMPILER_UINT length,
- const UINT64_STRUCT *startDataUnitNo,
- unsigned int startCipherBlockNo,
- unsigned __int8 *ks,
- unsigned __int8 *ks2,
- int cipher)
-{
- unsigned __int8 finalCarry;
- unsigned __int8 whiteningValues [ENCRYPTION_DATA_UNIT_SIZE];
- unsigned __int8 whiteningValue [BYTES_PER_XTS_BLOCK];
- unsigned __int8 byteBufUnitNo [BYTES_PER_XTS_BLOCK];
- unsigned __int64 *whiteningValuesPtr64 = (unsigned __int64 *) whiteningValues;
- unsigned __int64 *whiteningValuePtr64 = (unsigned __int64 *) whiteningValue;
- unsigned __int64 *bufPtr = (unsigned __int64 *) buffer;
- unsigned __int64 *dataUnitBufPtr;
- unsigned int startBlock = startCipherBlockNo, endBlock, block;
- unsigned __int64 *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;
- *((unsigned __int64 *) byteBufUnitNo) = LE64 (dataUnitNo);
- *((unsigned __int64 *) 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
- 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 = (unsigned __int64 *) whiteningValue;
-
- // Encrypt the data unit number using the secondary key (in order to generate the first
- // whitening value for this data unit)
- *whiteningValuePtr64 = *((unsigned __int64 *) 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
-
- finalCarry =
- (*whiteningValuePtr64 & 0x8000000000000000) ?
- 135 : 0;
-
- *whiteningValuePtr64-- <<= 1;
-
- if (*whiteningValuePtr64 & 0x8000000000000000)
- *(whiteningValuePtr64 + 1) |= 1;
-
- *whiteningValuePtr64 <<= 1;
-
-#else
- // Big-endian platforms
-
- 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;
- }
-
- dataUnitBufPtr = bufPtr;
- whiteningValuesPtr64 = finalInt64WhiteningValuesPtr;
-
- // Decrypt blocks in this data unit
-
- for (block = startBlock; block < endBlock; block++)
- {
- *bufPtr++ ^= *whiteningValuesPtr64--;
- *bufPtr++ ^= *whiteningValuesPtr64--;
- }
-
- DecipherBlocks (cipher, dataUnitBufPtr, ks, endBlock - startBlock);
-
- bufPtr = dataUnitBufPtr;
- whiteningValuesPtr64 = finalInt64WhiteningValuesPtr;
-
- for (block = startBlock; block < endBlock; block++)
- {
- *bufPtr++ ^= *whiteningValuesPtr64--;
- *bufPtr++ ^= *whiteningValuesPtr64--;
- }
-
- blockCount -= endBlock - startBlock;
- startBlock = 0;
- dataUnitNo++;
-
- *((unsigned __int64 *) byteBufUnitNo) = LE64 (dataUnitNo);
- }
-
- FAST_ERASE64 (whiteningValue, sizeof (whiteningValue));
- FAST_ERASE64 (whiteningValues, sizeof (whiteningValues));
-}
-
-
-// Optimized for encryption algorithms not supporting intra-data-unit parallelization
-static void DecryptBufferXTSNonParallel (unsigned __int8 *buffer,
- TC_LARGEST_COMPILER_UINT length,
- const UINT64_STRUCT *startDataUnitNo,
- unsigned int startCipherBlockNo,
- unsigned __int8 *ks,
- unsigned __int8 *ks2,
- int cipher)
-{
- unsigned __int8 finalCarry;
- unsigned __int8 whiteningValue [BYTES_PER_XTS_BLOCK];
- unsigned __int8 byteBufUnitNo [BYTES_PER_XTS_BLOCK];
- unsigned __int64 *whiteningValuePtr64 = (unsigned __int64 *) whiteningValue;
- unsigned __int64 *bufPtr = (unsigned __int64 *) buffer;
- unsigned int startBlock = startCipherBlockNo, endBlock, block;
- 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;
- *((unsigned __int64 *) byteBufUnitNo) = LE64 (dataUnitNo);
- *((unsigned __int64 *) 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
- while (blockCount > 0)
- {
- if (blockCount < BLOCKS_PER_XTS_DATA_UNIT)
- endBlock = startBlock + (unsigned int) blockCount;
- else
- endBlock = BLOCKS_PER_XTS_DATA_UNIT;
-
- whiteningValuePtr64 = (unsigned __int64 *) whiteningValue;
-
- // Encrypt the data unit number using the secondary key (in order to generate the first
- // whitening value for this data unit)
- *whiteningValuePtr64 = *((unsigned __int64 *) byteBufUnitNo);
- *(whiteningValuePtr64 + 1) = 0;
- EncipherBlock (cipher, whiteningValue, ks2);
-
- // Generate (and apply) subsequent whitening values for blocks in this data unit and
- // decrypt all relevant blocks in this data unit
- for (block = 0; block < endBlock; block++)
- {
- if (block >= startBlock)
- {
- // Post-whitening
- *bufPtr++ ^= *whiteningValuePtr64++;
- *bufPtr-- ^= *whiteningValuePtr64--;
-
- // Actual decryption
- DecipherBlock (cipher, bufPtr, ks);
-
- // Pre-whitening
- *bufPtr++ ^= *whiteningValuePtr64++;
- *bufPtr++ ^= *whiteningValuePtr64;
- }
- else
- whiteningValuePtr64++;
-
- // Derive the next whitening value
-
-#if BYTE_ORDER == LITTLE_ENDIAN
-
- // Little-endian platforms
-
- finalCarry =
- (*whiteningValuePtr64 & 0x8000000000000000) ?
- 135 : 0;
-
- *whiteningValuePtr64-- <<= 1;
-
- if (*whiteningValuePtr64 & 0x8000000000000000)
- *(whiteningValuePtr64 + 1) |= 1;
-
- *whiteningValuePtr64 <<= 1;
-
-#else
- // Big-endian platforms
-
- 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;
- }
-
- blockCount -= endBlock - startBlock;
- startBlock = 0;
- dataUnitNo++;
- *((unsigned __int64 *) byteBufUnitNo) = LE64 (dataUnitNo);
- }
-
- FAST_ERASE64 (whiteningValue, sizeof (whiteningValue));
-}
-
-
-#else // TC_NO_COMPILER_INT64
-
-/* ---- The following code is to be used only when native 64-bit data types are not available. ---- */
-
-#if BYTE_ORDER == BIG_ENDIAN
-#error The TC_NO_COMPILER_INT64 version of the XTS code is not compatible with big-endian platforms
-#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 (unsigned __int8 *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;
-}
-
-
-// Encrypts or decrypts all blocks in the buffer in XTS mode. For descriptions of the input parameters,
-// see the 64-bit version of EncryptBufferXTS().
-static void EncryptDecryptBufferXTS32 (const unsigned __int8 *buffer,
- TC_LARGEST_COMPILER_UINT length,
- const UINT64_STRUCT *startDataUnitNo,
- unsigned int startBlock,
- unsigned __int8 *ks,
- unsigned __int8 *ks2,
- int cipher,
- BOOL decryption)
-{
- TC_LARGEST_COMPILER_UINT blockCount;
- UINT64_STRUCT dataUnitNo;
- unsigned int block;
- unsigned int endBlock;
- unsigned __int8 byteBufUnitNo [BYTES_PER_XTS_BLOCK];
- unsigned __int8 whiteningValue [BYTES_PER_XTS_BLOCK];
- unsigned __int32 *bufPtr32 = (unsigned __int32 *) buffer;
- unsigned __int32 *whiteningValuePtr32 = (unsigned __int32 *) whiteningValue;
- unsigned __int8 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 (and apply) subsequent whitening values for blocks in this data unit and
- // encrypt/decrypt all relevant blocks in this data unit
- for (block = 0; block < endBlock; block++)
- {
- if (block >= startBlock)
- {
- whiteningValuePtr32 = (unsigned __int32 *) whiteningValue;
-
- // Whitening
- *bufPtr32++ ^= *whiteningValuePtr32++;
- *bufPtr32++ ^= *whiteningValuePtr32++;
- *bufPtr32++ ^= *whiteningValuePtr32++;
- *bufPtr32 ^= *whiteningValuePtr32;
-
- bufPtr32 -= BYTES_PER_XTS_BLOCK / sizeof (*bufPtr32) - 1;
-
- // Actual encryption/decryption
- if (decryption)
- DecipherBlock (cipher, bufPtr32, ks);
- else
- EncipherBlock (cipher, bufPtr32, ks);
-
- whiteningValuePtr32 = (unsigned __int32 *) whiteningValue;
-
- // Whitening
- *bufPtr32++ ^= *whiteningValuePtr32++;
- *bufPtr32++ ^= *whiteningValuePtr32++;
- *bufPtr32++ ^= *whiteningValuePtr32++;
- *bufPtr32++ ^= *whiteningValuePtr32;
- }
-
- // 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;
- }
-
- blockCount -= endBlock - startBlock;
- startBlock = 0;
-
- // Increase the data unit number by one
- if (!++dataUnitNo.LowPart)
- {
- dataUnitNo.HighPart++;
- }
-
- // 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));
-}
-
-
-// For descriptions of the input parameters, see the 64-bit version of EncryptBufferXTS() above.
-void EncryptBufferXTS (unsigned __int8 *buffer,
- TC_LARGEST_COMPILER_UINT length,
- const UINT64_STRUCT *startDataUnitNo,
- unsigned int startCipherBlockNo,
- unsigned __int8 *ks,
- unsigned __int8 *ks2,
- int cipher)
-{
- // Encrypt all plaintext blocks in the buffer
- EncryptDecryptBufferXTS32 (buffer, length, startDataUnitNo, startCipherBlockNo, ks, ks2, cipher, FALSE);
-}
-
-
-// For descriptions of the input parameters, see the 64-bit version of EncryptBufferXTS().
-void DecryptBufferXTS (unsigned __int8 *buffer,
- TC_LARGEST_COMPILER_UINT length,
- const UINT64_STRUCT *startDataUnitNo,
- unsigned int startCipherBlockNo,
- unsigned __int8 *ks,
- unsigned __int8 *ks2,
- int cipher)
-{
- // Decrypt all ciphertext blocks in the buffer
- EncryptDecryptBufferXTS32 (buffer, length, startDataUnitNo, startCipherBlockNo, ks, ks2, cipher, TRUE);
-}
-
-#endif // TC_NO_COMPILER_INT64
+/*
+ Derived from source code of TrueCrypt 7.1a, which is
+ Copyright (c) 2008-2012 TrueCrypt Developers Association and which is governed
+ by the TrueCrypt License 3.0.
+
+ Modifications and additions to the original source code (contained in this file)
+ and all other portions of this file are Copyright (c) 2013-2016 IDRIX
+ and are governed by the Apache License 2.0 the full text of which is
+ contained in the file License.txt included in VeraCrypt binary and source
+ code distribution packages.
+*/
+
+/* If native 64-bit data types are not available, define TC_NO_COMPILER_INT64.
+
+For big-endian platforms define BYTE_ORDER as BIG_ENDIAN. */
+
+
+#ifdef TC_MINIMIZE_CODE_SIZE
+// Preboot/boot version
+# ifndef TC_NO_COMPILER_INT64
+# define TC_NO_COMPILER_INT64
+# endif
+# pragma optimize ("tl", on)
+#endif
+
+#ifdef TC_NO_COMPILER_INT64
+# include <memory.h>
+#endif
+
+#include "Xts.h"
+
+
+#ifndef TC_NO_COMPILER_INT64
+
+// 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 (unsigned __int8 *buffer,
+ TC_LARGEST_COMPILER_UINT length,
+ const UINT64_STRUCT *startDataUnitNo,
+ unsigned int startCipherBlockNo,
+ unsigned __int8 *ks,
+ unsigned __int8 *ks2,
+ int cipher)
+{
+ if (CipherSupportsIntraDataUnitParallelization (cipher))
+ EncryptBufferXTSParallel (buffer, length, startDataUnitNo, startCipherBlockNo, ks, ks2, cipher);
+ else
+ EncryptBufferXTSNonParallel (buffer, length, startDataUnitNo, startCipherBlockNo, ks, ks2, cipher);
+}
+
+
+// Optimized for encryption algorithms supporting intra-data-unit parallelization
+static void EncryptBufferXTSParallel (unsigned __int8 *buffer,
+ TC_LARGEST_COMPILER_UINT length,
+ const UINT64_STRUCT *startDataUnitNo,
+ unsigned int startCipherBlockNo,
+ unsigned __int8 *ks,
+ unsigned __int8 *ks2,
+ int cipher)
+{
+ unsigned __int8 finalCarry;
+ unsigned __int8 whiteningValues [ENCRYPTION_DATA_UNIT_SIZE];
+ unsigned __int8 whiteningValue [BYTES_PER_XTS_BLOCK];
+ unsigned __int8 byteBufUnitNo [BYTES_PER_XTS_BLOCK];
+ unsigned __int64 *whiteningValuesPtr64 = (unsigned __int64 *) whiteningValues;
+ unsigned __int64 *whiteningValuePtr64 = (unsigned __int64 *) whiteningValue;
+ unsigned __int64 *bufPtr = (unsigned __int64 *) buffer;
+ unsigned __int64 *dataUnitBufPtr;
+ unsigned int startBlock = startCipherBlockNo, endBlock, block;
+ unsigned __int64 *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;
+ *((unsigned __int64 *) byteBufUnitNo) = LE64 (dataUnitNo);
+ *((unsigned __int64 *) 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
+ 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 = (unsigned __int64 *) whiteningValue;
+
+ // Encrypt the data unit number using the secondary key (in order to generate the first
+ // whitening value for this data unit)
+ *whiteningValuePtr64 = *((unsigned __int64 *) 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
+
+ finalCarry =
+ (*whiteningValuePtr64 & 0x8000000000000000) ?
+ 135 : 0;
+
+ *whiteningValuePtr64-- <<= 1;
+
+ if (*whiteningValuePtr64 & 0x8000000000000000)
+ *(whiteningValuePtr64 + 1) |= 1;
+
+ *whiteningValuePtr64 <<= 1;
+#else
+
+ // Big-endian platforms
+
+ 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;
+ }
+
+ dataUnitBufPtr = bufPtr;
+ whiteningValuesPtr64 = finalInt64WhiteningValuesPtr;
+
+ // Encrypt all blocks in this data unit
+
+ for (block = startBlock; block < endBlock; block++)
+ {
+ // Pre-whitening
+ *bufPtr++ ^= *whiteningValuesPtr64--;
+ *bufPtr++ ^= *whiteningValuesPtr64--;
+ }
+
+ // Actual encryption
+ EncipherBlocks (cipher, dataUnitBufPtr, ks, endBlock - startBlock);
+
+ bufPtr = dataUnitBufPtr;
+ whiteningValuesPtr64 = finalInt64WhiteningValuesPtr;
+
+ for (block = startBlock; block < endBlock; block++)
+ {
+ // Post-whitening
+ *bufPtr++ ^= *whiteningValuesPtr64--;
+ *bufPtr++ ^= *whiteningValuesPtr64--;
+ }
+
+ blockCount -= endBlock - startBlock;
+ startBlock = 0;
+ dataUnitNo++;
+ *((unsigned __int64 *) byteBufUnitNo) = LE64 (dataUnitNo);
+ }
+
+ FAST_ERASE64 (whiteningValue, sizeof (whiteningValue));
+ FAST_ERASE64 (whiteningValues, sizeof (whiteningValues));
+}
+
+
+// Optimized for encryption algorithms not supporting intra-data-unit parallelization
+static void EncryptBufferXTSNonParallel (unsigned __int8 *buffer,
+ TC_LARGEST_COMPILER_UINT length,
+ const UINT64_STRUCT *startDataUnitNo,
+ unsigned int startCipherBlockNo,
+ unsigned __int8 *ks,
+ unsigned __int8 *ks2,
+ int cipher)
+{
+ unsigned __int8 finalCarry;
+ unsigned __int8 whiteningValue [BYTES_PER_XTS_BLOCK];
+ unsigned __int8 byteBufUnitNo [BYTES_PER_XTS_BLOCK];
+ unsigned __int64 *whiteningValuePtr64 = (unsigned __int64 *) whiteningValue;
+ unsigned __int64 *bufPtr = (unsigned __int64 *) buffer;
+ unsigned int startBlock = startCipherBlockNo, endBlock, block;
+ 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;
+ *((unsigned __int64 *) byteBufUnitNo) = LE64 (dataUnitNo);
+ *((unsigned __int64 *) 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
+ while (blockCount > 0)
+ {
+ if (blockCount < BLOCKS_PER_XTS_DATA_UNIT)
+ endBlock = startBlock + (unsigned int) blockCount;
+ else
+ endBlock = BLOCKS_PER_XTS_DATA_UNIT;
+
+ whiteningValuePtr64 = (unsigned __int64 *) whiteningValue;
+
+ // Encrypt the data unit number using the secondary key (in order to generate the first
+ // whitening value for this data unit)
+ *whiteningValuePtr64 = *((unsigned __int64 *) byteBufUnitNo);
+ *(whiteningValuePtr64 + 1) = 0;
+ EncipherBlock (cipher, whiteningValue, ks2);
+
+ // Generate (and apply) subsequent whitening values for blocks in this data unit and
+ // encrypt all relevant blocks in this data unit
+ for (block = 0; block < endBlock; block++)
+ {
+ if (block >= startBlock)
+ {
+ // Pre-whitening
+ *bufPtr++ ^= *whiteningValuePtr64++;
+ *bufPtr-- ^= *whiteningValuePtr64--;
+
+ // Actual encryption
+ EncipherBlock (cipher, bufPtr, ks);
+
+ // Post-whitening
+ *bufPtr++ ^= *whiteningValuePtr64++;
+ *bufPtr++ ^= *whiteningValuePtr64;
+ }
+ else
+ whiteningValuePtr64++;
+
+ // Derive the next whitening value
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+
+ // Little-endian platforms
+
+ finalCarry =
+ (*whiteningValuePtr64 & 0x8000000000000000) ?
+ 135 : 0;
+
+ *whiteningValuePtr64-- <<= 1;
+
+ if (*whiteningValuePtr64 & 0x8000000000000000)
+ *(whiteningValuePtr64 + 1) |= 1;
+
+ *whiteningValuePtr64 <<= 1;
+#else
+
+ // Big-endian platforms
+
+ 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;
+ }
+
+ blockCount -= endBlock - startBlock;
+ startBlock = 0;
+ dataUnitNo++;
+ *((unsigned __int64 *) byteBufUnitNo) = LE64 (dataUnitNo);
+ }
+
+ FAST_ERASE64 (whiteningValue, sizeof (whiteningValue));
+}
+
+
+// For descriptions of the input parameters, see EncryptBufferXTS().
+void DecryptBufferXTS (unsigned __int8 *buffer,
+ TC_LARGEST_COMPILER_UINT length,
+ const UINT64_STRUCT *startDataUnitNo,
+ unsigned int startCipherBlockNo,
+ unsigned __int8 *ks,
+ unsigned __int8 *ks2,
+ int cipher)
+{
+ if (CipherSupportsIntraDataUnitParallelization (cipher))
+ DecryptBufferXTSParallel (buffer, length, startDataUnitNo, startCipherBlockNo, ks, ks2, cipher);
+ else
+ DecryptBufferXTSNonParallel (buffer, length, startDataUnitNo, startCipherBlockNo, ks, ks2, cipher);
+}
+
+
+// Optimized for encryption algorithms supporting intra-data-unit parallelization
+static void DecryptBufferXTSParallel (unsigned __int8 *buffer,
+ TC_LARGEST_COMPILER_UINT length,
+ const UINT64_STRUCT *startDataUnitNo,
+ unsigned int startCipherBlockNo,
+ unsigned __int8 *ks,
+ unsigned __int8 *ks2,
+ int cipher)
+{
+ unsigned __int8 finalCarry;
+ unsigned __int8 whiteningValues [ENCRYPTION_DATA_UNIT_SIZE];
+ unsigned __int8 whiteningValue [BYTES_PER_XTS_BLOCK];
+ unsigned __int8 byteBufUnitNo [BYTES_PER_XTS_BLOCK];
+ unsigned __int64 *whiteningValuesPtr64 = (unsigned __int64 *) whiteningValues;
+ unsigned __int64 *whiteningValuePtr64 = (unsigned __int64 *) whiteningValue;
+ unsigned __int64 *bufPtr = (unsigned __int64 *) buffer;
+ unsigned __int64 *dataUnitBufPtr;
+ unsigned int startBlock = startCipherBlockNo, endBlock, block;
+ unsigned __int64 *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;
+ *((unsigned __int64 *) byteBufUnitNo) = LE64 (dataUnitNo);
+ *((unsigned __int64 *) 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
+ 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 = (unsigned __int64 *) whiteningValue;
+
+ // Encrypt the data unit number using the secondary key (in order to generate the first
+ // whitening value for this data unit)
+ *whiteningValuePtr64 = *((unsigned __int64 *) 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
+
+ finalCarry =
+ (*whiteningValuePtr64 & 0x8000000000000000) ?
+ 135 : 0;
+
+ *whiteningValuePtr64-- <<= 1;
+
+ if (*whiteningValuePtr64 & 0x8000000000000000)
+ *(whiteningValuePtr64 + 1) |= 1;
+
+ *whiteningValuePtr64 <<= 1;
+
+#else
+ // Big-endian platforms
+
+ 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;
+ }
+
+ dataUnitBufPtr = bufPtr;
+ whiteningValuesPtr64 = finalInt64WhiteningValuesPtr;
+
+ // Decrypt blocks in this data unit
+
+ for (block = startBlock; block < endBlock; block++)
+ {
+ *bufPtr++ ^= *whiteningValuesPtr64--;
+ *bufPtr++ ^= *whiteningValuesPtr64--;
+ }
+
+ DecipherBlocks (cipher, dataUnitBufPtr, ks, endBlock - startBlock);
+
+ bufPtr = dataUnitBufPtr;
+ whiteningValuesPtr64 = finalInt64WhiteningValuesPtr;
+
+ for (block = startBlock; block < endBlock; block++)
+ {
+ *bufPtr++ ^= *whiteningValuesPtr64--;
+ *bufPtr++ ^= *whiteningValuesPtr64--;
+ }
+
+ blockCount -= endBlock - startBlock;
+ startBlock = 0;
+ dataUnitNo++;
+
+ *((unsigned __int64 *) byteBufUnitNo) = LE64 (dataUnitNo);
+ }
+
+ FAST_ERASE64 (whiteningValue, sizeof (whiteningValue));
+ FAST_ERASE64 (whiteningValues, sizeof (whiteningValues));
+}
+
+
+// Optimized for encryption algorithms not supporting intra-data-unit parallelization
+static void DecryptBufferXTSNonParallel (unsigned __int8 *buffer,
+ TC_LARGEST_COMPILER_UINT length,
+ const UINT64_STRUCT *startDataUnitNo,
+ unsigned int startCipherBlockNo,
+ unsigned __int8 *ks,
+ unsigned __int8 *ks2,
+ int cipher)
+{
+ unsigned __int8 finalCarry;
+ unsigned __int8 whiteningValue [BYTES_PER_XTS_BLOCK];
+ unsigned __int8 byteBufUnitNo [BYTES_PER_XTS_BLOCK];
+ unsigned __int64 *whiteningValuePtr64 = (unsigned __int64 *) whiteningValue;
+ unsigned __int64 *bufPtr = (unsigned __int64 *) buffer;
+ unsigned int startBlock = startCipherBlockNo, endBlock, block;
+ 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;
+ *((unsigned __int64 *) byteBufUnitNo) = LE64 (dataUnitNo);
+ *((unsigned __int64 *) 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
+ while (blockCount > 0)
+ {
+ if (blockCount < BLOCKS_PER_XTS_DATA_UNIT)
+ endBlock = startBlock + (unsigned int) blockCount;
+ else
+ endBlock = BLOCKS_PER_XTS_DATA_UNIT;
+
+ whiteningValuePtr64 = (unsigned __int64 *) whiteningValue;
+
+ // Encrypt the data unit number using the secondary key (in order to generate the first
+ // whitening value for this data unit)
+ *whiteningValuePtr64 = *((unsigned __int64 *) byteBufUnitNo);
+ *(whiteningValuePtr64 + 1) = 0;
+ EncipherBlock (cipher, whiteningValue, ks2);
+
+ // Generate (and apply) subsequent whitening values for blocks in this data unit and
+ // decrypt all relevant blocks in this data unit
+ for (block = 0; block < endBlock; block++)
+ {
+ if (block >= startBlock)
+ {
+ // Post-whitening
+ *bufPtr++ ^= *whiteningValuePtr64++;
+ *bufPtr-- ^= *whiteningValuePtr64--;
+
+ // Actual decryption
+ DecipherBlock (cipher, bufPtr, ks);
+
+ // Pre-whitening
+ *bufPtr++ ^= *whiteningValuePtr64++;
+ *bufPtr++ ^= *whiteningValuePtr64;
+ }
+ else
+ whiteningValuePtr64++;
+
+ // Derive the next whitening value
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+
+ // Little-endian platforms
+
+ finalCarry =
+ (*whiteningValuePtr64 & 0x8000000000000000) ?
+ 135 : 0;
+
+ *whiteningValuePtr64-- <<= 1;
+
+ if (*whiteningValuePtr64 & 0x8000000000000000)
+ *(whiteningValuePtr64 + 1) |= 1;
+
+ *whiteningValuePtr64 <<= 1;
+
+#else
+ // Big-endian platforms
+
+ 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;
+ }
+
+ blockCount -= endBlock - startBlock;
+ startBlock = 0;
+ dataUnitNo++;
+ *((unsigned __int64 *) byteBufUnitNo) = LE64 (dataUnitNo);
+ }
+
+ FAST_ERASE64 (whiteningValue, sizeof (whiteningValue));
+}
+
+
+#else // TC_NO_COMPILER_INT64
+
+/* ---- The following code is to be used only when native 64-bit data types are not available. ---- */
+
+#if BYTE_ORDER == BIG_ENDIAN
+#error The TC_NO_COMPILER_INT64 version of the XTS code is not compatible with big-endian platforms
+#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 (unsigned __int8 *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;
+}
+
+
+// Encrypts or decrypts all blocks in the buffer in XTS mode. For descriptions of the input parameters,
+// see the 64-bit version of EncryptBufferXTS().
+static void EncryptDecryptBufferXTS32 (const unsigned __int8 *buffer,
+ TC_LARGEST_COMPILER_UINT length,
+ const UINT64_STRUCT *startDataUnitNo,
+ unsigned int startBlock,
+ unsigned __int8 *ks,
+ unsigned __int8 *ks2,
+ int cipher,
+ BOOL decryption)
+{
+ TC_LARGEST_COMPILER_UINT blockCount;
+ UINT64_STRUCT dataUnitNo;
+ unsigned int block;
+ unsigned int endBlock;
+ unsigned __int8 byteBufUnitNo [BYTES_PER_XTS_BLOCK];
+ unsigned __int8 whiteningValue [BYTES_PER_XTS_BLOCK];
+ unsigned __int32 *bufPtr32 = (unsigned __int32 *) buffer;
+ unsigned __int32 *whiteningValuePtr32 = (unsigned __int32 *) whiteningValue;
+ unsigned __int8 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 (and apply) subsequent whitening values for blocks in this data unit and
+ // encrypt/decrypt all relevant blocks in this data unit
+ for (block = 0; block < endBlock; block++)
+ {
+ if (block >= startBlock)
+ {
+ whiteningValuePtr32 = (unsigned __int32 *) whiteningValue;
+
+ // Whitening
+ *bufPtr32++ ^= *whiteningValuePtr32++;
+ *bufPtr32++ ^= *whiteningValuePtr32++;
+ *bufPtr32++ ^= *whiteningValuePtr32++;
+ *bufPtr32 ^= *whiteningValuePtr32;
+
+ bufPtr32 -= BYTES_PER_XTS_BLOCK / sizeof (*bufPtr32) - 1;
+
+ // Actual encryption/decryption
+ if (decryption)
+ DecipherBlock (cipher, bufPtr32, ks);
+ else
+ EncipherBlock (cipher, bufPtr32, ks);
+
+ whiteningValuePtr32 = (unsigned __int32 *) whiteningValue;
+
+ // Whitening
+ *bufPtr32++ ^= *whiteningValuePtr32++;
+ *bufPtr32++ ^= *whiteningValuePtr32++;
+ *bufPtr32++ ^= *whiteningValuePtr32++;
+ *bufPtr32++ ^= *whiteningValuePtr32;
+ }
+
+ // 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;
+ }
+
+ blockCount -= endBlock - startBlock;
+ startBlock = 0;
+
+ // Increase the data unit number by one
+ if (!++dataUnitNo.LowPart)
+ {
+ dataUnitNo.HighPart++;
+ }
+
+ // 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));
+}
+
+
+// For descriptions of the input parameters, see the 64-bit version of EncryptBufferXTS() above.
+void EncryptBufferXTS (unsigned __int8 *buffer,
+ TC_LARGEST_COMPILER_UINT length,
+ const UINT64_STRUCT *startDataUnitNo,
+ unsigned int startCipherBlockNo,
+ unsigned __int8 *ks,
+ unsigned __int8 *ks2,
+ int cipher)
+{
+ // Encrypt all plaintext blocks in the buffer
+ EncryptDecryptBufferXTS32 (buffer, length, startDataUnitNo, startCipherBlockNo, ks, ks2, cipher, FALSE);
+}
+
+
+// For descriptions of the input parameters, see the 64-bit version of EncryptBufferXTS().
+void DecryptBufferXTS (unsigned __int8 *buffer,
+ TC_LARGEST_COMPILER_UINT length,
+ const UINT64_STRUCT *startDataUnitNo,
+ unsigned int startCipherBlockNo,
+ unsigned __int8 *ks,
+ unsigned __int8 *ks2,
+ int cipher)
+{
+ // Decrypt all ciphertext blocks in the buffer
+ EncryptDecryptBufferXTS32 (buffer, length, startDataUnitNo, startCipherBlockNo, ks, ks2, cipher, TRUE);
+}
+
+#endif // TC_NO_COMPILER_INT64