encrypted-vfs is an experimental Rust crate that explores page-level encryption for a file-backed virtual storage layer, inspired by how SQLite’s VFS operates.
The current implementation focuses on:
- AES‑GCM–based encryption for file contents.
- Page-level encryption with a fixed page size.
- A simple Rust API for opening an encrypted file and reading/writing pages.
This is work in progress, not a production-ready library. It is intended as an educational/portfolio project to demonstrate systems-level Rust, encryption, and storage abstractions.
-
AES‑256‑GCM encryption
- Uses
aes-gcmwith a 32-byte key. - Authenticated encryption (ciphertext includes an authentication tag).
- Uses
-
Page-level layout
PAGE_SIZEis fixed at4096bytes.- Each page is encrypted with its own per-page nonce derived from:
- The encryption key.
- The page number.
- On disk, each page is stored as
PAGE_SIZE + TAG_SIZEbytes.
-
Deterministic nonces
- Per-file nonce is derived from
(key, path)for the basicwrite_at/read_atAPI. - Per-page nonces are derived from
(key, page_number)forwrite_page/read_page.
- Per-file nonce is derived from
-
Minimal, focused API
EncryptedFile::opento create/open an encrypted file.write_page/read_pagefor page-level I/O.write_at/read_atas a simple, non-page-aware encrypted I/O layer.
This crate currently provides:
- A compiling demo showing page-level encrypted I/O.
- A clean separation between:
- Core encrypted file abstraction (
EncryptedFile). - Demo code (in
src/main.rs).
- Core encrypted file abstraction (
There is no full SQLite VFS integration yet. The code is structured so that a future VFS adapter can be built on top of the existing page-level API.
If you’re using this repository directly:
[dependencies]
encrypted-vfs = { path = "./encrypted-vfs" }use encrypted_vfs::EncryptedFile;
use std::{path::Path, sync::Arc};
fn main() -> std::io::Result<()> {
// 32-byte AES-256 key.
// In real applications, derive this from a passphrase or key management system.
let key = [0u8; 32];
let path = Path::new("encrypted_demo.bin");
let mut file = EncryptedFile::open(path, Arc::new(key))?;
// Basic byte-level write/read (non-page-aware)
let data = b"hello encrypted world";
file.write_at(0, data)?;
let mut buf = vec![0u8; data.len()];
file.read_at(0, &mut buf)?;
assert_eq!(&buf, data);
Ok(())
}The primary abstraction is page-level I/O.
use encrypted_vfs::{EncryptedFile, PAGE_SIZE};
use std::{path::Path, sync::Arc};
fn main() -> std::io::Result<()> {
let key = [0u8; 32];
let path = Path::new("encrypted_pages.bin");
let mut file = EncryptedFile::open(path, Arc::new(key))?;
// Prepare a single page with some application data at the start
let mut page = [0u8; PAGE_SIZE];
let msg = b"hello encrypted page";
page[..msg.len()].copy_from_slice(msg);
// Page-level write and read
file.write_page(0, &page)?;
let mut read_back = [0u8; PAGE_SIZE];
file.read_page(0, &mut read_back)?;
assert_eq!(&read_back[..msg.len()], msg);
Ok(())
}Under the hood:
-
write_page(page_no, data):- Derives a per-page nonce from
(key, page_no). - Encrypts
datawith AES‑GCM. - Writes
PAGE_SIZE + TAG_SIZEbytes to the underlying file at the calculated offset.
- Derives a per-page nonce from
-
read_page(page_no, buf):- Reads
PAGE_SIZE + TAG_SIZEbytes from the underlying file. - Decrypts using the same per-page nonce.
- Copies the resulting plaintext into
buf.
- Reads
This crate is not production-ready. Some important caveats:
- Key management is intentionally simplified:
- Keys are currently passed as raw
[u8; 32]. - There is no KDF (e.g., PBKDF2, scrypt, Argon2) or integration with AWS KMS, HashiCorp Vault, etc.
- Keys are currently passed as raw
- Nonce derivation is deterministic:
- Useful for page-based schemes, but must be carefully audited for uniqueness and security properties in real deployments.
- Threat model and side channels:
- The implementation does not attempt to handle side-channel attacks, secure key erasure, or multi-tenant isolation.
Treat this as a learning tool and prototype, not as a drop-in encryption layer for sensitive data.
From the repository root:
cargo build
cargo runThe demo (src/main.rs) will:
- Open an encrypted file.
- Write a page at page 0.
- Read that page back.
- Assert that the plaintext matches.
This project is licensed under the Apache-2.0 License. See LICENSE for details.