interop/clients/cryptobox/
native.rs

1// Wire
2// Copyright (C) 2022 Wire Swiss GmbH
3
4// This program is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13
14// You should have received a copy of the GNU General Public License
15// along with this program. If not, see http://www.gnu.org/licenses/.
16
17use crate::clients::{EmulatedClient, EmulatedClientProtocol, EmulatedClientType, EmulatedProteusClient};
18use color_eyre::eyre::{eyre, Result};
19
20pub(crate) struct CryptoboxNativeClient {
21    client_id: Vec<u8>,
22    last_prekey_id: u16,
23    cbox: Option<cryptobox::CBox<cryptobox::store::file::FileStore>>,
24    tempdir: Option<tempfile::TempDir>,
25}
26
27impl CryptoboxNativeClient {
28    pub(crate) fn new() -> Self {
29        let client_id = uuid::Uuid::new_v4().into_bytes().to_vec();
30        Self {
31            client_id,
32            last_prekey_id: 0,
33            cbox: None,
34            tempdir: None,
35        }
36    }
37}
38
39#[async_trait::async_trait(?Send)]
40impl EmulatedClient for CryptoboxNativeClient {
41    fn client_name(&self) -> &str {
42        "Cryptobox::native"
43    }
44
45    fn client_type(&self) -> EmulatedClientType {
46        EmulatedClientType::Native
47    }
48
49    fn client_id(&self) -> &[u8] {
50        &self.client_id
51    }
52
53    fn client_protocol(&self) -> EmulatedClientProtocol {
54        EmulatedClientProtocol::PROTEUS
55    }
56
57    async fn wipe(mut self) -> Result<()> {
58        let _ = self.cbox.take();
59        if let Some(tempdir) = self.tempdir.take() {
60            tempdir.close()?;
61        }
62
63        Ok(())
64    }
65}
66
67#[async_trait::async_trait(?Send)]
68impl EmulatedProteusClient for CryptoboxNativeClient {
69    async fn init(&mut self) -> Result<()> {
70        let tempdir = tempfile::tempdir()?;
71        self.cbox = Some(cryptobox::CBox::file_open(tempdir.path())?);
72        self.tempdir = Some(tempdir);
73        Ok(())
74    }
75
76    async fn get_prekey(&mut self) -> Result<Vec<u8>> {
77        if let Some(cbox) = &mut self.cbox {
78            self.last_prekey_id += 1;
79            let prekey_bundle = cbox.new_prekey(proteus::keys::PreKeyId::new(self.last_prekey_id))?;
80            Ok(prekey_bundle.serialise()?)
81        } else {
82            return Err(eyre!("Cryptobox isn't initialized"));
83        }
84    }
85
86    async fn session_from_prekey(&mut self, session_id: &str, prekey: &[u8]) -> Result<()> {
87        if let Some(cbox) = &mut self.cbox {
88            let mut session = cbox.session_from_prekey(session_id.to_string(), prekey)?;
89            cbox.session_save(&mut session)?;
90            Ok(())
91        } else {
92            return Err(eyre!("Cryptobox isn't initialized"));
93        }
94    }
95
96    async fn session_from_message(&mut self, session_id: &str, message: &[u8]) -> Result<Vec<u8>> {
97        if let Some(cbox) = &mut self.cbox {
98            let (mut session, message) = cbox.session_from_message(session_id.to_string(), message)?;
99            cbox.session_save(&mut session)?;
100            Ok(message)
101        } else {
102            return Err(eyre!("Cryptobox isn't initialized"));
103        }
104    }
105
106    async fn encrypt(&mut self, session_id: &str, plaintext: &[u8]) -> Result<Vec<u8>> {
107        if let Some(cbox) = &mut self.cbox {
108            if let Some(mut session) = cbox.session_load(session_id.to_string())? {
109                let encrypted = session.encrypt(plaintext)?;
110                cbox.session_save(&mut session)?;
111                Ok(encrypted)
112            } else {
113                return Err(eyre!("session not found"));
114            }
115        } else {
116            return Err(eyre!("Cryptobox isn't initialized"));
117        }
118    }
119
120    async fn decrypt(&mut self, session_id: &str, ciphertext: &[u8]) -> Result<Vec<u8>> {
121        if let Some(cbox) = &mut self.cbox {
122            if let Some(mut session) = cbox.session_load(session_id.to_string())? {
123                let decrypted = session.decrypt(ciphertext)?;
124                cbox.session_save(&mut session)?;
125                Ok(decrypted)
126            } else {
127                return Err(eyre!("session not found"));
128            }
129        } else {
130            return Err(eyre!("Cryptobox isn't initialized"));
131        }
132    }
133
134    async fn fingerprint(&self) -> Result<String> {
135        if let Some(cbox) = &self.cbox {
136            Ok(cbox.fingerprint())
137        } else {
138            return Err(eyre!("Cryptobox isn't initialized"));
139        }
140    }
141}