Skip to main content

shield_core/
lib.rs

1//! # Shield Core
2//!
3//! EXPTIME-secure encryption library - Rust implementation.
4//!
5//! ## Security Model
6//!
7//! Shield uses only symmetric primitives with proven exponential-time security.
8//! Breaking requires 2^256 operations - no shortcut exists.
9//! - PBKDF2-SHA256 for key derivation
10//! - AES-256-CTR-like stream cipher (SHA256-based keystream)
11//! - HMAC-SHA256 for authentication
12//!
13//! ## Usage
14//!
15//! ```rust
16//! use shield_core::Shield;
17//!
18//! let shield = Shield::new("password", "service.com");
19//! let ciphertext = shield.encrypt(b"secret data").unwrap();
20//! let plaintext = shield.decrypt(&ciphertext).unwrap();
21//! ```
22//!
23//! ## Error Handling
24//!
25//! All fallible operations return `Result<T, ShieldError>`. Common errors:
26//! - [`ShieldError::AuthenticationFailed`] - MAC verification failed (tampered/wrong key)
27//! - [`ShieldError::CiphertextTooShort`] - Input too small to be valid ciphertext
28//! - [`ShieldError::RandomFailed`] - System RNG failure (extremely rare)
29//! - [`ShieldError::InvalidFormat`] - Malformed input data
30//!
31//! ## Panics
32//!
33//! Functions that may panic are documented, but panics are rare and indicate:
34//! - Internal invariant violations (should never happen in correct usage)
35//! - System-level failures (e.g., time going backwards)
36
37#![forbid(unsafe_code)]
38// Clippy configuration is in Cargo.toml [lints.clippy]
39
40pub mod channel;
41#[cfg(feature = "async")]
42pub mod channel_async;
43#[cfg(feature = "confidential")]
44pub mod confidential;
45mod error;
46mod exchange;
47#[cfg(feature = "fido2")]
48pub mod fido2;
49pub mod fingerprint;
50mod group;
51mod identity;
52pub mod password;
53#[cfg(feature = "pgvector")]
54pub mod pgvector;
55mod random;
56mod ratchet;
57mod rotation;
58mod shield;
59mod signatures;
60mod stream;
61mod totp;
62#[cfg(feature = "wasm")]
63mod wasm;
64
65pub use channel::{ChannelConfig, ShieldChannel, ShieldListener};
66#[cfg(feature = "async")]
67pub use channel_async::AsyncShieldChannel;
68pub use error::{Result, ShieldError};
69pub use exchange::{KeySplitter, PAKEExchange, QRExchange};
70pub use fingerprint::FingerprintMode;
71pub use group::{BroadcastEncryption, EncryptedBroadcast, EncryptedGroupMessage, GroupEncryption};
72pub use identity::{Identity, IdentityProvider, SecureSession, Session};
73pub use ratchet::RatchetSession;
74pub use rotation::KeyRotationManager;
75pub use shield::Shield;
76pub use signatures::{LamportSignature, SymmetricSignature};
77pub use stream::StreamCipher;
78pub use totp::{RecoveryCodes, TOTP};
79
80#[cfg(feature = "wasm")]
81pub use wasm::*;
82
83/// Quick encrypt with pre-shared key (no password derivation)
84pub fn quick_encrypt(key: &[u8; 32], data: &[u8]) -> Result<Vec<u8>> {
85    Shield::encrypt_with_key(key, data)
86}
87
88/// Quick decrypt with pre-shared key
89pub fn quick_decrypt(key: &[u8; 32], encrypted: &[u8]) -> Result<Vec<u8>> {
90    Shield::decrypt_with_key(key, encrypted)
91}
92
93#[cfg(test)]
94mod tests {
95    use super::*;
96
97    #[test]
98    fn test_roundtrip() {
99        let shield = Shield::new("test_password", "test.service");
100        let plaintext = b"Hello, EXPTIME-secure world!";
101
102        let encrypted = shield.encrypt(plaintext).unwrap();
103        let decrypted = shield.decrypt(&encrypted).unwrap();
104
105        assert_eq!(plaintext.as_slice(), decrypted.as_slice());
106    }
107
108    #[test]
109    fn test_quick_functions() {
110        let key = [0x42u8; 32];
111        let data = b"Quick test message";
112
113        let encrypted = quick_encrypt(&key, data).unwrap();
114        let decrypted = quick_decrypt(&key, &encrypted).unwrap();
115
116        assert_eq!(data.as_slice(), decrypted.as_slice());
117    }
118
119    #[test]
120    fn test_tamper_detection() {
121        let shield = Shield::new("password", "service");
122        let mut encrypted = shield.encrypt(b"data").unwrap();
123
124        // Tamper with ciphertext
125        encrypted[20] ^= 0xFF;
126
127        assert!(shield.decrypt(&encrypted).is_err());
128    }
129
130    #[test]
131    fn test_wrong_password() {
132        let shield1 = Shield::new("password1", "service");
133        let shield2 = Shield::new("password2", "service");
134
135        let encrypted = shield1.encrypt(b"secret").unwrap();
136
137        assert!(shield2.decrypt(&encrypted).is_err());
138    }
139
140    #[test]
141    fn test_different_services() {
142        let shield1 = Shield::new("password", "service1");
143        let shield2 = Shield::new("password", "service2");
144
145        let encrypted = shield1.encrypt(b"secret").unwrap();
146
147        assert!(shield2.decrypt(&encrypted).is_err());
148    }
149}