From 9cfce29514b38255b3d9ee46379cf329636440ac Mon Sep 17 00:00:00 2001 From: damianrickard <154095072+damianrickard@users.noreply.github.com> Date: Wed, 14 Oct 2026 05:42:51 -0400 Subject: [PATCH] Use direct burn in BufferPtr::Erase and guard token keyfile data (#1816) BufferPtr::Erase() previously delegated to Zero()/memset even though its current callers use it to wipe sensitive data. Expand burn() directly in the inline Erase implementation, matching VeraCrypt's established erasure design without adding an out-of-line wrapper. Install vector-referencing cleanup guards before token keyfile reads and fetches in the four GUI and text-mode import/export paths. This ensures partially populated data is wiped when an operation throws and avoids retaining a stale BufferPtr if the vector reallocates. Reject empty token exports before accessing vector::front(). Memory::Zero(), Buffer::Erase(), and the existing password guards remain unchanged. Co-authored-by: Damian Rickard --- src/Main/Forms/SecurityTokenKeyfilesDialog.cpp | 15 +++++++++++++-- src/Main/TextUserInterface.cpp | 15 +++++++++++++-- src/Platform/Buffer.h | 6 +++++- 3 files changed, 31 insertions(+), 5 deletions(-) diff --git a/src/Main/Forms/SecurityTokenKeyfilesDialog.cpp b/src/Main/Forms/SecurityTokenKeyfilesDialog.cpp index 84c30d65..c3bfd308 100644 --- a/src/Main/Forms/SecurityTokenKeyfilesDialog.cpp +++ b/src/Main/Forms/SecurityTokenKeyfilesDialog.cpp @@ -104,10 +104,17 @@ namespace VeraCrypt wxBusyCursor busy; vector keyfileData; + finally_do_arg ( + vector *, &keyfileData, + { if (!finally_arg->empty()) burn (&finally_arg->front(), finally_arg->size()); } + ); + keyfile->GetKeyfileData (keyfileData); + if (keyfileData.empty()) + throw InsufficientData (SRC_POS); + BufferPtr keyfileDataBuf (&keyfileData.front(), keyfileData.size()); - finally_do_arg (BufferPtr, keyfileDataBuf, { finally_arg.Erase(); }); File keyfile; keyfile.Open (*files.front(), File::CreateWrite); @@ -142,10 +149,14 @@ namespace VeraCrypt if (keyfile.Length() > 0) { vector keyfileData (keyfile.Length()); + finally_do_arg ( + vector *, &keyfileData, + { if (!finally_arg->empty()) burn (&finally_arg->front(), finally_arg->size()); } + ); + BufferPtr keyfileDataBuf (&keyfileData.front(), keyfileData.size()); keyfile.ReadCompleteBuffer (keyfileDataBuf); - finally_do_arg (BufferPtr, keyfileDataBuf, { finally_arg.Erase(); }); NewSecurityTokenKeyfileDialog newKeyfileDialog (this, keyfilePath.ToBaseName()); diff --git a/src/Main/TextUserInterface.cpp b/src/Main/TextUserInterface.cpp index e6da7215..62eeda36 100644 --- a/src/Main/TextUserInterface.cpp +++ b/src/Main/TextUserInterface.cpp @@ -1286,10 +1286,17 @@ namespace VeraCrypt shared_ptr tokenKeyfile = Token::getTokenKeyfile(keyfilePath); vector keyfileData; + finally_do_arg ( + vector *, &keyfileData, + { if (!finally_arg->empty()) burn (&finally_arg->front(), finally_arg->size()); } + ); + tokenKeyfile->GetKeyfileData (keyfileData); + if (keyfileData.empty()) + throw InsufficientData (SRC_POS); + BufferPtr keyfileDataBuf (&keyfileData.front(), keyfileData.size()); - finally_do_arg (BufferPtr, keyfileDataBuf, { finally_arg.Erase(); }); FilePath exportFilePath = AskFilePath(); @@ -1353,10 +1360,14 @@ namespace VeraCrypt if (keyfile.Length() > 0) { vector keyfileData (keyfile.Length()); + finally_do_arg ( + vector *, &keyfileData, + { if (!finally_arg->empty()) burn (&finally_arg->front(), finally_arg->size()); } + ); + BufferPtr keyfileDataBuf (&keyfileData.front(), keyfileData.size()); keyfile.ReadCompleteBuffer (keyfileDataBuf); - finally_do_arg (BufferPtr, keyfileDataBuf, { finally_arg.Erase(); }); SecurityToken::CreateKeyfile (slotId, keyfileData, string (FilePath (keyfilePath).ToBaseName())); } diff --git a/src/Platform/Buffer.h b/src/Platform/Buffer.h index 5e5e9895..5d14d6a6 100644 --- a/src/Platform/Buffer.h +++ b/src/Platform/Buffer.h @@ -53,7 +53,11 @@ namespace VeraCrypt operator uint8 * () const { return DataPtr; } void CopyFrom (const ConstBufferPtr &bufferPtr) const; - void Erase () const { Zero(); } + void Erase () const + { + if (DataSize > 0) + burn (DataPtr, DataSize); + } uint8 *Get () const { return DataPtr; } BufferPtr GetRange (size_t offset, size_t size) const; void Set (uint8 *data, size_t size) { DataPtr = data; DataSize = size; }