AbsurderSQL supports optional database encryption using SQLCipher for native applications (not available in WASM/browser mode).
When enabled with the encryption feature flag, AbsurderSQL provides:
- AES-256 encryption for data at rest
- Key-based access control - wrong key = no access
- Re-keying capability - change encryption keys without re-creating database
- Zero performance impact when disabled (optional feature)
Add to your Cargo.toml:
[dependencies]
absurder-sql = { version = "0.1", features = ["encryption", "fs_persist"] }Or build with:
cargo build --features encryption,fs_persistuse absurder_sql::{Database, DatabaseConfig};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let config = DatabaseConfig {
name: "secure.db".to_string(),
..Default::default()
};
let encryption_key = "your-secure-key-min-8-chars";
let mut db = Database::new_encrypted(config, encryption_key).await?;
// Use database normally
db.execute("CREATE TABLE secrets (id INTEGER, data TEXT)").await?;
db.execute("INSERT INTO secrets VALUES (1, 'confidential')").await?;
Ok(())
}let new_key = "new-secure-key-min-8-chars";
db.rekey(new_key).await?;
// Old key no longer works
// New key is required to access databaselet config = DatabaseConfig {
name: "secure.db".to_string(),
..Default::default()
};
// Must use the correct key
let db = Database::new_encrypted(config, "your-secure-key-min-8-chars").await?;Store encryption keys in iOS Keychain:
// Store key securely
let keyData = key.data(using: .utf8)!
let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrAccount as String: "database_encryption_key",
kSecValueData as String: keyData
]
SecItemAdd(query as CFDictionary, nil)
// Retrieve key
let searchQuery: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrAccount as String: "database_encryption_key",
kSecReturnData as String: true
]
var result: AnyObject?
SecItemCopyMatching(searchQuery as CFDictionary, &result)Store encryption keys in Android Keystore:
// Generate or retrieve key
val keyStore = KeyStore.getInstance("AndroidKeyStore")
keyStore.load(null)
val keyGenerator = KeyGenerator.getInstance(
KeyProperties.KEY_ALGORITHM_AES,
"AndroidKeyStore"
)
val keyGenSpec = KeyGenParameterSpec.Builder(
"database_key",
KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT
)
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
.build()
keyGenerator.init(keyGenSpec)
val secretKey = keyGenerator.generateKey()- Store keys in environment variables (not in code)
- Use secrets management (HashiCorp Vault, AWS Secrets Manager)
- Implement key rotation policies
- Never commit keys to version control
- Minimum: 8 characters (enforced)
- Recommended: 16+ characters
- Best: 32+ random characters
SQLCipher automatically applies PBKDF2 key derivation:
- 256,000 iterations (SQLCipher 4.x)
- Makes brute-force attacks computationally expensive
Attempting to open an encrypted database with the wrong key will:
- Either fail immediately with an error, OR
- Succeed in opening but fail on first query attempt
This is SQLCipher's security-by-design behavior.
- Encryption overhead: < 10% (typical)
- Query performance: Nearly identical to unencrypted
- File size: Same as unencrypted database
# Run encryption benchmarks
cargo test --features encryption,fs_persist --test encryption_tests| Platform | Encryption Support |
|---|---|
| Native (Rust) | [x] Full support |
| iOS (React Native) | [x] Via FFI (Phase II) |
| Android (React Native) | [x] Via FFI (Phase II) |
| WASM/Browser | [ ] Not supported |
Note: Browser environments cannot use SQLCipher. For browser encryption, use Web Crypto API separately.
SQLCipher encryption helps meet:
- HIPAA - Healthcare data protection
- GDPR - EU data privacy
- PCI DSS - Payment card data security
- SOC 2 - Security controls
Important: Encryption alone doesn't guarantee compliance. Consult with legal/compliance teams.
ENCRYPTION_ERROR: Database is locked
Solution: Ensure no other process has the database open.
ENCRYPTION_ERROR: Failed to set encryption key
Solution: Verify you're using the correct encryption key.
# Check if database is encrypted (will fail if encrypted)
sqlite3 secure.db "SELECT * FROM sqlite_master"
# Error: file is not a database
This confirms the database is properly encrypted.
See /tests/encryption_tests.rs for comprehensive examples:
- Creating encrypted databases
- Re-keying
- Persistence validation
- Error handling
Q: Can I convert an unencrypted database to encrypted?
A: Not directly. You must export data, create new encrypted database, and re-import.
Q: Can I use encryption in browser/WASM?
A: No. SQLCipher requires native compilation. Use Web Crypto API for browser encryption.
Q: What happens if I lose the encryption key?
A: The data is permanently inaccessible. There is no recovery mechanism.
Q: Can I change the encryption algorithm?
A: SQLCipher uses AES-256 by default. This cannot be changed.
Q: Is the encryption FIPS 140-2 compliant?
A: SQLCipher itself can be FIPS-compliant when built with appropriate OpenSSL. Check SQLCipher documentation.
- v0.1.7 - Initial encryption support (native only)
- v0.2.0 - Mobile FFI support (planned)