VeraCrypt Volume Structure Explained: A Deep Dive into the On-Disk Format

A VeraCrypt volume is a self-contained encrypted container composed of a 64-byte salt, an encrypted header storing master keys and volume parameters, optional backup headers, and the encrypted data area starting at sector 2048.

Understanding the VeraCrypt volume structure is essential for developers auditing the encryption implementation or building compatible tools. The layout is defined in the veracrypt/VeraCrypt repository, specifically within src/Volume/VolumeHeader.h and implemented through the VolumeHeader class. This binary format ensures data confidentiality while supporting advanced features like plausible deniability through hidden volumes.

On-Disk Layout and Header Organization

The physical structure of a VeraCrypt volume follows a strict sequential layout. Each section serves a specific cryptographic or functional purpose, with offsets and sizes defined as constants in the source code.

Salt and Encrypted Header Data

The volume begins with 64 bytes of random salt stored at offset 0 (defined by SaltOffset and SaltSize in src/Volume/VolumeHeader.h). This salt acts as the initialization input to the PBKDF2/KDF when deriving the header key from the user password.

Immediately following the salt, at EncryptedHeaderDataOffset (64 bytes), resides the Encrypted Header Data. This block occupies EncryptedHeaderDataSize bytes and stores critical volume parameters including the master encryption key, encryption algorithm identifiers, mode of operation, key size, volume type flags, timestamps, and sector size. This entire block is encrypted using the header key derived from the user's password and optional PIM (Personal Iterations Multiplier).

Header Key Derivation Area

Following the encrypted header data is the Header Key Derivation Area, with a variable length determined by GetHeaderKeyDerivationSize(). This section stores the KDF parameters—such as iteration counts and memory costs—required to recompute the header key during volume mounting. The derivation uses implementations like Pkcs5HmacSha256 as specified in the Pkcs5Kdf interface.

Backup Headers and Hidden Volumes

VeraCrypt implements resilience through backup headers. For normal volumes, a complete copy of the header (salt + encrypted data) is placed at the end of the volume. For hidden volumes, the backup header resides at the beginning of the hidden volume's data area.

The hidden volume structure enables plausible deniability. When present, a second independent set of header fields and encrypted data occupies free space within the outer volume. The hidden volume header is located at HiddenVolumeDataStart, with its encrypted data area following immediately. This inner volume is mathematically indistinguishable from random data, protecting against coercion.

Volume Header Implementation in Code

The VolumeHeader class in src/Volume/VolumeHeader.cpp manages the serialization and deserialization of these structures. The constructor VolumeHeader(uint32 HeaderSize) initializes the header size—512 bytes for normal volumes or 256 bytes for hidden volumes.

Key metadata fields include:

  • Sector Size: Normally 512 bytes, stored in the SectorSize field and dictating data area alignment
  • Flags: Bitmask options including cascade encryption, hidden-volume protection, and XTS key-vulnerability mitigation flags
  • Versioning: HeaderVersion and RequiredMinProgramVersion fields ensure backward compatibility and security policy enforcement

The VolumeHeader::Serialize and VolumeHeader::Deserialize methods handle the direct binary read/write operations to disk, while VolumeHeader::Decrypt and VolumeHeader::EncryptNew manage the cryptographic protection of the header contents.

Creating and Mounting VeraCrypt Volumes

The following code illustrates the programmatic creation and mounting of volumes using the internal API.

Creating a new volume header:

// Creating a new VeraCrypt volume header (simplified)
VolumeHeader header(HEADER_SIZE);          // HEADER_SIZE = 512 for normal volumes
VolumeHeaderCreationOptions opts;
opts.DataKey      = masterKey;              // Random master key for data encryption
opts.EA           = std::make_shared<AES>(); 
opts.Kdf          = std::make_shared<Pkcs5HmacSha256>();
opts.HeaderKey   = headerKey;               // Derived from password + PIM
opts.Salt         = randomSalt(VolumeHeader::GetSaltSize());
opts.SectorSize   = 512;
opts.VolumeDataSize = userRequestedSize;
opts.Type         = VolumeType::Normal;

