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