|
|
1.1 ! root 1: /* ! 2: Copyright (c) 2008 TrueCrypt Foundation. All rights reserved. ! 3: ! 4: Governed by the TrueCrypt License 2.4 the full text of which is contained ! 5: in the file License.txt included in TrueCrypt binary and source code ! 6: distribution packages. ! 7: */ ! 8: ! 9: #include "EncryptionModeXTS.h" ! 10: #include "Common/Crypto.h" ! 11: ! 12: namespace TrueCrypt ! 13: { ! 14: void EncryptionModeXTS::Decrypt (byte *data, uint64 length) const ! 15: { ! 16: DecryptBuffer (data, length, 0); ! 17: } ! 18: ! 19: void EncryptionModeXTS::DecryptBuffer (byte *data, uint64 length, uint64 startDataUnitNo) const ! 20: { ! 21: if_debug (ValidateState ()); ! 22: ! 23: CipherList::const_iterator iSecondaryCipher = SecondaryCiphers.end(); ! 24: foreach_reverse_ref (const Cipher &cipher, Ciphers) ! 25: { ! 26: --iSecondaryCipher; ! 27: DecryptBufferXTS (cipher, **iSecondaryCipher, data, length, startDataUnitNo, 0); ! 28: } ! 29: ! 30: assert (iSecondaryCipher == SecondaryCiphers.begin()); ! 31: } ! 32: ! 33: void EncryptionModeXTS::DecryptBufferXTS (const Cipher &cipher, const Cipher &secondaryCipher, byte *buffer, uint64 length, uint64 startDataUnitNo, unsigned int startCipherBlockNo) const ! 34: { ! 35: byte finalCarry; ! 36: byte whiteningValues [ENCRYPTION_DATA_UNIT_SIZE]; ! 37: byte whiteningValue [BYTES_PER_XTS_BLOCK]; ! 38: byte byteBufUnitNo [BYTES_PER_XTS_BLOCK]; ! 39: uint64 *whiteningValuesPtr64 = (uint64 *) whiteningValues; ! 40: uint64 *whiteningValuePtr64 = (uint64 *) whiteningValue; ! 41: uint64 *bufPtr = (uint64 *) buffer; ! 42: unsigned int startBlock = startCipherBlockNo, endBlock, block; ! 43: uint64 *const finalInt64WhiteningValuesPtr = whiteningValuesPtr64 + sizeof (whiteningValues) / sizeof (*whiteningValuesPtr64) - 1; ! 44: uint64 blockCount, dataUnitNo; ! 45: ! 46: // Convert the 64-bit data unit number into a little-endian 16-byte array. ! 47: // Note that as we are converting a 64-bit number into a 16-byte array we can always zero the last 8 bytes. ! 48: dataUnitNo = startDataUnitNo; ! 49: *((uint64 *) byteBufUnitNo) = Endian::Little (dataUnitNo); ! 50: *((uint64 *) byteBufUnitNo + 1) = 0; ! 51: ! 52: if (length % BYTES_PER_XTS_BLOCK) ! 53: TC_THROW_FATAL_EXCEPTION; ! 54: ! 55: blockCount = length / BYTES_PER_XTS_BLOCK; ! 56: ! 57: // Process all blocks in the buffer ! 58: // When length > ENCRYPTION_DATA_UNIT_SIZE, this can be parallelized (one data unit per core) ! 59: while (blockCount > 0) ! 60: { ! 61: if (blockCount < BLOCKS_PER_XTS_DATA_UNIT) ! 62: endBlock = startBlock + (unsigned int) blockCount; ! 63: else ! 64: endBlock = BLOCKS_PER_XTS_DATA_UNIT; ! 65: ! 66: whiteningValuesPtr64 = finalInt64WhiteningValuesPtr; ! 67: whiteningValuePtr64 = (uint64 *) whiteningValue; ! 68: ! 69: // Encrypt the data unit number using the secondary key (in order to generate the first ! 70: // whitening value for this data unit) ! 71: *whiteningValuePtr64 = *((uint64 *) byteBufUnitNo); ! 72: *(whiteningValuePtr64 + 1) = 0; ! 73: secondaryCipher.EncryptBlock (whiteningValue); ! 74: ! 75: // Generate subsequent whitening values for blocks in this data unit. Note that all generated 128-bit ! 76: // whitening values are stored in memory as a sequence of 64-bit integers in reverse order. ! 77: for (block = 0; block < endBlock; block++) ! 78: { ! 79: if (block >= startBlock) ! 80: { ! 81: *whiteningValuesPtr64-- = *whiteningValuePtr64++; ! 82: *whiteningValuesPtr64-- = *whiteningValuePtr64; ! 83: } ! 84: else ! 85: whiteningValuePtr64++; ! 86: ! 87: // Derive the next whiteningValue ! 88: ! 89: #if BYTE_ORDER != BIG_ENDIAN ! 90: ! 91: finalCarry = ! 92: (*whiteningValuePtr64 & 0x8000000000000000ULL) ? ! 93: 135 : 0; ! 94: ! 95: *whiteningValuePtr64-- <<= 1; ! 96: ! 97: if (*whiteningValuePtr64 & 0x8000000000000000ULL) ! 98: *(whiteningValuePtr64 + 1) |= 1; ! 99: ! 100: *whiteningValuePtr64 <<= 1; ! 101: ! 102: #else ! 103: ! 104: finalCarry = ! 105: (*whiteningValuePtr64 & 0x80) ? ! 106: 135 : 0; ! 107: ! 108: *whiteningValuePtr64 = Endian::Little (Endian::Little (*whiteningValuePtr64) << 1); ! 109: --whiteningValuePtr64; ! 110: ! 111: if (*whiteningValuePtr64 & 0x80) ! 112: *(whiteningValuePtr64 + 1) |= 0x0100000000000000ULL; ! 113: ! 114: *whiteningValuePtr64 = Endian::Little (Endian::Little (*whiteningValuePtr64) << 1); ! 115: #endif ! 116: ! 117: whiteningValue[0] ^= finalCarry; ! 118: } ! 119: ! 120: whiteningValuesPtr64 = finalInt64WhiteningValuesPtr; ! 121: ! 122: // Encrypt all blocks in this data unit ! 123: // TO DO: This should be parallelized (one block per core) ! 124: for (block = startBlock; block < endBlock; block++) ! 125: { ! 126: *bufPtr++ ^= *whiteningValuesPtr64--; ! 127: *bufPtr-- ^= *whiteningValuesPtr64++; ! 128: ! 129: cipher.DecryptBlock (reinterpret_cast <byte *> (bufPtr)); ! 130: ! 131: *bufPtr++ ^= *whiteningValuesPtr64--; ! 132: *bufPtr++ ^= *whiteningValuesPtr64--; ! 133: ! 134: blockCount--; ! 135: } ! 136: ! 137: startBlock = 0; ! 138: ! 139: dataUnitNo++; ! 140: ! 141: *((uint64 *) byteBufUnitNo) = Endian::Little (dataUnitNo); ! 142: } ! 143: ! 144: FAST_ERASE64 (whiteningValue, sizeof(whiteningValue)); ! 145: FAST_ERASE64 (whiteningValues, sizeof(whiteningValues)); ! 146: } ! 147: ! 148: void EncryptionModeXTS::DecryptSectors (byte *data, uint64 sectorIndex, uint64 sectorCount, size_t sectorSize) const ! 149: { ! 150: DecryptBuffer (data, sectorCount * sectorSize, sectorIndex * sectorSize / ENCRYPTION_DATA_UNIT_SIZE); ! 151: } ! 152: ! 153: void EncryptionModeXTS::Encrypt (byte *data, uint64 length) const ! 154: { ! 155: EncryptBuffer (data, length, 0); ! 156: } ! 157: ! 158: void EncryptionModeXTS::EncryptBuffer (byte *data, uint64 length, uint64 startDataUnitNo) const ! 159: { ! 160: if_debug (ValidateState ()); ! 161: ! 162: CipherList::const_iterator iSecondaryCipher = SecondaryCiphers.begin(); ! 163: foreach_ref (const Cipher &cipher, Ciphers) ! 164: { ! 165: EncryptBufferXTS (cipher, **iSecondaryCipher, data, length, startDataUnitNo, 0); ! 166: ++iSecondaryCipher; ! 167: } ! 168: ! 169: assert (iSecondaryCipher == SecondaryCiphers.end()); ! 170: } ! 171: ! 172: void EncryptionModeXTS::EncryptBufferXTS (const Cipher &cipher, const Cipher &secondaryCipher, byte *buffer, uint64 length, uint64 startDataUnitNo, unsigned int startCipherBlockNo) const ! 173: { ! 174: byte finalCarry; ! 175: byte whiteningValues [ENCRYPTION_DATA_UNIT_SIZE]; ! 176: byte whiteningValue [BYTES_PER_XTS_BLOCK]; ! 177: byte byteBufUnitNo [BYTES_PER_XTS_BLOCK]; ! 178: uint64 *whiteningValuesPtr64 = (uint64 *) whiteningValues; ! 179: uint64 *whiteningValuePtr64 = (uint64 *) whiteningValue; ! 180: uint64 *bufPtr = (uint64 *) buffer; ! 181: unsigned int startBlock = startCipherBlockNo, endBlock, block; ! 182: uint64 *const finalInt64WhiteningValuesPtr = whiteningValuesPtr64 + sizeof (whiteningValues) / sizeof (*whiteningValuesPtr64) - 1; ! 183: uint64 blockCount, dataUnitNo; ! 184: ! 185: /* The encrypted data unit number (i.e. the resultant ciphertext block) is to be multiplied in the ! 186: finite field GF(2^128) by j-th power of n, where j is the sequential plaintext/ciphertext block ! 187: number and n is 2, a primitive element of GF(2^128). This can be (and is) simplified and implemented ! 188: as a left shift of the preceding whitening value by one bit (with carry propagating). In addition, if ! 189: the shift of the highest byte results in a carry, 135 is XORed into the lowest byte. The value 135 is ! 190: derived from the modulus of the Galois Field (x^128+x^7+x^2+x+1). */ ! 191: ! 192: // Convert the 64-bit data unit number into a little-endian 16-byte array. ! 193: // Note that as we are converting a 64-bit number into a 16-byte array we can always zero the last 8 bytes. ! 194: dataUnitNo = startDataUnitNo; ! 195: *((uint64 *) byteBufUnitNo) = Endian::Little (dataUnitNo); ! 196: *((uint64 *) byteBufUnitNo + 1) = 0; ! 197: ! 198: if (length % BYTES_PER_XTS_BLOCK) ! 199: TC_THROW_FATAL_EXCEPTION; ! 200: ! 201: blockCount = length / BYTES_PER_XTS_BLOCK; ! 202: ! 203: // Process all blocks in the buffer ! 204: // When length > ENCRYPTION_DATA_UNIT_SIZE, this can be parallelized (one data unit per core) ! 205: while (blockCount > 0) ! 206: { ! 207: if (blockCount < BLOCKS_PER_XTS_DATA_UNIT) ! 208: endBlock = startBlock + (unsigned int) blockCount; ! 209: else ! 210: endBlock = BLOCKS_PER_XTS_DATA_UNIT; ! 211: ! 212: whiteningValuesPtr64 = finalInt64WhiteningValuesPtr; ! 213: whiteningValuePtr64 = (uint64 *) whiteningValue; ! 214: ! 215: // Encrypt the data unit number using the secondary key (in order to generate the first ! 216: // whitening value for this data unit) ! 217: *whiteningValuePtr64 = *((uint64 *) byteBufUnitNo); ! 218: *(whiteningValuePtr64 + 1) = 0; ! 219: secondaryCipher.EncryptBlock (whiteningValue); ! 220: ! 221: // Generate subsequent whitening values for blocks in this data unit. Note that all generated 128-bit ! 222: // whitening values are stored in memory as a sequence of 64-bit integers in reverse order. ! 223: for (block = 0; block < endBlock; block++) ! 224: { ! 225: if (block >= startBlock) ! 226: { ! 227: *whiteningValuesPtr64-- = *whiteningValuePtr64++; ! 228: *whiteningValuesPtr64-- = *whiteningValuePtr64; ! 229: } ! 230: else ! 231: whiteningValuePtr64++; ! 232: ! 233: // Derive the next whiteningValue ! 234: ! 235: #if BYTE_ORDER != BIG_ENDIAN ! 236: ! 237: finalCarry = ! 238: (*whiteningValuePtr64 & 0x8000000000000000ULL) ? ! 239: 135 : 0; ! 240: ! 241: *whiteningValuePtr64-- <<= 1; ! 242: ! 243: if (*whiteningValuePtr64 & 0x8000000000000000ULL) ! 244: *(whiteningValuePtr64 + 1) |= 1; ! 245: ! 246: *whiteningValuePtr64 <<= 1; ! 247: ! 248: #else ! 249: ! 250: finalCarry = ! 251: (*whiteningValuePtr64 & 0x80) ? ! 252: 135 : 0; ! 253: ! 254: *whiteningValuePtr64 = Endian::Little (Endian::Little (*whiteningValuePtr64) << 1); ! 255: --whiteningValuePtr64; ! 256: ! 257: if (*whiteningValuePtr64 & 0x80) ! 258: *(whiteningValuePtr64 + 1) |= 0x0100000000000000ULL; ! 259: ! 260: *whiteningValuePtr64 = Endian::Little (Endian::Little (*whiteningValuePtr64) << 1); ! 261: #endif ! 262: ! 263: whiteningValue[0] ^= finalCarry; ! 264: } ! 265: ! 266: whiteningValuesPtr64 = finalInt64WhiteningValuesPtr; ! 267: ! 268: // Decrypt blocks in this data unit ! 269: // TO DO: This should be parallelized (one block per core) ! 270: for (block = startBlock; block < endBlock; block++) ! 271: { ! 272: *bufPtr++ ^= *whiteningValuesPtr64--; ! 273: *bufPtr-- ^= *whiteningValuesPtr64++; ! 274: ! 275: cipher.EncryptBlock (reinterpret_cast <byte *> (bufPtr)); ! 276: ! 277: *bufPtr++ ^= *whiteningValuesPtr64--; ! 278: *bufPtr++ ^= *whiteningValuesPtr64--; ! 279: ! 280: blockCount--; ! 281: } ! 282: ! 283: startBlock = 0; ! 284: ! 285: dataUnitNo++; ! 286: ! 287: *((uint64 *) byteBufUnitNo) = Endian::Little (dataUnitNo); ! 288: } ! 289: ! 290: FAST_ERASE64 (whiteningValue, sizeof(whiteningValue)); ! 291: FAST_ERASE64 (whiteningValues, sizeof(whiteningValues)); ! 292: } ! 293: ! 294: void EncryptionModeXTS::EncryptSectors (byte *data, uint64 sectorIndex, uint64 sectorCount, size_t sectorSize) const ! 295: { ! 296: EncryptBuffer (data, sectorCount * sectorSize, sectorIndex * sectorSize / ENCRYPTION_DATA_UNIT_SIZE); ! 297: } ! 298: ! 299: size_t EncryptionModeXTS::GetKeySize () const ! 300: { ! 301: if (Ciphers.empty()) ! 302: throw NotInitialized (SRC_POS); ! 303: ! 304: size_t keySize = 0; ! 305: foreach_ref (const Cipher &cipher, SecondaryCiphers) ! 306: { ! 307: keySize += cipher.GetKeySize(); ! 308: } ! 309: ! 310: return keySize; ! 311: } ! 312: ! 313: void EncryptionModeXTS::SetCiphers (const CipherList &ciphers) ! 314: { ! 315: EncryptionMode::SetCiphers (ciphers); ! 316: ! 317: SecondaryCiphers.clear(); ! 318: ! 319: foreach_ref (const Cipher &cipher, ciphers) ! 320: { ! 321: SecondaryCiphers.push_back (cipher.GetNew()); ! 322: } ! 323: ! 324: if (SecondaryKey.Size() > 0) ! 325: SetSecondaryCipherKeys(); ! 326: } ! 327: ! 328: void EncryptionModeXTS::SetKey (const ConstBufferPtr &key) ! 329: { ! 330: SecondaryKey.Allocate (key.Size()); ! 331: SecondaryKey.CopyFrom (key); ! 332: ! 333: if (!SecondaryCiphers.empty()) ! 334: SetSecondaryCipherKeys(); ! 335: } ! 336: ! 337: void EncryptionModeXTS::SetSecondaryCipherKeys () ! 338: { ! 339: size_t keyOffset = 0; ! 340: foreach_ref (Cipher &cipher, SecondaryCiphers) ! 341: { ! 342: cipher.SetKey (SecondaryKey.GetRange (keyOffset, cipher.GetKeySize())); ! 343: keyOffset += cipher.GetKeySize(); ! 344: } ! 345: ! 346: KeySet = true; ! 347: } ! 348: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.