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#![warn(clippy::all, clippy::pedantic)]
39#![allow(clippy::module_name_repetitions)]
40// Error/panic docs are centralized above; individual function docs are concise
41#![allow(clippy::missing_errors_doc, clippy::missing_panics_doc)]
42
43pub mod channel;
44#[cfg(feature = "async")]
45pub mod channel_async;
46mod error;
47mod exchange;
48mod group;
49mod identity;
50pub mod password;
51mod ratchet;
52mod rotation;
53mod shield;
54mod signatures;
55mod stream;
56mod totp;
57#[cfg(feature = "wasm")]
58mod wasm;
59
60pub use channel::{ChannelConfig, ShieldChannel, ShieldListener};
61#[cfg(feature = "async")]
62pub use channel_async::AsyncShieldChannel;
63pub use error::{Result, ShieldError};
64pub use exchange::{KeySplitter, PAKEExchange, QRExchange};
65pub use group::{BroadcastEncryption, EncryptedBroadcast, EncryptedGroupMessage, GroupEncryption};
66pub use identity::{Identity, IdentityProvider, SecureSession, Session};
67pub use ratchet::RatchetSession;
68pub use rotation::KeyRotationManager;
69pub use shield::Shield;
70pub use signatures::{LamportSignature, SymmetricSignature};
71pub use stream::StreamCipher;
72pub use totp::{RecoveryCodes, TOTP};
73
74#[cfg(feature = "wasm")]
75pub use wasm::*;
76
77/// Quick encrypt with pre-shared key (no password derivation)
78pub fn quick_encrypt(key: &[u8; 32], data: &[u8]) -> Result<Vec<u8>> {
79    Shield::encrypt_with_key(key, data)
80}
81
82/// Quick decrypt with pre-shared key
83pub fn quick_decrypt(key: &[u8; 32], encrypted: &[u8]) -> Result<Vec<u8>> {
84    Shield::decrypt_with_key(key, encrypted)
85}
86
87#[cfg(test)]
88mod tests {
89    use super::*;
90
91    #[test]
92    fn test_roundtrip() {
93        let shield = Shield::new("test_password", "test.service");
94        let plaintext = b"Hello, EXPTIME-secure world!";
95
96        let encrypted = shield.encrypt(plaintext).unwrap();
97        let decrypted = shield.decrypt(&encrypted).unwrap();
98
99        assert_eq!(plaintext.as_slice(), decrypted.as_slice());
100    }
101
102    #[test]
103    fn test_quick_functions() {
104        let key = [0x42u8; 32];
105        let data = b"Quick test message";
106
107        let encrypted = quick_encrypt(&key, data).unwrap();
108        let decrypted = quick_decrypt(&key, &encrypted).unwrap();
109
110        assert_eq!(data.as_slice(), decrypted.as_slice());
111    }
112
113    #[test]
114    fn test_tamper_detection() {
115        let shield = Shield::new("password", "service");
116        let mut encrypted = shield.encrypt(b"data").unwrap();
117
118        // Tamper with ciphertext
119        encrypted[20] ^= 0xFF;
120
121        assert!(shield.decrypt(&encrypted).is_err());
122    }
123
124    #[test]
125    fn test_wrong_password() {
126        let shield1 = Shield::new("password1", "service");
127        let shield2 = Shield::new("password2", "service");
128
129        let encrypted = shield1.encrypt(b"secret").unwrap();
130
131        assert!(shield2.decrypt(&encrypted).is_err());
132    }
133
134    #[test]
135    fn test_different_services() {
136        let shield1 = Shield::new("password", "service1");
137        let shield2 = Shield::new("password", "service2");
138
139        let encrypted = shield1.encrypt(b"secret").unwrap();
140
141        assert!(shield2.decrypt(&encrypted).is_err());
142    }
143}