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)); }
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 DecipherBlocks (int cipher, void *dataPtr, void *ks, size_t blockCount) { byte *data = dataPtr; size_t blockSize = CipherGetBlockSize (cipher); while (blockCount-- > 0) { DecipherBlock (cipher, data, ks); data += blockSize; } }
void DecipherBlocks (int cipher, void *dataPtr, void *ks, size_t blockCount) { byte *data = dataPtr; #if defined (TC_WINDOWS_DRIVER) && !defined (_WIN64) KFLOATING_SAVE floatingPointState; #endif if (cipher == AES && (blockCount & (32 - 1)) == 0 && IsAesHwCpuSupported() #if defined (TC_WINDOWS_DRIVER) && !defined (_WIN64) && NT_SUCCESS (KeSaveFloatingPointState (&floatingPointState)) #endif ) { while (blockCount > 0) { aes_hw_cpu_decrypt_32_blocks ((byte *) ks + sizeof (aes_encrypt_ctx), data); data += 32 * 16; blockCount -= 32; } #if defined (TC_WINDOWS_DRIVER) && !defined (_WIN64) KeRestoreFloatingPointState (&floatingPointState); #endif } else { size_t blockSize = CipherGetBlockSize (cipher); while (blockCount-- > 0) { DecipherBlock (cipher, data, ks); data += blockSize; } } }
static void DecryptBufferCBC (unsigned __int32 *data, unsigned int len, unsigned __int8 *ks, unsigned __int32 *iv, unsigned __int32 *whitening, int ea, int cipher) { /* IMPORTANT: This function has been deprecated (legacy) */ unsigned __int32 bufIV[4]; unsigned __int64 i; unsigned __int32 ct[4]; int blockSize = CipherGetBlockSize (ea != 0 ? EAGetFirstCipher (ea) : cipher); if (len % blockSize) GST_THROW_FATAL_EXCEPTION; // IV bufIV[0] = iv[0]; bufIV[1] = iv[1]; if (blockSize == 16) { bufIV[2] = iv[2]; bufIV[3] = iv[3]; } // Decrypt each block for (i = 0; i < len/blockSize; i++) { // Dewhitening data[0] ^= whitening[0]; data[1] ^= whitening[1]; if (blockSize == 16) { data[2] ^= whitening[0]; data[3] ^= whitening[1]; } // CBC ct[0] = data[0]; ct[1] = data[1]; if (blockSize == 16) { ct[2] = data[2]; ct[3] = data[3]; } if (ea != 0) { // Outer-CBC ks += EAGetKeyScheduleSize (ea); for (cipher = EAGetLastCipher (ea); cipher != 0; cipher = EAGetPreviousCipher (ea, cipher)) { ks -= CipherGetKeyScheduleSize (cipher); DecipherBlock (cipher, data, ks); } } else { // CBC/inner-CBC DecipherBlock (cipher, data, ks); } // CBC data[0] ^= bufIV[0]; data[1] ^= bufIV[1]; bufIV[0] = ct[0]; bufIV[1] = ct[1]; if (blockSize == 16) { data[2] ^= bufIV[2]; data[3] ^= bufIV[3]; bufIV[2] = ct[2]; bufIV[3] = ct[3]; } data += blockSize / sizeof(*data); } }
// 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 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)); }
static void DecryptBufferXTS8Byte (unsigned __int8 *buffer, GST_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_SMALL]; unsigned __int8 byteBufUnitNo [BYTES_PER_XTS_BLOCK_SMALL]; unsigned __int32 *whiteningValuePtr32 = (unsigned __int32 *) whiteningValue; unsigned __int32 *bufPtr = (unsigned __int32 *) buffer; unsigned __int32 startBlock = startCipherBlockNo, endBlock, block; GST_LARGEST_COMPILER_UINT blockCount; UINT64_STRUCT dataUnitNo; unsigned __int8 xor_ks[MAX_EXPANDED_KEY]; dataUnitNo.LowPart = startDataUnitNo->LowPart; dataUnitNo.HighPart = startDataUnitNo->HighPart; *((unsigned __int32 *) byteBufUnitNo) = (unsigned __int32) LE32 (dataUnitNo.LowPart); *((unsigned __int32 *) byteBufUnitNo + 1) = (unsigned __int32) LE32 (dataUnitNo.HighPart); if (length % BYTES_PER_XTS_BLOCK_SMALL) GST_THROW_FATAL_EXCEPTION; blockCount = length / BYTES_PER_XTS_BLOCK_SMALL; memcpy(xor_ks, ks, CipherGetKeyScheduleSize(cipher)); while (blockCount > 0) { if (blockCount < BLOCKS_PER_XTS_DATA_UNIT_SMALL) endBlock = startBlock + (unsigned __int32) blockCount; else endBlock = BLOCKS_PER_XTS_DATA_UNIT_SMALL; whiteningValuePtr32 = (unsigned __int32 *) whiteningValue; //Encrypt data unit using the second key to generate the first whitening value *whiteningValuePtr32 = *((unsigned __int32 *) byteBufUnitNo); *(whiteningValuePtr32+1) = *((unsigned __int32 *) byteBufUnitNo+1); EncipherBlock (cipher, whiteningValue, ks2); //XOR ks with the current DataUnitNo XorKeySchedule(cipher, ks, xor_ks, byteBufUnitNo, 8); for (block = 0; block < endBlock; block++) { if (block >= startBlock) { //Post-whitening *bufPtr++ ^= *whiteningValuePtr32++; *bufPtr-- ^= *whiteningValuePtr32--; //Actual decryption DecipherBlock (cipher, bufPtr, xor_ks); //Pre-whitening *bufPtr++ ^= *whiteningValuePtr32++; *bufPtr++ ^= *whiteningValuePtr32; } else whiteningValuePtr32++; //Derive the next whitening value #if BYTE_ORDER == LITTLE_ENDIAN //Little-endian platforms finalCarry = (*whiteningValuePtr32 & 0x80000000) ? 135 : 0; *whiteningValuePtr32-- <<= 1; if (*whiteningValuePtr32 & 0x80000000) *(whiteningValuePtr32 + 1) |= 1; *whiteningValuePtr32 <<= 1; #else //Big-endian platforms finalCarry = (*whiteningValuePtr32 & 0x80) ? 135 : 0); *whiteningValuePtr32 = LE32 (LE32 (*whiteningValuePtr32) << 1); whiteningValuePtr32--; if (*whiteningValuePtr32 & 0x80) *(whiteningValuePtr32 + 1) |= 0x1000000; *whiteningValuePtr32 = LE32 (LE32 (*whiteningValuePtr32) << 1); #endif whiteningValue[0] ^= finalCarry; } blockCount -= endBlock - startBlock; startBlock = 0; if (!++dataUnitNo.LowPart) dataUnitNo.HighPart++; *((unsigned __int32 *) byteBufUnitNo) = (unsigned __int32) LE32 (dataUnitNo.LowPart); *((unsigned __int32 *) byteBufUnitNo+1) = (unsigned __int32) LE32 (dataUnitNo.HighPart); } FAST_ERASE32 (whiteningValue, sizeof (whiteningValue)); }