# How VeraCrypt's Encryption Algorithm Works: XTS Mode and Cascaded Ciphers Explained

> Discover how VeraCrypt encrypts data using XTS mode and cascaded ciphers. Understand its modular architecture for secure disk encryption with AES, Serpent, and Twofish.

- Repository: [VeraCrypt/VeraCrypt](https://github.com/veracrypt/VeraCrypt)
- Tags: deep-dive
- Published: 2026-06-30

---

**VeraCrypt encrypts data at the sector level using a modular architecture that separates block ciphers (AES, Serpent, Twofish) from encryption modes, implementing XTS mode exclusively for disk encryption with support for both single-cipher and cascaded algorithms.**

VeraCrypt's encryption algorithm is implemented in the `src/Volume` directory of the veracrypt/VeraCrypt repository. The design follows a composable pattern that allows combining multiple block ciphers while standardizing on the XTS mode for all on-disk encryption operations.

## Modular Architecture: Ciphers and Modes

VeraCrypt separates **cipher primitives** from **encryption modes** through three core abstractions defined in [`src/Volume/EncryptionAlgorithm.cpp`](https://github.com/veracrypt/VeraCrypt/blob/main/src/Volume/EncryptionAlgorithm.cpp), [`src/Volume/Cipher.cpp`](https://github.com/veracrypt/VeraCrypt/blob/main/src/Volume/Cipher.cpp), and [`src/Volume/EncryptionModeXTS.cpp`](https://github.com/veracrypt/VeraCrypt/blob/main/src/Volume/EncryptionModeXTS.cpp).

### EncryptionAlgorithm Class

The `EncryptionAlgorithm` class acts as a container that manages one or more `Cipher` objects and a single `EncryptionMode`. It calculates the total key size by summing individual cipher key requirements and builds human-readable algorithm names. In `EncryptionAlgorithm::GetAvailableAlgorithms()`, VeraCrypt registers supported configurations:

```cpp
EncryptionAlgorithmList l;
l.push_back (shared_ptr<EncryptionAlgorithm>(new AES()));
l.push_back (shared_ptr<EncryptionAlgorithm>(new Serpent()));
l.push_back (shared_ptr<EncryptionAlgorithm>(new Twofish()));
l.push_back (shared_ptr<EncryptionAlgorithm>(new Camellia()));
l.push_back (shared_ptr<EncryptionAlgorithm>(new Kuznyechik()));
l.push_back (shared_ptr<EncryptionAlgorithm>(new AESTwofish()));
l.push_back (shared_ptr<EncryptionAlgorithm>(new AESTwofishSerpent()));

```

### Cipher Implementations

Individual ciphers like `CipherAES`, `CipherSerpent`, and `CipherTwofish` inherit from the base `Cipher` class in [`src/Volume/Cipher.cpp`](https://github.com/veracrypt/VeraCrypt/blob/main/src/Volume/Cipher.cpp). Each implements `Encrypt()`, `Decrypt()`, and hardware-accelerated variants. The base class handles runtime detection of AES-NI support via `HasAESNI()`, routing operations to CPU-intrinsic implementations when available.

### EncryptionModeXTS

VeraCrypt exclusively uses **XTS mode** (XEX-based tweaked-codebook mode with ciphertext stealing) for volume encryption. The `EncryptionModeXTS` class in [`src/Volume/EncryptionModeXTS.cpp`](https://github.com/veracrypt/VeraCrypt/blob/main/src/Volume/EncryptionModeXTS.cpp) manages per-sector encryption by handling sector numbers as tweaks and coordinating with underlying ciphers.

## Algorithm Composition and Key Distribution

VeraCrypt supports both **single-cipher** algorithms (e.g., AES) and **cascaded** algorithms (e.g., AES-Twofish-Serpent). When constructing a cascaded algorithm, the constructor populates the `Ciphers` vector with multiple cipher instances:

```cpp
// AESTwofish constructor from EncryptionAlgorithm.cpp
Ciphers.push_back (shared_ptr<Cipher>(new CipherTwofish()));
Ciphers.push_back (shared_ptr<Cipher>(new CipherAES()));
SupportedModes.push_back (shared_ptr<EncryptionMode>(new EncryptionModeXTS()));

```

The **total key size** equals the sum of all cipher key sizes. In `EncryptionAlgorithm::SetKey()`, VeraCrypt segments the master key across ciphers using `GetRange()`:

```cpp
size_t keyOffset = 0;
foreach_ref (Cipher &c, Ciphers)
{
    c.SetKey (key.GetRange(keyOffset, c.GetKeySize()));
    keyOffset += c.GetKeySize();
}

```

For AES-Twofish-Serpent with 256-bit keys, this requires 96 bytes of key material (32 bytes × 3 ciphers).

## XTS Mode Implementation Details

XTS mode operates on **data units** (typically 512-byte sectors) using **two distinct keys**:

- **Data key**: Encrypts the actual plaintext via the primary cipher
- **Tweak key**: Encrypts the sector number to generate a whitening value

In `EncryptionModeXTS::EncryptBufferXTS()`, the implementation performs:

1. Derives the tweak from the sector number (`startDataUnitNo`)
2. Encrypts the tweak with the secondary cipher to produce the whitening value
3. Iterates through each block, XORing plaintext with the whitening value, encrypting with the primary cipher, then XORing back
4. Applies **ciphertext stealing** for final partial blocks when sector size isn't a multiple of the block size

The high-level `EncryptionAlgorithm::Encrypt()` method delegates to the mode:

```cpp
void EncryptionAlgorithm::Encrypt (uint8 *data, uint64 length) const
{
    if_debug (ValidateState());
    Mode->Encrypt (data, length);          // XTS mode drives the cipher
}

```

## Hardware Acceleration

VeraCrypt detects AES-NI support at runtime in [`src/Volume/Cipher.cpp`](https://github.com/veracrypt/VeraCrypt/blob/main/src/Volume/Cipher.cpp):

```cpp
#ifdef TC_AES_HW_CPU
    state = HasAESNI() ? true : false;
#endif

```

When available, `CipherAES` routes encryption operations to hardware-accelerated implementations, significantly improving throughput for large volumes.

## End-to-End Encryption Flow

The complete encryption path for a VeraCrypt volume follows these steps:

1. **Algorithm Selection**: User selects an algorithm (e.g., "AES-Twofish"), instantiating the corresponding `EncryptionAlgorithm` object
2. **Key Derivation**: User password and/or keyfiles are processed through PBKDF2 (implemented in [`src/Volume/Pkcs5Kdf.cpp`](https://github.com/veracrypt/VeraCrypt/blob/main/src/Volume/Pkcs5Kdf.cpp)) to generate the master key
3. **Key Distribution**: `EncryptionAlgorithm::SetKey()` splits the master key across the cipher chain
4. **Mode Attachment**: `SetMode()` attaches an `EncryptionModeXTS` instance
5. **Sector Processing**: For each read/write operation, `EncryptSectors()` or `DecryptSectors()` invokes XTS mode, which calls the underlying `CipherAES` or other ciphers to transform data
6. **Header Storage**: Volume metadata including the selected algorithm and encrypted keys are stored via [`src/Volume/VolumeHeader.cpp`](https://github.com/veracrypt/VeraCrypt/blob/main/src/Volume/VolumeHeader.cpp)

## Practical Code Examples

### Single-Cipher Encryption (AES-XTS)

```cpp
#include "EncryptionAlgorithm.h"
#include "Cipher.h"

int main ()
{
    // Initialize AES algorithm
    VeraCrypt::shared_ptr<VeraCrypt::EncryptionAlgorithm> algo (new VeraCrypt::AES());
    
    // Prepare 256-bit key (two 128-bit keys for XTS)
    uint8 key[32];
    // ... populate key from cryptographically secure source ...
    
    // Install key and encrypt sector
    algo->SetKey (VeraCrypt::ConstBufferPtr (key, sizeof(key)));
    
    uint8 sector[512] = { /* plaintext data */ };
    algo->EncryptSectors (sector, 0, 1, 512);   // sector 0, count 1, size 512
    
    // Decrypt verification
    algo->DecryptSectors (sector, 0, 1, 512);
}

```

### Cascaded Algorithm (AES-Twofish-Serpent)

```cpp
// Initialize triple-cascade algorithm
VeraCrypt::shared_ptr<VeraCrypt::EncryptionAlgorithm> algo 
    (new VeraCrypt::AESTwofishSerpent());

// Total key size: 256 + 256 + 256 = 768 bits (96 bytes)
uint8 key[96];   
// ... fill with derived key material from PBKDF2 ...

algo->SetKey (VeraCrypt::ConstBufferPtr (key, sizeof(key)));

// Encrypt 4KB (8 sectors)
uint8 data[4096];
algo->Encrypt (data, sizeof(data));

```

## Summary

- **Modular Design**: VeraCrypt separates ciphers from modes through `EncryptionAlgorithm`, `Cipher`, and `EncryptionModeXTS` classes in `src/Volume/`
- **XTS Exclusive**: Only XTS mode is supported for disk encryption, using dual keys (data and tweak) with per-sector whitening
- **Cascading Support**: Algorithms can chain multiple ciphers (e.g., AES-Twofish-Serpent), with keys split proportionally across the cipher chain via `SetKey()`
- **Hardware Acceleration**: Automatic AES-NI detection in [`Cipher.cpp`](https://github.com/veracrypt/VeraCrypt/blob/main/Cipher.cpp) routes to optimized CPU intrinsics when available
- **Sector-Level Operations**: All encryption happens at the sector level (typically 512 bytes) through `EncryptSectors()` and `DecryptSectors()`

## Frequently Asked Questions

### What encryption algorithm does VeraCrypt use for disk encryption?

VeraCrypt uses the **XTS mode** exclusively for on-disk encryption, combined with block ciphers such as AES, Serpent, Twofish, Camellia, or Kuznyechik. XTS treats each disk sector as an independent data unit encrypted with a tweak derived from the sector number, preventing patterns from emerging across identical plaintext sectors.

### How does VeraCrypt handle multiple ciphers in a cascade?

When using cascaded algorithms like AES-Twofish-Serpent, VeraCrypt initializes multiple `Cipher` objects in the `Ciphers` vector within the `EncryptionAlgorithm` constructor. The master key is divided sequentially across ciphers in `SetKey()`, with each cipher receiving its required key size (e.g., 32 bytes for AES-256) from the appropriate byte range of the master key.

### Why does VeraCrypt use XTS mode instead of CBC or other modes?

VeraCrypt implements XTS mode because it provides **tweakable encryption** that doesn't require an initialization vector (IV) stored on disk. By deriving the tweak from the sector number, XTS ensures that identical plaintext blocks in different sectors produce different ciphertexts, while remaining deterministic for decryption without additional metadata storage.

### Does VeraCrypt support hardware acceleration for encryption?

Yes. VeraCrypt detects AES-NI (Advanced Encryption Standard New Instructions) support at runtime via `HasAESNI()` in [`src/Volume/Cipher.cpp`](https://github.com/veracrypt/VeraCrypt/blob/main/src/Volume/Cipher.cpp). When available, the `CipherAES` class routes encryption operations to hardware-accelerated implementations, significantly improving throughput while maintaining compatibility with software fallback for systems without AES-NI support.