secured_cipher/lib.rs
1//! # Secured-Cipher Library
2//!
3//! `secured-cipher` is a Rust library offering an implementation of the ChaCha20 and XChaCha20 encryption algorithms.
4//! It provides both high-level and low-level cryptographic functionalities through a common interface.
5//!
6//! ## Overview
7//!
8//! The library includes the following key components:
9//!
10//! - `core`: A module containing essential ChaCha20 cryptographic functionalities.
11//! - `ChaCha20`: A struct for the ChaCha20 stream cipher algorithm.
12//! - `Cipher`: A struct that provides a common interface for cryptographic operations, focusing on encryption and decryption.
13//! - `CipherMode`: An enum to specify the mode of the cipher (only ChaCha20 for now).
14//!
15//! ## Features
16//!
17//! - High-level interfaces for ChaCha20 and XChaCha20 ciphers.
18//! - Common `Cipher` interface for encryption and decryption operations.
19//! - Flexible usage with support for both raw and high-level cryptographic operations.
20//!
21//! ## Usage
22//!
23//! ### Basic Encryption and Decryption
24//!
25//! This example demonstrates encrypting and decrypting data using the ChaCha20 cipher.
26//!
27//! ```rust
28//! use secured_cipher::Cipher;
29//!
30//! let key: [u8; 32] = [0; 32]; // Your key
31//! let nonce: [u8; 12] = [0; 12]; // Your nonce
32//! let data: &[u8] = b"Your data here"; // Data to be encrypted
33//!
34//! let mut cipher = Cipher::default();
35//! cipher.init(&key, &nonce);
36//!
37//! // Encrypt and decrypt
38//! let encrypted_data = cipher.encrypt(data);
39//! let decrypted_data = cipher.decrypt(&encrypted_data);
40//!
41//! // Sign - the secret evelope contains the encrypted data and its MAC (message authentication code)
42//! let signed_secret_envelope = cipher.sign(b"your readable header", &encrypted_data);
43//!
44//! // Decrypt and verify - the verified decrypted data is returned if the MAC is valid
45//! let verified_decrypted_data = cipher.decrypt_and_verify(&signed_secret_envelope);
46//!
47//! // if the MAC is invalid, the decryption will fail
48//! let is_decryption_ok = verified_decrypted_data.is_ok();
49//!
50//! println!("Decrypted and verified data: {:?}", verified_decrypted_data.unwrap());
51//!
52//! ```
53//!
54//! ## Modules
55//!
56//! - `core`: Core functionalities and algorithmic implementations.
57//! - `stream`: Internal stream cipher operations, including `ChaChaStream`.
58
59pub mod algorithm;
60
61pub use secured_cipher_key::{random_bytes, Key, KeyDerivationStrategy};
62
63pub use algorithm::{
64 AEADAlgorithm, AlgorithmKeyIVInit, AlgorithmKeyInit, AlgorithmProcess, AlgorithmProcessInPlace,
65 ChaCha20, EncryptionAlgorithm, Poly1305, SignedEnvelope,
66};
67
68use std::error::Error;
69
70/// The `Cipher` struct provides a common interface for cryptographic operations,
71/// specifically focusing on encryption and decryption.
72pub struct Cipher {
73 /// The cipher's internal encryption logic.
74 encryption: Box<dyn EncryptionAlgorithm>,
75
76 // The cipher's AEAD (authenticated encryption with associated data) logic.
77 aead: Box<dyn AEADAlgorithm>,
78}
79
80pub enum CipherMode {
81 ChaCha20Poly1305,
82 Custom(Box<dyn EncryptionAlgorithm>, Box<dyn AEADAlgorithm>),
83}
84
85impl Cipher {
86 /// Constructs a new `Cipher` instance using the specified cipher mode.
87 ///
88 /// # Arguments
89 /// * `mode` - The mode of cipher (ChaCha20 or Custom) to use.
90 ///
91 /// # Returns
92 /// A new instance of `Cipher`.
93 pub fn new(mode: CipherMode) -> Self {
94 let (encryption, aead): (Box<dyn EncryptionAlgorithm>, Box<dyn AEADAlgorithm>) = match mode {
95 CipherMode::ChaCha20Poly1305 => (Box::new(ChaCha20::new()), Box::new(Poly1305::new())),
96 CipherMode::Custom(encryption, aead) => (encryption, aead),
97 };
98
99 Self { encryption, aead }
100 }
101
102 /// Initializes the cipher with a key and IV (initialization vector).
103 /// Sets up the cipher's internal state for encryption or decryption.
104 ///
105 /// # Arguments
106 /// * `key` - A byte slice representing the key.
107 /// * `iv` - A byte slice representing the initialization vector.
108 ///
109 /// # Returns
110 /// A mutable reference to the cipher instance.
111 pub fn init(&mut self, key: &[u8], iv: &[u8]) -> &mut Self {
112 self.encryption.init(key, iv);
113
114 // The Poly1305 authenticator uses a subkey derived from the cipher's key.
115 // This subkey is generated by running the ChaCha20 permutation on a block of zeros.
116 self.aead.init(&self.encryption.process(&[0; 64]));
117
118 self
119 }
120
121 /// Encrypts the provided data.
122 ///
123 /// # Arguments
124 /// * `data` - A slice of data to be encrypted.
125 ///
126 /// # Returns
127 /// Encrypted data as a vector of bytes (`Bytes`).
128 pub fn encrypt(&mut self, data: &[u8]) -> Vec<u8> {
129 // Encrypt the data using the ChaCha20 permutation
130 self.encryption.process(data)
131 }
132
133 /// Signs the provided data.
134 ///
135 /// # Arguments
136 /// * `header` - A slice of unencrypted data to be signed.
137 /// * `data` - A slice of data to be signed.
138 ///
139 /// # Returns
140 /// A signed envelope containing the data and its MAC (message authentication code).
141 pub fn sign(&mut self, header: &[u8], data: &[u8]) -> SignedEnvelope {
142 let mac = self
143 .aead
144 .process(&[header.to_vec(), data.to_vec()].concat());
145
146 SignedEnvelope {
147 header: header.to_vec(),
148 data: data.into(),
149 mac,
150 }
151 }
152
153 /// Decrypts the provided data.
154 /// Note that this method does not provide any integrity checks. Most of the
155 /// use cases should be covered by `decrypt_and_verify()` instead.
156 ///
157 /// # Arguments
158 /// * `data` - A slice of data to be decrypted.
159 ///
160 /// # Returns
161 /// Decrypted data as a vector of bytes (`Bytes`).
162 pub fn decrypt(&mut self, data: &[u8]) -> Vec<u8> {
163 // Decrypt the data using the ChaCha20 permutation
164 self.encryption.process(data)
165 }
166
167 /// Decrypts the provided data and verifies the MAC.
168 ///
169 /// # Arguments
170 /// * `envelope` - A signed envelope containing encrypted data to be decrypted.
171 ///
172 /// # Returns
173 /// Decrypted data as a vector of bytes (`Bytes`), or an error in case of decryption failure.
174 pub fn decrypt_and_verify(&mut self, envelope: &SignedEnvelope) -> Result<Vec<u8>, CipherError> {
175 // Check the MAC (message authentication code) to ensure the integrity of the data
176 if envelope.mac
177 != self
178 .aead
179 .process(&[envelope.header.clone(), envelope.data.clone()].concat())
180 {
181 return Err(CipherError::AuthenticationFailed);
182 }
183
184 // Decrypt the data using the ChaCha20 permutation
185 Ok(self.encryption.process(&envelope.data))
186 }
187}
188
189impl Default for Cipher {
190 /// Provides a default instance of `Cipher` using the XChaCha20 mode.
191 ///
192 /// # Returns
193 /// A new instance of `Cipher` with XChaCha20 mode.
194 fn default() -> Self {
195 Self::new(CipherMode::ChaCha20Poly1305)
196 }
197}
198
199#[derive(Debug)]
200pub enum CipherError {
201 AuthenticationFailed,
202}
203
204impl Error for CipherError {}
205
206impl std::fmt::Display for CipherError {
207 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
208 match self {
209 CipherError::AuthenticationFailed => write!(f, "Authentication failed"),
210 }
211 }
212}