header.Create(buffer, opts);                // `buffer` receives the raw header bytes

Mounting an existing volume:

// Mounting (reading) an existing volume header
VolumeHeader header(HEADER_SIZE);
bool ok = header.Decrypt(
    encryptedHeader,                     // raw header read from disk
    userPassword,                       // password entered by the user
    pim,                                 // optional PIM
    std::make_shared<Pkcs5HmacSha256>(),// KDF to try first
    allKdfs,                            // list of supported KDFs
    allEas,                             // list of supported encryption algorithms
    allModes);                          // list of supported encryption modes

if (ok) {
    // Header successfully decrypted – we can now access the master key,
    // sector size, encrypted‑area offsets, etc.
    uint64 dataStart = header.GetEncryptedAreaStart();
    uint64 dataLen   = header.GetEncryptedAreaLength();
    // ... continue mounting the volume ...
}

The EncryptedAreaStart field typically points to sector 2048 (1 MiB offset), marking where user data actually begins, while EncryptedAreaLength defines the volume's capacity.

Key Source Files

The VeraCrypt volume structure is implemented across these critical files:

  • src/Volume/VolumeHeader.h: Defines the VolumeHeader class layout and constants like SaltOffset, EncryptedHeaderDataOffset, and SaltSize
  • src/Volume/VolumeHeader.cpp: Implements header creation, encryption via EncryptNew, decryption via Decrypt, and serialization logic
  • src/Volume/VolumeLayout.cpp: Calculates offsets including EncryptedAreaStart and determines layouts for normal versus hidden volumes
  • src/Common/Volumes.c: Low-level C specifications defining the fundamental on-disk format referenced by the C++ implementation

Summary

  • VeraCrypt volumes begin with a 64-byte salt at offset 0, followed by encrypted header data containing the master key and volume parameters.
  • The default header size is 512 bytes for normal volumes and 256 bytes for hidden volumes, with the encrypted data area typically starting at the 1 MiB mark (sector 2048).
  • Backup headers provide corruption resilience, with hidden volumes embedded within outer volume free space for plausible deniability.
  • The VolumeHeader class in src/Volume/VolumeHeader.cpp manages all serialization, encryption, and decryption operations through methods like Serialize, Deserialize, and Decrypt.
  • Volume metadata includes sector size, encryption algorithm identifiers, KDF parameters, and versioning information to ensure compatibility and security.

Frequently Asked Questions

Where is the VeraCrypt volume header located on disk?

The primary volume header is located at the very beginning of the container file (offset 0), starting with a 64-byte salt followed immediately by the encrypted header data. A backup copy of the entire header is stored at the end of the volume for normal volumes, or at the beginning of the hidden volume data area for hidden volumes, providing redundancy against corruption.

How does VeraCrypt derive the key used to encrypt the volume header?

VeraCrypt derives the header key using a Password-Based Key Derivation Function (PBKDF) such as Pkcs5HmacSha256, implemented in the Pkcs5Kdf class. The derivation combines the user's password with the 64-byte salt and an optional PIM (Personal Iterations Multiplier) to generate the key that decrypts the master key stored within the header.

What is the difference between a normal and hidden VeraCrypt volume structure?

A normal volume contains one header (plus backup) at the start of the file with the encrypted data area following at EncryptedAreaStart (typically 1 MiB). A hidden volume embeds a secondary, independent header and encrypted data area within the free space of an outer normal volume, making it indistinguishable from random data and providing plausible deniability.

How large is the VeraCrypt volume header?

The header size is configurable during volume creation but defaults to 512 bytes for normal volumes and 256 bytes for hidden volumes, as defined by the HeaderSize parameter passed to the VolumeHeader constructor in src/Volume/VolumeHeader.h. This size includes the salt, encrypted data block, and key derivation parameters.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →