mirror of
https://github.com/veracrypt/VeraCrypt.git
synced 2026-05-30 00:10:22 +00:00
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:
@@ -29,6 +29,7 @@ namespace VeraCrypt
|
||||
SyncEvent ();
|
||||
~SyncEvent ();
|
||||
|
||||
void Reset ();
|
||||
void Signal ();
|
||||
void Wait ();
|
||||
|
||||
|
||||
@@ -41,6 +41,14 @@ namespace VeraCrypt
|
||||
Initialized = false;
|
||||
}
|
||||
|
||||
void SyncEvent::Reset ()
|
||||
{
|
||||
assert (Initialized);
|
||||
|
||||
ScopeLock lock (EventMutex);
|
||||
Signaled = false;
|
||||
}
|
||||
|
||||
void SyncEvent::Signal ()
|
||||
{
|
||||
assert (Initialized);
|
||||
|
||||
@@ -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"; }
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user