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 <damian@rickard.us>
This commit is contained in:
damianrickard
2026-10-14 11:42:51 +02:00
committed by GitHub
co-authored by Damian Rickard
parent fe33e4474e
commit 9cfce29514
3 changed files with 31 additions and 5 deletions
+13 -2
View File
@@ -104,10 +104,17 @@ namespace VeraCrypt
wxBusyCursor busy;
vector <uint8> keyfileData;
finally_do_arg (
vector <uint8> *, &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 <uint8> keyfileData (keyfile.Length());
finally_do_arg (
vector <uint8> *, &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());
+13 -2
View File
@@ -1286,10 +1286,17 @@ namespace VeraCrypt
shared_ptr<TokenKeyfile> tokenKeyfile = Token::getTokenKeyfile(keyfilePath);
vector <uint8> keyfileData;
finally_do_arg (
vector <uint8> *, &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 <uint8> keyfileData (keyfile.Length());
finally_do_arg (
vector <uint8> *, &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()));
}
+5 -1
View File
@@ -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; }