mirror of
https://github.com/86Box/86Box.git
synced 2026-02-21 17:15:32 -07:00
596 lines
19 KiB
C
596 lines
19 KiB
C
/*
|
|
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.
|
|
*/
|
|
|
|
#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,
|
|
uint64_t 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;
|
|
uint64_t 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)
|
|
fatal("EncryptBufferXTS: Length not divisible by %i\n", BYTES_PER_XTS_BLOCK);
|
|
|
|
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);
|
|
}
|
|
|
|
memset (whiteningValue, 0x00, sizeof(whiteningValue));
|
|
memset (whiteningValues, 0x00, sizeof(whiteningValues));
|
|
}
|
|
|
|
|
|
// For descriptions of the input parameters, see EncryptBufferXTS().
|
|
void DecryptBufferXTS (uint8_t *buffer,
|
|
uint64_t 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;
|
|
uint64_t 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)
|
|
fatal("DecryptBufferXTS: Length not divisible by %i\n", BYTES_PER_XTS_BLOCK);
|
|
|
|
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);
|
|
}
|
|
|
|
memset (whiteningValue, 0x00, sizeof(whiteningValue));
|
|
memset (whiteningValues, 0x00, 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,
|
|
uint64_t 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;
|
|
uint64_t 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);
|
|
}
|
|
|
|
memset (whiteningValue, 0x00, 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)
|
|
{
|
|
uint64Struct->Value++;
|
|
}
|
|
|
|
|
|
// 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,
|
|
uint64_t length,
|
|
const UINT64_STRUCT *startDataUnitNo,
|
|
unsigned int startBlock,
|
|
uint8_t *ks2,
|
|
int cipher)
|
|
{
|
|
uint64_t 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);
|
|
}
|
|
|
|
memset (whiteningValue, 0x00, 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,
|
|
uint64_t length,
|
|
const UINT64_STRUCT *dataUnitNo,
|
|
unsigned int startCipherBlockNo,
|
|
uint8_t *ks,
|
|
uint8_t *ks2,
|
|
int cipher)
|
|
{
|
|
uint64_t blockCount;
|
|
uint8_t *bufPtr = buffer;
|
|
|
|
if (length % BYTES_PER_XTS_BLOCK)
|
|
fatal("EncryptBufferXTS(): Length not divisibly by %i\n", BYTES_PER_XTS_BLOCK);
|
|
|
|
// 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,
|
|
uint64_t length,
|
|
const UINT64_STRUCT *dataUnitNo,
|
|
unsigned int startCipherBlockNo,
|
|
uint8_t *ks,
|
|
uint8_t *ks2,
|
|
int cipher)
|
|
{
|
|
uint64_t blockCount;
|
|
uint8_t *bufPtr = buffer;
|
|
|
|
if (length % BYTES_PER_XTS_BLOCK)
|
|
fatal("DecryptBufferXTS(): Length not disivibly by %i\n", BYTES_PER_XTS_BLOCK);
|
|
|
|
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
|