/* Copyright (c) 2008-2010 TrueCrypt Developers Association. All rights reserved. Governed by the TrueCrypt License 3.0 the full text of which is contained in the file License.txt included in TrueCrypt binary and source code distribution packages. */ #include "System.h" #ifdef TC_UNIX #include #include #include #include #include #include "Platform/Unix/Process.h" #endif #include "Common/SecurityToken.h" #include "Core/RandomNumberGenerator.h" #include "Application.h" #include "TextUserInterface.h" namespace VeraCrypt { TextUserInterface::TextUserInterface () { #ifdef TC_UNIX signal (SIGHUP, OnSignal); signal (SIGINT, OnSignal); signal (SIGQUIT, OnSignal); signal (SIGTERM, OnSignal); struct stat statBuf; if (fstat (0, &statBuf) != -1) #endif { FInputStream.reset (new wxFFileInputStream (stdin)); TextInputStream.reset (new wxTextInputStream (*FInputStream)); } } TextUserInterface::~TextUserInterface () { try { if (RandomNumberGenerator::IsRunning()) RandomNumberGenerator::Stop(); } catch (...) { } #ifdef TC_UNIX signal (SIGHUP, SIG_DFL); signal (SIGINT, SIG_DFL); signal (SIGQUIT, SIG_DFL); signal (SIGTERM, SIG_DFL); #endif } FilePath TextUserInterface::AskFilePath (const wxString &message) const { return AskString (!message.empty() ? message : wxString (_("Enter filename: "))); } shared_ptr TextUserInterface::AskKeyfiles (const wxString &message) const { wxString msg = _("Enter keyfile"); if (!message.empty()) msg = message; make_shared_auto (KeyfileList, keyfiles); wxString s; wxString m = msg + L" [" + _("none") + L"]: "; while (!(s = AskString (m)).empty()) { keyfiles->push_back (make_shared (wstring (s))); m = msg + L" [" + _("finish") + L"]: "; } return keyfiles; } shared_ptr TextUserInterface::AskPassword (const wxString &message, bool verify) const { wxString msg = LangString["ENTER_PASSWORD"] + L": "; if (!message.empty()) msg = message + L": "; SetTerminalEcho (false); finally_do ({ TextUserInterface::SetTerminalEcho (true); }); wchar_t passwordBuf[4096]; finally_do_arg (BufferPtr, BufferPtr (reinterpret_cast (passwordBuf), sizeof (passwordBuf)), { finally_arg.Erase(); }); make_shared_auto (VolumePassword, password); bool verPhase = false; while (true) { ShowString (verPhase ? wxString (_("Re-enter password: ")) : msg); wxString passwordStr; ReadInputStreamLine (passwordStr); size_t length = passwordStr.size(); ShowString (L"\n"); if (!verPhase && length < 1) { password->Set (passwordBuf, 0); return password; } for (size_t i = 0; i < length && i < VolumePassword::MaxSize; ++i) { passwordBuf[i] = (wchar_t) passwordStr[i]; const_cast (passwordStr.wc_str())[i] = L'X'; } if (verify && verPhase) { make_shared_auto (VolumePassword, verPassword); verPassword->Set (passwordBuf, length); if (*password != *verPassword) { ShowInfo (_("Passwords do not match.")); ShowString (L"\n"); verPhase = false; continue; } } password->Set (passwordBuf, length); if (!verPhase) { try { password->CheckPortability(); } catch (UnportablePassword &e) { if (verify) { ShowError (e); verPhase = false; continue; } ShowWarning ("UNSUPPORTED_CHARS_IN_PWD_RECOM"); } if (verify) { if (password->Size() < VolumePassword::WarningSizeThreshold) { SetTerminalEcho (true); finally_do ({ TextUserInterface::SetTerminalEcho (false); }); if (!AskYesNo (LangString ["PASSWORD_LENGTH_WARNING"], false, true)) { ShowString (L"\n"); continue; } ShowString (L"\n"); } } } if (!verify || verPhase) return password; if (!verPhase) verPhase = true; } return password; } ssize_t TextUserInterface::AskSelection (ssize_t optionCount, ssize_t defaultOption) const { while (true) { wstring selectionStr = AskString (defaultOption == -1 ? wxString (_("Select: ")) : wxString (wstring (StringFormatter (_("Select [{0}]: "), (uint32) defaultOption)))); ssize_t selection; if (selectionStr.empty() && defaultOption != -1) return defaultOption; try { selection = StringConverter::ToUInt32 (selectionStr); } catch (...) { continue; } if (selection > 0 && selection <= optionCount) return selection; } } wstring TextUserInterface::AskString (const wxString &message) const { ShowString (message); return wstring (ReadInputStreamLine()); } bool TextUserInterface::AskYesNo (const wxString &message, bool defaultYes, bool warning) const { while (true) { wxString s = AskString (StringFormatter (L"{0} (y={1}/n={2}) [{3}]: ", message, LangString["YES"], LangString["NO"], LangString[defaultYes ? "YES" : "NO"])); if (s.IsSameAs (L'n', false) || s.IsSameAs (L"no", false) || (!defaultYes && s.empty())) return false; if (s.IsSameAs (L'y', false) || s.IsSameAs (L"yes", false) || (defaultYes && s.empty())) return true; }; } shared_ptr TextUserInterface::AskVolumePath (const wxString &message) const { return make_shared (AskString (message.empty() ? wxString (_("Enter volume path: ")) : message)); } void TextUserInterface::BackupVolumeHeaders (shared_ptr volumePath) const { if (!volumePath) volumePath = AskVolumePath(); if (!volumePath) throw UserAbort (SRC_POS); #ifdef TC_WINDOWS if (Core->IsVolumeMounted (*volumePath)) throw_err (LangString["DISMOUNT_FIRST"]); #endif ShowInfo ("EXTERNAL_VOL_HEADER_BAK_FIRST_INFO"); shared_ptr normalVolume; shared_ptr hiddenVolume;
/*
 Derived from source code of TrueCrypt 7.1a, which is
 Copyright (c) 2008-2012 TrueCrypt Developers Association and which is governed
 by the TrueCrypt License 3.0.

 Modifications and additions to the original source code (contained in this file) 
 and all other portions of this file are Copyright (c) 2013-2015 IDRIX
 and are governed by the Apache License 2.0 the full text of which is
 contained in the file License.txt included in VeraCrypt binary and source
 code distribution packages.
*/

