1 unstable release
| 0.1.0 | Oct 18, 2025 |
|---|
#60 in #security-privacy
Used in syntarq-cli
240KB
4K
SLoC
syntarq-core
Core library for the Syntarq ecosystem - A robust cryptographic identity and data management system built in Rust.
Features
π Post-Quantum Cryptography
- Kyber-1024 - NIST-standardized key encapsulation mechanism
- Dilithium5 - Post-quantum digital signatures
- Hybrid Encryption - Combines quantum-resistant KEM with AES-256-GCM
- Optional feature flag for zero-overhead when not needed
ποΈ Identity Management
- Hierarchical key derivation for service-specific keys
- Argon2id password hashing with secure defaults
- Ed25519 digital signatures
- X25519 key exchange
- Session management with expiration and refresh
π Secure Storage
- Pluggable storage backends (Memory, SQLite)
- Transparent encryption for any storage backend
- Async-first design for optimal performance
- Thread-safe operations with Arc/Mutex
π Service Framework
- Service registry for managing multiple services
- Deep linking support with custom URL schemes
- Health monitoring and lifecycle management
- Async trait-based service abstraction
π‘οΈ Security Guarantees
- Memory-safe: All sensitive data automatically zeroized when dropped
- Constant-time comparisons: Prevents timing attacks
- Offline-first: Core functionality works without network
- No plaintext secrets: Keys never stored unencrypted
Quick Start
Add to your Cargo.toml:
[dependencies]
syntarq-core = "0.1.0"
# Optional features
syntarq-core = { version = "0.1.0", features = ["post-quantum", "sqlite"] }
Basic Identity Creation
use syntarq_core::identity::SyntarqIdentity;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Create a new identity with a master password
let password = "secure_password_123";
let (identity, password_hash) = SyntarqIdentity::create(password)?;
println!("Identity created: {}", identity.id());
// Later: Unlock the identity
let unlocked = SyntarqIdentity::unlock(
identity.id(),
password,
&password_hash
)?;
println!("Identity unlocked successfully!");
Ok(())
}
Service Key Derivation
use syntarq_core::identity::{SyntarqIdentity, ServiceType};
let password = "secure_password_123";
let (identity, _) = SyntarqIdentity::create(password)?;
// Derive service-specific keys
let pass_key = identity.derive_service_key(ServiceType::Pass)?;
let vpn_key = identity.derive_service_key(ServiceType::VPN)?;
let drive_key = identity.derive_service_key(ServiceType::Drive)?;
let mail_key = identity.derive_service_key(ServiceType::Mail)?;
// Each service gets a unique 256-bit key
assert_eq!(pass_key.as_bytes().len(), 32);
Encrypted Storage
use syntarq_core::storage::{
MemoryStorage, EncryptedStorageWrapper,
Storage, EncryptedStorage
};
use syntarq_core::crypto::aes_gcm::AesGcmCipher;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Create storage backend
let storage = MemoryStorage::new();
// Wrap with encryption
let cipher = AesGcmCipher::generate();
let encrypted = EncryptedStorageWrapper::new(storage, Box::new(cipher));
// Store encrypted data
encrypted.store_encrypted("secret_key", b"sensitive data").await?;
// Retrieve and decrypt
let data = encrypted.retrieve_decrypted("secret_key").await?;
assert_eq!(data, Some(b"sensitive data".to_vec()));
Ok(())
}
Session Management
use syntarq_core::identity::{SyntarqIdentity, Session, ServiceType};
use chrono::Duration;
let password = "secure_password_123";
let (identity, _) = SyntarqIdentity::create(password)?;
// Create a session for a specific service
let session = Session::new(
&identity,
ServiceType::Pass,
Duration::hours(1)
);
// Check if session is still valid
if session.is_valid() {
println!("Session active for: {:?}", session.time_remaining());
}
// Refresh the session
let mut session = session;
session.refresh(Duration::hours(2))?;
Post-Quantum Cryptography
Enable the post-quantum feature:
[dependencies]
syntarq-core = { version = "0.1.0", features = ["post-quantum"] }
use syntarq_core::crypto::pq::{
kyber::KyberCipher,
dilithium::DilithiumSigner,
hybrid::HybridCipher
};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Kyber key encapsulation
let kyber = KyberCipher::new()?;
let (public_key, secret_key) = kyber.generate_keypair()?;
let (ciphertext, shared_secret1) = kyber.encapsulate(&public_key)?;
let shared_secret2 = kyber.decapsulate(&secret_key, &ciphertext)?;
assert_eq!(shared_secret1.as_bytes(), shared_secret2.as_bytes());
// Dilithium signatures
let signer = DilithiumSigner::new()?;
let (pk, sk) = signer.generate_keypair()?;
let message = b"Important message";
let signature = signer.sign(message, &sk)?;
let valid = signer.verify(message, &signature, &pk)?;
assert!(valid);
// Hybrid encryption (Kyber + AES-256-GCM)
let hybrid = HybridCipher::new()?;
let (pk, sk) = hybrid.generate_keypair()?;
let plaintext = b"Quantum-resistant secret";
let ciphertext = hybrid.hybrid_encrypt(plaintext, &pk)?;
let decrypted = hybrid.hybrid_decrypt(&ciphertext, &sk)?;
assert_eq!(plaintext.as_slice(), decrypted.as_slice());
Ok(())
}
Deep Linking
use syntarq_core::services::linking::{DeepLink, PassAction};
use url::Url;
// Parse a deep link
let url = Url::parse("syntarqpass://item/550e8400-e29b-41d4-a716-446655440000")?;
let link = DeepLink::from_url(&url)?;
match link {
DeepLink::Pass { action } => {
match action {
PassAction::Item(id) => {
println!("Open password item: {}", id);
}
_ => {}
}
}
_ => {}
}
// Create a deep link
let link = DeepLink::Pass {
action: PassAction::Generate
};
let url = link.to_url();
assert_eq!(url.as_str(), "syntarqpass://generate");
Architecture
Module Organization
syntarq-core/
βββ crypto/ # Cryptographic primitives
β βββ aes_gcm # AES-256-GCM encryption
β βββ argon2 # Password hashing
β βββ chacha20poly1305 # ChaCha20-Poly1305 encryption
β βββ hashing # SHA-256, BLAKE3
β βββ keys # Key derivation
β βββ pq/ # Post-quantum crypto (optional)
β βββ kyber # Kyber-1024 KEM
β βββ dilithium # Dilithium5 signatures
β βββ hybrid # Hybrid encryption
βββ identity/ # Identity management
β βββ user # SyntarqIdentity
β βββ service # Service-specific keys
β βββ session # Session management
βββ storage/ # Data persistence
β βββ memory # In-memory storage
β βββ sqlite # SQLite backend (optional)
β βββ encrypted # Encryption wrapper
βββ services/ # Service framework
β βββ traits # Service trait definitions
β βββ registry # Service registry
β βββ linking # Deep linking support
βββ linking/ # External service linking
Cryptographic Algorithms
| Purpose | Algorithm | Key Size | Notes |
|---|---|---|---|
| Password Hashing | Argon2id | - | Memory-hard, resistant to GPU attacks |
| Symmetric Encryption | AES-256-GCM | 256-bit | Authenticated encryption |
| Symmetric Encryption | ChaCha20-Poly1305 | 256-bit | Alternative to AES |
| Digital Signatures | Ed25519 | 256-bit | Fast, secure signatures |
| Key Exchange | X25519 | 256-bit | Elliptic curve Diffie-Hellman |
| Hashing | SHA-256 | 256-bit | Standard cryptographic hash |
| Hashing | BLAKE3 | 256-bit | High-performance hash |
| PQ Key Encapsulation | Kyber-1024 | - | NIST-standardized (optional) |
| PQ Signatures | Dilithium5 | - | NIST-standardized (optional) |
Security Model
Threat Model
Protected Against:
- Password cracking (Argon2id with high iteration count)
- Timing attacks (constant-time comparisons)
- Memory dumps (automatic zeroization)
- Quantum attacks (when post-quantum feature enabled)
- Side-channel attacks (memory-safe Rust)
Not Protected Against:
- Physical access to unlocked device
- Malicious code running with same privileges
- Hardware keyloggers
- Compromised master password
Key Derivation Hierarchy
Master Password
ββ> Argon2id
ββ> Master Key (256-bit)
ββ> Service Key (Pass) [HKDF]
ββ> Service Key (VPN) [HKDF]
ββ> Service Key (Drive) [HKDF]
ββ> Service Key (Mail) [HKDF]
Each service key is derived using HKDF with a unique context, ensuring complete key isolation.
Feature Flags
| Feature | Description | Default |
|---|---|---|
offline |
Core functionality without network | β Yes |
sqlite |
SQLite storage backend | β No |
networking |
QUIC-based networking | β No |
post-quantum |
Post-quantum cryptography (Kyber, Dilithium) | β No |
Enabling Features
# All features
syntarq-core = { version = "0.1.0", features = ["sqlite", "post-quantum"] }
# Minimal (no additional dependencies)
syntarq-core = { version = "0.1.0", default-features = false }
Performance
Benchmarks
Run benchmarks with:
cargo bench --features post-quantum
Typical Performance (AMD Ryzen 9 5950X):
| Operation | Time | Notes |
|---|---|---|
| Password Hash | ~100ms | Argon2id (m=19456, t=2, p=1) |
| AES-256-GCM Encrypt (1KB) | ~2Β΅s | Hardware acceleration |
| AES-256-GCM Decrypt (1KB) | ~2Β΅s | Hardware acceleration |
| Ed25519 Sign | ~50Β΅s | |
| Ed25519 Verify | ~120Β΅s | |
| Kyber-1024 Encapsulate | ~150Β΅s | Post-quantum |
| Kyber-1024 Decapsulate | ~200Β΅s | Post-quantum |
| Dilithium5 Sign | ~1.5ms | Post-quantum |
| Dilithium5 Verify | ~1.2ms | Post-quantum |
Benchmarks are indicative and may vary based on hardware
Testing
Run All Tests
# Unit tests
cargo test
# Integration tests
cargo test --test '*integration*'
# With all features
cargo test --all-features
# With post-quantum tests
cargo test --features post-quantum
Test Coverage
- Unit Tests: 127 tests covering all modules
- Integration Tests: 54 tests for end-to-end workflows
- Doctests: 34 documentation examples
Examples
See the examples/ directory for complete examples:
basic_identity.rs- Identity creation and managementcrypto_demo.rs- Cryptographic operationsstorage_demo.rs- Storage backends and encryption
Run examples:
cargo run --example basic_identity
cargo run --example crypto_demo --features post-quantum
Security Considerations
Password Requirements
Passwords must meet the following criteria:
- Minimum 10 characters
- At least one letter
- At least one number
These requirements are enforced during identity creation.
Key Storage
- Master Key: Derived from password, never stored
- Service Keys: Derived from master key, never stored
- Password Hash: Stored for verification (Argon2id PHC format)
- Session Keys: Ephemeral, destroyed on logout
Memory Safety
All sensitive types implement Zeroize:
DerivedKeyServiceKeyKyberSecretKey,KyberSharedSecretDilithiumSecretKey
Memory is automatically zeroed when dropped.
Debug Output
Sensitive fields are hidden in Debug output:
// This is safe - no secrets leaked
println!("{:?}", identity); // ServiceKey { *** REDACTED *** }
Dependencies
Core Dependencies
tokio- Async runtimeserde- Serializationuuid- Unique identifierschrono- Date/time handlinged25519-dalek- Digital signaturesx25519-dalek- Key exchangeaes-gcm- Authenticated encryptionchacha20poly1305- Authenticated encryptionargon2- Password hashingblake3- Hashingsha2- SHA-256hkdf- Key derivationzeroize- Secure memory zeroing
Optional Dependencies
sqlx(withsqlitefeature) - SQLite supportliboqs-sys(withpost-quantumfeature) - Post-quantum crypto
Minimum Supported Rust Version (MSRV)
Rust 1.70 or higher is required.
Contributing
Contributions are welcome! Please ensure:
- All tests pass:
cargo test --all-features - Code is formatted:
cargo fmt - No clippy warnings:
cargo clippy --all-features - Documentation is updated
License
Licensed under either of:
- Apache License, Version 2.0 (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT)
at your option.
Acknowledgments
- Open Quantum Safe for liboqs
- RustCrypto for cryptographic implementations
- The Rust community for excellent tooling and libraries
Built with β€οΈ in Rust
Dependencies
~16β44MB
~624K SLoC