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