Encryption

SwirlDB provides pluggable encryption at multiple levels through the EncryptionProvider trait. All encryption works on all platforms (browser + server).

Encryption Architecture

Encryption Layers

  • At-Rest Encryption: Data encrypted before storage (localStorage, IndexedDB, redb)
  • Over-the-Wire: CRDT changes encrypted during sync between clients
  • Field-Level: Selective encryption based on field patterns

Built-in Providers

UnencryptedProvider (Default)

No-op provider that passes data through unchanged. Use when encryption is handled externally (encrypted filesystem, TLS, etc.) or not required.

// Rust
use swirldb_core::encryption::UnencryptedProvider;

let provider = UnencryptedProvider::new();

// TypeScript
const provider = new UnencryptedProvider();

AesGcmProvider (AES-256-GCM)

Authenticated encryption with 256-bit keys. Provides confidentiality and authenticity.

// Rust
use swirldb_core::encryption::AesGcmProvider;

// Random key
let provider = AesGcmProvider::new_random();

// Fixed key (32 bytes)
let key = [0u8; 32]; // In production: use secure random
let provider = AesGcmProvider::new(&key);

// Derive from password
let provider = AesGcmProvider::from_password(
    b"user-password",
    b"unique-salt-12345"
).unwrap();

// TypeScript
const provider = await AesGcmProvider.fromPassword('password', 'salt');

FieldEncryptionProvider

Pattern-based selective encryption. Encrypts matching fields while leaving others in plaintext.

// Rust
use swirldb_core::encryption::{FieldEncryptionProvider, AesGcmProvider};

let mut provider = FieldEncryptionProvider::new();

// Encrypt all SSN fields
provider.add_pattern("*.ssn", Box::new(AesGcmProvider::new_random()));

// Encrypt all password fields
provider.add_pattern("user.*.password", Box::new(AesGcmProvider::new_random()));

// Everything else remains unencrypted

Encryption At Rest

Browser Example

import { SwirlDB, AesGcmProvider } from '@swirldb/js';

// Create encrypted storage
const encryption = await AesGcmProvider.fromPassword(
  'user-password',
  'app-salt'
);

const db = await SwirlDB.withLocalStorage('my-app', {
  encryption
});

// All data automatically encrypted before localStorage
db.data.user.ssn = '123-45-6789';  // Encrypted in storage
db.data.user.name = 'Alice';        // Encrypted in storage

Server Example

use swirldb_core::{SwirlDB, encryption::AesGcmProvider};
use swirldb_server::storage::RedbAdapter;

// Create encrypted storage
let encryption = AesGcmProvider::new_random();
let storage = RedbAdapter::new("./data")
    .with_encryption(encryption);

let db = SwirlDB::with_storage(storage, "db-key").await;

// All saves encrypted on disk
db.set_path("user.ssn", "123-45-6789".into())?;
db.persist().await?;  // Encrypted to redb

Encryption Over the Wire

For end-to-end encrypted sync, wrap CRDT changes before transmission. The server never sees plaintext data.

Encrypted Sync Example

use swirldb_core::encryption::AesGcmProvider;

// Shared encryption key (use key exchange in production)
let sync_key = [0u8; 32];
let provider = AesGcmProvider::new(&sync_key);

// Get local changes
let changes = db.get_changes();

// Encrypt each change
let encrypted_changes: Vec<Vec<u8>> = changes
    .iter()
    .map(|change| provider.encrypt(change).await.unwrap())
    .collect();

// Send encrypted changes to server
sync_client.push(encrypted_changes).await?;

Architecture

┌─────────┐                           ┌─────────┐
│ Client  │                           │ Server  │
│         │                           │         │
│  CRDT   │                           │  CRDT   │
│    ↓    │                           │    ↓    │
│ Encrypt │ ──── Encrypted Wire ────→ │ Decrypt │
│    ↓    │                           │    ↓    │
│ Storage │                           │ Storage │
└─────────┘                           └─────────┘

Server never sees plaintext data

Security Best Practices

Key Management

  • Browser: Store keys in IndexedDB, protect with Web Crypto API
  • Server: Store keys in secure vault (HashiCorp Vault, AWS KMS)
  • Never: Hard-code keys in source code or commit to git

Nonce Reuse

AES-GCM uses random nonces per encryption. Never reuse nonces with the same key. SwirlDB automatically generates fresh nonces for each encryption operation.

Authentication

AES-GCM provides authenticated encryption (AEAD). Tampering with ciphertext will fail decryption. This protects against data corruption and malicious modification.

Performance

  • AES-GCM throughput: ~1GB/s on modern hardware
  • Field-level encryption encrypts only matching fields
  • Transport encryption (TLS/WSS) provides additional protection
  • Encryption overhead: typically <5% for document operations

Future Enhancements

  • X25519 key exchange for multi-party encryption
  • RSA-OAEP for asymmetric encryption
  • Automatic key rotation support
  • Hardware security module (HSM) integration
  • Pattern matching for field-level encryption