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