aft_crypto/
data.rs

1//! Data encryption with AEAD (Authenticated encryption).
2pub use aes_gcm::{
3    aead::{generic_array::GenericArray, rand_core::RngCore, AeadInPlace, KeyInit, OsRng},
4    Aes128Gcm, Aes256Gcm, Nonce, Tag, TagSize
5};
6use crate::exchange::KEY_LENGTH;
7use crate::errors::EncryptionErrors;
8use zeroize::Zeroize;
9
10pub type Result<T> = core::result::Result<T, EncryptionErrors>;
11pub type AesGcm128Enc = EncAlgo<Aes128Gcm>;
12pub type AesGcm256Enc = EncAlgo<Aes256Gcm>;
13
14/// Nonce size (in bytes) of AES-GCM (excludes 0)
15pub const AES_GCM_NONCE_SIZE: usize = 12;
16pub const AES_GCM_TAG_SIZE: usize = 16;
17
18#[derive(Debug, PartialEq, Eq)]
19pub enum Algo {
20    Aes128,
21    Aes256,
22    Unknown,
23}
24
25impl From<&str> for Algo {
26    fn from(v: &str) -> Self {
27        match v {
28            "aes128" => Algo::Aes128,
29            "aes256" => Algo::Aes256,
30            _ => Algo::Unknown
31        }
32    }
33}
34
35impl From<&Algo> for &str {
36    fn from(v: &Algo) -> Self {
37        match v {
38            Algo::Aes128 => "aes128",
39            Algo::Aes256 => "aes256",
40            Algo::Unknown => "unknown"
41        }
42    }
43}
44
45
46// Creates a new AES-GCM encryptor.
47macro_rules! create_aes_gcm_encryptor {
48    ($key:expr, $aesgcm:ident) => {{
49        let arr_key = GenericArray::from_slice($key);
50        $aesgcm::new(arr_key)
51    }};
52}
53
54#[macro_export]
55/// Quickly decrypt AES-GCM data.
56macro_rules! decrypt_aes_gcm {
57    ($encryptor:expr, $data:expr) => {
58        $encryptor.decrypt(
59            &$data[..$data.len()-AES_GCM_NONCE_SIZE], &$data[$data.len()-AES_GCM_NONCE_SIZE..])
60            .expect("Could not decrypt")
61    }
62} pub use decrypt_aes_gcm;
63
64pub trait EncryptorBase<CiAlgo>
65where
66    CiAlgo: AeadInPlace,
67{
68    /// Encrypt data without changing the original data.
69    fn encrypt(&self, data: &[u8]) -> Result<Vec<u8>> {
70        let mut encrypted_data = data.to_vec();
71        self.encrypt_in_place(&mut encrypted_data)?;
72
73        Ok(encrypted_data)
74    }
75
76    /// Decrypt data without changing the original data.
77    fn decrypt(&self, data: &[u8], nonce: &[u8]) -> Result<Vec<u8>> {
78        let mut decrypted_data = data.to_vec();
79        self.decrypt_in_place(&mut decrypted_data, nonce)?;
80
81        Ok(decrypted_data)
82    }
83
84    /// Encrypt data in-place.
85    fn encrypt_in_place(&self, data: &mut Vec<u8>) -> Result<()> {
86        // The nonce is 12 bytes (96 bits) long.
87        // According to NIST 38D, 12 bytes should be used for efficiency and simplicity.
88        let mut nonce = vec![0; AES_GCM_NONCE_SIZE];
89        OsRng.fill_bytes(&mut nonce);
90
91        // Note: authentication tag is appended to the encrypted data.
92        if self.get_encryptor().encrypt_in_place(Nonce::from_slice(&nonce), b"", data).is_err() {
93            return Err(EncryptionErrors::FailedEncrypt);
94        }
95
96        // Adding nonce to data
97        data.append(&mut nonce);
98
99        Ok(())
100    }
101
102    /// Decrypt data in-place.
103    fn decrypt_in_place(&self, data: &mut Vec<u8>, nonce: &[u8]) -> Result<()> {
104        let nonce = Nonce::from_slice(nonce);
105        if self.get_encryptor().decrypt_in_place(nonce, b"", data).is_err() {
106            return Err(EncryptionErrors::FailedDecrypt);
107        }
108
109        Ok(())
110    }
111
112    fn decrypt_in_place_detached(&self, data: &mut [u8], nonce: &[u8]) -> Result<()> {
113        if data.len() < AES_GCM_TAG_SIZE {
114            return Err(EncryptionErrors::InvalidLength);
115        }
116
117        let tag_pos = data.len() - AES_GCM_TAG_SIZE;
118        let (d, tag) = data.as_mut().split_at_mut(tag_pos);
119        // TODO: remove expect
120        self.get_encryptor().
121            decrypt_in_place_detached(nonce.into(), b"", d, Tag::from_slice(tag)).expect("FailedDecrypting");
122
123        Ok(())
124    }
125
126    fn get_encryptor(&self) -> &CiAlgo;
127}
128
129/// Struct to represent an object to encrypt data with some encryption algorithm.
130pub struct EncAlgo<T> {
131    key: [u8; KEY_LENGTH],
132    encryptor_func: fn(&[u8]) -> T,
133    encryptor: T,
134}
135
136impl<T> EncAlgo<T> {
137    pub fn new(key: &[u8; KEY_LENGTH], encryptor_func: fn(&[u8]) -> T) -> Self {
138        Self {
139            key: *key,
140            encryptor_func,
141            encryptor: encryptor_func(key),
142        }
143    }
144}
145
146impl<T> Clone for EncAlgo<T> {
147    fn clone(&self) -> Self {
148        Self {
149            key: self.key.clone(),
150            encryptor_func: self.encryptor_func,
151            encryptor: (self.encryptor_func)(&self.key),
152        }
153    }
154}
155
156/// Creates a new AES-GCM-128 encryptor.
157/// [`key`] must be at least 16 bytes long.
158pub fn create_128_encryptor(key: &[u8]) -> Aes128Gcm {
159    // AES-128 uses 16 bytes keys
160    create_aes_gcm_encryptor!(&key[..16], Aes128Gcm)
161}
162
163/// Creates a new AES-GCM-256 encryptor.
164/// [`key`] must be at least 32 bytes long.
165pub fn create_256_encryptor(key: &[u8]) -> Aes256Gcm {
166    // AES-256 uses 32 bytes keys
167    create_aes_gcm_encryptor!(&key[..32], Aes256Gcm)
168}
169
170impl<CiAlgo> EncryptorBase<CiAlgo> for EncAlgo<CiAlgo>
171where
172    CiAlgo: AeadInPlace,
173{
174    fn get_encryptor(&self) -> &CiAlgo {
175        &self.encryptor
176    }
177}
178
179/// Safe Data. Zeros when dropped.
180pub struct SData<T: Zeroize>(pub T);
181
182impl<T: Zeroize> Drop for SData<T> {
183    fn drop(&mut self) {
184        self.0.zeroize();
185    }
186}