From a173a11cfe5f3233f70f256cf3bddf381ea2fca2 Mon Sep 17 00:00:00 2001 From: Mounir IDRASSI Date: Mon, 25 May 2026 15:43:00 +0900 Subject: [PATCH] Linux: parallelize header KDF autodetection Extend the Unix encryption thread pool to run key-derivation work items and use it when mounting volumes without an explicitly selected KDF. This brings Linux/macOS header PRF autodetection closer to the Windows path while keeping selected-KDF mounts unchanged. Fixes #1610. --- src/Platform/SyncEvent.h | 1 + src/Platform/Unix/SyncEvent.cpp | 8 ++ src/Volume/EncryptionTest.cpp | 6 + src/Volume/EncryptionThreadPool.cpp | 93 ++++++++++++++- src/Volume/EncryptionThreadPool.h | 35 ++++++ src/Volume/Pkcs5Kdf.cpp | 82 +++++++++++-- src/Volume/Pkcs5Kdf.h | 12 ++ src/Volume/VolumeHeader.cpp | 176 +++++++++++++++++++++------- src/Volume/VolumeHeader.h | 1 + 9 files changed, 357 insertions(+), 57 deletions(-) diff --git a/src/Platform/SyncEvent.h b/src/Platform/SyncEvent.h index 108c6352..97aae9e7 100644 --- a/src/Platform/SyncEvent.h +++ b/src/Platform/SyncEvent.h @@ -29,6 +29,7 @@ namespace VeraCrypt SyncEvent (); ~SyncEvent (); + void Reset (); void Signal (); void Wait (); diff --git a/src/Platform/Unix/SyncEvent.cpp b/src/Platform/Unix/SyncEvent.cpp index ad069cdb..c965807b 100644 --- a/src/Platform/Unix/SyncEvent.cpp +++ b/src/Platform/Unix/SyncEvent.cpp @@ -41,6 +41,14 @@ namespace VeraCrypt Initialized = false; } + void SyncEvent::Reset () + { + assert (Initialized); + + ScopeLock lock (EventMutex); + Signaled = false; + } + void SyncEvent::Signal () { assert (Initialized); diff --git a/src/Volume/EncryptionTest.cpp b/src/Volume/EncryptionTest.cpp index c98db964..be84beb1 100644 --- a/src/Volume/EncryptionTest.cpp +++ b/src/Volume/EncryptionTest.cpp @@ -50,6 +50,12 @@ namespace VeraCrypt return 1; } + virtual int DeriveKey (const BufferPtr &key, const VolumePassword &password, const ConstBufferPtr &salt, int iterationCount, long volatile *pAbortKeyDerivation) const + { + (void) pAbortKeyDerivation; + return DeriveKey (key, password, salt, iterationCount); + } + virtual shared_ptr GetHash () const { return shared_ptr (new Blake2b); } virtual int GetIterationCount (int pim) const { return 1; } virtual wstring GetName () const { return L"Argon2"; } diff --git a/src/Volume/EncryptionThreadPool.cpp b/src/Volume/EncryptionThreadPool.cpp index 9434a5ec..8bb99f7b 100644 --- a/src/Volume/EncryptionThreadPool.cpp +++ b/src/Volume/EncryptionThreadPool.cpp @@ -23,9 +23,62 @@ #include "Platform/SystemLog.h" #include "Common/Crypto.h" #include "EncryptionThreadPool.h" +#include "Pkcs5Kdf.h" namespace VeraCrypt { + EncryptionThreadPool::KeyDerivationWorkItem::KeyDerivationWorkItem (shared_ptr kdf, size_t derivedKeySize) + : Completed (false), DerivedKey (derivedKeySize), Kdf (kdf), Processed (false), Result (0) + { + } + + EncryptionThreadPool::KeyDerivationWorkItem::~KeyDerivationWorkItem () + { + } + + void EncryptionThreadPool::BeginKeyDerivation (KeyDerivationWorkItem &keyDerivationWorkItem, const VolumePassword &password, int pim, const ConstBufferPtr &salt, SyncEvent &completionEvent, SyncEvent &noOutstandingWorkItemEvent, SharedVal &outstandingWorkItemCount, long volatile *abortFlag) + { + if (!ThreadPoolRunning) + throw NotInitialized (SRC_POS); + + ScopeLock lock (EnqueueMutex); + + WorkItem *workItem = &WorkItemQueue[EnqueuePosition++]; + + if (EnqueuePosition >= QueueSize) + EnqueuePosition = 0; + + while (workItem->State != WorkItem::State::Free) + { + WorkItemCompletedEvent.Wait(); + } + + keyDerivationWorkItem.Completed.Set (false); + keyDerivationWorkItem.ItemException.reset(); + keyDerivationWorkItem.Processed = false; + keyDerivationWorkItem.Result = 0; + + workItem->Type = WorkType::DeriveKey; + workItem->KeyDerivation.AbortFlag = abortFlag; + workItem->KeyDerivation.CompletionEvent = &completionEvent; + workItem->KeyDerivation.NoOutstandingWorkItemEvent = &noOutstandingWorkItemEvent; + workItem->KeyDerivation.OutstandingWorkItemCount = &outstandingWorkItemCount; + workItem->KeyDerivation.Password = &password; + workItem->KeyDerivation.Pim = pim; + workItem->KeyDerivation.Salt = salt.Get(); + workItem->KeyDerivation.SaltSize = salt.Size(); + workItem->KeyDerivation.WorkItem = &keyDerivationWorkItem; + + { + ScopeLock outstandingWorkItemLock (KeyDerivationCompletionMutex); + if (outstandingWorkItemCount.Increment() == 1) + noOutstandingWorkItemEvent.Reset(); + } + + workItem->State.Set (WorkItem::State::Ready); + WorkItemReadyEvent.Signal(); + } + void EncryptionThreadPool::DoWork (WorkType::Enum type, const EncryptionMode *encryptionMode, uint8 *data, uint64 startUnitNo, uint64 unitCount, size_t sectorSize) { size_t fragmentCount; @@ -272,21 +325,54 @@ namespace VeraCrypt workItem->Encryption.Mode->EncryptSectorsCurrentThread (workItem->Encryption.Data, workItem->Encryption.StartUnitNo, workItem->Encryption.UnitCount, workItem->Encryption.SectorSize); break; + case WorkType::DeriveKey: + { + KeyDerivationWorkItem *keyDerivationWorkItem = workItem->KeyDerivation.WorkItem; + if (workItem->KeyDerivation.AbortFlag && *workItem->KeyDerivation.AbortFlag) + keyDerivationWorkItem->Result = ERR_USER_ABORT; + else + keyDerivationWorkItem->Result = keyDerivationWorkItem->Kdf->DeriveKey (keyDerivationWorkItem->DerivedKey, *workItem->KeyDerivation.Password, workItem->KeyDerivation.Pim, ConstBufferPtr (workItem->KeyDerivation.Salt, workItem->KeyDerivation.SaltSize), workItem->KeyDerivation.AbortFlag); + } + break; + default: throw ParameterIncorrect (SRC_POS); } } catch (Exception &e) { - workItem->FirstFragment->ItemException.reset (e.CloneNew()); + if (workItem->Type == WorkType::DeriveKey) + workItem->KeyDerivation.WorkItem->ItemException.reset (e.CloneNew()); + else + workItem->FirstFragment->ItemException.reset (e.CloneNew()); } catch (exception &e) { - workItem->FirstFragment->ItemException.reset (new ExternalException (SRC_POS, StringConverter::ToExceptionString (e))); + if (workItem->Type == WorkType::DeriveKey) + workItem->KeyDerivation.WorkItem->ItemException.reset (new ExternalException (SRC_POS, StringConverter::ToExceptionString (e))); + else + workItem->FirstFragment->ItemException.reset (new ExternalException (SRC_POS, StringConverter::ToExceptionString (e))); } catch (...) { - workItem->FirstFragment->ItemException.reset (new UnknownException (SRC_POS)); + if (workItem->Type == WorkType::DeriveKey) + workItem->KeyDerivation.WorkItem->ItemException.reset (new UnknownException (SRC_POS)); + else + workItem->FirstFragment->ItemException.reset (new UnknownException (SRC_POS)); + } + + if (workItem->Type == WorkType::DeriveKey) + { + workItem->KeyDerivation.WorkItem->Completed.Set (true); + workItem->KeyDerivation.CompletionEvent->Signal(); + { + ScopeLock outstandingWorkItemLock (KeyDerivationCompletionMutex); + if (workItem->KeyDerivation.OutstandingWorkItemCount->Decrement() == 0) + workItem->KeyDerivation.NoOutstandingWorkItemEvent->Signal(); + } + workItem->State.Set (WorkItem::State::Free); + WorkItemCompletedEvent.Signal(); + continue; } if (workItem != workItem->FirstFragment) @@ -321,6 +407,7 @@ namespace VeraCrypt Mutex EncryptionThreadPool::EnqueueMutex; Mutex EncryptionThreadPool::DequeueMutex; + Mutex EncryptionThreadPool::KeyDerivationCompletionMutex; SyncEvent EncryptionThreadPool::WorkItemReadyEvent; SyncEvent EncryptionThreadPool::WorkItemCompletedEvent; diff --git a/src/Volume/EncryptionThreadPool.h b/src/Volume/EncryptionThreadPool.h index 3ed50d51..28e2f7a8 100644 --- a/src/Volume/EncryptionThreadPool.h +++ b/src/Volume/EncryptionThreadPool.h @@ -18,6 +18,9 @@ namespace VeraCrypt { + class Pkcs5Kdf; + class VolumePassword; + class EncryptionThreadPool { public: @@ -31,6 +34,8 @@ namespace VeraCrypt }; }; + struct KeyDerivationWorkItem; + struct WorkItem { struct State @@ -60,9 +65,37 @@ namespace VeraCrypt uint64 UnitCount; size_t SectorSize; } Encryption; + + struct + { + long volatile *AbortFlag; + SyncEvent *CompletionEvent; + SyncEvent *NoOutstandingWorkItemEvent; + SharedVal *OutstandingWorkItemCount; + const VolumePassword *Password; + int Pim; + const uint8 *Salt; + size_t SaltSize; + KeyDerivationWorkItem *WorkItem; + } KeyDerivation; }; }; + struct KeyDerivationWorkItem + { + KeyDerivationWorkItem (shared_ptr kdf, size_t derivedKeySize); + ~KeyDerivationWorkItem (); + + SharedVal Completed; + SecureBuffer DerivedKey; + unique_ptr ItemException; + shared_ptr Kdf; + bool Processed; + int Result; + }; + + // Caller-owned references and pointers must remain valid until noOutstandingWorkItemEvent is signaled. + static void BeginKeyDerivation (KeyDerivationWorkItem &keyDerivationWorkItem, const VolumePassword &password, int pim, const ConstBufferPtr &salt, SyncEvent &completionEvent, SyncEvent &noOutstandingWorkItemEvent, SharedVal &outstandingWorkItemCount, long volatile *abortFlag); static void DoWork (WorkType::Enum type, const EncryptionMode *mode, uint8 *data, uint64 startUnitNo, uint64 unitCount, size_t sectorSize); static bool IsRunning () { return ThreadPoolRunning; } static void Start (); @@ -78,6 +111,8 @@ namespace VeraCrypt static volatile size_t DequeuePosition; static volatile size_t EnqueuePosition; static Mutex EnqueueMutex; + // Orders KDF outstanding-count transitions against no-outstanding event updates. + static Mutex KeyDerivationCompletionMutex; static list < shared_ptr > RunningThreads; static volatile bool StopPending; static size_t ThreadCount; diff --git a/src/Volume/Pkcs5Kdf.cpp b/src/Volume/Pkcs5Kdf.cpp index fc16660d..6de57a63 100644 --- a/src/Volume/Pkcs5Kdf.cpp +++ b/src/Volume/Pkcs5Kdf.cpp @@ -30,7 +30,18 @@ namespace VeraCrypt int Pkcs5Kdf::DeriveKey (const BufferPtr &key, const VolumePassword &password, int pim, const ConstBufferPtr &salt) const { - return DeriveKey (key, password, salt, GetIterationCount(pim)); + return DeriveKey (key, password, pim, salt, nullptr); + } + + int Pkcs5Kdf::DeriveKey (const BufferPtr &key, const VolumePassword &password, int pim, const ConstBufferPtr &salt, long volatile *pAbortKeyDerivation) const + { + return DeriveKey (key, password, salt, GetIterationCount(pim), pAbortKeyDerivation); + } + + int Pkcs5Kdf::DeriveKey (const BufferPtr &key, const VolumePassword &password, const ConstBufferPtr &salt, int iterationCount, long volatile *pAbortKeyDerivation) const + { + (void) pAbortKeyDerivation; + return DeriveKey (key, password, salt, iterationCount); } wstring Pkcs5Kdf::GetDerivationFailureMessage (int result) const @@ -88,65 +99,105 @@ namespace VeraCrypt #ifndef WOLFCRYPT_BACKEND int Pkcs5HmacBlake2s_Boot::DeriveKey (const BufferPtr &key, const VolumePassword &password, const ConstBufferPtr &salt, int iterationCount) const + { + return DeriveKey (key, password, salt, iterationCount, nullptr); + } + + int Pkcs5HmacBlake2s_Boot::DeriveKey (const BufferPtr &key, const VolumePassword &password, const ConstBufferPtr &salt, int iterationCount, long volatile *pAbortKeyDerivation) const { ValidateParameters (key, password, salt, iterationCount); - derive_key_blake2s (password.DataPtr(), (int) password.Size(), salt.Get(), (int) salt.Size(), iterationCount, key.Get(), (int) key.Size(), NULL); + derive_key_blake2s (password.DataPtr(), (int) password.Size(), salt.Get(), (int) salt.Size(), iterationCount, key.Get(), (int) key.Size(), pAbortKeyDerivation); return 0; } int Pkcs5HmacBlake2s::DeriveKey (const BufferPtr &key, const VolumePassword &password, const ConstBufferPtr &salt, int iterationCount) const + { + return DeriveKey (key, password, salt, iterationCount, nullptr); + } + + int Pkcs5HmacBlake2s::DeriveKey (const BufferPtr &key, const VolumePassword &password, const ConstBufferPtr &salt, int iterationCount, long volatile *pAbortKeyDerivation) const { ValidateParameters (key, password, salt, iterationCount); - derive_key_blake2s (password.DataPtr(), (int) password.Size(), salt.Get(), (int) salt.Size(), iterationCount, key.Get(), (int) key.Size(), NULL); + derive_key_blake2s (password.DataPtr(), (int) password.Size(), salt.Get(), (int) salt.Size(), iterationCount, key.Get(), (int) key.Size(), pAbortKeyDerivation); return 0; } #endif int Pkcs5HmacSha256_Boot::DeriveKey (const BufferPtr &key, const VolumePassword &password, const ConstBufferPtr &salt, int iterationCount) const + { + return DeriveKey (key, password, salt, iterationCount, nullptr); + } + + int Pkcs5HmacSha256_Boot::DeriveKey (const BufferPtr &key, const VolumePassword &password, const ConstBufferPtr &salt, int iterationCount, long volatile *pAbortKeyDerivation) const { ValidateParameters (key, password, salt, iterationCount); - derive_key_sha256 (password.DataPtr(), (int) password.Size(), salt.Get(), (int) salt.Size(), iterationCount, key.Get(), (int) key.Size(), NULL); + derive_key_sha256 (password.DataPtr(), (int) password.Size(), salt.Get(), (int) salt.Size(), iterationCount, key.Get(), (int) key.Size(), pAbortKeyDerivation); return 0; } int Pkcs5HmacSha256::DeriveKey (const BufferPtr &key, const VolumePassword &password, const ConstBufferPtr &salt, int iterationCount) const + { + return DeriveKey (key, password, salt, iterationCount, nullptr); + } + + int Pkcs5HmacSha256::DeriveKey (const BufferPtr &key, const VolumePassword &password, const ConstBufferPtr &salt, int iterationCount, long volatile *pAbortKeyDerivation) const { ValidateParameters (key, password, salt, iterationCount); - derive_key_sha256 (password.DataPtr(), (int) password.Size(), salt.Get(), (int) salt.Size(), iterationCount, key.Get(), (int) key.Size(), NULL); + derive_key_sha256 (password.DataPtr(), (int) password.Size(), salt.Get(), (int) salt.Size(), iterationCount, key.Get(), (int) key.Size(), pAbortKeyDerivation); return 0; } int Pkcs5HmacSha512::DeriveKey (const BufferPtr &key, const VolumePassword &password, const ConstBufferPtr &salt, int iterationCount) const + { + return DeriveKey (key, password, salt, iterationCount, nullptr); + } + + int Pkcs5HmacSha512::DeriveKey (const BufferPtr &key, const VolumePassword &password, const ConstBufferPtr &salt, int iterationCount, long volatile *pAbortKeyDerivation) const { ValidateParameters (key, password, salt, iterationCount); - derive_key_sha512 (password.DataPtr(), (int) password.Size(), salt.Get(), (int) salt.Size(), iterationCount, key.Get(), (int) key.Size(), NULL); + derive_key_sha512 (password.DataPtr(), (int) password.Size(), salt.Get(), (int) salt.Size(), iterationCount, key.Get(), (int) key.Size(), pAbortKeyDerivation); return 0; } #ifndef WOLFCRYPT_BACKEND int Pkcs5HmacWhirlpool::DeriveKey (const BufferPtr &key, const VolumePassword &password, const ConstBufferPtr &salt, int iterationCount) const + { + return DeriveKey (key, password, salt, iterationCount, nullptr); + } + + int Pkcs5HmacWhirlpool::DeriveKey (const BufferPtr &key, const VolumePassword &password, const ConstBufferPtr &salt, int iterationCount, long volatile *pAbortKeyDerivation) const { ValidateParameters (key, password, salt, iterationCount); - derive_key_whirlpool (password.DataPtr(), (int) password.Size(), salt.Get(), (int) salt.Size(), iterationCount, key.Get(), (int) key.Size(), NULL); + derive_key_whirlpool (password.DataPtr(), (int) password.Size(), salt.Get(), (int) salt.Size(), iterationCount, key.Get(), (int) key.Size(), pAbortKeyDerivation); return 0; } int Pkcs5HmacStreebog::DeriveKey (const BufferPtr &key, const VolumePassword &password, const ConstBufferPtr &salt, int iterationCount) const + { + return DeriveKey (key, password, salt, iterationCount, nullptr); + } + + int Pkcs5HmacStreebog::DeriveKey (const BufferPtr &key, const VolumePassword &password, const ConstBufferPtr &salt, int iterationCount, long volatile *pAbortKeyDerivation) const { ValidateParameters (key, password, salt, iterationCount); - derive_key_streebog (password.DataPtr(), (int) password.Size(), salt.Get(), (int) salt.Size(), iterationCount, key.Get(), (int) key.Size(), NULL); + derive_key_streebog (password.DataPtr(), (int) password.Size(), salt.Get(), (int) salt.Size(), iterationCount, key.Get(), (int) key.Size(), pAbortKeyDerivation); return 0; } #ifndef VC_DCS_DISABLE_ARGON2 int Pkcs5Argon2::DeriveKey (const BufferPtr &key, const VolumePassword &password, int pim, const ConstBufferPtr &salt) const + { + return DeriveKey (key, password, pim, salt, nullptr); + } + + int Pkcs5Argon2::DeriveKey (const BufferPtr &key, const VolumePassword &password, int pim, const ConstBufferPtr &salt, long volatile *pAbortKeyDerivation) const { int iterationCount; int memoryCost; get_argon2_params (pim, &iterationCount, &memoryCost); ValidateParameters (key, password, salt, iterationCount); - return derive_key_argon2 (password.DataPtr(), (int) password.Size(), salt.Get(), (int) salt.Size(), iterationCount, memoryCost, key.Get(), (int) key.Size(), NULL); + return derive_key_argon2 (password.DataPtr(), (int) password.Size(), salt.Get(), (int) salt.Size(), iterationCount, memoryCost, key.Get(), (int) key.Size(), pAbortKeyDerivation); } int Pkcs5Argon2::DeriveKey (const BufferPtr &key, const VolumePassword &password, const ConstBufferPtr &salt, int iterationCount) const @@ -158,6 +209,12 @@ namespace VeraCrypt throw ParameterIncorrect (SRC_POS); } + int Pkcs5Argon2::DeriveKey (const BufferPtr &key, const VolumePassword &password, const ConstBufferPtr &salt, int iterationCount, long volatile *pAbortKeyDerivation) const + { + (void) pAbortKeyDerivation; + return DeriveKey (key, password, salt, iterationCount); + } + wstring Pkcs5Argon2::GetDerivationFailureMessage (int result) const { return L"Argon2 key derivation failed: " + StringConverter::ToWide (argon2_error_message (result)); @@ -173,9 +230,14 @@ namespace VeraCrypt #endif int Pkcs5HmacStreebog_Boot::DeriveKey (const BufferPtr &key, const VolumePassword &password, const ConstBufferPtr &salt, int iterationCount) const + { + return DeriveKey (key, password, salt, iterationCount, nullptr); + } + + int Pkcs5HmacStreebog_Boot::DeriveKey (const BufferPtr &key, const VolumePassword &password, const ConstBufferPtr &salt, int iterationCount, long volatile *pAbortKeyDerivation) const { ValidateParameters (key, password, salt, iterationCount); - derive_key_streebog (password.DataPtr(), (int) password.Size(), salt.Get(), (int) salt.Size(), iterationCount, key.Get(), (int) key.Size(), NULL); + derive_key_streebog (password.DataPtr(), (int) password.Size(), salt.Get(), (int) salt.Size(), iterationCount, key.Get(), (int) key.Size(), pAbortKeyDerivation); return 0; } #endif diff --git a/src/Volume/Pkcs5Kdf.h b/src/Volume/Pkcs5Kdf.h index 30af3753..1e40c607 100644 --- a/src/Volume/Pkcs5Kdf.h +++ b/src/Volume/Pkcs5Kdf.h @@ -28,7 +28,9 @@ namespace VeraCrypt virtual ~Pkcs5Kdf (); virtual int DeriveKey (const BufferPtr &key, const VolumePassword &password, int pim, const ConstBufferPtr &salt) const; + virtual int DeriveKey (const BufferPtr &key, const VolumePassword &password, int pim, const ConstBufferPtr &salt, long volatile *pAbortKeyDerivation) const; virtual int DeriveKey (const BufferPtr &key, const VolumePassword &password, const ConstBufferPtr &salt, int iterationCount) const = 0; + virtual int DeriveKey (const BufferPtr &key, const VolumePassword &password, const ConstBufferPtr &salt, int iterationCount, long volatile *pAbortKeyDerivation) const = 0; static shared_ptr GetAlgorithm (const wstring &name); static shared_ptr GetAlgorithm (const Hash &hash); static Pkcs5KdfList GetAvailableAlgorithms (); @@ -63,6 +65,7 @@ namespace VeraCrypt virtual ~Pkcs5HmacBlake2s_Boot () { } virtual int DeriveKey (const BufferPtr &key, const VolumePassword &password, const ConstBufferPtr &salt, int iterationCount) const; + virtual int DeriveKey (const BufferPtr &key, const VolumePassword &password, const ConstBufferPtr &salt, int iterationCount, long volatile *pAbortKeyDerivation) const; virtual shared_ptr GetHash () const { return shared_ptr (new Blake2s); } virtual int GetDefaultPim () const { return 98; } virtual int GetIterationCount (int pim) const { return pim <= 0 ? 200000 : (pim * 2048); } @@ -81,6 +84,7 @@ namespace VeraCrypt virtual ~Pkcs5HmacBlake2s () { } virtual int DeriveKey (const BufferPtr &key, const VolumePassword &password, const ConstBufferPtr &salt, int iterationCount) const; + virtual int DeriveKey (const BufferPtr &key, const VolumePassword &password, const ConstBufferPtr &salt, int iterationCount, long volatile *pAbortKeyDerivation) const; virtual shared_ptr GetHash () const { return shared_ptr (new Blake2s); } virtual int GetIterationCount (int pim) const { return pim <= 0 ? 500000 : (15000 + (pim * 1000)); } virtual wstring GetName () const { return L"HMAC-BLAKE2s-256"; } @@ -99,6 +103,7 @@ namespace VeraCrypt virtual ~Pkcs5HmacSha256_Boot () { } virtual int DeriveKey (const BufferPtr &key, const VolumePassword &password, const ConstBufferPtr &salt, int iterationCount) const; + virtual int DeriveKey (const BufferPtr &key, const VolumePassword &password, const ConstBufferPtr &salt, int iterationCount, long volatile *pAbortKeyDerivation) const; virtual shared_ptr GetHash () const { return shared_ptr (new Sha256); } virtual int GetDefaultPim () const { return 98; } virtual int GetIterationCount (int pim) const { return pim <= 0 ? 200000 : (pim * 2048); } @@ -117,6 +122,7 @@ namespace VeraCrypt virtual ~Pkcs5HmacSha256 () { } virtual int DeriveKey (const BufferPtr &key, const VolumePassword &password, const ConstBufferPtr &salt, int iterationCount) const; + virtual int DeriveKey (const BufferPtr &key, const VolumePassword &password, const ConstBufferPtr &salt, int iterationCount, long volatile *pAbortKeyDerivation) const; virtual shared_ptr GetHash () const { return shared_ptr (new Sha256); } virtual int GetIterationCount (int pim) const { return pim <= 0 ? 500000 : (15000 + (pim * 1000)); } virtual wstring GetName () const { return L"HMAC-SHA-256"; } @@ -134,6 +140,7 @@ namespace VeraCrypt virtual ~Pkcs5HmacSha512 () { } virtual int DeriveKey (const BufferPtr &key, const VolumePassword &password, const ConstBufferPtr &salt, int iterationCount) const; + virtual int DeriveKey (const BufferPtr &key, const VolumePassword &password, const ConstBufferPtr &salt, int iterationCount, long volatile *pAbortKeyDerivation) const; virtual shared_ptr GetHash () const { return shared_ptr (new Sha512); } virtual int GetIterationCount (int pim) const { return (pim <= 0 ? 500000 : (15000 + (pim * 1000))); } virtual wstring GetName () const { return L"HMAC-SHA-512"; } @@ -151,6 +158,7 @@ namespace VeraCrypt virtual ~Pkcs5HmacWhirlpool () { } virtual int DeriveKey (const BufferPtr &key, const VolumePassword &password, const ConstBufferPtr &salt, int iterationCount) const; + virtual int DeriveKey (const BufferPtr &key, const VolumePassword &password, const ConstBufferPtr &salt, int iterationCount, long volatile *pAbortKeyDerivation) const; virtual shared_ptr GetHash () const { return shared_ptr (new Whirlpool); } virtual int GetIterationCount (int pim) const { return (pim <= 0 ? 500000 : (15000 + (pim * 1000))); } virtual wstring GetName () const { return L"HMAC-Whirlpool"; } @@ -168,6 +176,7 @@ namespace VeraCrypt virtual ~Pkcs5HmacStreebog () { } virtual int DeriveKey (const BufferPtr &key, const VolumePassword &password, const ConstBufferPtr &salt, int iterationCount) const; + virtual int DeriveKey (const BufferPtr &key, const VolumePassword &password, const ConstBufferPtr &salt, int iterationCount, long volatile *pAbortKeyDerivation) const; virtual shared_ptr GetHash () const { return shared_ptr (new Streebog); } virtual int GetIterationCount (int pim) const { return pim <= 0 ? 500000 : (15000 + (pim * 1000)); } virtual wstring GetName () const { return L"HMAC-Streebog"; } @@ -186,7 +195,9 @@ namespace VeraCrypt virtual ~Pkcs5Argon2 () { } virtual int DeriveKey (const BufferPtr &key, const VolumePassword &password, int pim, const ConstBufferPtr &salt) const; + virtual int DeriveKey (const BufferPtr &key, const VolumePassword &password, int pim, const ConstBufferPtr &salt, long volatile *pAbortKeyDerivation) const; virtual int DeriveKey (const BufferPtr &key, const VolumePassword &password, const ConstBufferPtr &salt, int iterationCount) const; + virtual int DeriveKey (const BufferPtr &key, const VolumePassword &password, const ConstBufferPtr &salt, int iterationCount, long volatile *pAbortKeyDerivation) const; virtual wstring GetDerivationFailureMessage (int result) const; virtual shared_ptr GetHash () const { return shared_ptr (new Blake2b); } virtual int GetDefaultPim () const { return 12; } @@ -212,6 +223,7 @@ namespace VeraCrypt virtual ~Pkcs5HmacStreebog_Boot () { } virtual int DeriveKey (const BufferPtr &key, const VolumePassword &password, const ConstBufferPtr &salt, int iterationCount) const; + virtual int DeriveKey (const BufferPtr &key, const VolumePassword &password, const ConstBufferPtr &salt, int iterationCount, long volatile *pAbortKeyDerivation) const; virtual shared_ptr GetHash () const { return shared_ptr (new Streebog); } virtual int GetDefaultPim () const { return 98; } virtual int GetIterationCount (int pim) const { return pim <= 0 ? 200000 : pim * 2048; } diff --git a/src/Volume/VolumeHeader.cpp b/src/Volume/VolumeHeader.cpp index 69d9d0eb..5287f5fd 100644 --- a/src/Volume/VolumeHeader.cpp +++ b/src/Volume/VolumeHeader.cpp @@ -11,18 +11,27 @@ */ #include "Crc32.h" +#include "EncryptionThreadPool.h" #include "EncryptionModeXTS.h" #ifdef WOLFCRYPT_BACKEND #include "EncryptionModeWolfCryptXTS.h" #endif #include "Pkcs5Kdf.h" -#include "Pkcs5Kdf.h" #include "VolumeHeader.h" #include "VolumeException.h" #include "Common/Crypto.h" namespace VeraCrypt { + static void DrainKeyDerivationWorkItems (SyncEvent &noOutstandingWorkItemEvent, size_t enqueuedWorkItemCount, bool &workItemsDrained) + { + if (enqueuedWorkItemCount > 0 && !workItemsDrained) + { + noOutstandingWorkItemEvent.Wait(); + workItemsDrained = true; + } + } + VolumeHeader::VolumeHeader (uint32 size) { Init(); @@ -99,7 +108,76 @@ namespace VeraCrypt throw PasswordEmpty (SRC_POS); ConstBufferPtr salt (encryptedData.GetRange (SaltOffset, SaltSize)); - SecureBuffer header (EncryptedHeaderDataSize); + + if (!kdf && EncryptionThreadPool::IsRunning() && keyDerivationFunctions.size() > 1) + { + typedef EncryptionThreadPool::KeyDerivationWorkItem KeyDerivationWorkItem; + + list < shared_ptr > keyDerivationWorkItems; + SharedVal outstandingWorkItemCount (0); + SyncEvent keyDerivationCompletedEvent; + SyncEvent noOutstandingWorkItemEvent; + long volatile abortKeyDerivation = 0; + size_t enqueuedWorkItemCount = 0; + size_t processedWorkItemCount = 0; + bool workItemsDrained = false; + + try + { + foreach (shared_ptr pkcs5, keyDerivationFunctions) + { + shared_ptr keyDerivationWorkItem (new KeyDerivationWorkItem (pkcs5, GetHeaderKeyDerivationSize (pkcs5))); + keyDerivationWorkItems.push_back (keyDerivationWorkItem); + EncryptionThreadPool::BeginKeyDerivation (*keyDerivationWorkItem, password, pim, salt, keyDerivationCompletedEvent, noOutstandingWorkItemEvent, outstandingWorkItemCount, &abortKeyDerivation); + ++enqueuedWorkItemCount; + } + + while (processedWorkItemCount < keyDerivationWorkItems.size()) + { + bool processed = false; + + foreach (shared_ptr keyDerivationWorkItem, keyDerivationWorkItems) + { + if (!keyDerivationWorkItem->Processed && keyDerivationWorkItem->Completed.Get()) + { + keyDerivationWorkItem->Processed = true; + ++processedWorkItemCount; + processed = true; + + if (keyDerivationWorkItem->ItemException.get()) + { + // KDF exceptions are fatal setup/runtime errors; candidate failures are reported via Result. + abortKeyDerivation = 1; + DrainKeyDerivationWorkItems (noOutstandingWorkItemEvent, enqueuedWorkItemCount, workItemsDrained); + keyDerivationWorkItem->ItemException->Throw(); + } + + if (keyDerivationWorkItem->Result != 0) + continue; + + if (DecryptWithHeaderKey (encryptedData, keyDerivationWorkItem->Kdf, keyDerivationWorkItem->DerivedKey, encryptionAlgorithms, encryptionModes)) + { + abortKeyDerivation = 1; + DrainKeyDerivationWorkItems (noOutstandingWorkItemEvent, enqueuedWorkItemCount, workItemsDrained); + return true; + } + } + } + + if (processedWorkItemCount < keyDerivationWorkItems.size() && !processed) + keyDerivationCompletedEvent.Wait(); + } + } + catch (...) + { + abortKeyDerivation = 1; + DrainKeyDerivationWorkItems (noOutstandingWorkItemEvent, enqueuedWorkItemCount, workItemsDrained); + throw; + } + + DrainKeyDerivationWorkItems (noOutstandingWorkItemEvent, enqueuedWorkItemCount, workItemsDrained); + return false; + } foreach (shared_ptr pkcs5, keyDerivationFunctions) { @@ -116,56 +194,66 @@ namespace VeraCrypt throw ExternalException (SRC_POS, pkcs5->GetDerivationFailureMessage (derivationResult)); } - foreach (shared_ptr mode, encryptionModes) + if (DecryptWithHeaderKey (encryptedData, pkcs5, headerKey, encryptionAlgorithms, encryptionModes)) + return true; + } + + return false; + } + + bool VolumeHeader::DecryptWithHeaderKey (const ConstBufferPtr &encryptedData, shared_ptr pkcs5, const ConstBufferPtr &headerKey, const EncryptionAlgorithmList &encryptionAlgorithms, const EncryptionModeList &encryptionModes) + { + SecureBuffer header (EncryptedHeaderDataSize); + + foreach (shared_ptr mode, encryptionModes) + { + #ifdef WOLFCRYPT_BACKEND + bool xtsMode = typeid (*mode) == typeid (EncryptionModeWolfCryptXTS); + #else + bool xtsMode = typeid (*mode) == typeid (EncryptionModeXTS); + #endif + + if (!xtsMode) { + if (mode->GetKeySize() > headerKey.Size()) + continue; + mode->SetKey (headerKey.GetRange (0, mode->GetKeySize())); + } + + foreach (shared_ptr ea, encryptionAlgorithms) + { + if (!ea->IsModeSupported (mode)) + continue; + + size_t requiredHeaderKeySize = xtsMode ? ea->GetKeySize() * 2 : LegacyEncryptionModeKeyAreaSize + ea->GetKeySize(); + if (requiredHeaderKeySize > headerKey.Size()) + continue; + + if (xtsMode) + { + ea->SetKey (headerKey.GetRange (0, ea->GetKeySize())); #ifdef WOLFCRYPT_BACKEND - bool xtsMode = typeid (*mode) == typeid (EncryptionModeWolfCryptXTS); - #else - bool xtsMode = typeid (*mode) == typeid (EncryptionModeXTS); + ea->SetKeyXTS (headerKey.GetRange (ea->GetKeySize(), ea->GetKeySize())); #endif - if (!xtsMode) + mode = mode->GetNew(); + mode->SetKey (headerKey.GetRange (ea->GetKeySize(), ea->GetKeySize())); + } + else { - if (mode->GetKeySize() > headerKey.Size()) - continue; - mode->SetKey (headerKey.GetRange (0, mode->GetKeySize())); + ea->SetKey (headerKey.GetRange (LegacyEncryptionModeKeyAreaSize, ea->GetKeySize())); } - foreach (shared_ptr ea, encryptionAlgorithms) + ea->SetMode (mode); + + header.CopyFrom (encryptedData.GetRange (EncryptedHeaderDataOffset, EncryptedHeaderDataSize)); + ea->Decrypt (header); + + if (Deserialize (header, ea, mode)) { - if (!ea->IsModeSupported (mode)) - continue; - - size_t requiredHeaderKeySize = xtsMode ? ea->GetKeySize() * 2 : LegacyEncryptionModeKeyAreaSize + ea->GetKeySize(); - if (requiredHeaderKeySize > headerKey.Size()) - continue; - - if (xtsMode) - { - ea->SetKey (headerKey.GetRange (0, ea->GetKeySize())); - #ifdef WOLFCRYPT_BACKEND - ea->SetKeyXTS (headerKey.GetRange (ea->GetKeySize(), ea->GetKeySize())); - #endif - - 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; - } + EA = ea; + Pkcs5 = pkcs5; + return true; } } } diff --git a/src/Volume/VolumeHeader.h b/src/Volume/VolumeHeader.h index b76c37d7..b18f864f 100644 --- a/src/Volume/VolumeHeader.h +++ b/src/Volume/VolumeHeader.h @@ -80,6 +80,7 @@ namespace VeraCrypt bool IsMasterKeyVulnerable () const { return XtsKeyVulnerable; } protected: + bool DecryptWithHeaderKey (const ConstBufferPtr &encryptedData, shared_ptr pkcs5, const ConstBufferPtr &headerKey, const EncryptionAlgorithmList &encryptionAlgorithms, const EncryptionModeList &encryptionModes); bool Deserialize (const ConstBufferPtr &header, shared_ptr &ea, shared_ptr &mode); template T DeserializeEntry (const ConstBufferPtr &header, size_t &offset) const; template T DeserializeEntryAt (const ConstBufferPtr &header, const size_t &offset) const;