|
|
5.0
/*
Copyright (c) 2008 TrueCrypt Foundation. All rights reserved.
Governed by the TrueCrypt License 2.4 the full text of which is contained
in the file License.txt included in TrueCrypt binary and source code
distribution packages.
*/
#ifndef TC_WINDOWS
#include <errno.h>
#endif
#include "EncryptionModeLRW.h"
#include "EncryptionModeXTS.h"
#include "Volume.h"
#include "VolumeHeader.h"
#include "VolumeLayout.h"
namespace TrueCrypt
{
Volume::Volume ()
: HiddenVolumeProtectionTriggered (false),
VolumeDataSize (0),
TotalDataRead (0),
TotalDataWritten (0)
{
}
Volume::~Volume ()
{
}
void Volume::CheckProtectedRange (uint64 writeHostOffset, uint64 writeLength)
{
uint64 writeHostEndOffset = writeHostOffset + writeLength - 1;
if ((writeHostOffset < ProtectedRangeStart) ? (writeHostEndOffset >= ProtectedRangeStart) : (writeHostOffset <= ProtectedRangeEnd - 1))
{
HiddenVolumeProtectionTriggered = true;
throw VolumeProtected (SRC_POS);
}
}
void Volume::Close ()
{
if (VolumeFile.get() == nullptr)
throw NotInitialized (SRC_POS);
VolumeFile.reset();
}
shared_ptr <EncryptionAlgorithm> Volume::GetEncryptionAlgorithm () const
{
if_debug (ValidateState ());
return EA;
}
shared_ptr <EncryptionMode> Volume::GetEncryptionMode () const
{
if_debug (ValidateState ());
return EA->GetMode();
}
void Volume::Open (const VolumePath &volumePath, bool preserveTimestamps, shared_ptr <VolumePassword> password, shared_ptr <KeyfileList> keyfiles, VolumeProtection::Enum protection, shared_ptr <VolumePassword> protectionPassword, shared_ptr <KeyfileList> protectionKeyfiles, bool sharedAccessAllowed, VolumeType::Enum volumeType)
{
make_shared_auto (File, file);
File::FileOpenFlags flags = (preserveTimestamps ? File::PreserveTimestamps : File::FlagsNone);
try
{
if (protection == VolumeProtection::ReadOnly)
file->Open (volumePath, File::OpenRead, File::ShareRead, flags);
else
file->Open (volumePath, File::OpenReadWrite, File::ShareNone, flags);
}
catch (SystemException &e)
{
if (e.GetErrorCode() ==
#ifdef TC_WINDOWS
ERROR_SHARING_VIOLATION)
#else
EAGAIN)
#endif
{
if (!sharedAccessAllowed)
throw VolumeHostInUse (SRC_POS);
file->Open (volumePath, protection == VolumeProtection::ReadOnly ? File::OpenRead : File::OpenReadWrite, File::ShareReadWriteIgnoreLock, flags);
}
else
throw;
}
return Open (file, password, keyfiles, protection, protectionPassword, protectionKeyfiles, volumeType);
}
void Volume::Open (shared_ptr <File> volumeFile, shared_ptr <VolumePassword> password, shared_ptr <KeyfileList> keyfiles, VolumeProtection::Enum protection, shared_ptr <VolumePassword> protectionPassword, shared_ptr <KeyfileList> protectionKeyfiles, VolumeType::Enum volumeType)
{
if (!volumeFile)
throw ParameterIncorrect (SRC_POS);
Protection = protection;
VolumeFile = volumeFile;
try
{
VolumeHostSize = VolumeFile->Length();
shared_ptr <VolumePassword> passwordKey = Keyfile::ApplyListToPassword (keyfiles, password);
// Test volume layouts
foreach (shared_ptr <VolumeLayout> layout, VolumeLayout::GetAvailableLayouts (volumeType))
{
if (layout->GetHeaderOffset() >= 0)
VolumeFile->SeekAt (layout->GetHeaderOffset());
else
VolumeFile->SeekEnd (layout->GetHeaderOffset());
SecureBuffer headerBuffer (layout->GetHeaderSize());
if (VolumeFile->Read (headerBuffer) != layout->GetHeaderSize())
throw MissingVolumeData (SRC_POS);
shared_ptr <VolumeHeader> header = layout->GetHeader();
if (header->Decrypt (headerBuffer, *passwordKey, layout->GetSupportedEncryptionAlgorithms(), layout->GetSupportedEncryptionModes ()))
{
// Header decrypted
Type = layout->GetType();
SectorSize = header->GetSectorSize();
VolumeDataOffset = layout->GetDataOffset (VolumeHostSize);
VolumeDataSize = layout->GetDataSize (VolumeHostSize);
Header = header;
Layout = layout;
EA = header->GetEncryptionAlgorithm();
EncryptionMode &mode = *EA->GetMode();
if (typeid (mode) == typeid (EncryptionModeLRW))
mode.SetSectorOffset (VolumeDataOffset / SectorSize);
// Volume protection
if (Protection == VolumeProtection::HiddenVolumeReadOnly)
{
if (Type == VolumeType::Hidden)
Protection = VolumeProtection::ReadOnly;
else
{
try
{
Volume protectedVolume;
protectedVolume.Open (VolumeFile,
protectionPassword, protectionKeyfiles,
VolumeProtection::ReadOnly,
shared_ptr <VolumePassword> (), shared_ptr <KeyfileList> (),
VolumeType::Hidden);
if (protectedVolume.GetType() != VolumeType::Hidden)
ParameterIncorrect (SRC_POS);
ProtectedRangeStart = protectedVolume.VolumeDataOffset;
ProtectedRangeEnd = protectedVolume.VolumeDataOffset + protectedVolume.VolumeDataSize + protectedVolume.Layout->GetHeaderSize();
}
catch (PasswordException&)
{
if (protectionKeyfiles && !protectionKeyfiles->empty())
throw ProtectionPasswordKeyfilesIncorrect (SRC_POS);
throw ProtectionPasswordIncorrect (SRC_POS);
}
}
}
return;
}
}
if (keyfiles && !keyfiles->empty())
throw PasswordKeyfilesIncorrect (SRC_POS);
throw PasswordIncorrect (SRC_POS);
}
catch (...)
{
Close();
throw;
}
}
void Volume::ReadSectors (const BufferPtr &buffer, uint64 byteOffset)
{
if_debug (ValidateState ());
uint64 length = buffer.Size();
uint64 hostOffset = VolumeDataOffset + byteOffset;
if (length % SectorSize != 0 || byteOffset % SectorSize != 0)
throw ParameterIncorrect (SRC_POS);
if (VolumeFile->ReadAt (buffer, hostOffset) != length)
throw MissingVolumeData (SRC_POS);
EA->DecryptSectors (buffer, hostOffset / SectorSize, length / SectorSize, SectorSize);
TotalDataRead += length;
}
void Volume::ReEncryptHeader (const ConstBufferPtr &newSalt, const ConstBufferPtr &newHeaderKey, shared_ptr <Pkcs5Kdf> newPkcs5Kdf)
{
if_debug (ValidateState ());
if (Protection == VolumeProtection::ReadOnly)
throw VolumeReadOnly (SRC_POS);
SecureBuffer newHeaderBuffer (Layout->GetHeaderSize());
Header->EncryptNew (newHeaderBuffer, newSalt, newHeaderKey, newPkcs5Kdf);
if (Layout->GetHeaderOffset() >= 0)
VolumeFile->SeekAt (Layout->GetHeaderOffset());
else
VolumeFile->SeekEnd (Layout->GetHeaderOffset());
VolumeFile->Write (newHeaderBuffer);
}
void Volume::ValidateState () const
{
if (VolumeFile.get() == nullptr)
throw NotInitialized (SRC_POS);
}
void Volume::WriteSectors (const ConstBufferPtr &buffer, uint64 byteOffset)
{
if_debug (ValidateState ());
uint64 length = buffer.Size();
uint64 hostOffset = VolumeDataOffset + byteOffset;
if (length % SectorSize != 0
|| byteOffset % SectorSize != 0
|| byteOffset + length > VolumeDataSize)
throw ParameterIncorrect (SRC_POS);
if (Protection == VolumeProtection::ReadOnly)
throw VolumeReadOnly (SRC_POS);
if (HiddenVolumeProtectionTriggered)
throw VolumeProtected (SRC_POS);
if (Protection == VolumeProtection::HiddenVolumeReadOnly)
CheckProtectedRange (hostOffset, length);
SecureBuffer encBuf (buffer.Size());
encBuf.CopyFrom (buffer);
EA->EncryptSectors (encBuf, hostOffset / SectorSize, length / SectorSize, SectorSize);
VolumeFile->WriteAt (encBuf, hostOffset);
TotalDataWritten += length;
}
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.