From f9a6cde79ac377b5fc41ae9ffbb059d69f9c030e Mon Sep 17 00:00:00 2001 From: Avinash Sajjanshetty Date: Wed, 17 Sep 2025 21:55:23 +0530 Subject: [PATCH 1/3] Make encryption::CipherMode public --- core/lib.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/core/lib.rs b/core/lib.rs index 71007918c..574701998 100644 --- a/core/lib.rs +++ b/core/lib.rs @@ -40,7 +40,6 @@ pub mod numeric; mod numeric; use crate::storage::checksum::CHECKSUM_REQUIRED_RESERVED_BYTES; -use crate::storage::encryption::CipherMode; use crate::translate::pragma::TURSO_CDC_DEFAULT_TABLE_NAME; #[cfg(all(feature = "fs", feature = "conn_raw_api"))] use crate::types::{WalFrameInfo, WalState}; @@ -79,7 +78,7 @@ use std::{ #[cfg(feature = "fs")] use storage::database::DatabaseFile; pub use storage::database::IOContext; -pub use storage::encryption::{EncryptionContext, EncryptionKey}; +pub use storage::encryption::{CipherMode, EncryptionContext, EncryptionKey}; use storage::page_cache::PageCache; use storage::pager::{AtomicDbState, DbState}; use storage::sqlite3_ondisk::PageSize; From 10137ffaa44282ccf3424e9361c0c286c86781d9 Mon Sep 17 00:00:00 2001 From: Avinash Sajjanshetty Date: Wed, 17 Sep 2025 21:58:27 +0530 Subject: [PATCH 2/3] run whopper with encryption if arg is passed --- Cargo.lock | 1 + whopper/Cargo.toml | 4 ++- whopper/main.rs | 75 +++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 72 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d2e512cf4..9e2bb330d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4338,6 +4338,7 @@ version = "0.2.0-pre.3" dependencies = [ "anyhow", "clap", + "hex", "memmap2", "rand 0.9.2", "rand_chacha 0.9.0", diff --git a/whopper/Cargo.toml b/whopper/Cargo.toml index 0695ebcf4..8056fbc43 100644 --- a/whopper/Cargo.toml +++ b/whopper/Cargo.toml @@ -25,6 +25,8 @@ tracing = { workspace = true } tracing-subscriber = { workspace = true, features = ["env-filter"] } turso_core = { workspace = true, features = ["simulator"]} turso_parser = { workspace = true } +hex = "0.4.3" [features] -checksum = ["turso_core/checksum"] \ No newline at end of file +checksum = ["turso_core/checksum"] +encryption = ["turso_core/encryption"] \ No newline at end of file diff --git a/whopper/main.rs b/whopper/main.rs index ef6f1788e..ba155ca7e 100644 --- a/whopper/main.rs +++ b/whopper/main.rs @@ -14,7 +14,9 @@ use std::cell::RefCell; use std::sync::Arc; use tracing::trace; use tracing_subscriber::{EnvFilter, layer::SubscriberExt, util::SubscriberInitExt}; -use turso_core::{Connection, Database, IO, Statement}; +use turso_core::{ + CipherMode, Connection, Database, DatabaseOpts, EncryptionOpts, IO, OpenFlags, Statement, +}; use turso_parser::ast::SortOrder; mod io; @@ -36,6 +38,9 @@ struct Args { /// Enable MVCC (Multi-Version Concurrency Control) #[arg(long)] enable_mvcc: bool, + /// Enable database encryption + #[arg(long)] + enable_encryption: bool, } struct SimulatorConfig { @@ -74,6 +79,17 @@ struct Stats { integrity_checks: usize, } +fn may_be_set_encryption( + conn: Arc, + opts: &Option, +) -> anyhow::Result> { + if let Some(opts) = opts { + conn.pragma_update("cipher", format!("'{}'", opts.cipher.clone()))?; + conn.pragma_update("hexkey", format!("'{}'", opts.hexkey.clone()))?; + } + Ok(conn) +} + fn main() -> anyhow::Result<()> { init_logger(); @@ -109,14 +125,35 @@ fn main() -> anyhow::Result<()> { let db_path = format!("whopper-{}-{}.db", seed, std::process::id()); - let db = match Database::open_file(io.clone(), &db_path, args.enable_mvcc, true) { - Ok(db) => db, - Err(e) => { - return Err(anyhow::anyhow!("Database open failed: {}", e)); + let encryption_opts = if args.enable_encryption { + let opts = random_encryption_config(&mut rng); + println!("cipher = {}, key = {}", opts.cipher, opts.hexkey); + Some(opts) + } else { + None + }; + + let db = { + let opts = DatabaseOpts::new() + .with_mvcc(args.enable_mvcc) + .with_indexes(true); + + match Database::open_file_with_flags( + io.clone(), + &db_path, + OpenFlags::default(), + opts, + encryption_opts.clone(), + ) { + Ok(db) => db, + Err(e) => { + return Err(anyhow::anyhow!("Database open failed: {}", e)); + } } }; + let boostrap_conn = match db.connect() { - Ok(conn) => conn, + Ok(conn) => may_be_set_encryption(conn, &encryption_opts)?, Err(e) => { return Err(anyhow::anyhow!("Connection failed: {}", e)); } @@ -146,7 +183,7 @@ fn main() -> anyhow::Result<()> { let mut fibers = Vec::new(); for i in 0..config.max_connections { let conn = match db.connect() { - Ok(conn) => conn, + Ok(conn) => may_be_set_encryption(conn, &encryption_opts)?, Err(e) => { return Err(anyhow::anyhow!( "Failed to create fiber connection {}: {}", @@ -323,6 +360,30 @@ fn create_initial_schema(rng: &mut ChaCha8Rng) -> Vec { schema } +fn random_encryption_config(rng: &mut ChaCha8Rng) -> EncryptionOpts { + let cipher_modes = [ + CipherMode::Aes128Gcm, + CipherMode::Aes256Gcm, + CipherMode::Aegis256, + CipherMode::Aegis128L, + CipherMode::Aegis128X2, + CipherMode::Aegis128X4, + CipherMode::Aegis256X2, + CipherMode::Aegis256X4, + ]; + + let cipher_mode = cipher_modes[rng.random_range(0..cipher_modes.len())]; + + let key_size = cipher_mode.required_key_size(); + let mut key = vec![0u8; key_size]; + rng.fill_bytes(&mut key); + + EncryptionOpts { + cipher: cipher_mode.to_string(), + hexkey: hex::encode(&key), + } +} + fn perform_work( fiber_idx: usize, rng: &mut ChaCha8Rng, From 94e7f6defca4c49a22bfb719ddeaee43694f0f5c Mon Sep 17 00:00:00 2001 From: Avinash Sajjanshetty Date: Wed, 17 Sep 2025 21:58:54 +0530 Subject: [PATCH 3/3] Update whopper run and explore scripts --- CONTRIBUTING.md | 2 +- whopper/bin/explore | 18 +++++++++++++++++- whopper/bin/run | 18 +++++++++++++++++- 3 files changed, 35 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9d8f7e4aa..9a33c7319 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -248,7 +248,7 @@ Note that exploration uses the `chaos` mode so if you need to reproduce a run, u SEED=1234 ./whopper/bin/run --mode chaos ``` -Both `explore` and `run` accept `--enable-checksums` flag to enable per page checksums. +Both `explore` and `run` accept the `--enable-checksums` and `--enable-encryption` flags for per page checksums and encryption respectively. ## Python Bindings diff --git a/whopper/bin/explore b/whopper/bin/explore index c5480a3a7..6c664fffe 100755 --- a/whopper/bin/explore +++ b/whopper/bin/explore @@ -1,18 +1,34 @@ #!/bin/bash +# Usage: ./explore.sh [--enable-checksums|--enable-encryption] [other-args...] + set -e -# Check for special build time flags (e.g. `--enable-checksums`) +# Check for special build time flags (e.g. `--enable-checksums`, `--enable-encryption`) FEATURES="" ARGS=() +CHECKSUM_ENABLED=false +ENCRYPTION_ENABLED=false + for arg in "$@"; do if [[ "$arg" == "--enable-checksums" ]]; then FEATURES="--features checksum" + CHECKSUM_ENABLED=true + elif [[ "$arg" == "--enable-encryption" ]]; then + FEATURES="--features encryption" + ENCRYPTION_ENABLED=true + ARGS+=("$arg") else ARGS+=("$arg") fi done +# check for incompatible options +if [[ "$CHECKSUM_ENABLED" == true && "$ENCRYPTION_ENABLED" == true ]]; then + echo "Error: --enable-checksums and --enable-encryption are not compatible with each other" + exit 1 +fi + cargo build $FEATURES -p turso_whopper echo "Running Whopper in an infinite loop in 'chaos' mode..." diff --git a/whopper/bin/run b/whopper/bin/run index 8d6fc4b4e..79aead371 100755 --- a/whopper/bin/run +++ b/whopper/bin/run @@ -1,18 +1,34 @@ #!/bin/bash +# Usage: ./run.sh [--enable-checksums|--enable-encryption] [other-args...] + set -e -# Check for special build time flags (e.g. `--enable-checksums`) +# Check for special build time flags (e.g. `--enable-checksums`, `--enable-encryption`) FEATURES="" ARGS=() +CHECKSUM_ENABLED=false +ENCRYPTION_ENABLED=false + for arg in "$@"; do if [[ "$arg" == "--enable-checksums" ]]; then FEATURES="--features checksum" + CHECKSUM_ENABLED=true + elif [[ "$arg" == "--enable-encryption" ]]; then + FEATURES="--features encryption" + ENCRYPTION_ENABLED=true + ARGS+=("$arg") else ARGS+=("$arg") fi done +# check for incompatible options +if [[ "$CHECKSUM_ENABLED" == true && "$ENCRYPTION_ENABLED" == true ]]; then + echo "Error: --enable-checksums and --enable-encryption are not compatible with each other" + exit 1 +fi + cargo build $FEATURES -p turso_whopper time RUST_BACKTRACE=full ./target/debug/turso_whopper "${ARGS[@]}" \ No newline at end of file