|
|
1.1.1.10 root 1: /*
1.1.1.12 root 2: Legal Notice: Some portions of the source code contained in this file were
3: derived from the source code of Encryption for the Masses 2.02a, which is
4: Copyright (c) 1998-2000 Paul Le Roux and which is governed by the 'License
5: Agreement for Encryption for the Masses'. Modifications and additions to
6: the original source code (contained in this file) and all other portions of
7: this file are Copyright (c) 2003-2008 TrueCrypt Foundation and are governed
1.1.1.15! root 8: by the TrueCrypt License 2.6 the full text of which is contained in the
1.1.1.12 root 9: file License.txt included in TrueCrypt binary and source code distribution
1.1.1.10 root 10: packages. */
1.1 root 11:
1.1.1.6 root 12: #include "Tcdefs.h"
1.1 root 13:
1.1.1.12 root 14: #ifndef TC_WINDOWS_BOOT
1.1 root 15: #include <fcntl.h>
1.1.1.10 root 16: #include <string.h>
1.1 root 17: #include <sys/types.h>
18: #include <sys/stat.h>
19: #include <time.h>
1.1.1.14 root 20: #include "EncryptionThreadPool.h"
1.1.1.12 root 21: #endif
1.1 root 22:
1.1.1.15! root 23: #include <stddef.h>
1.1.1.6 root 24: #include <io.h>
25: #include "Random.h"
26:
1.1.1.14 root 27: #include "Crc.h"
1.1.1.6 root 28: #include "Crypto.h"
1.1.1.15! root 29: #include "Endian.h"
1.1.1.6 root 30: #include "Volumes.h"
31: #include "Pkcs5.h"
1.1 root 32:
33:
1.1.1.15! root 34: /* Volume header v4 structure (used since TrueCrypt 6.0): */
1.1.1.14 root 35: //
36: // Offset Length Description
37: // ------------------------------------------
38: // Unencrypted:
39: // 0 64 Salt
40: // Encrypted:
41: // 64 4 ASCII string 'TRUE'
42: // 68 2 Header version
43: // 70 2 Required program version
44: // 72 4 CRC-32 checksum of the (decrypted) bytes 256-511
45: // 76 8 Reserved (set to zero)
46: // 84 8 Reserved (set to zero)
47: // 92 8 Size of hidden volume in bytes (0 = normal volume)
48: // 100 8 Size of the volume in bytes (identical with field 92 for hidden volumes)
49: // 108 8 Byte offset of the start of the master key scope
50: // 116 8 Size of the encrypted area within the master key scope
1.1.1.15! root 51: // 124 4 Flags: bit 0 set = system encryption; bit 1 set = non-system in-place encryption, bits 2-31 are reserved
1.1.1.14 root 52: // 128 124 Reserved (set to zero)
53: // 252 4 CRC-32 checksum of the (decrypted) bytes 64-251
54: // 256 256 Concatenated primary master key(s) and secondary master key(s) (XTS mode)
55: // 512 65024 Reserved
1.1.1.12 root 56:
1.1.1.14 root 57:
1.1.1.15! root 58: /* Deprecated/legacy volume header v3 structure (used by TrueCrypt 5.x): */
1.1.1.12 root 59: //
60: // Offset Length Description
61: // ------------------------------------------
62: // Unencrypted:
63: // 0 64 Salt
64: // Encrypted:
65: // 64 4 ASCII string 'TRUE'
66: // 68 2 Header version
67: // 70 2 Required program version
68: // 72 4 CRC-32 checksum of the (decrypted) bytes 256-511
69: // 76 8 Volume creation time
70: // 84 8 Header creation time
71: // 92 8 Size of hidden volume in bytes (0 = normal volume)
72: // 100 8 Size of the volume in bytes (identical with field 92 for hidden volumes)
73: // 108 8 Start byte offset of the encrypted area of the volume
74: // 116 8 Size of the encrypted area of the volume in bytes
75: // 124 132 Reserved (set to zero)
76: // 256 256 Concatenated primary master key(s) and secondary master key(s) (XTS mode)
1.1 root 77:
78:
1.1.1.12 root 79: /* Deprecated/legacy volume header v2 structure (used before TrueCrypt 5.0): */
1.1 root 80: //
81: // Offset Length Description
82: // ------------------------------------------
83: // Unencrypted:
1.1.1.6 root 84: // 0 64 Salt
1.1 root 85: // Encrypted:
1.1.1.4 root 86: // 64 4 ASCII string 'TRUE'
1.1 root 87: // 68 2 Header version
88: // 70 2 Required program version
1.1.1.7 root 89: // 72 4 CRC-32 checksum of the (decrypted) bytes 256-511
1.1 root 90: // 76 8 Volume creation time
91: // 84 8 Header creation time
1.1.1.4 root 92: // 92 8 Size of hidden volume in bytes (0 = normal volume)
1.1.1.7 root 93: // 100 156 Reserved (set to zero)
1.1.1.12 root 94: // 256 32 For LRW (deprecated/legacy), secondary key
95: // For CBC (deprecated/legacy), data used to generate IV and whitening values
1.1.1.7 root 96: // 288 224 Master key(s)
1.1 root 97:
1.1.1.12 root 98:
99:
1.1.1.15! root 100: uint16 GetHeaderField16 (byte *header, int offset)
1.1.1.12 root 101: {
102: return BE16 (*(uint16 *) (header + offset));
103: }
104:
105:
1.1.1.15! root 106: uint32 GetHeaderField32 (byte *header, int offset)
1.1.1.12 root 107: {
108: return BE32 (*(uint32 *) (header + offset));
109: }
110:
111:
1.1.1.15! root 112: UINT64_STRUCT GetHeaderField64 (byte *header, int offset)
1.1.1.12 root 113: {
114: UINT64_STRUCT uint64Struct;
115:
116: #ifndef TC_NO_COMPILER_INT64
117: uint64Struct.Value = BE64 (*(uint64 *) (header + offset));
118: #else
119: uint64Struct.HighPart = BE32 (*(uint32 *) (header + offset));
120: uint64Struct.LowPart = BE32 (*(uint32 *) (header + offset + 4));
121: #endif
122: return uint64Struct;
123: }
124:
125:
1.1.1.13 root 126: #ifndef TC_WINDOWS_BOOT
127:
1.1.1.14 root 128: typedef struct
129: {
130: char DerivedKey[MASTER_KEYDATA_SIZE];
131: BOOL Free;
132: LONG KeyReady;
133: int Pkcs5Prf;
134: } KeyDerivationWorkItem;
135:
136:
1.1.1.15! root 137: BOOL ReadVolumeHeaderRecoveryMode = FALSE;
! 138:
! 139: int ReadVolumeHeader (BOOL bBoot, char *encryptedHeader, Password *password, PCRYPTO_INFO *retInfo, CRYPTO_INFO *retHeaderCryptoInfo)
1.1 root 140: {
1.1.1.14 root 141: char header[TC_VOLUME_HEADER_EFFECTIVE_SIZE];
1.1 root 142: KEY_INFO keyInfo;
143: PCRYPTO_INFO cryptoInfo;
1.1.1.12 root 144: char dk[MASTER_KEYDATA_SIZE];
1.1.1.14 root 145: int enqPkcs5Prf, pkcs5_prf;
146: int headerVersion;
1.1.1.15! root 147: int status = ERR_PARAMETER_INCORRECT;
1.1.1.12 root 148: int primaryKeyOffset;
1.1.1.6 root 149:
1.1.1.14 root 150: TC_EVENT keyDerivationCompletedEvent;
151: TC_EVENT noOutstandingWorkItemEvent;
152: KeyDerivationWorkItem *keyDerivationWorkItems;
153: KeyDerivationWorkItem *item;
154: int pkcs5PrfCount = LAST_PRF_ID - FIRST_PRF_ID + 1;
155: int encryptionThreadCount = GetEncryptionThreadCount();
156: int queuedWorkItems = 0;
157: LONG outstandingWorkItemCount = 0;
158: int i;
1.1.1.7 root 159:
1.1.1.12 root 160: if (retHeaderCryptoInfo != NULL)
161: {
162: cryptoInfo = retHeaderCryptoInfo;
163: }
164: else
165: {
166: cryptoInfo = *retInfo = crypto_open ();
167: if (cryptoInfo == NULL)
168: return ERR_OUTOFMEMORY;
169: }
1.1 root 170:
1.1.1.14 root 171: if (encryptionThreadCount > 1)
172: {
173: keyDerivationWorkItems = TCalloc (sizeof (KeyDerivationWorkItem) * pkcs5PrfCount);
174: if (!keyDerivationWorkItems)
175: return ERR_OUTOFMEMORY;
176:
177: for (i = 0; i < pkcs5PrfCount; ++i)
178: keyDerivationWorkItems[i].Free = TRUE;
179:
180: #ifdef DEVICE_DRIVER
181: KeInitializeEvent (&keyDerivationCompletedEvent, SynchronizationEvent, FALSE);
182: KeInitializeEvent (&noOutstandingWorkItemEvent, SynchronizationEvent, TRUE);
183: #else
184: keyDerivationCompletedEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
185: if (!keyDerivationCompletedEvent)
186: {
187: TCfree (keyDerivationWorkItems);
188: return ERR_OUTOFMEMORY;
189: }
190:
191: noOutstandingWorkItemEvent = CreateEvent (NULL, FALSE, TRUE, NULL);
192: if (!noOutstandingWorkItemEvent)
193: {
194: CloseHandle (keyDerivationCompletedEvent);
195: TCfree (keyDerivationWorkItems);
196: return ERR_OUTOFMEMORY;
197: }
198: #endif
199: }
200:
201: #ifndef DEVICE_DRIVER
202: VirtualLock (&keyInfo, sizeof (keyInfo));
203: VirtualLock (&dk, sizeof (dk));
204: #endif
205:
1.1.1.12 root 206: crypto_loadkey (&keyInfo, password->Text, (int) password->Length);
1.1 root 207:
1.1.1.12 root 208: // PKCS5 is used to derive the primary header key(s) and secondary header key(s) (XTS mode) from the password
209: memcpy (keyInfo.salt, encryptedHeader + HEADER_SALT_OFFSET, PKCS5_SALT_SIZE);
1.1 root 210:
1.1.1.3 root 211: // Test all available PKCS5 PRFs
1.1.1.14 root 212: for (enqPkcs5Prf = FIRST_PRF_ID; enqPkcs5Prf <= LAST_PRF_ID || queuedWorkItems > 0; ++enqPkcs5Prf)
1.1 root 213: {
1.1.1.12 root 214: BOOL lrw64InitDone = FALSE; // Deprecated/legacy
215: BOOL lrw128InitDone = FALSE; // Deprecated/legacy
1.1.1.7 root 216:
1.1.1.14 root 217: if (encryptionThreadCount > 1)
218: {
219: // Enqueue key derivation on thread pool
220: if (queuedWorkItems < encryptionThreadCount && enqPkcs5Prf <= LAST_PRF_ID)
221: {
222: for (i = 0; i < pkcs5PrfCount; ++i)
223: {
224: item = &keyDerivationWorkItems[i];
225: if (item->Free)
226: {
227: item->Free = FALSE;
228: item->KeyReady = FALSE;
229: item->Pkcs5Prf = enqPkcs5Prf;
230:
231: EncryptionThreadPoolBeginKeyDerivation (&keyDerivationCompletedEvent, &noOutstandingWorkItemEvent,
232: &item->KeyReady, &outstandingWorkItemCount, enqPkcs5Prf, keyInfo.userKey,
233: keyInfo.keyLength, keyInfo.salt, get_pkcs5_iteration_count (enqPkcs5Prf, bBoot), item->DerivedKey);
234:
235: ++queuedWorkItems;
236: break;
237: }
238: }
239:
240: if (enqPkcs5Prf < LAST_PRF_ID)
241: continue;
242: }
243: else
244: --enqPkcs5Prf;
245:
246: // Wait for completion of a key derivation
247: while (queuedWorkItems > 0)
248: {
249: for (i = 0; i < pkcs5PrfCount; ++i)
250: {
251: item = &keyDerivationWorkItems[i];
252: if (!item->Free && InterlockedExchangeAdd (&item->KeyReady, 0) == TRUE)
253: {
254: pkcs5_prf = item->Pkcs5Prf;
255: keyInfo.noIterations = get_pkcs5_iteration_count (pkcs5_prf, bBoot);
256: memcpy (dk, item->DerivedKey, sizeof (dk));
257:
258: item->Free = TRUE;
259: --queuedWorkItems;
260: goto KeyReady;
261: }
262: }
1.1.1.6 root 263:
1.1.1.14 root 264: if (queuedWorkItems > 0)
265: TC_WAIT_EVENT (keyDerivationCompletedEvent);
266: }
267: continue;
268: KeyReady: ;
269: }
270: else
1.1.1.3 root 271: {
1.1.1.14 root 272: pkcs5_prf = enqPkcs5Prf;
273: keyInfo.noIterations = get_pkcs5_iteration_count (enqPkcs5Prf, bBoot);
274:
275: switch (pkcs5_prf)
276: {
277: case RIPEMD160:
278: derive_key_ripemd160 (keyInfo.userKey, keyInfo.keyLength, keyInfo.salt,
279: PKCS5_SALT_SIZE, keyInfo.noIterations, dk, GetMaxPkcs5OutSize());
280: break;
281:
282: case SHA512:
283: derive_key_sha512 (keyInfo.userKey, keyInfo.keyLength, keyInfo.salt,
284: PKCS5_SALT_SIZE, keyInfo.noIterations, dk, GetMaxPkcs5OutSize());
285: break;
286:
287: case SHA1:
288: // Deprecated/legacy
289: derive_key_sha1 (keyInfo.userKey, keyInfo.keyLength, keyInfo.salt,
290: PKCS5_SALT_SIZE, keyInfo.noIterations, dk, GetMaxPkcs5OutSize());
291: break;
292:
293: case WHIRLPOOL:
294: derive_key_whirlpool (keyInfo.userKey, keyInfo.keyLength, keyInfo.salt,
295: PKCS5_SALT_SIZE, keyInfo.noIterations, dk, GetMaxPkcs5OutSize());
296: break;
297:
298: default:
299: // Unknown/wrong ID
300: TC_THROW_FATAL_EXCEPTION;
301: }
302: }
1.1 root 303:
1.1.1.12 root 304: // Test all available modes of operation
305: for (cryptoInfo->mode = FIRST_MODE_OF_OPERATION_ID;
306: cryptoInfo->mode <= LAST_MODE_OF_OPERATION;
307: cryptoInfo->mode++)
1.1.1.3 root 308: {
1.1.1.12 root 309: switch (cryptoInfo->mode)
310: {
311: case LRW:
312: case CBC:
313: case INNER_CBC:
314: case OUTER_CBC:
315:
316: // For LRW (deprecated/legacy), copy the tweak key
317: // For CBC (deprecated/legacy), copy the IV/whitening seed
318: memcpy (cryptoInfo->k2, dk, LEGACY_VOL_IV_SIZE);
319: primaryKeyOffset = LEGACY_VOL_IV_SIZE;
320: break;
1.1.1.13 root 321:
1.1.1.12 root 322: default:
323: primaryKeyOffset = 0;
324: }
1.1.1.6 root 325:
1.1.1.12 root 326: // Test all available encryption algorithms
327: for (cryptoInfo->ea = EAGetFirst ();
328: cryptoInfo->ea != 0;
329: cryptoInfo->ea = EAGetNext (cryptoInfo->ea))
1.1.1.6 root 330: {
1.1.1.12 root 331: int blockSize;
332:
333: if (!EAIsModeSupported (cryptoInfo->ea, cryptoInfo->mode))
334: continue; // This encryption algorithm has never been available with this mode of operation
1.1.1.7 root 335:
1.1.1.12 root 336: blockSize = CipherGetBlockSize (EAGetFirstCipher (cryptoInfo->ea));
337:
338: status = EAInit (cryptoInfo->ea, dk + primaryKeyOffset, cryptoInfo->ks);
339: if (status == ERR_CIPHER_INIT_FAILURE)
340: goto err;
341:
342: // Init objects related to the mode of operation
343:
344: if (cryptoInfo->mode == XTS)
345: {
346: // Copy the secondary key (if cascade, multiple concatenated)
347: memcpy (cryptoInfo->k2, dk + EAGetKeySize (cryptoInfo->ea), EAGetKeySize (cryptoInfo->ea));
348:
349: // Secondary key schedule
350: if (!EAInitMode (cryptoInfo))
351: {
352: status = ERR_MODE_INIT_FAILED;
353: goto err;
354: }
355: }
356: else if (cryptoInfo->mode == LRW
1.1.1.7 root 357: && (blockSize == 8 && !lrw64InitDone || blockSize == 16 && !lrw128InitDone))
358: {
1.1.1.12 root 359: // Deprecated/legacy
360:
1.1.1.7 root 361: if (!EAInitMode (cryptoInfo))
362: {
363: status = ERR_MODE_INIT_FAILED;
364: goto err;
365: }
366:
1.1.1.12 root 367: if (blockSize == 8)
1.1.1.7 root 368: lrw64InitDone = TRUE;
369: else if (blockSize == 16)
370: lrw128InitDone = TRUE;
371: }
372:
1.1.1.12 root 373: // Copy the header for decryption
1.1.1.14 root 374: memcpy (header, encryptedHeader, sizeof (header));
1.1.1.7 root 375:
376: // Try to decrypt header
377:
1.1.1.12 root 378: DecryptBuffer (header + HEADER_ENCRYPTED_DATA_OFFSET, HEADER_ENCRYPTED_DATA_SIZE, cryptoInfo);
1.1.1.7 root 379:
380: // Magic 'TRUE'
1.1.1.12 root 381: if (GetHeaderField32 (header, TC_HEADER_OFFSET_MAGIC) != 0x54525545)
1.1.1.7 root 382: continue;
383:
384: // Header version
1.1.1.12 root 385: headerVersion = GetHeaderField16 (header, TC_HEADER_OFFSET_VERSION);
1.1.1.14 root 386:
387: // Check CRC of the header fields
1.1.1.15! root 388: if (!ReadVolumeHeaderRecoveryMode
! 389: && headerVersion >= 4
! 390: && GetHeaderField32 (header, TC_HEADER_OFFSET_HEADER_CRC) != GetCrc32 (header + TC_HEADER_OFFSET_MAGIC, TC_HEADER_OFFSET_HEADER_CRC - TC_HEADER_OFFSET_MAGIC))
1.1.1.14 root 391: continue;
1.1.1.7 root 392:
393: // Required program version
1.1.1.14 root 394: cryptoInfo->RequiredProgramVersion = GetHeaderField16 (header, TC_HEADER_OFFSET_REQUIRED_VERSION);
395: cryptoInfo->LegacyVolume = cryptoInfo->RequiredProgramVersion < 0x600;
1.1.1.7 root 396:
397: // Check CRC of the key set
1.1.1.15! root 398: if (!ReadVolumeHeaderRecoveryMode
! 399: && GetHeaderField32 (header, TC_HEADER_OFFSET_KEY_AREA_CRC) != GetCrc32 (header + HEADER_MASTER_KEYDATA_OFFSET, MASTER_KEYDATA_SIZE))
1.1.1.7 root 400: continue;
401:
402: // Now we have the correct password, cipher, hash algorithm, and volume type
403:
404: // Check the version required to handle this volume
1.1.1.14 root 405: if (cryptoInfo->RequiredProgramVersion > VERSION_NUM)
1.1.1.7 root 406: {
407: status = ERR_NEW_VERSION_REQUIRED;
408: goto err;
409: }
410:
1.1.1.14 root 411: // Volume creation time (legacy)
1.1.1.12 root 412: cryptoInfo->volume_creation_time = GetHeaderField64 (header, TC_HEADER_OFFSET_VOLUME_CREATION_TIME).Value;
1.1.1.7 root 413:
1.1.1.14 root 414: // Header creation time (legacy)
1.1.1.12 root 415: cryptoInfo->header_creation_time = GetHeaderField64 (header, TC_HEADER_OFFSET_MODIFICATION_TIME).Value;
1.1.1.7 root 416:
417: // Hidden volume size (if any)
1.1.1.12 root 418: cryptoInfo->hiddenVolumeSize = GetHeaderField64 (header, TC_HEADER_OFFSET_HIDDEN_VOLUME_SIZE).Value;
1.1.1.13 root 419:
1.1.1.14 root 420: // Hidden volume status
421: cryptoInfo->hiddenVolume = (cryptoInfo->hiddenVolumeSize != 0);
422:
1.1.1.12 root 423: // Volume size
424: cryptoInfo->VolumeSize = GetHeaderField64 (header, TC_HEADER_OFFSET_VOLUME_SIZE);
425:
426: // Encrypted area size and length
427: cryptoInfo->EncryptedAreaStart = GetHeaderField64 (header, TC_HEADER_OFFSET_ENCRYPTED_AREA_START);
428: cryptoInfo->EncryptedAreaLength = GetHeaderField64 (header, TC_HEADER_OFFSET_ENCRYPTED_AREA_LENGTH);
429:
1.1.1.14 root 430: // Flags
431: cryptoInfo->HeaderFlags = GetHeaderField32 (header, TC_HEADER_OFFSET_FLAGS);
432:
1.1.1.12 root 433: // Preserve scheduled header keys if requested
434: if (retHeaderCryptoInfo)
435: {
436: if (retInfo == NULL)
437: {
438: cryptoInfo->pkcs5 = pkcs5_prf;
439: cryptoInfo->noIterations = keyInfo.noIterations;
440: goto ret;
441: }
442:
443: cryptoInfo = *retInfo = crypto_open ();
444: if (cryptoInfo == NULL)
445: {
446: status = ERR_OUTOFMEMORY;
447: goto err;
448: }
1.1.1.7 root 449:
1.1.1.12 root 450: memcpy (cryptoInfo, retHeaderCryptoInfo, sizeof (*cryptoInfo));
451: }
452:
453: // Master key data
454: memcpy (keyInfo.master_keydata, header + HEADER_MASTER_KEYDATA_OFFSET, MASTER_KEYDATA_SIZE);
455: memcpy (cryptoInfo->master_keydata, keyInfo.master_keydata, MASTER_KEYDATA_SIZE);
456:
457: // PKCS #5
458: memcpy (cryptoInfo->salt, keyInfo.salt, PKCS5_SALT_SIZE);
459: cryptoInfo->pkcs5 = pkcs5_prf;
1.1.1.7 root 460: cryptoInfo->noIterations = keyInfo.noIterations;
461:
1.1.1.15! root 462: // Init the cipher with the decrypted master key
1.1.1.12 root 463: status = EAInit (cryptoInfo->ea, keyInfo.master_keydata + primaryKeyOffset, cryptoInfo->ks);
1.1.1.7 root 464: if (status == ERR_CIPHER_INIT_FAILURE)
465: goto err;
466:
1.1.1.12 root 467: switch (cryptoInfo->mode)
468: {
469: case LRW:
470: case CBC:
471: case INNER_CBC:
472: case OUTER_CBC:
473:
474: // For LRW (deprecated/legacy), the tweak key
475: // For CBC (deprecated/legacy), the IV/whitening seed
476: memcpy (cryptoInfo->k2, keyInfo.master_keydata, LEGACY_VOL_IV_SIZE);
477: break;
1.1.1.13 root 478:
1.1.1.12 root 479: default:
480: // The secondary master key (if cascade, multiple concatenated)
481: memcpy (cryptoInfo->k2, keyInfo.master_keydata + EAGetKeySize (cryptoInfo->ea), EAGetKeySize (cryptoInfo->ea));
482:
483: }
1.1.1.7 root 484:
485: if (!EAInitMode (cryptoInfo))
486: {
487: status = ERR_MODE_INIT_FAILED;
488: goto err;
489: }
1.1.1.6 root 490:
1.1.1.15! root 491: status = ERR_SUCCESS;
1.1.1.14 root 492: goto ret;
1.1.1.7 root 493: }
1.1.1.2 root 494: }
1.1 root 495: }
1.1.1.6 root 496: status = ERR_PASSWORD_WRONG;
1.1 root 497:
1.1.1.6 root 498: err:
1.1.1.12 root 499: if (cryptoInfo != retHeaderCryptoInfo)
500: {
501: crypto_close(cryptoInfo);
502: *retInfo = NULL;
503: }
504:
1.1.1.14 root 505: ret:
1.1 root 506: burn (&keyInfo, sizeof (keyInfo));
1.1.1.12 root 507: burn (dk, sizeof(dk));
1.1.1.14 root 508:
509: #ifndef DEVICE_DRIVER
510: VirtualUnlock (&keyInfo, sizeof (keyInfo));
511: VirtualUnlock (&dk, sizeof (dk));
512: #endif
513:
514: if (encryptionThreadCount > 1)
515: {
516: TC_WAIT_EVENT (noOutstandingWorkItemEvent);
517:
518: burn (keyDerivationWorkItems, sizeof (KeyDerivationWorkItem) * pkcs5PrfCount);
519: TCfree (keyDerivationWorkItems);
520:
521: #ifndef DEVICE_DRIVER
522: CloseHandle (keyDerivationCompletedEvent);
523: CloseHandle (noOutstandingWorkItemEvent);
524: #endif
525: }
526:
1.1.1.6 root 527: return status;
1.1 root 528: }
529:
1.1.1.13 root 530: #else // TC_WINDOWS_BOOT
531:
1.1.1.15! root 532: int ReadVolumeHeader (BOOL bBoot, char *header, Password *password, PCRYPTO_INFO *retInfo, CRYPTO_INFO *retHeaderCryptoInfo)
1.1.1.13 root 533: {
534: #ifdef TC_WINDOWS_BOOT_SINGLE_CIPHER_MODE
535: char dk[32 * 2]; // 2 * 256-bit key
536: char masterKey[32 * 2];
537: #else
538: char dk[32 * 2 * 3]; // 6 * 256-bit key
539: char masterKey[32 * 2 * 3];
540: #endif
541:
542: PCRYPTO_INFO cryptoInfo;
543: int status;
544:
545: if (retHeaderCryptoInfo != NULL)
546: cryptoInfo = retHeaderCryptoInfo;
547: else
548: cryptoInfo = *retInfo = crypto_open ();
549:
550: // PKCS5 PRF
551: derive_key_ripemd160 (password->Text, (int) password->Length, header + HEADER_SALT_OFFSET,
1.1.1.14 root 552: PKCS5_SALT_SIZE, bBoot ? 1000 : 2000, dk, sizeof (dk));
1.1.1.13 root 553:
554: // Mode of operation
555: cryptoInfo->mode = FIRST_MODE_OF_OPERATION_ID;
556:
557: // Test all available encryption algorithms
558: for (cryptoInfo->ea = EAGetFirst (); cryptoInfo->ea != 0; cryptoInfo->ea = EAGetNext (cryptoInfo->ea))
559: {
560: status = EAInit (cryptoInfo->ea, dk, cryptoInfo->ks);
561: if (status == ERR_CIPHER_INIT_FAILURE)
562: goto err;
563:
564: // Secondary key schedule
565: EAInit (cryptoInfo->ea, dk + EAGetKeySize (cryptoInfo->ea), cryptoInfo->ks2);
566:
567: // Try to decrypt header
568: DecryptBuffer (header + HEADER_ENCRYPTED_DATA_OFFSET, HEADER_ENCRYPTED_DATA_SIZE, cryptoInfo);
569:
1.1.1.14 root 570: // Check magic 'TRUE' and CRC-32 of header fields and master keydata
1.1.1.13 root 571: if (GetHeaderField32 (header, TC_HEADER_OFFSET_MAGIC) != 0x54525545
1.1.1.14 root 572: || (GetHeaderField16 (header, TC_HEADER_OFFSET_VERSION) >= 4 && GetHeaderField32 (header, TC_HEADER_OFFSET_HEADER_CRC) != GetCrc32 (header + TC_HEADER_OFFSET_MAGIC, TC_HEADER_OFFSET_HEADER_CRC - TC_HEADER_OFFSET_MAGIC))
1.1.1.13 root 573: || GetHeaderField32 (header, TC_HEADER_OFFSET_KEY_AREA_CRC) != GetCrc32 (header + HEADER_MASTER_KEYDATA_OFFSET, MASTER_KEYDATA_SIZE))
574: {
575: EncryptBuffer (header + HEADER_ENCRYPTED_DATA_OFFSET, HEADER_ENCRYPTED_DATA_SIZE, cryptoInfo);
576: continue;
577: }
578:
579: // Header decrypted
580: status = 0;
581:
1.1.1.14 root 582: // Hidden volume status
583: cryptoInfo->VolumeSize = GetHeaderField64 (header, TC_HEADER_OFFSET_HIDDEN_VOLUME_SIZE);
584: cryptoInfo->hiddenVolume = (cryptoInfo->VolumeSize.LowPart != 0 || cryptoInfo->VolumeSize.HighPart != 0);
585:
1.1.1.13 root 586: // Volume size
587: cryptoInfo->VolumeSize = GetHeaderField64 (header, TC_HEADER_OFFSET_VOLUME_SIZE);
588:
589: // Encrypted area size and length
590: cryptoInfo->EncryptedAreaStart = GetHeaderField64 (header, TC_HEADER_OFFSET_ENCRYPTED_AREA_START);
591: cryptoInfo->EncryptedAreaLength = GetHeaderField64 (header, TC_HEADER_OFFSET_ENCRYPTED_AREA_LENGTH);
592:
1.1.1.14 root 593: // Flags
594: cryptoInfo->HeaderFlags = GetHeaderField32 (header, TC_HEADER_OFFSET_FLAGS);
595:
1.1.1.13 root 596: memcpy (masterKey, header + HEADER_MASTER_KEYDATA_OFFSET, sizeof (masterKey));
597: EncryptBuffer (header + HEADER_ENCRYPTED_DATA_OFFSET, HEADER_ENCRYPTED_DATA_SIZE, cryptoInfo);
598:
599: if (retHeaderCryptoInfo)
600: goto ret;
601:
602: // Init the encryption algorithm with the decrypted master key
603: status = EAInit (cryptoInfo->ea, masterKey, cryptoInfo->ks);
604: if (status == ERR_CIPHER_INIT_FAILURE)
605: goto err;
606:
607: // The secondary master key (if cascade, multiple concatenated)
608: EAInit (cryptoInfo->ea, masterKey + EAGetKeySize (cryptoInfo->ea), cryptoInfo->ks2);
609: goto ret;
610: }
611:
612: status = ERR_PASSWORD_WRONG;
613:
614: err:
615: if (cryptoInfo != retHeaderCryptoInfo)
616: {
617: crypto_close(cryptoInfo);
618: *retInfo = NULL;
619: }
620:
621: ret:
622: burn (dk, sizeof(dk));
623: burn (masterKey, sizeof(masterKey));
624: return status;
625: }
626:
627: #endif // TC_WINDOWS_BOOT
628:
629:
1.1.1.12 root 630: #if !defined (DEVICE_DRIVER) && !defined (TC_WINDOWS_BOOT)
1.1 root 631:
632: #ifdef VOLFORMAT
1.1.1.15! root 633: # include "../Format/TcFormat.h"
! 634: # include "Dlgcode.h"
1.1 root 635: #endif
636:
1.1.1.12 root 637: // Creates a volume header in memory
1.1.1.15! root 638: int CreateVolumeHeaderInMemory (BOOL bBoot, char *header, int ea, int mode, Password *password,
1.1.1.14 root 639: int pkcs5_prf, char *masterKeydata, PCRYPTO_INFO *retInfo,
1.1.1.12 root 640: unsigned __int64 volumeSize, unsigned __int64 hiddenVolumeSize,
1.1.1.14 root 641: unsigned __int64 encryptedAreaStart, unsigned __int64 encryptedAreaLength, uint16 requiredProgramVersion, uint32 headerFlags, BOOL bWipeMode)
1.1 root 642: {
643: unsigned char *p = (unsigned char *) header;
1.1.1.6 root 644: static KEY_INFO keyInfo;
1.1 root 645:
1.1.1.6 root 646: int nUserKeyLen = password->Length;
1.1 root 647: PCRYPTO_INFO cryptoInfo = crypto_open ();
1.1.1.12 root 648: static char dk[MASTER_KEYDATA_SIZE];
1.1 root 649: int x;
1.1.1.6 root 650: int retVal = 0;
1.1.1.12 root 651: int primaryKeyOffset;
1.1 root 652:
653: if (cryptoInfo == NULL)
654: return ERR_OUTOFMEMORY;
655:
1.1.1.14 root 656: memset (header, 0, TC_VOLUME_HEADER_EFFECTIVE_SIZE);
1.1.1.8 root 657:
1.1.1.2 root 658: VirtualLock (&keyInfo, sizeof (keyInfo));
1.1.1.6 root 659: VirtualLock (&dk, sizeof (dk));
1.1 root 660:
1.1.1.6 root 661: /* Encryption setup */
1.1 root 662:
1.1.1.12 root 663: if (masterKeydata == NULL)
1.1.1.7 root 664: {
1.1.1.12 root 665: // We have no master key data (creating a new volume) so we'll use the TrueCrypt RNG to generate them
1.1.1.7 root 666:
1.1.1.12 root 667: int bytesNeeded;
668:
669: switch (mode)
670: {
671: case LRW:
672: case CBC:
673: case INNER_CBC:
674: case OUTER_CBC:
675:
676: // Deprecated/legacy modes of operation
677: bytesNeeded = LEGACY_VOL_IV_SIZE + EAGetKeySize (ea);
678:
679: /* In fact, this should never be the case since new volumes are not supposed to use
680: any deprecated mode of operation. */
681: return ERR_VOL_FORMAT_BAD;
682:
683: default:
684: bytesNeeded = EAGetKeySize (ea) * 2; // Size of primary + secondary key(s)
685: }
686:
687: if (!RandgetBytes (keyInfo.master_keydata, bytesNeeded, TRUE))
1.1.1.8 root 688: return ERR_CIPHER_INIT_WEAK_KEY;
1.1.1.7 root 689: }
1.1.1.2 root 690: else
1.1.1.12 root 691: {
692: // We already have existing master key data (the header is being re-encrypted)
693: memcpy (keyInfo.master_keydata, masterKeydata, MASTER_KEYDATA_SIZE);
694: }
1.1.1.2 root 695:
1.1.1.6 root 696: // User key
697: memcpy (keyInfo.userKey, password->Text, nUserKeyLen);
1.1 root 698: keyInfo.keyLength = nUserKeyLen;
1.1.1.12 root 699: keyInfo.noIterations = get_pkcs5_iteration_count (pkcs5_prf, bBoot);
1.1 root 700:
701: // User selected encryption algorithm
1.1.1.4 root 702: cryptoInfo->ea = ea;
1.1 root 703:
1.1.1.7 root 704: // Mode of operation
705: cryptoInfo->mode = mode;
706:
1.1.1.8 root 707: // Salt for header key derivation
1.1.1.12 root 708: if (!RandgetBytes (keyInfo.salt, PKCS5_SALT_SIZE, !bWipeMode))
1.1.1.8 root 709: return ERR_CIPHER_INIT_WEAK_KEY;
1.1 root 710:
1.1.1.12 root 711: // PBKDF2 (PKCS5) is used to derive primary header key(s) and secondary header key(s) (XTS) from the password/keyfiles
712: switch (pkcs5_prf)
1.1 root 713: {
1.1.1.12 root 714: case SHA512:
715: derive_key_sha512 (keyInfo.userKey, keyInfo.keyLength, keyInfo.salt,
716: PKCS5_SALT_SIZE, keyInfo.noIterations, dk, GetMaxPkcs5OutSize());
717: break;
718:
1.1.1.6 root 719: case SHA1:
1.1.1.12 root 720: // Deprecated/legacy
721: derive_key_sha1 (keyInfo.userKey, keyInfo.keyLength, keyInfo.salt,
722: PKCS5_SALT_SIZE, keyInfo.noIterations, dk, GetMaxPkcs5OutSize());
1.1.1.6 root 723: break;
724:
725: case RIPEMD160:
1.1.1.12 root 726: derive_key_ripemd160 (keyInfo.userKey, keyInfo.keyLength, keyInfo.salt,
727: PKCS5_SALT_SIZE, keyInfo.noIterations, dk, GetMaxPkcs5OutSize());
1.1.1.6 root 728: break;
729:
730: case WHIRLPOOL:
1.1.1.12 root 731: derive_key_whirlpool (keyInfo.userKey, keyInfo.keyLength, keyInfo.salt,
732: PKCS5_SALT_SIZE, keyInfo.noIterations, dk, GetMaxPkcs5OutSize());
1.1.1.6 root 733: break;
1.1.1.7 root 734:
1.1.1.12 root 735: default:
736: // Unknown/wrong ID
737: TC_THROW_FATAL_EXCEPTION;
738: }
1.1 root 739:
1.1.1.6 root 740: /* Header setup */
1.1 root 741:
742: // Salt
1.1.1.12 root 743: mputBytes (p, keyInfo.salt, PKCS5_SALT_SIZE);
1.1 root 744:
745: // Magic
1.1.1.8 root 746: mputLong (p, 0x54525545);
1.1 root 747:
748: // Header version
1.1.1.12 root 749: switch (mode)
750: {
751: case LRW:
752: case CBC:
753: case OUTER_CBC:
754: case INNER_CBC:
755: // Deprecated/legacy modes (used before TrueCrypt 5.0)
756: mputWord (p, 0x0002);
757: break;
758: default:
759: mputWord (p, VOLUME_HEADER_VERSION);
760: }
1.1 root 761:
762: // Required program version to handle this volume
1.1.1.12 root 763: switch (mode)
764: {
765: case LRW:
766: // Deprecated/legacy
767: mputWord (p, 0x0410);
768: break;
769: case OUTER_CBC:
770: case INNER_CBC:
771: // Deprecated/legacy
772: mputWord (p, 0x0300);
773: break;
774: case CBC:
775: // Deprecated/legacy
776: mputWord (p, hiddenVolumeSize > 0 ? 0x0300 : 0x0100);
777: break;
778: default:
1.1.1.14 root 779: mputWord (p, requiredProgramVersion != 0 ? requiredProgramVersion : TC_VOLUME_MIN_REQUIRED_PROGRAM_VERSION);
1.1.1.12 root 780: }
1.1 root 781:
1.1.1.12 root 782: // CRC of the master key data
783: x = GetCrc32(keyInfo.master_keydata, MASTER_KEYDATA_SIZE);
1.1 root 784: mputLong (p, x);
785:
1.1.1.14 root 786: // Reserved fields
787: p += 2 * 8;
1.1 root 788:
1.1.1.12 root 789: // Size of hidden volume (if any)
1.1.1.4 root 790: cryptoInfo->hiddenVolumeSize = hiddenVolumeSize;
791: mputInt64 (p, cryptoInfo->hiddenVolumeSize);
1.1.1.12 root 792:
1.1.1.7 root 793: cryptoInfo->hiddenVolume = cryptoInfo->hiddenVolumeSize != 0;
1.1.1.4 root 794:
1.1.1.12 root 795: // Volume size
796: cryptoInfo->VolumeSize.Value = volumeSize;
797: mputInt64 (p, volumeSize);
798:
799: // Encrypted area start
800: cryptoInfo->EncryptedAreaStart.Value = encryptedAreaStart;
801: mputInt64 (p, encryptedAreaStart);
802:
803: // Encrypted area size
804: cryptoInfo->EncryptedAreaLength.Value = encryptedAreaLength;
805: mputInt64 (p, encryptedAreaLength);
806:
1.1.1.14 root 807: // Flags
808: cryptoInfo->HeaderFlags = headerFlags;
809: mputLong (p, headerFlags);
810:
811: // CRC of the header fields
812: x = GetCrc32 (header + TC_HEADER_OFFSET_MAGIC, TC_HEADER_OFFSET_HEADER_CRC - TC_HEADER_OFFSET_MAGIC);
813: p = header + TC_HEADER_OFFSET_HEADER_CRC;
814: mputLong (p, x);
815:
1.1.1.12 root 816: // The master key data
817: memcpy (header + HEADER_MASTER_KEYDATA_OFFSET, keyInfo.master_keydata, MASTER_KEYDATA_SIZE);
1.1 root 818:
819:
1.1.1.6 root 820: /* Header encryption */
1.1 root 821:
1.1.1.12 root 822: switch (mode)
823: {
824: case LRW:
825: case CBC:
826: case INNER_CBC:
827: case OUTER_CBC:
828:
829: // For LRW (deprecated/legacy), the tweak key
830: // For CBC (deprecated/legacy), the IV/whitening seed
831: memcpy (cryptoInfo->k2, dk, LEGACY_VOL_IV_SIZE);
832: primaryKeyOffset = LEGACY_VOL_IV_SIZE;
833: break;
834:
835: default:
836: // The secondary key (if cascade, multiple concatenated)
837: memcpy (cryptoInfo->k2, dk + EAGetKeySize (cryptoInfo->ea), EAGetKeySize (cryptoInfo->ea));
838: primaryKeyOffset = 0;
839: }
840:
841: retVal = EAInit (cryptoInfo->ea, dk + primaryKeyOffset, cryptoInfo->ks);
842: if (retVal != ERR_SUCCESS)
1.1.1.6 root 843: return retVal;
1.1 root 844:
1.1.1.7 root 845: // Mode of operation
846: if (!EAInitMode (cryptoInfo))
847: return ERR_OUTOFMEMORY;
848:
1.1.1.12 root 849:
850: // Encrypt the entire header (except the salt)
851: EncryptBuffer (header + HEADER_ENCRYPTED_DATA_OFFSET,
852: HEADER_ENCRYPTED_DATA_SIZE,
1.1.1.7 root 853: cryptoInfo);
1.1 root 854:
855:
1.1.1.6 root 856: /* cryptoInfo setup for further use (disk format) */
1.1 root 857:
1.1.1.12 root 858: // Init with the master key(s)
859: retVal = EAInit (cryptoInfo->ea, keyInfo.master_keydata + primaryKeyOffset, cryptoInfo->ks);
860: if (retVal != ERR_SUCCESS)
1.1.1.6 root 861: return retVal;
1.1 root 862:
1.1.1.12 root 863: memcpy (cryptoInfo->master_keydata, keyInfo.master_keydata, MASTER_KEYDATA_SIZE);
864:
865: switch (cryptoInfo->mode)
866: {
867: case LRW:
868: case CBC:
869: case INNER_CBC:
870: case OUTER_CBC:
871:
872: // For LRW (deprecated/legacy), the tweak key
873: // For CBC (deprecated/legacy), the IV/whitening seed
874: memcpy (cryptoInfo->k2, keyInfo.master_keydata, LEGACY_VOL_IV_SIZE);
875: break;
876:
877: default:
878: // The secondary master key (if cascade, multiple concatenated)
879: memcpy (cryptoInfo->k2, keyInfo.master_keydata + EAGetKeySize (cryptoInfo->ea), EAGetKeySize (cryptoInfo->ea));
880: }
1.1 root 881:
1.1.1.7 root 882: // Mode of operation
883: if (!EAInitMode (cryptoInfo))
884: return ERR_OUTOFMEMORY;
885:
1.1.1.2 root 886:
1.1 root 887: #ifdef VOLFORMAT
1.1.1.15! root 888: if (showKeys && !bInPlaceEncNonSys)
1.1 root 889: {
890: BOOL dots3 = FALSE;
891: int i, j;
892:
1.1.1.4 root 893: j = EAGetKeySize (ea);
1.1 root 894:
1.1.1.6 root 895: if (j > NBR_KEY_BYTES_TO_DISPLAY)
1.1 root 896: {
897: dots3 = TRUE;
1.1.1.6 root 898: j = NBR_KEY_BYTES_TO_DISPLAY;
1.1 root 899: }
900:
1.1.1.12 root 901: MasterKeyGUIView[0] = 0;
1.1 root 902: for (i = 0; i < j; i++)
903: {
1.1.1.12 root 904: char tmp2[8] = {0};
905: sprintf (tmp2, "%02X", (int) (unsigned char) keyInfo.master_keydata[i + primaryKeyOffset]);
906: strcat (MasterKeyGUIView, tmp2);
1.1 root 907: }
908:
1.1.1.6 root 909: if (dots3)
1.1 root 910: {
1.1.1.12 root 911: strcat (MasterKeyGUIView, "...");
1.1 root 912: }
913:
1.1.1.12 root 914: SendMessage (hMasterKey, WM_SETTEXT, 0, (LPARAM) MasterKeyGUIView);
1.1 root 915:
1.1.1.12 root 916: HeaderKeyGUIView[0] = 0;
1.1.1.6 root 917: for (i = 0; i < NBR_KEY_BYTES_TO_DISPLAY; i++)
1.1 root 918: {
919: char tmp2[8];
1.1.1.12 root 920: sprintf (tmp2, "%02X", (int) (unsigned char) dk[primaryKeyOffset + i]);
921: strcat (HeaderKeyGUIView, tmp2);
1.1 root 922: }
923:
1.1.1.6 root 924: if (dots3)
1.1.1.3 root 925: {
1.1.1.12 root 926: strcat (HeaderKeyGUIView, "...");
1.1.1.3 root 927: }
928:
1.1.1.12 root 929: SendMessage (hHeaderKey, WM_SETTEXT, 0, (LPARAM) HeaderKeyGUIView);
1.1 root 930: }
1.1.1.12 root 931: #endif // #ifdef VOLFORMAT
1.1 root 932:
1.1.1.3 root 933: burn (dk, sizeof(dk));
1.1 root 934: burn (&keyInfo, sizeof (keyInfo));
935:
936: *retInfo = cryptoInfo;
937: return 0;
938: }
939:
1.1.1.15! root 940:
! 941: // Writes randomly generated data to unused/reserved header areas.
! 942: // When bPrimaryOnly is TRUE, then only the primary header area (not the backup header area) is filled with random data.
! 943: // When bBackupOnly is TRUE, only the backup header area (not the primary header area) is filled with random data.
! 944: int WriteRandomDataToReservedHeaderAreas (HANDLE dev, CRYPTO_INFO *cryptoInfo, uint64 dataAreaSize, BOOL bPrimaryOnly, BOOL bBackupOnly)
! 945: {
! 946: char temporaryKey[MASTER_KEYDATA_SIZE];
! 947: char originalK2[MASTER_KEYDATA_SIZE];
! 948:
! 949: byte buf[TC_VOLUME_HEADER_GROUP_SIZE - TC_VOLUME_HEADER_EFFECTIVE_SIZE];
! 950:
! 951: LARGE_INTEGER offset;
! 952: int nStatus = ERR_SUCCESS;
! 953: DWORD dwError;
! 954: BOOL backupHeaders = bBackupOnly;
! 955:
! 956: if (bPrimaryOnly && bBackupOnly)
! 957: TC_THROW_FATAL_EXCEPTION;
! 958:
! 959: memcpy (originalK2, cryptoInfo->k2, sizeof (cryptoInfo->k2));
! 960:
! 961: while (TRUE)
! 962: {
! 963: // Temporary keys
! 964: if (!RandgetBytes (temporaryKey, EAGetKeySize (cryptoInfo->ea), TRUE)
! 965: || !RandgetBytes (cryptoInfo->k2, sizeof (cryptoInfo->k2), FALSE))
! 966: {
! 967: nStatus = ERR_PARAMETER_INCORRECT;
! 968: goto final_seq;
! 969: }
! 970:
! 971: nStatus = EAInit (cryptoInfo->ea, temporaryKey, cryptoInfo->ks);
! 972: if (nStatus != ERR_SUCCESS)
! 973: goto final_seq;
! 974:
! 975: if (!EAInitMode (cryptoInfo))
! 976: {
! 977: nStatus = ERR_MODE_INIT_FAILED;
! 978: goto final_seq;
! 979: }
! 980:
! 981: offset.QuadPart = backupHeaders ? dataAreaSize + TC_VOLUME_HEADER_GROUP_SIZE : TC_VOLUME_HEADER_OFFSET;
! 982: offset.QuadPart += TC_VOLUME_HEADER_EFFECTIVE_SIZE;
! 983:
! 984: if (!SetFilePointerEx (dev, offset, NULL, FILE_BEGIN))
! 985: {
! 986: nStatus = ERR_OS_ERROR;
! 987: goto final_seq;
! 988: }
! 989:
! 990: EncryptBuffer (buf, sizeof (buf), cryptoInfo);
! 991:
! 992: if (_lwrite ((HFILE) dev, buf, sizeof (buf)) == HFILE_ERROR)
! 993: {
! 994: nStatus = ERR_OS_ERROR;
! 995: goto final_seq;
! 996: }
! 997:
! 998: if (backupHeaders || bPrimaryOnly)
! 999: break;
! 1000:
! 1001: backupHeaders = TRUE;
! 1002: }
! 1003:
! 1004: memcpy (cryptoInfo->k2, originalK2, sizeof (cryptoInfo->k2));
! 1005:
! 1006: nStatus = EAInit (cryptoInfo->ea, cryptoInfo->master_keydata, cryptoInfo->ks);
! 1007: if (nStatus != ERR_SUCCESS)
! 1008: goto final_seq;
! 1009:
! 1010: if (!EAInitMode (cryptoInfo))
! 1011: {
! 1012: nStatus = ERR_MODE_INIT_FAILED;
! 1013: goto final_seq;
! 1014: }
! 1015:
! 1016: final_seq:
! 1017:
! 1018: dwError = GetLastError();
! 1019:
! 1020: burn (temporaryKey, sizeof (temporaryKey));
! 1021: burn (originalK2, sizeof (originalK2));
! 1022:
! 1023: if (nStatus != ERR_SUCCESS)
! 1024: SetLastError (dwError);
! 1025:
! 1026: return nStatus;
! 1027: }
! 1028:
1.1.1.12 root 1029: #endif // !defined (DEVICE_DRIVER) && !defined (TC_WINDOWS_BOOT)
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.