# Turso vs SQLite Encryption at Rest: Architecture, Cipher Suites, and Implementation Differences

> Explore Turso vs SQLite encryption at rest. Discover Turso's native AEGIS ciphers versus SQLCipher's AES-256-CBC for robust data protection.

- Repository: [Turso Database/turso](https://github.com/tursodatabase/turso)
- Tags: deep-dive
- Published: 2026-06-22

---

**Turso implements native encryption-at-rest using modern AEGIS ciphers directly in its core storage layer, while SQLite relies on third-party extensions like SQLCipher that wrap the page-cache I/O with AES-256-CBC.**

Turso is a modern, SQLite-compatible database engine that diverges significantly from standard SQLite when it comes to protecting data at rest. Unlike SQLite, which requires external extensions for encryption, Turso builds encryption directly into its storage architecture. This article examines the technical differences between Turso's native encryption and SQLite's extension-based approaches, referencing specific implementation details from the `tursodatabase/turso` repository.

## Architectural Differences: Native Integration vs Extension Layer

Encryption in Turso is not an add-on feature but a fundamental component of the storage engine.

### Turso's Core Storage Layer Encryption

In Turso, encryption logic resides in [`core/storage/encryption.rs`](https://github.com/tursodatabase/turso/blob/main/core/storage/encryption.rs), where the `CipherMode` enum defines supported algorithms including **AEGIS-256**, **AEGIS-256X2/X4**, **AEGIS-128L**, and **AEGIS-128X2/X4**. The encryption is applied per-page before writing to the WAL or database file, as implemented in [`core/storage/pager.rs`](https://github.com/tursodatabase/turso/blob/main/core/storage/pager.rs). This tight integration means the pager wraps every read and write operation with `EncryptionContext::encrypt_page` and `decrypt_page` methods.

The `EncryptionKey` enum in [`core/storage/encryption.rs`](https://github.com/tursodatabase/turso/blob/main/core/storage/encryption.rs) represents keys as either `Key256` or `Key128` variants, derived from hex strings via `EncryptionKey::from_hex_string`. When opening a database, [`core/connection.rs`](https://github.com/tursodatabase/turso/blob/main/core/connection.rs) validates the file header magic bytes against the supplied key before allowing access.

### SQLite's Extension-Based Approach

Standard SQLite does not ship with built-in encryption. Third-party solutions like **SQLCipher** or the commercial **SQLite Encryption Extension (SEE)** implement encryption by intercepting page-cache I/O operations. These extensions act as Virtual File System (VFS) wrappers or page-cache shims that encrypt/decrypt pages using AES-256-CBC. The key is typically supplied via `PRAGMA key = 'hexstring'` after connection establishment, and the cipher is usually fixed at compile time rather than selectable at runtime.

## Cipher Suites and Performance Characteristics

Turso leverages modern authenticated encryption designed for high-throughput scenarios.

**Turso's AEGIS implementation** utilizes SIMD-accelerated Rust crates (`aegis`) optimized for low-latency per-page encryption. The `CipherMode` enum allows selection of different AEGIS variants per database, with the chosen cipher encoded in the file header and validated during `EncryptionContext::new` in [`core/storage/pager.rs`](https://github.com/tursodatabase/turso/blob/main/core/storage/pager.rs).

**SQLCipher's AES-256-CBC** relies on OpenSSL or custom implementations that vary by platform. While secure, AES-CBC lacks the authentication tags and performance optimizations of AEGIS, and typically offers only a single cipher choice per database build.

## Key Management and Configuration

The two systems handle key derivation and storage differently.

**Turso** requires keys to be configured before database initialization using `DatabaseOpts::new().with_encryption(true)`. The key is stored in the `Database` struct as `encryption_key: Option<EncryptionKey>` (defined in [`core/lib.rs`](https://github.com/tursodatabase/turso/blob/main/core/lib.rs)) and passed to the pager via `EncryptionContext`. Runtime validation occurs in [`tests/integration/query_processing/encryption.rs`](https://github.com/tursodatabase/turso/blob/main/tests/integration/query_processing/encryption.rs), which confirms that cached databases reject incorrect keys even when the file is already in memory.

**SQLite with SQLCipher** accepts keys via `PRAGMA key` after opening the connection. As noted in the source analysis, Turso explicitly rejects late configuration attempts: the test suite verifies that calling `PRAGMA journal_mode='mvcc'` after encryption setup produces the error "configure encryption before PRAGMA journal_mode='mvcc'".

## MVCC Integration and Consistent Snapshotting

Turso's encryption design accounts for its Multi-Version Concurrency Control (MVCC) engine.

When a page is copied to create a new version, the same `EncryptionContext` and `EncryptionKey` are applied to ensure consistency across snapshots. The [`core/mvcc/persistent_storage/logical_log.rs`](https://github.com/tursodatabase/turso/blob/main/core/mvcc/persistent_storage/logical_log.rs) file reuses the encryption key for each logical log entry, guaranteeing that historical snapshots remain readable with the original key.

Standard SQLite lacks native MVCC, so SQLCipher and similar extensions do not need to coordinate with versioned pages or maintain encryption consistency across snapshot isolation levels.

## VACUUM Behavior and Data Migration

The two systems handle encrypted exports differently.

**Turso's `VACUUM INTO`** creates an unencrypted destination file by default. The implementation in [`core/vdbe/vacuum.rs`](https://github.com/tursodatabase/turso/blob/main/core/vdbe/vacuum.rs) explicitly copies pages while stripping encryption metadata, as verified in [`tests/integration/query_processing/encryption.rs`](https://github.com/tursodatabase/turso/blob/main/tests/integration/query_processing/encryption.rs) (test case `test_vacuum_into_unencrypts`).

**SQLCipher's VACUUM** maintains encryption on the destination unless the user explicitly disables it, preserving the security model but requiring additional steps to create unencrypted backups.

## Implementation Examples

### Opening an Encrypted Database in Turso (Rust)

```rust
use turso_core::{Database, DatabaseOpts, CipherMode};

let db = Database::open(
    "/path/to/db.sqlite",
    DatabaseOpts::new()
        .with_encryption(true)
        .with_cipher(CipherMode::Aegis256)
        .with_key_hex("0123abcd...deadbeef")?
)?;

```

### Opening an Encrypted Database in Turso (Go)

```go
import "github.com/tursodatabase/turso-go"

opts := turso.NewDatabaseOpts().
    WithEncryption(true).
    WithCipher(turso.Aegis256).
    WithKeyHex("0123abcd...deadbeef")
db, err := turso.Open("/path/to/db.sqlite", opts)

```

### Opening an Encrypted Database in Turso (JavaScript)

```javascript
import { openDatabase } from "@tursodatabase/turso";

const db = await openDatabase("/path/to/db.sqlite", {
  encryption: {
    cipher: "aegis256",
    hexkey: "0123abcd...deadbeef"
  }
});

```

### SQLite with SQLCipher (C API)

```c
sqlite3* db;
sqlite3_open("/path/to/db.sqlite", &db);
sqlite3_key(db, "0123abcd...deadbeef", 32);
// Subsequent queries use encrypted pages

```

## Summary

- **Turso** implements encryption natively in [`core/storage/encryption.rs`](https://github.com/tursodatabase/turso/blob/main/core/storage/encryption.rs) using AEGIS ciphers, while **SQLite** relies on external extensions like SQLCipher using AES-256-CBC.
- Turso supports multiple cipher selections via `CipherMode` and requires configuration through `DatabaseOpts` before opening, whereas SQLCipher uses `PRAGMA key` after connection.
- Turso's encryption integrates with its MVCC engine in [`core/mvcc/persistent_storage/logical_log.rs`](https://github.com/tursodatabase/turso/blob/main/core/mvcc/persistent_storage/logical_log.rs), ensuring consistent snapshot encryption.
- `VACUUM INTO` in Turso automatically produces unencrypted output ([`core/vdbe/vacuum.rs`](https://github.com/tursodatabase/turso/blob/main/core/vdbe/vacuum.rs)), while SQLCipher preserves encryption by default.
- Keys in Turso are handled as `EncryptionKey` enums derived from hex strings and stored in `Database` structs, with validation occurring in [`core/connection.rs`](https://github.com/tursodatabase/turso/blob/main/core/connection.rs).

## Frequently Asked Questions

### Can I use SQLCipher databases with Turso?

No, Turso uses AEGIS-based encryption stored in [`core/storage/encryption.rs`](https://github.com/tursodatabase/turso/blob/main/core/storage/encryption.rs) and is not compatible with SQLCipher's AES-256-CBC format. The file headers and encryption schemes differ fundamentally. To migrate data, you must export from SQLCipher to SQL and import into a new Turso encrypted database.

### What happens if I provide the wrong encryption key?

Turso validates the key against file header magic bytes during `Database::open` in [`core/connection.rs`](https://github.com/tursodatabase/turso/blob/main/core/connection.rs). If the key is incorrect, the open operation fails immediately. The test suite in [`tests/integration/query_processing/encryption.rs`](https://github.com/tursodatabase/turso/blob/main/tests/integration/query_processing/encryption.rs) verifies that even cached database handles reject wrong keys, preventing silent data corruption.

### Does Turso encryption support multiple ciphers simultaneously?

Yes, Turso supports multiple AEGIS variants (AEGIS-256, AEGIS-128L, etc.) selectable per database via the `CipherMode` enum. The chosen cipher is encoded in the database file header and validated by the `EncryptionContext` in [`core/storage/pager.rs`](https://github.com/tursodatabase/turso/blob/main/core/storage/pager.rs). However, once a database is created with a specific cipher, that cipher is fixed for that file.

### How does encryption affect Turso's performance?

Turso's AEGIS implementation leverages SIMD-accelerated Rust crates designed for high-throughput, low-latency per-page encryption. Unlike AES-256-CBC implementations that may vary by platform, AEGIS provides consistent performance across supported architectures while maintaining authentication tags that prevent tampering.