void DecryptBufferLRW64 (byte *buffer, uint64 length, uint64 blockIndex, PCRYPTO_INFO cryptoInfo) { /* Deprecated/legacy */ int cipher = EAGetFirstCipher (cryptoInfo->ea); unsigned __int8 *p = buffer; unsigned __int8 *ks = cryptoInfo->ks; unsigned __int8 i[8]; unsigned __int8 t[8]; unsigned __int64 b; *(unsigned __int64 *)i = BE64(blockIndex); if (length % 8) GST_THROW_FATAL_EXCEPTION; for (b = 0; b < length >> 3; b++) { Gf64MulTab (i, t, &cryptoInfo->gf_ctx); Xor64 ((unsigned __int64 *)p, (unsigned __int64 *)t); DecipherBlock (cipher, p, ks); Xor64 ((unsigned __int64 *)p, (unsigned __int64 *)t); p += 8; if (i[7] != 0xff) i[7]++; else *(unsigned __int64 *)i = BE64 ( BE64(*(unsigned __int64 *)i) + 1 ); } FAST_ERASE64 (t, sizeof(t)); }
void DecryptBufferLRW128 (byte *buffer, uint64 length, uint64 blockIndex, PCRYPTO_INFO cryptoInfo) { /* Deprecated/legacy */ int cipher = EAGetFirstCipher (cryptoInfo->ea); int cipherCount = EAGetCipherCount (cryptoInfo->ea); unsigned __int8 *p = buffer; unsigned __int8 *ks = cryptoInfo->ks; unsigned __int8 i[8]; unsigned __int8 t[16]; unsigned __int64 b; *(unsigned __int64 *)i = BE64(blockIndex); if (length % 16) GST_THROW_FATAL_EXCEPTION; // Note that the maximum supported volume size is 8589934592 GB (i.e., 2^63 bytes). for (b = 0; b < length >> 4; b++) { Gf128MulBy64Tab (i, t, &cryptoInfo->gf_ctx); Xor128 ((unsigned __int64 *)p, (unsigned __int64 *)t); if (cipherCount > 1) { // Cipher cascade ks = cryptoInfo->ks + EAGetKeyScheduleSize (cryptoInfo->ea); for (cipher = EAGetLastCipher (cryptoInfo->ea); cipher != 0; cipher = EAGetPreviousCipher (cryptoInfo->ea, cipher)) { ks -= CipherGetKeyScheduleSize (cipher); DecipherBlock (cipher, p, ks); } } else { DecipherBlock (cipher, p, ks); } Xor128 ((unsigned __int64 *)p, (unsigned __int64 *)t); p += 16; if (i[7] != 0xff) i[7]++; else *(unsigned __int64 *)i = BE64 ( BE64(*(unsigned __int64 *)i) + 1 ); } FAST_ERASE64 (t, sizeof(t)); }
// 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)); }
// 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 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)); }
// 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)); }
void EncryptionModeXTS::DecryptBufferXTS (const Cipher &cipher, const Cipher &secondaryCipher, byte *buffer, uint64 length, uint64 startDataUnitNo, unsigned int startCipherBlockNo) const { byte finalCarry; byte whiteningValues [ENCRYPTION_DATA_UNIT_SIZE]; byte whiteningValue [BYTES_PER_XTS_BLOCK]; byte byteBufUnitNo [BYTES_PER_XTS_BLOCK]; uint64 *whiteningValuesPtr64 = (uint64 *) whiteningValues; uint64 *whiteningValuePtr64 = (uint64 *) whiteningValue; uint64 *bufPtr = (uint64 *) buffer; uint64 *dataUnitBufPtr; unsigned int startBlock = startCipherBlockNo, endBlock, block; uint64 *const finalInt64WhiteningValuesPtr = whiteningValuesPtr64 + sizeof (whiteningValues) / sizeof (*whiteningValuesPtr64) - 1; uint64 blockCount, dataUnitNo; startDataUnitNo += SectorOffset; // 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; *((uint64 *) byteBufUnitNo) = Endian::Little (dataUnitNo); *((uint64 *) 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 = (uint64 *) whiteningValue; // Encrypt the data unit number using the secondary key (in order to generate the first // whitening value for this data unit) *whiteningValuePtr64 = *((uint64 *) byteBufUnitNo); *(whiteningValuePtr64 + 1) = 0; secondaryCipher.EncryptBlock (whiteningValue); // 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 & 0x8000000000000000ULL) ? 135 : 0; *whiteningValuePtr64-- <<= 1; if (*whiteningValuePtr64 & 0x8000000000000000ULL) *(whiteningValuePtr64 + 1) |= 1; *whiteningValuePtr64 <<= 1; #else // Big-endian platforms finalCarry = (*whiteningValuePtr64 & 0x80) ? 135 : 0; *whiteningValuePtr64 = Endian::Little (Endian::Little (*whiteningValuePtr64) << 1); whiteningValuePtr64--; if (*whiteningValuePtr64 & 0x80) *(whiteningValuePtr64 + 1) |= 0x0100000000000000ULL; *whiteningValuePtr64 = Endian::Little (Endian::Little (*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--; } cipher.DecryptBlocks ((byte *) dataUnitBufPtr, endBlock - startBlock); bufPtr = dataUnitBufPtr; whiteningValuesPtr64 = finalInt64WhiteningValuesPtr; for (block = startBlock; block < endBlock; block++) { *bufPtr++ ^= *whiteningValuesPtr64--; *bufPtr++ ^= *whiteningValuesPtr64--; } blockCount -= endBlock - startBlock; startBlock = 0; dataUnitNo++; *((uint64 *) byteBufUnitNo) = Endian::Little (dataUnitNo); } FAST_ERASE64 (whiteningValue, sizeof (whiteningValue)); FAST_ERASE64 (whiteningValues, sizeof (whiteningValues)); }
void EncryptionModeXTS::EncryptBufferXTS (const Cipher &cipher, const Cipher &secondaryCipher, byte *buffer, uint64 length, uint64 startDataUnitNo, unsigned int startCipherBlockNo) const { byte finalCarry; byte whiteningValues [ENCRYPTION_DATA_UNIT_SIZE]; byte whiteningValue [BYTES_PER_XTS_BLOCK]; byte byteBufUnitNo [BYTES_PER_XTS_BLOCK]; uint64 *whiteningValuesPtr64 = (uint64 *) whiteningValues; uint64 *whiteningValuePtr64 = (uint64 *) whiteningValue; uint64 *bufPtr = (uint64 *) buffer; uint64 *dataUnitBufPtr; unsigned int startBlock = startCipherBlockNo, endBlock, block, countBlock; uint64 remainingBlocks, dataUnitNo; startDataUnitNo += SectorOffset; /* 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; *((uint64 *) byteBufUnitNo) = Endian::Little (dataUnitNo); *((uint64 *) byteBufUnitNo + 1) = 0; if (length % BYTES_PER_XTS_BLOCK) TC_THROW_FATAL_EXCEPTION; remainingBlocks = length / BYTES_PER_XTS_BLOCK; // Process all blocks in the buffer while (remainingBlocks > 0) { if (remainingBlocks < BLOCKS_PER_XTS_DATA_UNIT) endBlock = startBlock + (unsigned int) remainingBlocks; else endBlock = BLOCKS_PER_XTS_DATA_UNIT; countBlock = endBlock - startBlock; whiteningValuesPtr64 = (uint64 *) whiteningValues; whiteningValuePtr64 = (uint64 *) whiteningValue; // Encrypt the data unit number using the secondary key (in order to generate the first // whitening value for this data unit) *whiteningValuePtr64 = *((uint64 *) byteBufUnitNo); *(whiteningValuePtr64 + 1) = 0; secondaryCipher.EncryptBlock (whiteningValue); // 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. 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 & 0x8000000000000000ULL) ? 135 : 0; *whiteningValuePtr64-- <<= 1; if (*whiteningValuePtr64 & 0x8000000000000000ULL) *(whiteningValuePtr64 + 1) |= 1; *whiteningValuePtr64 <<= 1; #else // Big-endian platforms finalCarry = (*whiteningValuePtr64 & 0x80) ? 135 : 0; *whiteningValuePtr64 = Endian::Little (Endian::Little (*whiteningValuePtr64) << 1); whiteningValuePtr64--; if (*whiteningValuePtr64 & 0x80) *(whiteningValuePtr64 + 1) |= 0x0100000000000000ULL; *whiteningValuePtr64 = Endian::Little (Endian::Little (*whiteningValuePtr64) << 1); #endif whiteningValue[0] ^= finalCarry; } dataUnitBufPtr = bufPtr; whiteningValuesPtr64 = (uint64 *) whiteningValues; // Encrypt all blocks in this data unit #if (CRYPTOPP_BOOL_SSE2_INTRINSICS_AVAILABLE && CRYPTOPP_BOOL_X64) XorBlocks (bufPtr, whiteningValuesPtr64, countBlock, startBlock, endBlock); #else for (block = 0; block < countBlock; block++) { // Pre-whitening *bufPtr++ ^= *whiteningValuesPtr64++; *bufPtr++ ^= *whiteningValuesPtr64++; } #endif // Actual encryption cipher.EncryptBlocks ((byte *) dataUnitBufPtr, countBlock); bufPtr = dataUnitBufPtr; whiteningValuesPtr64 = (uint64 *) whiteningValues; #if (CRYPTOPP_BOOL_SSE2_INTRINSICS_AVAILABLE && CRYPTOPP_BOOL_X64) XorBlocks (bufPtr, whiteningValuesPtr64, countBlock, startBlock, endBlock); #else for (block = 0; block < countBlock; block++) { // Post-whitening *bufPtr++ ^= *whiteningValuesPtr64++; *bufPtr++ ^= *whiteningValuesPtr64++; } #endif remainingBlocks -= countBlock; startBlock = 0; dataUnitNo++; *((uint64 *) byteBufUnitNo) = Endian::Little (dataUnitNo); } FAST_ERASE64 (whiteningValue, sizeof (whiteningValue)); FAST_ERASE64 (whiteningValues, sizeof (whiteningValues)); }