#include "Platform/SystemException.h"
#include "Platform/SystemInfo.h"
#include <sys/utsname.h>

namespace VeraCrypt
{
	wstring SystemInfo::GetPlatformName ()
	{
#ifdef TC_LINUX
		return L"Linux";
#elif defined (TC_MACOSX)
		return L"Mac OS X";
#elif defined (TC_FREEBSD)
		return L"FreeBSD";
#elif defined (TC_SOLARIS)
		return L"Solaris";
#else
#	error GetPlatformName() undefined
#endif

	}

	vector <int> SystemInfo::GetVersion ()
	{
		struct utsname unameData;
		throw_sys_if (uname (&unameData) == -1);

		vector <string> versionStrings = StringConverter::Split (unameData.release, ".");
		vector <int> version;

		for (size_t i = 0; i < versionStrings.size(); ++i)
		{
			string s = versionStrings[i];

			size_t p = s.find_first_not_of ("0123456789");
			if (p != string::npos)
				s = s.substr (0, p);

			if (s.empty())
				break;

			version.push_back (StringConverter::ToUInt32 (s));
		}

		return version;
	}

	bool SystemInfo::IsVersionAtLeast (int versionNumber1, int versionNumber2, int versionNumber3)
	{
		vector <int> osVersionNumbers = GetVersion();

		if (osVersionNumbers.size() < 2)
			throw ParameterIncorrect (SRC_POS);

		if (osVersionNumbers.size() < 3)
			osVersionNumbers[2] = 0;

		return (osVersionNumbers[0] * 10000000 +  osVersionNumbers[1] * 10000 + osVersionNumbers[2]) >=
			(versionNumber1 * 10000000 +  versionNumber2 * 10000 + versionNumber3);
	}
}
esystemType::FAT && (filesystemSize < TC_MIN_FAT_FS_SIZE || filesystemSize > TC_MAX_FAT_SECTOR_COUNT * options->SectorSize)) { throw_err (_("Specified volume size cannot be used with FAT filesystem.")); } // Password if (!options->Password && !Preferences.NonInteractive) { ShowString (L"\n"); options->Password = AskPassword (_("Enter password"), true); } if (options->Password) options->Password->CheckPortability(); // Keyfiles if (!options->Keyfiles && !Preferences.NonInteractive) { ShowString (L"\n"); options->Keyfiles = AskKeyfiles (_("Enter keyfile path")); } if ((!options->Keyfiles || options->Keyfiles->empty()) && (!options->Password || options->Password->IsEmpty())) { throw_err (_("Password cannot be empty when no keyfile is specified")); } // Random data RandomNumberGenerator::Start(); UserEnrichRandomPool(); ShowString (L"\n"); wxLongLong startTime = wxGetLocalTimeMillis(); VolumeCreator creator; creator.CreateVolume (options); bool volumeCreated = false; while (!volumeCreated) { VolumeCreator::ProgressInfo progress = creator.GetProgressInfo(); wxLongLong timeDiff = wxGetLocalTimeMillis() - startTime; if (timeDiff.GetValue() > 0) { uint64 speed = progress.SizeDone * 1000 / timeDiff.GetValue(); volumeCreated = !progress.CreationInProgress; ShowString (wxString::Format (L"\rDone: %7.3f%% Speed: %9s Left: %s ", 100.0 - double (options->Size - progress.SizeDone) / (double (options->Size) / 100.0), speed > 0 ? SpeedToString (speed).c_str() : L" ", speed > 0 ? TimeSpanToString ((options->Size - progress.SizeDone) / speed).c_str() : L"")); } Thread::Sleep (100); } ShowString (L"\n\n"); creator.CheckResult(); #ifdef TC_UNIX if (options->Filesystem != VolumeCreationOptions::FilesystemType::None && options->Filesystem != VolumeCreationOptions::FilesystemType::FAT) { const char *fsFormatter = nullptr; switch (options->Filesystem) { case VolumeCreationOptions::FilesystemType::Ext2: fsFormatter = "mkfs.ext2"; break; case VolumeCreationOptions::FilesystemType::Ext3: fsFormatter = "mkfs.ext3"; break; case VolumeCreationOptions::FilesystemType::Ext4: fsFormatter = "mkfs.ext4"; break; case VolumeCreationOptions::FilesystemType::MacOsExt: fsFormatter = "newfs_hfs"; break; case VolumeCreationOptions::FilesystemType::UFS: fsFormatter = "newfs" ; break; default: throw ParameterIncorrect (SRC_POS); } MountOptions mountOptions (GetPreferences().DefaultMountOptions); mountOptions.Path = make_shared (options->Path); mountOptions.NoFilesystem = true; mountOptions.Protection = VolumeProtection::None; mountOptions.Password = options->Password; mountOptions.Keyfiles = options->Keyfiles; shared_ptr volume = Core->MountVolume (mountOptions); finally_do_arg (shared_ptr , volume, { Core->DismountVolume (finally_arg, true); }); Thread::Sleep (2000); // Try to prevent race conditions caused by OS // Temporarily take ownership of the device if the user is not an administrator UserId origDeviceOwner ((uid_t) -1); DevicePath virtualDevice = volume->VirtualDevice; #ifdef TC_MACOSX string virtualDeviceStr = virtualDevice; if (virtualDeviceStr.find ("/dev/rdisk") != 0) virtualDevice = "/dev/r" + virtualDeviceStr.substr (5); #endif try { File file; file.Open (virtualDevice, File::OpenReadWrite); } catch (...) { if (!Core->HasAdminPrivileges()) { origDeviceOwner = virtualDevice.GetOwner(); Core->SetFileOwner (virtualDevice, UserId (getuid())); } } finally_do_arg2 (FilesystemPath, virtualDevice, UserId, origDeviceOwner, { if (finally_arg2.SystemId != (uid_t) -1) Core->SetFileOwner (finally_arg, finally_arg2); }); // Create filesystem list args; if (options->Filesystem == VolumeCreationOptions::FilesystemType::MacOsExt && options->Size >= 10 * BYTES_PER_MB) args.push_back ("-J"); args.push_back (string (virtualDevice)); Process::Execute (fsFormatter, args); } #endif // TC_UNIX ShowInfo (options->Type == VolumeType::Hidden ? "HIDVOL_FORMAT_FINISHED_HELP" : "FORMAT_FINISHED_INFO"); } void TextUserInterface::DeleteSecurityTokenKeyfiles () const { shared_ptr keyfiles = AskKeyfiles(); if (keyfiles->empty()) throw UserAbort(); foreach_ref (const Keyfile &keyfile, *keyfiles) { SecurityToken::DeleteKeyfile (SecurityTokenKeyfilePath (FilePath (keyfile))); } } void TextUserInterface::DoShowError (const wxString &message) const { wcerr << L"Error: " << static_cast (message) << endl; } void TextUserInterface::DoShowInfo (const wxString &message) const { wcout << static_cast (message) << endl; } void TextUserInterface::DoShowString (const wxString &str) const { wcout << str.c_str(); } void TextUserInterface::DoShowWarning (const wxString &message) const { wcerr << L"Warning: " << static_cast (message) << endl; } void TextUserInterface::ExportSecurityTokenKeyfile () const { wstring keyfilePath = AskString (_("Enter security token keyfile path: ")); if (keyfilePath.empty()) throw UserAbort (SRC_POS); SecurityTokenKeyfile tokenKeyfile (keyfilePath); vector keyfileData; SecurityToken::GetKeyfileData (tokenKeyfile, keyfileData); BufferPtr keyfileDataBuf (&keyfileData.front(), keyfileData.size()); finally_do_arg (BufferPtr, keyfileDataBuf, { finally_arg.Erase(); }); FilePath exportFilePath = AskFilePath(); if (exportFilePath.IsEmpty()) throw UserAbort (SRC_POS); File keyfile; keyfile.Open (exportFilePath, File::CreateWrite); keyfile.Write (keyfileDataBuf); } shared_ptr TextUserInterface::GetAdminPasswordRequestHandler () { struct AdminPasswordRequestHandler : public GetStringFunctor { AdminPasswordRequestHandler (TextUserInterface *userInterface) : UI (userInterface) { } virtual void operator() (string &passwordStr) { UI->ShowString (_("Enter your user password or administrator password: ")); TextUserInterface::SetTerminalEcho (false); finally_do ({ TextUserInterface::SetTerminalEcho (true); }); wstring wPassword (UI->ReadInputStreamLine()); finally_do_arg (wstring *, &wPassword, { StringConverter::Erase (*finally_arg); }); UI->ShowString (L"\n"); StringConverter::ToSingle (wPassword, passwordStr); } TextUserInterface *UI; }; return shared_ptr (new AdminPasswordRequestHandler (this)); } void TextUserInterface::ImportSecurityTokenKeyfiles () const { list tokens = SecurityToken::GetAvailableTokens(); if (tokens.empty()) throw_err (LangString ["NO_TOKENS_FOUND"]); CK_SLOT_ID slotId; if (tokens.size() == 1) { slotId = tokens.front().SlotId; } else { foreach (const SecurityTokenInfo &token, tokens) { wstringstream tokenLabel; tokenLabel << L"[" << token.SlotId << L"] " << LangString["TOKEN_SLOT_ID"].c_str() << L" " << token.SlotId << L" " << token.Label; ShowInfo (tokenLabel.str()); } slotId = (CK_SLOT_ID) AskSelection (tokens.back().SlotId, tokens.front().SlotId); } shared_ptr keyfiles = AskKeyfiles(); if (keyfiles->empty()) throw UserAbort(); foreach_ref (const Keyfile &keyfilePath, *keyfiles) { File keyfile; keyfile.Open (keyfilePath, File::OpenRead, File::ShareReadWrite, File::PreserveTimestamps); if (keyfile.Length() > 0) { vector keyfileData (keyfile.Length()); BufferPtr keyfileDataBuf (&keyfileData.front(), keyfileData.size()); keyfile.ReadCompleteBuffer (keyfileDataBuf); finally_do_arg (BufferPtr, keyfileDataBuf, { finally_arg.Erase(); }); SecurityToken::CreateKeyfile (slotId, keyfileData, string (FilePath (keyfilePath).ToBaseName())); } else throw InsufficientData (SRC_POS, FilePath (keyfilePath)); } } void TextUserInterface::InitSecurityTokenLibrary () const { if (Preferences.SecurityTokenModule.IsEmpty()) throw_err (LangString ["NO_PKCS11_MODULE_SPECIFIED"]); struct PinRequestHandler : public GetPinFunctor { PinRequestHandler (const TextUserInterface *userInterface) : UI (userInterface) { } virtual void operator() (string &passwordStr) { if (UI->GetPreferences().NonInteractive) throw MissingArgument (SRC_POS); UI->ShowString (wxString::Format (LangString["ENTER_TOKEN_PASSWORD"], StringConverter::ToWide (passwordStr).c_str()) + L" "); TextUserInterface::SetTerminalEcho (false); finally_do ({ TextUserInterface::SetTerminalEcho (true); }); wstring wPassword (UI->ReadInputStreamLine()); finally_do_arg (wstring *, &wPassword, { StringConverter::Erase (*finally_arg); }); UI->ShowString (L"\n"); StringConverter::ToSingle (wPassword, passwordStr); } const TextUserInterface *UI; }; struct WarningHandler : public SendExceptionFunctor { WarningHandler (const TextUserInterface *userInterface) : UI (userInterface) { } virtual void operator() (const Exception &e) { UI->ShowError (e); } const TextUserInterface *UI; }; try { SecurityToken::InitLibrary (Preferences.SecurityTokenModule, auto_ptr (new PinRequestHandler (this)), auto_ptr (new WarningHandler (this))); } catch (Exception &e) { ShowError (e); throw_err (LangString ["PKCS11_MODULE_INIT_FAILED"]); } } void TextUserInterface::ListSecurityTokenKeyfiles () const { foreach (const SecurityTokenKeyfile &keyfile, SecurityToken::GetAvailableKeyfiles()) { ShowString (wstring (SecurityTokenKeyfilePath (keyfile))); ShowString (L"\n"); } } VolumeInfoList TextUserInterface::MountAllDeviceHostedVolumes (MountOptions &options) const { while (true) { if (!options.Password) options.Password = AskPassword(); if (!options.Keyfiles) options.Keyfiles = AskKeyfiles(); VolumeInfoList mountedVolumes = UserInterface::MountAllDeviceHostedVolumes (options); if (!mountedVolumes.empty()) return mountedVolumes; options.Password.reset(); } } shared_ptr TextUserInterface::MountVolume (MountOptions &options) const { shared_ptr volume; CheckRequirementsForMountingVolume(); // Volume path while (!options.Path || options.Path->IsEmpty()) { if (Preferences.NonInteractive) throw MissingArgument (SRC_POS); options.Path = AskVolumePath (); } if (Core->IsVolumeMounted (*options.Path)) { ShowInfo (StringFormatter (LangString["VOLUME_ALREADY_MOUNTED"], wstring (*options.Path))); return volume; } // Mount point if (!options.MountPoint && !options.NoFilesystem) options.MountPoint.reset (new DirectoryPath (AskString (_("Enter mount directory [default]: ")))); VolumePassword password; KeyfileList keyfiles; if ((!options.Password || options.Password->IsEmpty()) && (!options.Keyfiles || options.Keyfiles->empty()) && !Core->IsPasswordCacheEmpty()) { // Cached password try { volume = UserInterface::MountVolume (options); } catch (PasswordException&) { } } int incorrectPasswordCount = 0; while (!volume) { // Password if (!options.Password) { options.Password = AskPassword (StringFormatter (_("Enter password for {0}"), wstring (*options.Path))); } else { try { if (options.Password) options.Password->CheckPortability(); } catch (UnportablePassword &) { ShowWarning ("UNSUPPORTED_CHARS_IN_PWD_RECOM"); } } // Keyfiles if (!options.Keyfiles) options.Keyfiles = AskKeyfiles(); // Hidden volume protection if (options.Protection == VolumeProtection::None && !CmdLine->ArgNoHiddenVolumeProtection && AskYesNo (_("Protect hidden volume (if any)?"))) options.Protection = VolumeProtection::HiddenVolumeReadOnly; if (options.Protection == VolumeProtection::HiddenVolumeReadOnly) { if (!options.ProtectionPassword) options.ProtectionPassword = AskPassword (_("Enter password for hidden volume")); if (!options.ProtectionKeyfiles) options.ProtectionKeyfiles = AskKeyfiles (_("Enter keyfile for hidden volume")); } try { volume = UserInterface::MountVolume (options); } catch (ProtectionPasswordIncorrect &e) { ShowInfo (e); options.ProtectionPassword.reset(); } catch (PasswordIncorrect &e) { if (++incorrectPasswordCount > 2 && !options.UseBackupHeaders) { // Try to mount the volume using the backup header options.UseBackupHeaders = true; try { volume = UserInterface::MountVolume (options); ShowWarning ("HEADER_DAMAGED_AUTO_USED_HEADER_BAK"); } catch (...) { options.UseBackupHeaders = false; ShowInfo (e); options.Password.reset(); } } else { ShowInfo (e); options.Password.reset(); } ShowString (L"\n"); } catch (PasswordException &e) { ShowInfo (e); options.Password.reset(); } } #ifdef TC_LINUX if (!Preferences.NonInteractive && !Preferences.DisableKernelEncryptionModeWarning && volume->EncryptionModeName != L"XTS" && (volume->EncryptionModeName != L"LRW" || volume->EncryptionAlgorithmMinBlockSize != 16 || volume->EncryptionAlgorithmKeySize != 32)) { ShowWarning (LangString["ENCRYPTION_MODE_NOT_SUPPORTED_BY_KERNEL"]); } #endif return volume; } bool TextUserInterface::OnInit () { try { DefaultMessageOutput = new wxMessageOutputStderr; wxMessageOutput::Set (DefaultMessageOutput); InterfaceType = UserInterfaceType::Text; Init(); } catch (exception &e) { ShowError (e); return false; } return true; } int TextUserInterface::OnRun() { try { if (ProcessCommandLine ()) { Application::SetExitCode (0); return 0; } } catch (exception &e) { ShowError (e); } Application::SetExitCode (1); return 1; } void TextUserInterface::OnSignal (int signal) { #ifdef TC_UNIX try { SetTerminalEcho (true); } catch (...) { } _exit (1); #endif } void TextUserInterface::ReadInputStreamLine (wxString &line) const { if (!TextInputStream.get() || feof (stdin) || ferror (stdin)) throw UserAbort (SRC_POS); line = TextInputStream->ReadLine(); if (ferror (stdin) || (line.empty() && feof (stdin))) throw UserAbort (SRC_POS); } wxString TextUserInterface::ReadInputStreamLine () const { wxString line; ReadInputStreamLine (line); return line; } void TextUserInterface::RestoreVolumeHeaders (shared_ptr volumePath) const { if (!volumePath) volumePath = AskVolumePath(); if (!volumePath) throw UserAbort (SRC_POS); #ifdef TC_WINDOWS if (Core->IsVolumeMounted (*volumePath)) throw_err (LangString["DISMOUNT_FIRST"]); #endif // Ask whether to restore internal or external backup bool restoreInternalBackup; ShowInfo (LangString["HEADER_RESTORE_EXTERNAL_INTERNAL"]); ShowInfo (L"\n1) " + LangString["HEADER_RESTORE_INTERNAL"]); ShowInfo (L"2) " + LangString["HEADER_RESTORE_EXTERNAL"] + L"\n"); switch (AskSelection (2)) { case 1: restoreInternalBackup = true; break; case 2: restoreInternalBackup = false; break; default: throw UserAbort (SRC_POS); } if (restoreInternalBackup) { // Restore header from the internal backup shared_ptr volume; MountOptions options; options.Path = volumePath; while (!volume) { ShowString (L"\n"); options.Password = AskPassword(); options.Keyfiles = AskKeyfiles(); try { volume = Core->OpenVolume ( options.Path, options.PreserveTimestamps, options.Password, options.Keyfiles, options.Protection, options.ProtectionPassword, options.ProtectionKeyfiles, options.SharedAccessAllowed, VolumeType::Unknown, true ); } catch (PasswordException &e) { ShowInfo (e); } } shared_ptr layout = volume->GetLayout(); if (typeid (*layout) == typeid (VolumeLayoutV1Normal) || typeid (*layout) == typeid (VolumeLayoutV1Hidden)) { throw_err (LangString ["VOLUME_HAS_NO_BACKUP_HEADER"]); } RandomNumberGenerator::Start(); UserEnrichRandomPool(); // Re-encrypt volume header SecureBuffer newHeaderBuffer (volume->GetLayout()->GetHeaderSize()); Core->ReEncryptVolumeHeaderWithNewSalt (newHeaderBuffer, volume->GetHeader(), options.Password, options.Keyfiles); // Write volume header int headerOffset = volume->GetLayout()->GetHeaderOffset(); shared_ptr volumeFile = volume->GetFile(); if (headerOffset >= 0) volumeFile->SeekAt (headerOffset); else volumeFile->SeekEnd (headerOffset); volumeFile->Write (newHeaderBuffer); } else { // Restore header from an external backup wxString confirmMsg = L"\n\n" + LangString["CONFIRM_VOL_HEADER_RESTORE"]; confirmMsg.Replace (L"%hs", L"%s"); if (!AskYesNo (wxString::Format (confirmMsg, wstring (*volumePath).c_str()), true, true)) return; ShowString (L"\n"); FilePath filePath = AskFilePath(); if (filePath.IsEmpty()) throw UserAbort (SRC_POS); File backupFile; backupFile.Open (filePath, File::OpenRead); uint64 headerSize; bool legacyBackup; // Determine the format of the backup file switch (backupFile.Length()) { case TC_VOLUME_HEADER_GROUP_SIZE: headerSize = TC_VOLUME_HEADER_SIZE; legacyBackup = false; break; case TC_VOLUME_HEADER_SIZE_LEGACY * 2: headerSize = TC_VOLUME_HEADER_SIZE_LEGACY; legacyBackup = true; break; default: throw_err (LangString ["HEADER_BACKUP_SIZE_INCORRECT"]); } // Open the volume header stored in the backup file MountOptions options; shared_ptr decryptedLayout; while (!decryptedLayout) { options.Password = AskPassword (L"\n" + LangString["ENTER_HEADER_BACKUP_PASSWORD"]); options.Keyfiles = AskKeyfiles(); try { // Test volume layouts foreach (shared_ptr layout, VolumeLayout::GetAvailableLayouts ()) { if (layout->HasDriveHeader()) continue; if (!legacyBackup && (typeid (*layout) == typeid (VolumeLayoutV1Normal) || typeid (*layout) == typeid (VolumeLayoutV1Hidden))) continue; if (legacyBackup && (typeid (*layout) == typeid (VolumeLayoutV2Normal) || typeid (*layout) == typeid (VolumeLayoutV2Hidden))) continue; SecureBuffer headerBuffer (layout->GetHeaderSize()); backupFile.ReadAt (headerBuffer, layout->GetType() == VolumeType::Hidden ? layout->GetHeaderSize() : 0); // Decrypt header shared_ptr passwordKey = Keyfile::ApplyListToPassword (options.Keyfiles, options.Password); if (layout->GetHeader()->Decrypt (headerBuffer, *passwordKey, layout->GetSupportedKeyDerivationFunctions(), layout->GetSupportedEncryptionAlgorithms(), layout->GetSupportedEncryptionModes())) { decryptedLayout = layout; break; } } if (!decryptedLayout) throw PasswordIncorrect (SRC_POS); } catch (PasswordException &e) { ShowWarning (e); } } File volumeFile; volumeFile.Open (*volumePath, File::OpenReadWrite, File::ShareNone, File::PreserveTimestamps); RandomNumberGenerator::Start(); UserEnrichRandomPool(); // Re-encrypt volume header SecureBuffer newHeaderBuffer (decryptedLayout->GetHeaderSize()); Core->ReEncryptVolumeHeaderWithNewSalt (newHeaderBuffer, decryptedLayout->GetHeader(), options.Password, options.Keyfiles); // Write volume header int headerOffset = decryptedLayout->GetHeaderOffset(); if (headerOffset >= 0) volumeFile.SeekAt (headerOffset); else volumeFile.SeekEnd (headerOffset); volumeFile.Write (newHeaderBuffer); if (decryptedLayout->HasBackupHeader()) { // Re-encrypt backup volume header Core->ReEncryptVolumeHeaderWithNewSalt (newHeaderBuffer, decryptedLayout->GetHeader(), options.Password, options.Keyfiles); // Write backup volume header headerOffset = decryptedLayout->GetBackupHeaderOffset(); if (headerOffset >= 0) volumeFile.SeekAt (headerOffset); else volumeFile.SeekEnd (headerOffset); volumeFile.Write (newHeaderBuffer); } } ShowString (L"\n"); ShowInfo ("VOL_HEADER_RESTORED"); } void TextUserInterface::SetTerminalEcho (bool enable) { if (CmdLine->ArgDisplayPassword) return; #ifdef TC_UNIX struct termios termAttr; if (tcgetattr (0, &termAttr) == 0) { if (!enable) { termAttr.c_lflag &= ~ECHO; throw_sys_if (tcsetattr (0, TCSANOW, &termAttr) != 0); } else { termAttr.c_lflag |= ECHO; throw_sys_if (tcsetattr (0, TCSANOW, &termAttr) != 0); } } #endif } void TextUserInterface::UserEnrichRandomPool () const { RandomNumberGenerator::Start(); if (RandomNumberGenerator::IsEnrichedByUser()) return; if (CmdLine->ArgHash) RandomNumberGenerator::SetHash (CmdLine->ArgHash); if (!CmdLine->ArgRandomSourcePath.IsEmpty()) { SecureBuffer buffer (RandomNumberGenerator::PoolSize); File randSourceFile; randSourceFile.Open (CmdLine->ArgRandomSourcePath, File::OpenRead); for (size_t i = 0; i < buffer.Size(); ++i) { if (randSourceFile.Read (buffer.GetRange (i, 1)) < 1) break; } RandomNumberGenerator::AddToPool (buffer); RandomNumberGenerator::SetEnrichedByUserStatus (true); } else if (!Preferences.NonInteractive) { int randCharsRequired = RandomNumberGenerator::PoolSize; ShowInfo (StringFormatter (_("\nPlease type at least {0} randomly chosen characters and then press Enter:"), randCharsRequired)); SetTerminalEcho (false); finally_do ({ TextUserInterface::SetTerminalEcho (true); }); while (randCharsRequired > 0) { wstring randStr = AskString(); RandomNumberGenerator::AddToPool (ConstBufferPtr ((byte *) randStr.c_str(), randStr.size() * sizeof (wchar_t))); randCharsRequired -= randStr.size(); if (randCharsRequired > 0) ShowInfo (StringFormatter (_("Characters remaining: {0}"), randCharsRequired)); } ShowString (L"\n"); RandomNumberGenerator::SetEnrichedByUserStatus (true); } } wxMessageOutput *DefaultMessageOutput; }