static void bignumToExternal( BYTE *outData, int *outDataLength, const LONG *inData, const int inDataLength ) { int inIndex = 0, outIndex; assert( isWritePtr( outData, CRYPT_MAX_PKCSIZE ) ); assert( isWritePtr( outDataLength, sizeof( int ) ) ); assert( isReadPtr( inData, inDataLength * sizeof( LONG ) ) ); REQUIRES_V( inDataLength > 0 && \ inDataLength <= CRYPT_MAX_PKCSIZE / sizeof( LONG ) ); memset( outData, 0, CRYPT_MAX_PKCSIZE ); for( outIndex = 0; outIndex < inDataLength; outIndex++ ) { const LONG value = inData[ inIndex++ ]; mputLong( outData, value ); } *outDataLength = outIndex * sizeof( LONG ); }
// Creates a volume header in memory int CreateVolumeHeaderInMemory (BOOL bBoot, char *header, int ea, int mode, Password *password, int pkcs5_prf, char *masterKeydata, PCRYPTO_INFO *retInfo, unsigned __int64 volumeSize, unsigned __int64 hiddenVolumeSize, unsigned __int64 encryptedAreaStart, unsigned __int64 encryptedAreaLength, uint16 requiredProgramVersion, uint32 headerFlags, uint32 sectorSize, BOOL bWipeMode) { unsigned char *p = (unsigned char *) header; static KEY_INFO keyInfo; int nUserKeyLen = password->Length; PCRYPTO_INFO cryptoInfo = crypto_open (); static char dk[MASTER_KEYDATA_SIZE]; int x; int retVal = 0; int primaryKeyOffset; if (cryptoInfo == NULL) return ERR_OUTOFMEMORY; memset (header, 0, TC_VOLUME_HEADER_EFFECTIVE_SIZE); VirtualLock (&keyInfo, sizeof (keyInfo)); VirtualLock (&dk, sizeof (dk)); /* Encryption setup */ if (masterKeydata == NULL) { // We have no master key data (creating a new volume) so we'll use the TrueCrypt RNG to generate them int bytesNeeded; switch (mode) { case LRW: case CBC: case INNER_CBC: case OUTER_CBC: // Deprecated/legacy modes of operation bytesNeeded = LEGACY_VOL_IV_SIZE + EAGetKeySize (ea); // In fact, this should never be the case since volumes being newly created are not // supposed to use any deprecated mode of operation. TC_THROW_FATAL_EXCEPTION; break; default: bytesNeeded = EAGetKeySize (ea) * 2; // Size of primary + secondary key(s) } if (!RandgetBytes (keyInfo.master_keydata, bytesNeeded, TRUE)) return ERR_CIPHER_INIT_WEAK_KEY; } else { // We already have existing master key data (the header is being re-encrypted) memcpy (keyInfo.master_keydata, masterKeydata, MASTER_KEYDATA_SIZE); } // User key memcpy (keyInfo.userKey, password->Text, nUserKeyLen); keyInfo.keyLength = nUserKeyLen; keyInfo.noIterations = get_pkcs5_iteration_count (pkcs5_prf, bBoot); // User selected encryption algorithm cryptoInfo->ea = ea; // Mode of operation cryptoInfo->mode = mode; // Salt for header key derivation if (!RandgetBytes (keyInfo.salt, PKCS5_SALT_SIZE, !bWipeMode)) return ERR_CIPHER_INIT_WEAK_KEY; // PBKDF2 (PKCS5) is used to derive primary header key(s) and secondary header key(s) (XTS) from the password/keyfiles switch (pkcs5_prf) { case SHA512: derive_key_sha512 (keyInfo.userKey, keyInfo.keyLength, keyInfo.salt, PKCS5_SALT_SIZE, keyInfo.noIterations, dk, GetMaxPkcs5OutSize()); break; case SHA1: // Deprecated/legacy derive_key_sha1 (keyInfo.userKey, keyInfo.keyLength, keyInfo.salt, PKCS5_SALT_SIZE, keyInfo.noIterations, dk, GetMaxPkcs5OutSize()); break; case RIPEMD160: derive_key_ripemd160 (keyInfo.userKey, keyInfo.keyLength, keyInfo.salt, PKCS5_SALT_SIZE, keyInfo.noIterations, dk, GetMaxPkcs5OutSize()); break; case WHIRLPOOL: derive_key_whirlpool (keyInfo.userKey, keyInfo.keyLength, keyInfo.salt, PKCS5_SALT_SIZE, keyInfo.noIterations, dk, GetMaxPkcs5OutSize()); break; default: // Unknown/wrong ID TC_THROW_FATAL_EXCEPTION; } /* Header setup */ // Salt mputBytes (p, keyInfo.salt, PKCS5_SALT_SIZE); // Magic mputLong (p, 0x54525545); // Header version mputWord (p, VOLUME_HEADER_VERSION); cryptoInfo->HeaderVersion = VOLUME_HEADER_VERSION; // Required program version to handle this volume switch (mode) { case LRW: // Deprecated/legacy mputWord (p, 0x0410); break; case OUTER_CBC: case INNER_CBC: // Deprecated/legacy mputWord (p, 0x0300); break; case CBC: // Deprecated/legacy mputWord (p, hiddenVolumeSize > 0 ? 0x0300 : 0x0100); break; default: mputWord (p, requiredProgramVersion != 0 ? requiredProgramVersion : TC_VOLUME_MIN_REQUIRED_PROGRAM_VERSION); } // CRC of the master key data x = GetCrc32(keyInfo.master_keydata, MASTER_KEYDATA_SIZE); mputLong (p, x); // Reserved fields p += 2 * 8; // Size of hidden volume (if any) cryptoInfo->hiddenVolumeSize = hiddenVolumeSize; mputInt64 (p, cryptoInfo->hiddenVolumeSize); cryptoInfo->hiddenVolume = cryptoInfo->hiddenVolumeSize != 0; // Volume size cryptoInfo->VolumeSize.Value = volumeSize; mputInt64 (p, volumeSize); // Encrypted area start cryptoInfo->EncryptedAreaStart.Value = encryptedAreaStart; mputInt64 (p, encryptedAreaStart); // Encrypted area size cryptoInfo->EncryptedAreaLength.Value = encryptedAreaLength; mputInt64 (p, encryptedAreaLength); // Flags cryptoInfo->HeaderFlags = headerFlags; mputLong (p, headerFlags); // Sector size if (sectorSize < TC_MIN_VOLUME_SECTOR_SIZE || sectorSize > TC_MAX_VOLUME_SECTOR_SIZE || sectorSize % ENCRYPTION_DATA_UNIT_SIZE != 0) { TC_THROW_FATAL_EXCEPTION; } cryptoInfo->SectorSize = sectorSize; mputLong (p, sectorSize); // CRC of the header fields x = GetCrc32 (header + TC_HEADER_OFFSET_MAGIC, TC_HEADER_OFFSET_HEADER_CRC - TC_HEADER_OFFSET_MAGIC); p = header + TC_HEADER_OFFSET_HEADER_CRC; mputLong (p, x); // The master key data memcpy (header + HEADER_MASTER_KEYDATA_OFFSET, keyInfo.master_keydata, MASTER_KEYDATA_SIZE); /* Header encryption */ switch (mode) { case LRW: case CBC: case INNER_CBC: case OUTER_CBC: // For LRW (deprecated/legacy), the tweak key // For CBC (deprecated/legacy), the IV/whitening seed memcpy (cryptoInfo->k2, dk, LEGACY_VOL_IV_SIZE); primaryKeyOffset = LEGACY_VOL_IV_SIZE; break; default: // The secondary key (if cascade, multiple concatenated) memcpy (cryptoInfo->k2, dk + EAGetKeySize (cryptoInfo->ea), EAGetKeySize (cryptoInfo->ea)); primaryKeyOffset = 0; } retVal = EAInit (cryptoInfo->ea, dk + primaryKeyOffset, cryptoInfo->ks); if (retVal != ERR_SUCCESS) return retVal; // Mode of operation if (!EAInitMode (cryptoInfo)) return ERR_OUTOFMEMORY; // Encrypt the entire header (except the salt) EncryptBuffer (header + HEADER_ENCRYPTED_DATA_OFFSET, HEADER_ENCRYPTED_DATA_SIZE, cryptoInfo); /* cryptoInfo setup for further use (disk format) */ // Init with the master key(s) retVal = EAInit (cryptoInfo->ea, keyInfo.master_keydata + primaryKeyOffset, cryptoInfo->ks); if (retVal != ERR_SUCCESS) return retVal; memcpy (cryptoInfo->master_keydata, keyInfo.master_keydata, MASTER_KEYDATA_SIZE); switch (cryptoInfo->mode) { case LRW: case CBC: case INNER_CBC: case OUTER_CBC: // For LRW (deprecated/legacy), the tweak key // For CBC (deprecated/legacy), the IV/whitening seed memcpy (cryptoInfo->k2, keyInfo.master_keydata, LEGACY_VOL_IV_SIZE); break; default: // The secondary master key (if cascade, multiple concatenated) memcpy (cryptoInfo->k2, keyInfo.master_keydata + EAGetKeySize (cryptoInfo->ea), EAGetKeySize (cryptoInfo->ea)); } // Mode of operation if (!EAInitMode (cryptoInfo)) return ERR_OUTOFMEMORY; #ifdef VOLFORMAT if (showKeys && !bInPlaceEncNonSys) { BOOL dots3 = FALSE; int i, j; j = EAGetKeySize (ea); if (j > NBR_KEY_BYTES_TO_DISPLAY) { dots3 = TRUE; j = NBR_KEY_BYTES_TO_DISPLAY; } MasterKeyGUIView[0] = 0; for (i = 0; i < j; i++) { char tmp2[8] = {0}; sprintf (tmp2, "%02X", (int) (unsigned char) keyInfo.master_keydata[i + primaryKeyOffset]); strcat (MasterKeyGUIView, tmp2); } HeaderKeyGUIView[0] = 0; for (i = 0; i < NBR_KEY_BYTES_TO_DISPLAY; i++) { char tmp2[8]; sprintf (tmp2, "%02X", (int) (unsigned char) dk[primaryKeyOffset + i]); strcat (HeaderKeyGUIView, tmp2); } if (dots3) { DisplayPortionsOfKeys (hHeaderKey, hMasterKey, HeaderKeyGUIView, MasterKeyGUIView, !showKeys); } else { SendMessage (hMasterKey, WM_SETTEXT, 0, (LPARAM) MasterKeyGUIView); SendMessage (hHeaderKey, WM_SETTEXT, 0, (LPARAM) HeaderKeyGUIView); } } #endif // #ifdef VOLFORMAT burn (dk, sizeof(dk)); burn (&keyInfo, sizeof (keyInfo)); *retInfo = cryptoInfo; return 0; }
BOOL MakeSelfExtractingPackage (HWND hwndDlg, char *szDestDir) { int i, x; unsigned char inputFile [TC_MAX_PATH]; unsigned char outputFile [TC_MAX_PATH]; unsigned char szTmpFilePath [TC_MAX_PATH]; unsigned char szTmp32bit [4] = {0}; unsigned char *szTmp32bitPtr = szTmp32bit; unsigned char *buffer = NULL, *compressedBuffer = NULL; unsigned char *bufIndex = NULL; char tmpStr [2048]; int bufLen = 0, compressedDataLen = 0, uncompressedDataLen = 0; x = strlen (szDestDir); if (x < 2) return FALSE; if (szDestDir[x - 1] != '\\') strcat (szDestDir, "\\"); GetModuleFileName (NULL, inputFile, sizeof (inputFile)); strcpy (outputFile, szDestDir); strncat (outputFile, OutputPackageFile, sizeof (outputFile) - strlen (outputFile) - 1); // Clone 'TrueCrypt Setup.exe' to create the base of the new self-extracting archive if (!TCCopyFile (inputFile, outputFile)) { handleWin32Error (hwndDlg); PkgError ("Cannot copy 'TrueCrypt Setup.exe' to the package"); return FALSE; } // Determine the buffer size needed for all the files and meta data and check if all required files exist bufLen = 0; for (i = 0; i < sizeof (szCompressedFiles) / sizeof (szCompressedFiles[0]); i++) { _snprintf (szTmpFilePath, sizeof(szTmpFilePath), "%s%s", szDestDir, szCompressedFiles[i]); if (!FileExists (szTmpFilePath)) { char tmpstr [1000]; _snprintf (tmpstr, sizeof(tmpstr), "File not found:\n\n'%s'", szTmpFilePath); remove (outputFile); PkgError (tmpstr); return FALSE; } bufLen += (int) GetFileSize64 (szTmpFilePath); bufLen += 2; // 16-bit filename length bufLen += strlen(szCompressedFiles[i]); // Filename bufLen += 4; // CRC-32 bufLen += 4; // 32-bit file length } buffer = malloc (bufLen + 524288); // + 512K reserve if (buffer == NULL) { PkgError ("Cannot allocate memory for uncompressed data"); remove (outputFile); return FALSE; } // Write the start marker if (!SaveBufferToFile (MAG_START_MARKER, outputFile, strlen (MAG_START_MARKER), TRUE)) { PkgError ("Cannot write the start marker"); remove (outputFile); return FALSE; } bufIndex = buffer; // Copy all required files and their meta data to the buffer for (i = 0; i < sizeof (szCompressedFiles) / sizeof (szCompressedFiles[0]); i++) { DWORD tmpFileSize; unsigned char *tmpBuffer; _snprintf (szTmpFilePath, sizeof(szTmpFilePath), "%s%s", szDestDir, szCompressedFiles[i]); tmpBuffer = LoadFile (szTmpFilePath, &tmpFileSize); if (tmpBuffer == NULL) { char tmpstr [1000]; free (tmpBuffer); _snprintf (tmpstr, sizeof(tmpstr), "Cannot load file \n'%s'", szTmpFilePath); remove (outputFile); PkgError (tmpstr); goto msep_err; } // Copy the filename length to the main buffer mputWord (bufIndex, (WORD) strlen(szCompressedFiles[i])); // Copy the filename to the main buffer memcpy (bufIndex, szCompressedFiles[i], strlen(szCompressedFiles[i])); bufIndex += strlen(szCompressedFiles[i]); // Compute CRC-32 hash of the uncompressed file and copy it to the main buffer mputLong (bufIndex, GetCrc32 (tmpBuffer, tmpFileSize)); // Copy the file length to the main buffer mputLong (bufIndex, (unsigned __int32) tmpFileSize); // Copy the file contents to the main buffer memcpy (bufIndex, tmpBuffer, tmpFileSize); bufIndex += tmpFileSize; free (tmpBuffer); } // Calculate the total size of the uncompressed data uncompressedDataLen = (int) (bufIndex - buffer); // Write total size of the uncompressed data szTmp32bitPtr = szTmp32bit; mputLong (szTmp32bitPtr, (unsigned __int32) uncompressedDataLen); if (!SaveBufferToFile (szTmp32bit, outputFile, sizeof (szTmp32bit), TRUE)) { remove (outputFile); PkgError ("Cannot write the total size of the uncompressed data"); return FALSE; } // Compress all the files and meta data in the buffer to create a solid archive compressedBuffer = malloc (uncompressedDataLen + 524288); // + 512K reserve if (compressedBuffer == NULL) { remove (outputFile); PkgError ("Cannot allocate memory for compressed data"); return FALSE; } compressedDataLen = CompressBuffer (compressedBuffer, buffer, uncompressedDataLen); if (compressedDataLen <= 0) { remove (outputFile); PkgError ("Failed to compress the data"); return FALSE; } free (buffer); // Write the total size of the compressed data szTmp32bitPtr = szTmp32bit; mputLong (szTmp32bitPtr, (unsigned __int32) compressedDataLen); if (!SaveBufferToFile (szTmp32bit, outputFile, sizeof (szTmp32bit), TRUE)) { remove (outputFile); PkgError ("Cannot write the total size of the compressed data"); return FALSE; } // Write the compressed data if (!SaveBufferToFile (compressedBuffer, outputFile, compressedDataLen, TRUE)) { remove (outputFile); PkgError ("Cannot write compressed data to the package"); return FALSE; } // Write the end marker if (!SaveBufferToFile (MagEndMarker, outputFile, strlen (MagEndMarker), TRUE)) { remove (outputFile); PkgError ("Cannot write the end marker"); return FALSE; } free (compressedBuffer); // Compute and write CRC-32 hash of the entire package { DWORD tmpFileSize; char *tmpBuffer; tmpBuffer = LoadFile (outputFile, &tmpFileSize); if (tmpBuffer == NULL) { handleWin32Error (hwndDlg); remove (outputFile); PkgError ("Cannot load the package to compute CRC"); return FALSE; } // Zero all bytes that change when the exe is digitally signed (except appended blocks). WipeSignatureAreas (tmpBuffer); szTmp32bitPtr = szTmp32bit; mputLong (szTmp32bitPtr, GetCrc32 (tmpBuffer, tmpFileSize)); if (!SaveBufferToFile (szTmp32bit, outputFile, sizeof (szTmp32bit), TRUE)) { remove (outputFile); PkgError ("Cannot write the total size of the compressed data"); return FALSE; } free (tmpBuffer); } sprintf (tmpStr, "Self-extracting package successfully created (%s)", outputFile); PkgInfo (tmpStr); return TRUE; msep_err: free (buffer); free (compressedBuffer); return FALSE; }