secured_enclave/
lib.rs

1pub mod errors;
2pub mod traits;
3
4pub use errors::EnclaveError;
5pub use traits::{Decryptable, Encryptable};
6
7pub use secured_cipher::{
8  algorithm::chacha20::CHACHA20_NONCE_SIZE, random_bytes, Cipher, Key, KeyDerivationStrategy,
9  SignedEnvelope,
10};
11
12const KEY_SIZE: usize = 32;
13const NONCE_SIZE: usize = CHACHA20_NONCE_SIZE;
14
15/// `Enclave` acts as a container for encrypted data, including metadata and the encrypted content itself.
16///
17/// Metadata is unencrypted and can be used to store information about the data,
18/// while the actual data is securely encrypted.
19///
20/// # Type Parameters
21/// * `T`: The type of metadata associated with the encrypted data.
22#[derive(Debug, Clone)]
23pub struct Enclave<T> {
24  /// Metadata associated with the encrypted data.
25  pub metadata: T,
26
27  /// The encrypted data.
28  pub encrypted_bytes: Box<[u8]>,
29
30  /// The nonce used in the encryption process, 8 bytes long (ChaCha20).
31  pub nonce: [u8; NONCE_SIZE],
32}
33
34impl<T> Enclave<T>
35where
36  T: TryFrom<Vec<u8>> + Into<Vec<u8>> + Clone,
37{
38  /// Creates a new `Enclave` instance from unencrypted data.
39  ///
40  /// # Arguments
41  /// * `metadata`: The metadata to be associated with the encrypted data.
42  /// * `key`: A 32-byte cipher key used for encryption.
43  /// * `plain_bytes`: The data to be encrypted.
44  ///
45  /// # Returns
46  /// A `Result` containing the newly created `Enclave` instance, or an error string if encryption fails.
47  pub fn from_plain_bytes(
48    metadata: T,
49    key: [u8; KEY_SIZE],
50    plain_bytes: Vec<u8>,
51  ) -> Result<Self, String> {
52    let nonce = random_bytes::<NONCE_SIZE>();
53    let mut cipher = Cipher::default();
54    cipher.init(&key, &nonce);
55
56    let encrypted_bytes = cipher.encrypt(&plain_bytes);
57    let envelope: Vec<u8> = cipher
58      .sign(&metadata.clone().into(), &encrypted_bytes)
59      .into();
60
61    Ok(Enclave {
62      metadata,
63      encrypted_bytes: envelope.into_boxed_slice(),
64      nonce,
65    })
66  }
67
68  /// Decrypts the contents of the enclave using a provided key.
69  ///
70  /// # Arguments
71  /// * `key`: The 32-byte cipher key used for decryption.
72  ///
73  /// # Returns
74  /// A `Result` containing the decrypted data as a vector of bytes, or an error string if decryption fails.
75  pub fn decrypt(&self, key: [u8; KEY_SIZE]) -> Result<Vec<u8>, EnclaveError> {
76    let envelope = SignedEnvelope::from(self.encrypted_bytes.to_vec());
77
78    Ok(
79      Cipher::default()
80        .init(&key, &self.nonce)
81        .decrypt_and_verify(&envelope)?,
82    )
83  }
84
85  /// Recovers the key used to encrypt the enclave using a provided password.
86  ///
87  /// # Arguments
88  /// * `encrypted_bytes`: The encrypted enclave.
89  ///
90  /// # Returns
91  /// A `Result` containing the recovered key, or an error string if recovery fails.
92  pub fn recover_key(
93    encrypted_bytes: &[u8],
94    password: &[u8],
95  ) -> Result<Key<KEY_SIZE, 16>, EnclaveError> {
96    let strategy = KeyDerivationStrategy::try_from(
97      encrypted_bytes[encrypted_bytes.len() - 9..encrypted_bytes.len()].to_vec(),
98    )?;
99    let salt: [u8; 16] = encrypted_bytes[encrypted_bytes.len() - 25..encrypted_bytes.len() - 9]
100      .try_into()
101      .unwrap();
102    let key = Key::<KEY_SIZE, 16>::with_salt(password, salt, strategy);
103
104    Ok(key)
105  }
106}
107
108impl<T> From<Enclave<T>> for Vec<u8>
109where
110  T: TryFrom<Vec<u8>> + Into<Vec<u8>>,
111{
112  /// Serializes an `Enclave` instance into a byte vector.
113  ///
114  /// # Arguments
115  /// * `enclave`: The `Enclave` instance to be serialized.
116  ///
117  /// # Returns
118  /// A `Vec<u8>` representing the serialized enclave.
119  fn from(enclave: Enclave<T>) -> Vec<u8> {
120    let mut bytes: Vec<u8> = vec![];
121    let metadata_bytes = enclave.metadata.into();
122
123    bytes.append(&mut vec![u8::try_from(metadata_bytes.len()).unwrap()]);
124    bytes.append(&mut metadata_bytes.into());
125    bytes.append(&mut enclave.encrypted_bytes.into());
126    bytes.append(&mut enclave.nonce.to_vec());
127
128    bytes
129  }
130}
131
132impl<T> TryFrom<Vec<u8>> for Enclave<T>
133where
134  T: TryFrom<Vec<u8>> + Into<Vec<u8>>,
135{
136  type Error = EnclaveError;
137
138  /// Deserializes a byte vector into an `Enclave` instance.
139  ///
140  /// # Arguments
141  /// * `bytes`: The byte vector representing the serialized enclave.
142  ///
143  /// # Returns
144  /// A `Result` containing the deserialized `Enclave` instance, or an `EnclaveError` if deserialization fails.
145  fn try_from(bytes: Vec<u8>) -> Result<Self, EnclaveError> {
146    if bytes.len() == 0 {
147      return Err(EnclaveError::Deserialization("No bytes found".to_string()));
148    }
149    let metadata_len = bytes[0];
150    if usize::from(metadata_len) > bytes.len() {
151      return Err(EnclaveError::Deserialization(
152        "unexpected metadata length".to_string(),
153      ));
154    }
155    let metadata = T::try_from(bytes[1..metadata_len as usize + 1].to_vec()).or(Err(
156      EnclaveError::Deserialization("error deserializing metadata".to_string()),
157    ))?;
158    let encrypted_bytes = bytes[metadata_len as usize + 1..bytes.len() - NONCE_SIZE].to_vec();
159    let nonce = bytes[bytes.len() - NONCE_SIZE..bytes.len()].to_vec();
160
161    Ok(Enclave {
162      metadata,
163      encrypted_bytes: encrypted_bytes.into_boxed_slice(),
164      nonce: nonce.try_into().or(Err(EnclaveError::Deserialization(
165        "unexpected bytes length".to_string(),
166      )))?,
167    })
168  }
169}
170
171impl<T> PartialEq for Enclave<T>
172where
173  T: PartialEq + TryFrom<Vec<u8>> + Into<Vec<u8>>,
174{
175  /// Compares two `Enclave` instances for equality.
176  ///
177  /// # Arguments
178  /// * `other`: Another `Enclave` instance to compare with.
179  ///
180  /// # Returns
181  /// `true` if both `Enclave` instances are equal, `false` otherwise.
182  fn eq(&self, other: &Self) -> bool {
183    self.metadata == other.metadata
184      && self.encrypted_bytes == other.encrypted_bytes
185      && self.nonce == other.nonce
186  }
187}
188
189impl Encryptable<KEY_SIZE> for Vec<u8> {
190  /// Encrypts a vector of bytes using a provided password.
191  ///
192  /// # Arguments
193  /// * `password`: The password to use for key derivation.
194  /// * `strategy`: The key derivation strategy to use.
195  ///
196  /// # Returns
197  /// A `Vec<u8>` containing the encrypted data.
198  fn encrypt(&self, password: String, strategy: KeyDerivationStrategy) -> Vec<u8> {
199    let key: Key<32, 16> = Key::new(password.as_bytes(), strategy.clone());
200    let enclave = Enclave::from_plain_bytes(vec![], key.pubk, self.clone()).unwrap();
201
202    [enclave.into(), key.salt.to_vec(), strategy.into()].concat()
203  }
204
205  /// Encrypts a vector of bytes using a provided key.
206  ///
207  /// # Arguments
208  /// * `key`: The 32-byte cipher key used for encryption.
209  ///
210  /// # Returns
211  /// A `Vec<u8>` containing the encrypted data.
212  fn encrypt_with_key(&self, key: &Key<32, 16>) -> Vec<u8> {
213    let enclave = Enclave::from_plain_bytes(vec![], key.pubk, self.clone()).unwrap();
214    [
215      enclave.into(),
216      key.salt.to_vec(),
217      key.strategy.clone().into(),
218    ]
219    .concat()
220  }
221
222  /// Encrypts a vector of bytes using a provided key.
223  ///
224  /// # Arguments
225  /// * `key`: The 32-byte cipher key used for encryption.
226  ///
227  /// # Returns
228  /// A `Vec<u8>` containing the encrypted data.
229  fn encrypt_with_raw_key(&self, key: [u8; KEY_SIZE]) -> Vec<u8> {
230    let enclave = Enclave::from_plain_bytes(vec![], key, self.clone()).unwrap();
231    enclave.into()
232  }
233
234  /// Encrypts a vector of bytes using a provided key and metadata.
235  ///
236  /// # Arguments
237  /// * `key`: The 32-byte cipher key used for encryption.
238  /// * `metadata`: The metadata to be associated with the encrypted data.
239  ///
240  /// # Returns
241  /// A `Vec<u8>` containing the encrypted data.
242  fn encrypt_with_metadata<M>(&self, key: [u8; KEY_SIZE], metadata: M) -> Vec<u8>
243  where
244    M: From<Vec<u8>> + Into<Vec<u8>> + Clone,
245  {
246    let enclave = Enclave::from_plain_bytes(metadata, key, self.clone()).unwrap();
247    enclave.into()
248  }
249}
250
251impl Decryptable<KEY_SIZE> for Vec<u8> {
252  /// Decrypts a slice of bytes using a provided password.
253  ///
254  /// # Arguments
255  /// * `password`: The password to use for decryption.
256  ///
257  /// # Returns
258  /// A `Result` containing the decrypted data as a vector of bytes, or an error string if decryption fails.
259  fn decrypt(&self, password: String) -> Result<Vec<u8>, EnclaveError> {
260    let strategy = KeyDerivationStrategy::try_from(self[self.len() - 9..self.len()].to_vec())?;
261    let salt: [u8; 16] = self[self.len() - 25..self.len() - 9].try_into().unwrap();
262    let key = Key::<KEY_SIZE, 16>::with_salt(password.as_bytes(), salt, strategy);
263
264    let enclave = Enclave::<Vec<u8>>::try_from(self[..self.len() - 25].to_vec())?;
265
266    enclave.decrypt(key.pubk)
267  }
268
269  /// Decrypts a slice of bytes using a provided key.
270  ///
271  /// # Arguments
272  /// * `key`: The 32-byte cipher key used for decryption.
273  ///
274  /// # Returns
275  /// A `Result` containing the decrypted data as a vector of bytes, or an error string if decryption fails.
276  fn decrypt_with_key(&self, key: [u8; KEY_SIZE]) -> Result<Vec<u8>, EnclaveError> {
277    let enclave = Enclave::<Vec<u8>>::try_from(self.clone())?;
278    enclave.decrypt(key)
279  }
280
281  /// Decrypts a slice of bytes using a provided key.
282  ///
283  /// # Arguments
284  /// * `key`: The 32-byte cipher key used for decryption.
285  ///
286  /// # Returns
287  /// A `Result` containing the decrypted data as a vector of bytes, or an error string if decryption fails.
288  fn decrypt_with_metadata<M>(&self, key: [u8; KEY_SIZE]) -> Result<(Vec<u8>, M), EnclaveError>
289  where
290    M: TryFrom<Vec<u8>> + Into<Vec<u8>> + Clone,
291  {
292    let enclave = Enclave::<M>::try_from(self.clone())?;
293    let decrypted_bytes = enclave.decrypt(key)?;
294    Ok((decrypted_bytes, enclave.metadata))
295  }
296}
297
298impl Decryptable<KEY_SIZE> for &[u8] {
299  /// Decrypts a slice of bytes using a provided password.
300  ///
301  /// # Arguments
302  /// * `password`: The password to use for decryption.
303  ///
304  /// # Returns
305  /// A `Result` containing the decrypted data as a vector of bytes, or an error string if decryption fails.
306  fn decrypt(&self, password: String) -> Result<Vec<u8>, EnclaveError> {
307    self.to_vec().decrypt(password)
308  }
309
310  /// Decrypts a slice of bytes using a provided key.
311  ///
312  /// # Arguments
313  /// * `key`: The 32-byte cipher key used for decryption.
314  ///
315  /// # Returns
316  /// A `Result` containing the decrypted data as a vector of bytes, or an error string if decryption fails.
317  fn decrypt_with_key(&self, key: [u8; KEY_SIZE]) -> Result<Vec<u8>, EnclaveError> {
318    self.to_vec().decrypt_with_key(key)
319  }
320
321  /// Decrypts a slice of bytes using a provided key.
322  ///
323  /// # Arguments
324  /// * `key`: The 32-byte cipher key used for decryption.
325  ///
326  /// # Returns
327  /// A `Result` containing the decrypted data as a vector of bytes, or an error string if decryption fails.
328  fn decrypt_with_metadata<M>(&self, key: [u8; KEY_SIZE]) -> Result<(Vec<u8>, M), EnclaveError>
329  where
330    M: TryFrom<Vec<u8>> + Into<Vec<u8>> + Clone,
331  {
332    self.to_vec().decrypt_with_metadata(key)
333  }
334}
335
336impl Encryptable<KEY_SIZE> for &[u8] {
337  /// Encrypts a slice of bytes using a provided password.
338  ///
339  /// # Arguments
340  /// * `password`: The password to use for key derivation.
341  /// * `strategy`: The key derivation strategy to use.
342  ///
343  /// # Returns
344  /// A `Vec<u8>` containing the encrypted data.
345  fn encrypt(&self, password: String, strategy: KeyDerivationStrategy) -> Vec<u8> {
346    self.to_vec().encrypt(password, strategy)
347  }
348
349  /// Encrypts a slice of bytes using a provided key.
350  ///
351  /// # Arguments
352  /// * `key`: The 32-byte cipher key used for encryption.
353  ///
354  /// # Returns
355  /// A `Vec<u8>` containing the encrypted data.
356  fn encrypt_with_key(&self, key: &Key<32, 16>) -> Vec<u8> {
357    self.to_vec().encrypt_with_key(key)
358  }
359
360  /// Encrypts a slice of bytes using a provided key.
361  ///
362  /// # Arguments
363  /// * `key`: The 32-byte cipher key used for encryption.
364  ///
365  /// # Returns
366  /// A `Vec<u8>` containing the encrypted data.
367  fn encrypt_with_raw_key(&self, key: [u8; KEY_SIZE]) -> Vec<u8> {
368    self.to_vec().encrypt_with_raw_key(key)
369  }
370
371  /// Encrypts a slice of bytes using a provided key and metadata.
372  ///
373  /// # Arguments
374  /// * `key`: The 32-byte cipher key used for encryption.
375  /// * `metadata`: The metadata to be associated with the encrypted data.
376  ///
377  /// # Returns
378  /// A `Vec<u8>` containing the encrypted data.
379  fn encrypt_with_metadata<M>(&self, key: [u8; KEY_SIZE], metadata: M) -> Vec<u8>
380  where
381    M: From<Vec<u8>> + Into<Vec<u8>> + Clone,
382  {
383    self.to_vec().encrypt_with_metadata(key, metadata)
384  }
385}
386
387impl Encryptable<KEY_SIZE> for String {
388  /// Encrypts a string using a provided password.
389  ///
390  /// # Arguments
391  /// * `key`: The 32-byte cipher key used for encryption.
392  /// * `strategy`: The key derivation strategy to use.
393  ///
394  /// # Returns
395  /// A `Vec<u8>` containing the encrypted data.
396  fn encrypt(&self, password: String, strategy: KeyDerivationStrategy) -> Vec<u8> {
397    self.as_bytes().to_vec().encrypt(password, strategy)
398  }
399
400  /// Encrypts a String using a provided key.
401  ///
402  /// # Arguments
403  /// * `key`: The 32-byte cipher key used for encryption.
404  ///
405  /// # Returns
406  /// A `Vec<u8>` containing the encrypted data.
407  fn encrypt_with_key(&self, key: &Key<32, 16>) -> Vec<u8> {
408    self.as_bytes().to_vec().encrypt_with_key(key)
409  }
410
411  /// Encrypts a String using a provided key.
412  ///
413  /// # Arguments
414  /// * `key`: The 32-byte cipher key used for encryption.
415  ///
416  /// # Returns
417  /// A `Vec<u8>` containing the encrypted data.
418  fn encrypt_with_raw_key(&self, key: [u8; KEY_SIZE]) -> Vec<u8> {
419    self.as_bytes().to_vec().encrypt_with_raw_key(key)
420  }
421
422  /// Encrypts a String using a provided key and metadata.
423  ///
424  /// # Arguments
425  /// * `key`: The 32-byte cipher key used for encryption.
426  /// * `metadata`: The metadata to be associated with the encrypted data.
427  ///
428  /// # Returns
429  /// A `Vec<u8>` containing the encrypted data.
430  fn encrypt_with_metadata<M>(&self, key: [u8; KEY_SIZE], metadata: M) -> Vec<u8>
431  where
432    M: From<Vec<u8>> + Into<Vec<u8>> + Clone,
433  {
434    self
435      .as_bytes()
436      .to_vec()
437      .encrypt_with_metadata(key, metadata)
438  }
439}
440
441impl Encryptable<KEY_SIZE> for &str {
442  /// Encrypts a &str using a provided password.
443  ///
444  /// # Arguments
445  /// * `password`: The password to use for key derivation.
446  ///
447  /// # Returns
448  /// A `Vec<u8>` containing the encrypted data.
449  fn encrypt(&self, password: String, strategy: KeyDerivationStrategy) -> Vec<u8> {
450    self.as_bytes().to_vec().encrypt(password, strategy)
451  }
452
453  /// Encrypts a string using a provided key.
454  ///
455  /// # Arguments
456  /// * `key`: The 32-byte cipher key used for encryption.
457  ///
458  /// # Returns
459  /// A `Vec<u8>` containing the encrypted data.
460  fn encrypt_with_key(&self, key: &Key<32, 16>) -> Vec<u8> {
461    self.as_bytes().to_vec().encrypt_with_key(key)
462  }
463
464  /// Encrypts a string using a provided key.
465  ///
466  /// # Arguments
467  /// * `key`: The 32-byte cipher key used for encryption.
468  ///
469  /// # Returns
470  /// A `Vec<u8>` containing the encrypted data.
471  fn encrypt_with_raw_key(&self, key: [u8; KEY_SIZE]) -> Vec<u8> {
472    self.as_bytes().to_vec().encrypt_with_raw_key(key)
473  }
474
475  /// Encrypts an &str using a provided key and metadata.
476  ///
477  /// # Arguments
478  /// * `key`: The 32-byte cipher key used for encryption.
479  /// * `metadata`: The metadata to be associated with the encrypted data.
480  ///
481  /// # Returns
482  /// A `Vec<u8>` containing the encrypted data.
483  fn encrypt_with_metadata<M>(&self, key: [u8; KEY_SIZE], metadata: M) -> Vec<u8>
484  where
485    M: From<Vec<u8>> + Into<Vec<u8>> + Clone,
486  {
487    self
488      .as_bytes()
489      .to_vec()
490      .encrypt_with_metadata(key, metadata)
491  }
492}
493
494#[cfg(test)]
495mod tests {
496  use super::*;
497
498  mod from_plain_bytes {
499    use super::*;
500
501    #[test]
502    fn it_should_create_enclave() {
503      let key = [0u8; KEY_SIZE];
504      let bytes = [0u8, 1u8, 2u8, 3u8, 4u8].to_vec();
505
506      let safe = Enclave::from_plain_bytes(b"metadata".to_owned(), key, bytes);
507
508      assert!(safe.is_ok());
509      assert_eq!(safe.unwrap().metadata, b"metadata".to_owned());
510    }
511  }
512
513  mod decrypt {
514    use super::*;
515
516    #[test]
517    fn it_should_decrypt_enclave() {
518      let key = [0u8; KEY_SIZE];
519      let bytes = [0u8, 1u8, 2u8, 3u8, 4u8].to_vec();
520      let safe = Enclave::from_plain_bytes(b"metadata".to_vec(), key, bytes.clone()).unwrap();
521
522      let decrypted_bytes = safe.decrypt(key);
523
524      assert!(decrypted_bytes.is_ok());
525      assert_eq!(decrypted_bytes.unwrap(), bytes);
526    }
527
528    #[test]
529    fn it_should_fail_with_wrong_key() {
530      let key = [0u8; KEY_SIZE];
531      let bytes = [0u8, 1u8, 2u8, 3u8, 4u8].to_vec();
532      let safe = Enclave::from_plain_bytes(b"metadata".to_vec(), key, bytes.clone()).unwrap();
533      let wrong_key = [1u8; KEY_SIZE];
534
535      let decrypted_bytes = safe.decrypt(wrong_key);
536
537      assert!(!decrypted_bytes.is_ok());
538    }
539
540    #[test]
541    fn it_should_serialize_and_deserialize_to_bytes() {
542      let key = [0u8; KEY_SIZE];
543      let bytes = [0u8, 1u8, 2u8, 3u8, 4u8].to_vec();
544      let enclave = Enclave::from_plain_bytes([0_u8, 1_u8], key, bytes.clone()).unwrap();
545
546      let serialized: Vec<u8> = enclave.clone().into();
547      let deserialized = Enclave::try_from(serialized).unwrap();
548
549      assert_eq!(enclave, deserialized);
550    }
551
552    #[test]
553    fn vec_u8_should_be_encryptable_and_decryptable_with_password() {
554      let bytes = [0u8, 1u8, 2u8, 3u8, 4u8].to_vec();
555      let password = "my password".to_string();
556
557      // Using a low number of iterations here because tests are slow
558      let encrypted_bytes = bytes.encrypt(password.clone(), KeyDerivationStrategy::PBKDF2(10_000));
559      let decrypted_bytes = encrypted_bytes.decrypt(password);
560
561      assert!(decrypted_bytes.is_ok());
562      assert_eq!(decrypted_bytes.unwrap(), bytes);
563    }
564
565    #[test]
566    fn vec_u8_should_be_encryptable_and_decryptable_with_key() {
567      let bytes = [0u8, 1u8, 2u8, 3u8, 4u8].to_vec();
568      let key = [0u8; KEY_SIZE];
569
570      let encrypted_bytes = bytes.encrypt_with_raw_key(key);
571      let decrypted_bytes = encrypted_bytes.decrypt_with_key(key);
572
573      assert!(decrypted_bytes.is_ok());
574      assert_eq!(decrypted_bytes.unwrap(), bytes);
575    }
576
577    #[test]
578    fn vec_u8_should_be_encryptable_and_decryptable_with_metadata() {
579      let bytes = [0u8, 1u8, 2u8, 3u8, 4u8].to_vec();
580      let key = [0u8; KEY_SIZE];
581
582      let encrypted_bytes = bytes.encrypt_with_metadata(key, b"metadata".to_vec());
583      let decrypted_bytes = encrypted_bytes.decrypt_with_metadata::<Vec<u8>>(key);
584
585      assert!(decrypted_bytes.is_ok());
586      assert_eq!(decrypted_bytes.unwrap(), (bytes, b"metadata".to_vec()));
587    }
588
589    #[test]
590    fn strings_should_be_encryptable_and_decryptable_with_password() {
591      let string = "my string".to_string();
592      let password = "my password".to_string();
593
594      // Using a low number of iterations here because tests are slow
595      let encrypted_bytes = string.encrypt(password.clone(), KeyDerivationStrategy::PBKDF2(10_000));
596      let decrypted_bytes = encrypted_bytes.decrypt(password);
597
598      assert!(decrypted_bytes.is_ok());
599      assert_eq!(decrypted_bytes.unwrap(), string.as_bytes());
600    }
601  }
602}