/* 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 "Crc32.h" #include "EncryptionModeXTS.h" #include "Pkcs5Kdf.h" #include "Pkcs5Kdf.h" #include "VolumeHeader.h" #include "VolumeException.h" #include "Common/Crypto.h" namespace TrueCrypt { VolumeHeader::VolumeHeader (uint32 size) { Init(); HeaderSize = size; EncryptedHeaderDataSize = size - EncryptedHeaderDataOffset; } VolumeHeader::~VolumeHeader () { Init(); } void VolumeHeader::Init () { VolumeKeyAreaCrc32 = 0; VolumeCreationTime = 0; HeaderCreationTime = 0; mVolumeType = VolumeType::Unknown; HiddenVolumeDataSize = 0; VolumeDataSize = 0; EncryptedAreaStart = 0; EncryptedAreaLength = 0; Flags = 0; SectorSize = 0; } void VolumeHeader::Create (const BufferPtr &headerBuffer, VolumeHeaderCreationOptions &options) { if (options.DataKey.Size() != options.EA->GetKeySize() * 2 || options.Salt.Size() != GetSaltSize()) throw ParameterIncorrect (SRC_POS); headerBuffer.Zero(); HeaderVersion = CurrentHeaderVersion; RequiredMinProgramVersion = CurrentRequiredMinProgramVersion; DataAreaKey.Zero(); DataAreaKey.CopyFrom (options.DataKey); VolumeCreationTime = 0; HiddenVolumeDataSize = (options.Type == VolumeType::Hidden ? options.VolumeDataSize : 0); VolumeDataSize = options.VolumeDataSize; EncryptedAreaStart = options.VolumeDataStart; EncryptedAreaLength = options.VolumeDataSize; SectorSize = options.SectorSize; if (SectorSize < TC_MIN_VOLUME_SECTOR_SIZE || SectorSize > TC_MAX_VOLUME_SECTOR_SIZE || SectorSize % ENCRYPTION_DATA_UNIT_SIZE != 0) { throw ParameterIncorrect (SRC_POS); } EA = options.EA; shared_ptr mode (new EncryptionModeXTS ()); EA->SetMode (mode); EncryptNew (headerBuffer, options.Salt, options.HeaderKey, options.Kdf); } bool VolumeHeader::Decrypt (const ConstBufferPtr &encryptedData, const VolumePassword &password, const Pkcs5KdfList &keyDerivationFunctions, const EncryptionAlgorithmList &encryptionAlgorithms, const EncryptionModeList &encryptionModes) { if (password.Size() < 1) throw PasswordEmpty (SRC_POS); ConstBufferPtr salt (encryptedData.GetRange (SaltOffset, SaltSize)); SecureBuffer header (EncryptedHeaderDataSize); SecureBuffer headerKey (GetLargestSerializedKeySize()); foreach (shared_ptr pkcs5, keyDerivationFunctions) { pkcs5->DeriveKey (headerKey, password, salt); foreach (shared_ptr mode, encryptionModes) { if (typeid (*mode) != typeid (EncryptionModeXTS)) mode->SetKey (headerKey.GetRange (0, mode->GetKeySize())); foreach (shared_ptr ea, encryptionAlgorithms) { if (!ea->IsModeSupported (mode)) continue; if (typeid (*mode) == typeid (EncryptionModeXTS)) { ea->SetKey (headerKey.GetRange (0, ea->GetKeySize())); mode = mode->GetNew(); mode->SetKey (headerKey.GetRange (ea->GetKeySize(), ea->GetKeySize())); } else { ea->SetKey (headerKey.GetRange (LegacyEncryptionModeKeyAreaSize, ea->GetKeySize())); } ea->SetMode (mode); header.CopyFrom (encryptedData.GetRange (EncryptedHeaderDataOffset, EncryptedHeaderDataSize)); ea->Decrypt (header); if (Deserialize (header, ea, mode)) { EA = ea; Pkcs5 = pkcs5; return true; } } } } return false; } bool VolumeHeader::Deserialize (const ConstBufferPtr &header, shared_ptr &ea, shared_ptr &mode) { if (header.Size() != EncryptedHeaderDataSize) throw ParameterIncorrect (SRC_POS); if (header[0] != 'V' || header[1] != 'E' || header[2] != 'R' || header[3] != 'A') return false; size_t offset = 4; HeaderVersion = DeserializeEntry (header, offset); if (HeaderVersion < MinAllowedHeaderVersion) return false; if (HeaderVersion > CurrentHeaderVersion) throw HigherVersionRequired (SRC_POS); if (HeaderVersion >= 4 && Crc32::ProcessBuffer (header.GetRange (0, TC_HEADER_OFFSET_HEADER_CRC - TC_HEADER_OFFSET_MAGIC)) != DeserializeEntryAt (header, TC_HEADER_OFFSET_HEADER_CRC - TC_HEADER_OFFSET_MAGIC)) { return false; } RequiredMinProgramVersion = DeserializeEntry (header, offset); if (RequiredMinProgramVersion > Version::Number()) throw HigherVersionRequired (SRC_POS); VolumeKeyAreaCrc32 = DeserializeEntry (header, offset); VolumeCreationTime = DeserializeEntry (header, offset); HeaderCreationTime = DeserializeEntry (header, offset); HiddenVolumeDataSize = DeserializeEntry (header, offset); mVolumeType = (HiddenVolumeDataSize != 0 ? VolumeType::Hidden : VolumeType::Normal); VolumeDataSize = DeserializeEntry (header, offset); EncryptedAreaStart = DeserializeEntry (header, offset); EncryptedAreaLength = DeserializeEntry (header, offset); Flags = DeserializeEntry (header, offset); SectorSize = DeserializeEntry (header, offset); if (HeaderVersion < 5) SectorSize = TC_SECTOR_SIZE_LEGACY; if (SectorSize < TC_MIN_VOLUME_SECTOR_SIZE || SectorSize > TC_MAX_VOLUME_SECTOR_SIZE || SectorSize % ENCRYPTION_DATA_UNIT_SIZE != 0) { throw ParameterIncorrect (SRC_POS); } #if !(defined (TC_WINDOWS) || defined (TC_LINUX)) if (SectorSize != TC_SECTOR_SIZE_LEGACY) throw UnsupportedSectorSize (SRC_POS); #endif offset = DataAreaKeyOffset; if (VolumeKeyAreaCrc32 != Crc32::ProcessBuffer (header.GetRange (offset, DataKeyAreaMaxSize))) return false; DataAreaKey.CopyFrom (header.GetRange (offset, DataKeyAreaMaxSize)); ea = ea->GetNew(); mode = mode->GetNew(); if (typeid (*mode) == typeid (EncryptionModeXTS)) { ea->SetKey (header.GetRange (offset, ea->GetKeySize())); mode->SetKey (header.GetRange (offset + ea->GetKeySize(), ea->GetKeySize())); } else { mode->SetKey (header.GetRange (offset, mode->GetKeySize())); ea->SetKey (header.GetRange (offset + LegacyEncryptionModeKeyAreaSize, ea->GetKeySize())); } ea->SetMode (mode); return true; } template T VolumeHeader::DeserializeEntry (const ConstBufferPtr &header, size_t &offset) const { offset += sizeof (T); if (offset > header.Size()) throw ParameterIncorrect (SRC_POS); return Endian::Big (*reinterpret_cast (header.Get() + offset - sizeof (T))); } template T VolumeHeader::DeserializeEntryAt (const ConstBufferPtr &header, const size_t &offset) const { if (offset > header.Size()) throw ParameterIncorrect (SRC_POS); return Endian::Big (*reinterpret_cast (header.Get() + offset)); } void VolumeHeader::EncryptNew (const BufferPtr &newHeaderBuffer, const ConstBufferPtr &newSalt, const ConstBufferPtr &newHeaderKey, shared_ptr newPkcs5Kdf) { if (newHeaderBuffer.Size() != HeaderSize || newSalt.Size() != SaltSize) throw ParameterIncorrect (SRC_POS); shared_ptr mode = EA->GetMode()->GetNew(); shared_ptr ea = EA->GetNew(); if (typeid (*mode) == typeid (EncryptionModeXTS)) { mode->SetKey (newHeaderKey.GetRange (EA->GetKeySize(), EA->GetKeySize())); ea->SetKey (newHeaderKey.GetRange (0, ea->GetKeySize())); } else { mode->SetKey (newHeaderKey.GetRange (0, mode->GetKeySize())); ea->SetKey (newHeaderKey.GetRange (LegacyEncryptionModeKeyAreaSize, ea->GetKeySize())); } ea->SetMode (mode); newHeaderBuffer.CopyFrom (newSalt); BufferPtr headerData = newHeaderBuffer.GetRange (EncryptedHeaderDataOffset, EncryptedHeaderDataSize); Serialize (headerData); ea->Encrypt (headerData); if (newPkcs5Kdf) Pkcs5 = newPkcs5Kdf; } size_t VolumeHeader::GetLargestSerializedKeySize () { size_t largestKey = EncryptionAlgorithm::GetLargestKeySize (EncryptionAlgorithm::GetAvailableAlgorithms()); // XTS mode requires the same key size as the encryption algorithm. // Legacy modes may require larger key than XTS. if (LegacyEncryptionModeKeyAreaSize + largestKey > largestKey * 2) return LegacyEncryptionModeKeyAreaSize + largestKey; return largestKey * 2; } void VolumeHeader::Serialize (const BufferPtr &header) const { if (header.Size() != EncryptedHeaderDataSize) throw ParameterIncorrect (SRC_POS); header.Zero(); header[0] = 'V'; header[1] = 'E'; header[2] = 'R'; header[3] = 'A'; size_t offset = 4; header.GetRange (DataAreaKeyOffset, DataAreaKey.Size()).CopyFrom (DataAreaKey); uint16 headerVersion = CurrentHeaderVersion; SerializeEntry (headerVersion, header, offset); SerializeEntry (RequiredMinProgramVersion, header, offset); SerializeEntry (Crc32::ProcessBuffer (header.GetRange (DataAreaKeyOffset, DataKeyAreaMaxSize)), header, offset); uint64 reserved64 = 0; SerializeEntry (reserved64, header, offset); SerializeEntry (reserved64, header, offset); SerializeEntry (HiddenVolumeDataSize, header, offset); SerializeEntry (VolumeDataSize, header, offset); SerializeEntry (EncryptedAreaStart, header, offset); SerializeEntry (EncryptedAreaLength, header, offset); SerializeEntry (Flags, header, offset); if (SectorSize < TC_MIN_VOLUME_SECTOR_SIZE || SectorSize > TC_MAX_VOLUME_SECTOR_SIZE || SectorSize % ENCRYPTION_DATA_UNIT_SIZE != 0) { throw ParameterIncorrect (SRC_POS); } SerializeEntry (SectorSize, header, offset); offset = TC_HEADER_OFFSET_HEADER_CRC - TC_HEADER_OFFSET_MAGIC; SerializeEntry (Crc32::ProcessBuffer (header.GetRange (0, TC_HEADER_OFFSET_HEADER_CRC - TC_HEADER_OFFSET_MAGIC)), header, offset); } template void VolumeHeader::SerializeEntry (const T &entry, const BufferPtr &header, size_t &offset) const { offset += sizeof (T); if (offset > header.Size()) throw ParameterIncorrect (SRC_POS); *reinterpret_cast (header.Get() + offset - sizeof (T)) = Endian::Big (entry); } void VolumeHeader::SetSize (uint32 headerSize) { HeaderSize = headerSize; EncryptedHeaderDataSize = HeaderSize - EncryptedHeaderDataOffset; } }