1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
//use super::*;
use crate::{
core::{
// removed unused KyberKeyFunctions per clippy
KeyControlVariant,
},
cryptography::{
hmac_sign::{Operation, Sign, SignType},
*,
},
error::CryptError,
*,
};
use aes::{
cipher::{generic_array::GenericArray, BlockDecrypt, BlockEncrypt, KeyInit},
Aes128, Aes256,
};
use std::{fs, path::PathBuf, result::Result};
use cbc::{
cipher::{BlockDecryptMut, BlockEncryptMut, KeyIvInit},
Decryptor as CbcDecryptor, Encryptor as CbcEncryptor,
};
use block_padding::Pkcs7;
use rand::Rng;
type Aes128CbcEnc = CbcEncryptor<Aes128>;
type Aes128CbcDec = CbcDecryptor<Aes128>;
/// Provides AES encryption functionality, handling cryptographic information and shared secrets.
impl CipherAES {
/// Initializes a new `CipherAES` instance with the provided cryptographic information.
///
/// # Parameters
/// - `infos`: Cryptographic information detailing the encryption or decryption process, content type, and more.
///
/// # Returns
/// A new instance of `CipherAES`.
pub fn new(infos: CryptographicInformation) -> Self {
CipherAES {
infos,
sharedsecret: Vec::new(),
}
}
/// Retrieves the current data intended for encryption or decryption.
///
/// # Returns
/// The data as a vector of bytes (`Vec<u8>`) or a `CryptError` if the content cannot be accessed.
pub fn get_data(&self) -> Result<Vec<u8>, CryptError> {
let data = &self.infos.content()?;
let data = data.to_vec();
Ok(data)
}
/// Sets the shared secret key used for AES encryption and decryption.
///
/// # Parameters
/// - `sharedsecret`: The shared secret as a byte vector.
///
/// # Returns
/// A mutable reference to the `CipherAES` instance, allowing for chaining of operations.
pub fn set_shared_secret(&mut self, sharedsecret: Vec<u8>) -> &Self {
self.sharedsecret = sharedsecret;
self
}
/// Retrieves the shared secret key.
///
/// # Returns
/// A reference to the shared secret as a byte vector or a `CryptError` if it cannot be accessed.
pub fn sharedsecret(&self) -> Result<&Vec<u8>, CryptError> {
Ok(&self.sharedsecret)
}
/// Retrieves the shared secret key.
///
/// # Returns
/// A reference to the shared secret as a byte vector or a `CryptError` if it cannot be accessed.
fn encryption(&mut self) -> Result<Vec<u8>, CryptError> {
let file_contained = self.infos.contains_file()?;
if file_contained && self.infos.metadata.content_type == ContentType::File {
self.infos.content = fs::read(self.infos.location()?).unwrap();
}
let encrypted_data = self.encrypt_aes()?;
// println!("Encrypted Data: {:?}", encrypted_data);
let passphrase = self.infos.passphrase()?.to_vec();
let mut hmac = Sign::new(
encrypted_data,
passphrase,
Operation::Sign,
SignType::Sha512,
);
let data = hmac.hmac();
if self.infos.safe()? {
self.infos.set_data(&data)?;
self.infos.safe_file()?;
}
Ok(data)
}
/// Saves the ciphertext to a file specified within the cryptographic information's location.
///
/// # Parameters
/// - `encrypted_data`: The ciphertext to be saved.
///
/// # Returns
/// An `Ok(())` upon successful save or a `CryptError` if saving fails.
#[allow(dead_code)]
fn save_ciphertext(&self, _encrypted_data: &[u8]) -> Result<(), CryptError> {
use std::{fs::File, io::Write};
if let Some(file_metadata) = &self.infos.location {
let file_path = file_metadata.parent()?;
let filename = format!("{}/ciphertext.pem", file_path.as_os_str().to_str().unwrap());
let file_path_with_enc = PathBuf::from(filename);
let mut buffer =
File::create(file_path_with_enc).map_err(|_| CryptError::WriteError)?;
buffer
.write_all(self.sharedsecret()?)
.map_err(|_| CryptError::WriteError)?;
Ok(())
} else {
Err(CryptError::PathError)
}
}
/// Encrypts the provided data with AES-256.
///
/// # Returns
/// A result containing the encrypted data as a byte vector or a `CryptError` if encryption fails.
fn encrypt_aes(&mut self) -> Result<Vec<u8>, CryptError> {
let block_size = 16;
let mut padded_data = self.get_data()?;
// Padding the data if necessary
let padding_needed = block_size - (padded_data.len() % block_size);
padded_data.extend(vec![padding_needed as u8; padding_needed]);
let mut encrypted_data = vec![0u8; padded_data.len()];
let sharedsecret = self.sharedsecret()?;
let cipher = Aes256::new(GenericArray::from_slice(sharedsecret));
for (chunk, encrypted_chunk) in padded_data
.chunks(block_size)
.zip(encrypted_data.chunks_mut(block_size))
{
let mut block = GenericArray::clone_from_slice(chunk);
cipher.encrypt_block(&mut block);
encrypted_chunk.copy_from_slice(&block);
}
Ok(encrypted_data)
}
#[allow(dead_code)]
fn generate_cbc_iv(&mut self) -> Result<Vec<u8>, CryptError> {
let mut iv = vec![0u8; 16];
let mut rng = rand::thread_rng();
let _ = rng.try_fill(&mut iv[..]);
Ok(iv)
}
/// Encrypts the provided data using AES-256 in CBC mode.
/// This function securely generates an IV for each encryption operation.
pub fn aes_cbc_encrypt(&mut self) -> Result<Vec<u8>, CryptError> {
let data = self.get_data()?;
let key = GenericArray::from_slice(&self.sharedsecret);
let mut iv = vec![0u8; 16]; // AES block size
rand::thread_rng().fill(&mut iv[..]);
let iv_arr = GenericArray::from_slice(&iv);
let cipher = Aes128CbcEnc::new(key, iv_arr);
let mut buffer = data.to_owned(); // Use to_owned() to duplicate data
let ciphertext = cipher
.encrypt_padded_mut::<Pkcs7>(&mut buffer, data.len())
.map_err(|_| CryptError::EncryptionFailed)?;
// Prepend IV to the ciphertext to use it during decryption
let mut result = iv;
result.extend_from_slice(ciphertext);
Ok(result)
}
/// Decrypts data encrypted using AES-256 in CBC mode.
/// Assumes the IV is prepended to the ciphertext.
pub fn aes_cbc_decrypt(&mut self, ciphertext: &[u8]) -> Result<Vec<u8>, CryptError> {
if ciphertext.len() < 16 {
return Err(CryptError::InvalidDataLength); // Ensure there's enough data for the IV
}
let (iv, encrypted_data) = ciphertext.split_at(16);
let key = GenericArray::from_slice(&self.sharedsecret);
let iv_arr = GenericArray::from_slice(iv);
let cipher = Aes128CbcDec::new(key, iv_arr);
let mut buffer = encrypted_data.to_vec();
cipher
.decrypt_padded_mut::<Pkcs7>(&mut buffer)
.map_err(|_| CryptError::DecryptionFailed)?;
Ok(buffer)
}
/// Decrypts data using AES-256.
///
/// # Returns
/// The decrypted data as a byte vector or a `CryptError` if decryption fails.
fn decryption(&mut self) -> Result<Vec<u8>, CryptError> {
let file_contained = self.infos.contains_file()?;
if file_contained && self.infos.metadata.content_type == ContentType::File {
self.infos.content = fs::read(self.infos.location()?).unwrap();
}
let encrypted_data_with_hmac = self.infos.content()?.to_vec();
let passphrase = self.infos.passphrase()?.to_vec();
// println!("Data Length: {}", encrypted_data_with_hmac.len());
let mut verifier = Sign::new(
encrypted_data_with_hmac,
passphrase,
Operation::Verify,
SignType::Sha512,
);
let verified_data = verifier.hmac();
self.infos.set_data(&verified_data)?;
// println!("{:?}", verified_data);
let data = self.decrypt_aes()?;
if self.infos.safe()? {
self.infos.set_data(&data)?;
self.infos.safe_file()?;
}
// println!("Decrypted Data: {:?}", data);
Ok(data)
}
/// Decrypts the provided data with AES-256.
///
/// # Returns
/// A result containing the decrypted data as a byte vector or a `CryptError` if decryption fails.
fn decrypt_aes(&mut self) -> Result<Vec<u8>, CryptError> {
let data = &self.infos.content()?;
let block_size = 16;
// Ensure the data length is a multiple of the block size
if data.len() % block_size != 0 {
return Err(CryptError::InvalidDataLength);
}
let mut decrypted_data = vec![0u8; data.len()];
let sharedsecret = self.sharedsecret()?;
let cipher = Aes256::new(GenericArray::from_slice(sharedsecret));
for (chunk, decrypted_chunk) in data
.chunks(block_size)
.zip(decrypted_data.chunks_mut(block_size))
{
let mut block = GenericArray::clone_from_slice(chunk);
cipher.decrypt_block(&mut block);
decrypted_chunk.copy_from_slice(&block);
}
if let Some(&padding_length) = decrypted_data.last() {
decrypted_data.truncate(decrypted_data.len() - padding_length as usize);
}
Ok(decrypted_data)
}
}
impl CryptographicFunctions for CipherAES {
/// Performs the encryption process using a public key.
///
/// # Parameters
/// - `public_key`: The public key for encryption.
///
/// # Returns
/// A result containing the encrypted data and the ciphertext as a key, or a `CryptError`.
fn encrypt(&mut self, public_key: Vec<u8>) -> Result<(Vec<u8>, Vec<u8>), CryptError> {
let key = KeyControlVariant::new(self.infos.metadata.key_type()?);
let (sharedsecret, ciphertext) = key.encap(&public_key)?;
// println!("Shared secret: {:?}\nLength: {}", sharedsecret, sharedsecret.len());
let _ = self.set_shared_secret(sharedsecret);
Ok((self.encryption()?, ciphertext))
}
/// Performs the decryption process using a secret key and ciphertext.
///
/// # Parameters
/// - `secret_key`: The secret key for decryption.
/// - `ciphertext`: The ciphertext to decrypt.
///
/// # Returns
/// The decrypted data as a byte vector or a `CryptError` if decryption fails.
fn decrypt(&mut self, secret_key: Vec<u8>, ciphertext: Vec<u8>) -> Result<Vec<u8>, CryptError> {
let key = KeyControlVariant::new(self.infos.metadata.key_type()?);
let sharedsecret = key.decap(&secret_key, &ciphertext)?;
// println!("shared secret: {:?}\nLength: {}", sharedsecret, sharedsecret.len());
let _ = self.set_shared_secret(sharedsecret);
self.decryption()
}
}