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.
This commit is contained in:
Mounir IDRASSI
2026-05-25 15:43:00 +09:00
parent 66ddd29c91
commit a173a11cfe
9 changed files with 357 additions and 57 deletions

View File

@@ -29,6 +29,7 @@ namespace VeraCrypt
SyncEvent ();
~SyncEvent ();
void Reset ();
void Signal ();
void Wait ();

View File

@@ -41,6 +41,14 @@ namespace VeraCrypt
Initialized = false;
}
void SyncEvent::Reset ()
{
assert (Initialized);
ScopeLock lock (EventMutex);
Signaled = false;
}
void SyncEvent::Signal ()
{
assert (Initialized);

View File

@@ -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 <Hash> GetHash () const { return shared_ptr <Hash> (new Blake2b); }
virtual int GetIterationCount (int pim) const { return 1; }
virtual wstring GetName () const { return L"Argon2"; }

View File

@@ -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 <Pkcs5Kdf> 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 <size_t> &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;

View File

@@ -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 <size_t> *OutstandingWorkItemCount;
const VolumePassword *Password;
int Pim;
const uint8 *Salt;
size_t SaltSize;
KeyDerivationWorkItem *WorkItem;
} KeyDerivation;
};
};
struct KeyDerivationWorkItem
{
KeyDerivationWorkItem (shared_ptr <Pkcs5Kdf> kdf, size_t derivedKeySize);
~KeyDerivationWorkItem ();
SharedVal <bool> Completed;
SecureBuffer DerivedKey;
unique_ptr <Exception> ItemException;
shared_ptr <Pkcs5Kdf> 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 <size_t> &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 <Thread> > RunningThreads;
static volatile bool StopPending;
static size_t ThreadCount;

View File

@@ -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

View File

@@ -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 <Pkcs5Kdf> GetAlgorithm (const wstring &name);
static shared_ptr <Pkcs5Kdf> 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 <Hash> GetHash () const { return shared_ptr <Hash> (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 <Hash> GetHash () const { return shared_ptr <Hash> (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 <Hash> GetHash () const { return shared_ptr <Hash> (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 <Hash> GetHash () const { return shared_ptr <Hash> (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 <Hash> GetHash () const { return shared_ptr <Hash> (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 <Hash> GetHash () const { return shared_ptr <Hash> (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 <Hash> GetHash () const { return shared_ptr <Hash> (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 <Hash> GetHash () const { return shared_ptr <Hash> (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 <Hash> GetHash () const { return shared_ptr <Hash> (new Streebog); }
virtual int GetDefaultPim () const { return 98; }
virtual int GetIterationCount (int pim) const { return pim <= 0 ? 200000 : pim * 2048; }

View File

@@ -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 <KeyDerivationWorkItem> > keyDerivationWorkItems;
SharedVal <size_t> 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 <Pkcs5Kdf> pkcs5, keyDerivationFunctions)
{
shared_ptr <KeyDerivationWorkItem> 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> 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 <Pkcs5Kdf> pkcs5, keyDerivationFunctions)
{
@@ -116,56 +194,66 @@ namespace VeraCrypt
throw ExternalException (SRC_POS, pkcs5->GetDerivationFailureMessage (derivationResult));
}
foreach (shared_ptr <EncryptionMode> mode, encryptionModes)
if (DecryptWithHeaderKey (encryptedData, pkcs5, headerKey, encryptionAlgorithms, encryptionModes))
return true;
}
return false;
}
bool VolumeHeader::DecryptWithHeaderKey (const ConstBufferPtr &encryptedData, shared_ptr <Pkcs5Kdf> pkcs5, const ConstBufferPtr &headerKey, const EncryptionAlgorithmList &encryptionAlgorithms, const EncryptionModeList &encryptionModes)
{
SecureBuffer header (EncryptedHeaderDataSize);
foreach (shared_ptr <EncryptionMode> 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 <EncryptionAlgorithm> 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 <EncryptionAlgorithm> 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;
}
}
}

View File

@@ -80,6 +80,7 @@ namespace VeraCrypt
bool IsMasterKeyVulnerable () const { return XtsKeyVulnerable; }
protected:
bool DecryptWithHeaderKey (const ConstBufferPtr &encryptedData, shared_ptr <Pkcs5Kdf> pkcs5, const ConstBufferPtr &headerKey, const EncryptionAlgorithmList &encryptionAlgorithms, const EncryptionModeList &encryptionModes);
bool Deserialize (const ConstBufferPtr &header, shared_ptr <EncryptionAlgorithm> &ea, shared_ptr <EncryptionMode> &mode);
template <typename T> T DeserializeEntry (const ConstBufferPtr &header, size_t &offset) const;
template <typename T> T DeserializeEntryAt (const ConstBufferPtr &header, const size_t &offset) const;