void DecryptDataUnitsCurrentThread (unsigned __int8 *buf, const UINT64_STRUCT *structUnitNo, TC_LARGEST_COMPILER_UINT nbrUnits, PCRYPTO_INFO ci) #endif // !TC_WINDOWS_BOOT { int ea = ci->ea; unsigned __int8 *ks = ci->ks; unsigned __int8 *ks2 = ci->ks2; int cipher; switch (ci->mode) { case XTS: ks += EAGetKeyScheduleSize (ea); ks2 += EAGetKeyScheduleSize (ea); for (cipher = EAGetLastCipher (ea); cipher != 0; cipher = EAGetPreviousCipher (ea, cipher)) { ks -= CipherGetKeyScheduleSize (cipher); ks2 -= CipherGetKeyScheduleSize (cipher); DecryptBufferXTS (buf, nbrUnits * ENCRYPTION_DATA_UNIT_SIZE, structUnitNo, 0, ks, ks2, cipher); } break; default: // Unknown/wrong ID TC_THROW_FATAL_EXCEPTION; } }
// DecryptBuffer // // buf: data to be decrypted; the start of the buffer is assumed to be aligned with the start of a data unit. // len: number of bytes to decrypt; must be divisible by the block size (for cascaded ciphers, divisible // by the largest block size used within the cascade) void DecryptBuffer (unsigned __int8 *buf, TC_LARGEST_COMPILER_UINT len, PCRYPTO_INFO cryptoInfo) { switch (cryptoInfo->mode) { case XTS: { unsigned __int8 *ks = cryptoInfo->ks + EAGetKeyScheduleSize (cryptoInfo->ea); unsigned __int8 *ks2 = cryptoInfo->ks2 + EAGetKeyScheduleSize (cryptoInfo->ea); UINT64_STRUCT dataUnitNo; int cipher; // When encrypting/decrypting a buffer (typically a volume header) the sequential number // of the first XTS data unit in the buffer is always 0 and the start of the buffer is // always assumed to be aligned with the start of the data unit 0. dataUnitNo.LowPart = 0; dataUnitNo.HighPart = 0; for (cipher = EAGetLastCipher (cryptoInfo->ea); cipher != 0; cipher = EAGetPreviousCipher (cryptoInfo->ea, cipher)) { ks -= CipherGetKeyScheduleSize (cipher); ks2 -= CipherGetKeyScheduleSize (cipher); DecryptBufferXTS (buf, len, &dataUnitNo, 0, ks, ks2, cipher); } } break; default: // Unknown/wrong ID TC_THROW_FATAL_EXCEPTION; } }
// Returns sum of key schedule sizes of all ciphers of the EA int EAGetKeyScheduleSize (int ea) { int i = EAGetFirstCipher(ea); int size = CipherGetKeyScheduleSize (i); while (i = EAGetNextCipher(ea, i)) { size += CipherGetKeyScheduleSize (i); } return size; }
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)); }
// Return values: 0 = success, ERR_CIPHER_INIT_FAILURE (fatal), ERR_CIPHER_INIT_WEAK_KEY (non-fatal) int EAInit (int ea, unsigned char *key, unsigned __int8 *ks) { int c, retVal = ERR_SUCCESS; if (ea == 0) return ERR_CIPHER_INIT_FAILURE; for (c = EAGetFirstCipher (ea); c != 0; c = EAGetNextCipher (ea, c)) { switch (CipherInit (c, key, ks)) { case ERR_CIPHER_INIT_FAILURE: return ERR_CIPHER_INIT_FAILURE; case ERR_CIPHER_INIT_WEAK_KEY: retVal = ERR_CIPHER_INIT_WEAK_KEY; // Non-fatal error break; } key += CipherGetKeySize (c); ks += CipherGetKeyScheduleSize (c); } return retVal; }
static void EncryptBufferCBC (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; 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]; } // Encrypt each block for (i = 0; i < len/blockSize; i++) { // CBC data[0] ^= bufIV[0]; data[1] ^= bufIV[1]; if (blockSize == 16) { data[2] ^= bufIV[2]; data[3] ^= bufIV[3]; } if (ea != 0) { // Outer-CBC for (cipher = EAGetFirstCipher (ea); cipher != 0; cipher = EAGetNextCipher (ea, cipher)) { EncipherBlock (cipher, data, ks); ks += CipherGetKeyScheduleSize (cipher); } ks -= EAGetKeyScheduleSize (ea); } else { // CBC/inner-CBC EncipherBlock (cipher, data, ks); } // CBC bufIV[0] = data[0]; bufIV[1] = data[1]; if (blockSize == 16) { bufIV[2] = data[2]; bufIV[3] = data[3]; } // Whitening data[0] ^= whitening[0]; data[1] ^= whitening[1]; if (blockSize == 16) { data[2] ^= whitening[0]; data[3] ^= whitening[1]; } data += blockSize / sizeof(*data); } }
void DecryptDataUnitsCurrentThread (unsigned __int8 *buf, const UINT64_STRUCT *structUnitNo, GST_LARGEST_COMPILER_UINT nbrUnits, PCRYPTO_INFO ci) #endif // !GST_WINDOWS_BOOT { int ea = ci->ea; unsigned __int8 *ks = ci->ks; unsigned __int8 *ks2 = ci->ks2; int cipher; #ifndef GST_NO_COMPILER_INT64 void *iv = ci->k2; // Deprecated/legacy unsigned __int64 unitNo = structUnitNo->Value; unsigned __int64 *iv64 = (unsigned __int64 *) iv; // Deprecated/legacy unsigned __int32 sectorIV[4]; // Deprecated/legacy unsigned __int32 secWhitening[2]; // Deprecated/legacy #endif // #ifndef GST_NO_COMPILER_INT64 switch (ci->mode) { case XTS: ks += EAGetKeyScheduleSize (ea); ks2 += EAGetKeyScheduleSize (ea); for (cipher = EAGetLastCipher (ea); cipher != 0; cipher = EAGetPreviousCipher (ea, cipher)) { ks -= CipherGetKeyScheduleSize (cipher); ks2 -= CipherGetKeyScheduleSize (cipher); DecryptBufferXTS (buf, nbrUnits * ENCRYPTION_DATA_UNIT_SIZE, structUnitNo, 0, ks, ks2, cipher); } break; #ifndef GST_NO_COMPILER_INT64 case LRW: /* Deprecated/legacy */ switch (CipherGetBlockSize (EAGetFirstCipher (ea))) { case 8: DecryptBufferLRW64 (buf, (unsigned __int64) nbrUnits * ENCRYPTION_DATA_UNIT_SIZE, DataUnit2LRWIndex (unitNo, 8, ci), ci); break; case 16: DecryptBufferLRW128 (buf, (unsigned __int64) nbrUnits * ENCRYPTION_DATA_UNIT_SIZE, DataUnit2LRWIndex (unitNo, 16, ci), ci); break; default: GST_THROW_FATAL_EXCEPTION; } break; case CBC: case INNER_CBC: /* Deprecated/legacy */ while (nbrUnits--) { ks += EAGetKeyScheduleSize (ea); for (cipher = EAGetLastCipher (ea); cipher != 0; cipher = EAGetPreviousCipher (ea, cipher)) { InitSectorIVAndWhitening (unitNo, CipherGetBlockSize (cipher), sectorIV, iv64, secWhitening); ks -= CipherGetKeyScheduleSize (cipher); DecryptBufferCBC ((unsigned __int32 *) buf, ENCRYPTION_DATA_UNIT_SIZE, ks, sectorIV, secWhitening, 0, cipher); } buf += ENCRYPTION_DATA_UNIT_SIZE; unitNo++; } break; case OUTER_CBC: /* Deprecated/legacy */ while (nbrUnits--) { InitSectorIVAndWhitening (unitNo, CipherGetBlockSize (EAGetFirstCipher (ea)), sectorIV, iv64, secWhitening); DecryptBufferCBC ((unsigned __int32 *) buf, ENCRYPTION_DATA_UNIT_SIZE, ks, sectorIV, secWhitening, ea, 0); buf += ENCRYPTION_DATA_UNIT_SIZE; unitNo++; } break; #endif // #ifndef GST_NO_COMPILER_INT64 default: // Unknown/wrong ID GST_THROW_FATAL_EXCEPTION; } }
// DecryptBuffer // // buf: data to be decrypted; the start of the buffer is assumed to be aligned with the start of a data unit. // len: number of bytes to decrypt; must be divisible by the block size (for cascaded ciphers, divisible // by the largest block size used within the cascade) void DecryptBuffer (unsigned __int8 *buf, GST_LARGEST_COMPILER_UINT len, PCRYPTO_INFO cryptoInfo) { switch (cryptoInfo->mode) { case XTS: { unsigned __int8 *ks = cryptoInfo->ks + EAGetKeyScheduleSize (cryptoInfo->ea); unsigned __int8 *ks2 = cryptoInfo->ks2 + EAGetKeyScheduleSize (cryptoInfo->ea); UINT64_STRUCT dataUnitNo; int cipher; // When encrypting/decrypting a buffer (typically a volume header) the sequential number // of the first XTS data unit in the buffer is always 0 and the start of the buffer is // always assumed to be aligned with the start of the data unit 0. dataUnitNo.LowPart = 0; dataUnitNo.HighPart = 0; for (cipher = EAGetLastCipher (cryptoInfo->ea); cipher != 0; cipher = EAGetPreviousCipher (cryptoInfo->ea, cipher)) { ks -= CipherGetKeyScheduleSize (cipher); ks2 -= CipherGetKeyScheduleSize (cipher); DecryptBufferXTS (buf, len, &dataUnitNo, 0, ks, ks2, cipher); } } break; #ifndef GST_NO_COMPILER_INT64 case LRW: /* Deprecated/legacy */ switch (CipherGetBlockSize (EAGetFirstCipher (cryptoInfo->ea))) { case 8: DecryptBufferLRW64 (buf, (unsigned __int64) len, 1, cryptoInfo); break; case 16: DecryptBufferLRW128 (buf, (unsigned __int64) len, 1, cryptoInfo); break; default: GST_THROW_FATAL_EXCEPTION; } break; case CBC: case INNER_CBC: { /* Deprecated/legacy */ unsigned __int8 *ks = cryptoInfo->ks + EAGetKeyScheduleSize (cryptoInfo->ea); int cipher; for (cipher = EAGetLastCipher (cryptoInfo->ea); cipher != 0; cipher = EAGetPreviousCipher (cryptoInfo->ea, cipher)) { ks -= CipherGetKeyScheduleSize (cipher); DecryptBufferCBC ((unsigned __int32 *) buf, (unsigned int) len, ks, (unsigned __int32 *) cryptoInfo->k2, (unsigned __int32 *) &cryptoInfo->k2[8], 0, cipher); } } break; case OUTER_CBC: /* Deprecated/legacy */ DecryptBufferCBC ((unsigned __int32 *) buf, (unsigned int) len, cryptoInfo->ks, (unsigned __int32 *) cryptoInfo->k2, (unsigned __int32 *) &cryptoInfo->k2[8], cryptoInfo->ea, 0); break; #endif // #ifndef GST_NO_COMPILER_INT64 default: // Unknown/wrong ID GST_THROW_FATAL_EXCEPTION; } }
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)); }