rejson/crypto/
encryptor.rs

1use anyhow::Result;
2use nacl::{public_box, secret_box};
3
4use super::{
5    keys::{Key, KeyPair, Nonce},
6    message::Message,
7};
8
9/// A struct for managing the encryption of strings into serialized messages for storing in EJSON
10/// files.
11pub struct Encryptor {
12    /// The keypair used for encryption/decryption.
13    keys: KeyPair,
14    /// The (typically DH) shared/stream key.
15    shared_key: Key,
16}
17
18impl Encryptor {
19    /// Creates a new [Encryptor] using the supplied key paid, peer public key, and shared key.
20    pub fn new(keys: KeyPair, shared_key: Key) -> Self {
21        Self { keys, shared_key }
22    }
23
24    /// Creates a new [Encryptor] from the given [KeyPair] and peer public key. A shared key is
25    /// calculated from these values and used to construct the [Encryptor].
26    pub fn create(keys: KeyPair, peer_public: Key) -> Result<Self> {
27        let shared_key = Key(public_box::calc_dhshared_key(&peer_public.0, &keys.private.0)
28            .map_err(|e| anyhow::anyhow!(e.message))?
29            .as_slice()
30            .try_into()?);
31
32        Ok(Self { keys, shared_key })
33    }
34
35    /// Encrypts the given string returning the value to be stored in the EJSON file.
36    pub fn encrypt<S: Into<String>>(&self, plaintext: S) -> Result<String> {
37        let nonce = Nonce::random();
38        let value = secret_box::pack(plaintext.into().as_bytes(), &nonce.0, &self.shared_key.0)
39            .map_err(|e| anyhow::anyhow!(e.message))?;
40
41        // Box the message and return in EJSON format
42        Ok(Message {
43            version: 1,
44            key: self.keys.public.clone(),
45            nonce,
46            value,
47        }
48        .to_string())
49    }
50}
51
52#[cfg(test)]
53mod tests {
54    use super::*;
55
56    #[test]
57    fn create() {
58        let keys = KeyPair::generate().unwrap();
59        let peer_key = Key::random();
60        let encryptor = Encryptor::create(keys.clone(), peer_key.clone()).unwrap();
61
62        assert_eq!(keys, encryptor.keys);
63        assert_ne!(Key::default(), encryptor.shared_key);
64    }
65
66    #[test]
67    fn encrypt() {
68        let encryptor = Encryptor::create(KeyPair::generate().unwrap(), Key::random()).unwrap();
69        assert!(Message::is_valid(&encryptor.encrypt("ssshhhhh").unwrap()));
70    }
71}