prople_crypto/aead/
mod.rs

1//! `aead` is a module used to maintain the primary object of `AEAD (Authenticated Encryption with Associated Data`
2//!
3//! This module provides an abstraction to maintain `AEAD` on top of `aead` from `RustCrypto/traits` repository
4use rst_common::with_cryptography::chacha20poly1305::{
5    aead::{Aead, AeadCore, KeyInit},
6    XChaCha20Poly1305,
7};
8
9use rst_common::with_cryptography::rand::{rngs::adapter::ReseedingRng, SeedableRng};
10use rst_common::with_cryptography::rand_chacha::{rand_core::OsRng as RandCoreOsRng, ChaCha20Core};
11
12mod key;
13pub use key::Key;
14
15mod types;
16pub use types::{KeyEncryption, KeyNonce, MessageCipher, MessagePlain, Nonce};
17
18use crate::{passphrase::prelude::errors::CommonError, types::VectorValue};
19
20pub mod errors {
21    use rst_common::with_errors::thiserror::{self, Error};
22
23    /// `AeadError` used specifically when manage cipher management
24    /// specifically `AEAD`
25    #[derive(Debug, Error)]
26    pub enum AeadError {
27        #[error("aead: unable to parse bytes: `{0}`")]
28        CipherGeneratorError(String),
29    }
30}
31
32/// `AEAD` is a main entrypoint to encrypt and decrypt the given data (in bytes), and also
33/// generate nonce (in bytes)
34pub struct AEAD;
35
36impl AEAD {
37    pub fn nonce() -> Nonce {
38        let prng = ChaCha20Core::from_entropy();
39        let reseeding_rng = ReseedingRng::new(prng, 0, RandCoreOsRng);
40        let nonce = XChaCha20Poly1305::generate_nonce(reseeding_rng);
41        Nonce::from(nonce.to_vec())
42    }
43
44    pub fn encrypt(key: &Key, message: &MessagePlain) -> Result<MessageCipher, errors::AeadError> {
45        let (key_bytes, nonce_bytes) = AEAD::key_extractor(key)
46            .map_err(|err| errors::AeadError::CipherGeneratorError(err.to_string()))?;
47
48        let cipher = XChaCha20Poly1305::new(&key_bytes.into());
49        cipher
50            .encrypt(&nonce_bytes.into(), message.vec().as_slice())
51            .map(MessageCipher::from)
52            .map_err(|err| errors::AeadError::CipherGeneratorError(err.to_string()))
53    }
54
55    pub fn decrypt(
56        key: &Key,
57        encrypted: &MessageCipher,
58    ) -> Result<MessagePlain, errors::AeadError> {
59        let (key_bytes, nonce_bytes) = AEAD::key_extractor(key)
60            .map_err(|err| errors::AeadError::CipherGeneratorError(err.to_string()))?;
61
62        let cipher = XChaCha20Poly1305::new(&key_bytes.into());
63        cipher
64            .decrypt(&nonce_bytes.into(), encrypted.vec().as_ref())
65            .map(MessagePlain::from)
66            .map_err(|err| errors::AeadError::CipherGeneratorError(err.to_string()))
67    }
68
69    fn key_extractor(key: &Key) -> Result<([u8; 32], [u8; 24]), CommonError> {
70        let nonce_bytes = key.get_nonce_bytes()?;
71        let key_bytes = key.get_key_bytes()?;
72
73        Ok((key_bytes, nonce_bytes))
74    }
75}
76
77#[cfg(test)]
78mod tests {
79    use super::*;
80    use crate::{ecdh::keypair::KeyPair, types::BytesValue};
81
82    #[test]
83    fn test_nonce() {
84        let nonce = AEAD::nonce();
85        let nonce_value: Result<[u8; 24], _> = nonce.vec().try_into();
86        assert!(!nonce_value.is_err())
87    }
88
89    #[test]
90    fn test_encrypt_decrypt() {
91        let keypair_alice = KeyPair::generate();
92        let keypair_bob = KeyPair::generate();
93
94        let pubkey_bob = keypair_bob.pub_key();
95        let public_bob_hex = pubkey_bob.to_hex();
96
97        let secret_alice = keypair_alice.secret(public_bob_hex);
98        let shared_secret_alice_blake3 = secret_alice.to_blake3();
99
100        let nonce = AEAD::nonce();
101        let nonce_value: Result<[u8; 24], _> = nonce.vec().try_into();
102
103        let alice_key = shared_secret_alice_blake3.unwrap();
104        let alice_key_bytes = alice_key.bytes();
105
106        let alice_key_encryption_builder = KeyEncryption::try_from(alice_key_bytes);
107        assert!(!alice_key_encryption_builder.is_err());
108
109        let key = Key::new(
110            alice_key_encryption_builder.as_ref().unwrap().to_owned(),
111            KeyNonce::from(nonce_value.unwrap()),
112        );
113
114        let message = String::from("plaintext");
115        let encrypted = AEAD::encrypt(&key, &MessagePlain::from(message.clone()));
116        assert!(!encrypted.is_err());
117
118        let encrypted_str = encrypted.unwrap();
119        let decrypted = AEAD::decrypt(&key, &encrypted_str);
120        assert!(!decrypted.is_err());
121
122        let decrypted_value = decrypted.unwrap();
123        let result = String::from_utf8(decrypted_value.vec());
124        assert!(!result.is_err());
125        assert_eq!(result.unwrap(), message);
126        assert_eq!(decrypted_value.vec(), message.clone().as_bytes().to_vec());
127
128        let nonce_missed = AEAD::nonce();
129        let nonce_missed_value: Result<[u8; 24], _> = nonce_missed.vec().try_into();
130
131        let key_invalid = Key::new(
132            alice_key_encryption_builder.unwrap(),
133            KeyNonce::from(nonce_missed_value.unwrap()),
134        );
135        let encrypted2 = AEAD::encrypt(&key, &MessagePlain::from(message));
136        let decrypted_unmatched = AEAD::decrypt(&key_invalid, &encrypted2.unwrap());
137
138        assert!(decrypted_unmatched.is_err());
139        assert!(matches!(
140            decrypted_unmatched,
141            Err(errors::AeadError::CipherGeneratorError(_))
142        ))
143    }
144}