|
|
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.