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