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::{Result, eyre};
19use std::cell::Cell;
20
21pub(crate) struct CryptoboxNativeClient {
22    client_id: Vec<u8>,
23    last_prekey_id: Cell<u16>,
24    cbox: Option<cryptobox::CBox<cryptobox::store::file::FileStore>>,
25    tempdir: Option<tempfile::TempDir>,
26}
27
28impl CryptoboxNativeClient {
29    pub(crate) fn new() -> Self {
30        let client_id = uuid::Uuid::new_v4().into_bytes().to_vec();
31        Self {
32            client_id,
33            last_prekey_id: Cell::new(0),
34            cbox: None,
35            tempdir: None,
36        }
37    }
38}
39
40#[async_trait::async_trait(?Send)]
41impl EmulatedClient for CryptoboxNativeClient {
42    fn client_name(&self) -> &str {
43        "Cryptobox::native"
44    }
45
46    fn client_type(&self) -> EmulatedClientType {
47        EmulatedClientType::Native
48    }
49
50    fn client_id(&self) -> &[u8] {
51        &self.client_id
52    }
53
54    fn client_protocol(&self) -> EmulatedClientProtocol {
55        EmulatedClientProtocol::PROTEUS
56    }
57
58    async fn wipe(mut self) -> Result<()> {
59        let _ = self.cbox.take();
60        if let Some(tempdir) = self.tempdir.take() {
61            tempdir.close()?;
62        }
63
64        Ok(())
65    }
66}
67
68#[async_trait::async_trait(?Send)]
69impl EmulatedProteusClient for CryptoboxNativeClient {
70    async fn init(&mut self) -> Result<()> {
71        let tempdir = tempfile::tempdir()?;
72        self.cbox = Some(cryptobox::CBox::file_open(tempdir.path())?);
73        self.tempdir = Some(tempdir);
74        Ok(())
75    }
76
77    async fn get_prekey(&self) -> Result<Vec<u8>> {
78        let cbox = self.cbox.as_ref().ok_or(eyre!("Cryptobox isn't initialized"))?;
79        self.last_prekey_id.replace(self.last_prekey_id.get() + 1);
80        let prekey_bundle = cbox.new_prekey(proteus::keys::PreKeyId::new(self.last_prekey_id.get()))?;
81        Ok(prekey_bundle.serialise()?)
82    }
83
84    async fn session_from_prekey(&self, session_id: &str, prekey: &[u8]) -> Result<()> {
85        let cbox = self.cbox.as_ref().ok_or(eyre!("Cryptobox isn't initialized"))?;
86        let mut session = cbox.session_from_prekey(session_id.to_string(), prekey)?;
87        cbox.session_save(&mut session)?;
88        Ok(())
89    }
90
91    async fn session_from_message(&self, session_id: &str, message: &[u8]) -> Result<Vec<u8>> {
92        let cbox = self.cbox.as_ref().ok_or(eyre!("Cryptobox isn't initialized"))?;
93        let (mut session, message) = cbox.session_from_message(session_id.to_string(), message)?;
94        cbox.session_save(&mut session)?;
95        Ok(message)
96    }
97
98    async fn encrypt(&self, session_id: &str, plaintext: &[u8]) -> Result<Vec<u8>> {
99        let cbox = self.cbox.as_ref().ok_or(eyre!("Cryptobox isn't initialized"))?;
100        let mut session = cbox
101            .session_load(session_id.to_string())?
102            .ok_or(eyre!("session not found"))?;
103        let encrypted = session.encrypt(plaintext)?;
104        cbox.session_save(&mut session)?;
105        Ok(encrypted)
106    }
107
108    async fn decrypt(&self, session_id: &str, ciphertext: &[u8]) -> Result<Vec<u8>> {
109        let cbox = self.cbox.as_ref().ok_or(eyre!("Cryptobox isn't initialized"))?;
110        let mut session = cbox
111            .session_load(session_id.to_string())?
112            .ok_or(eyre!("session not found"))?;
113        let decrypted = session.decrypt(ciphertext)?;
114        cbox.session_save(&mut session)?;
115        Ok(decrypted)
116    }
117
118    async fn fingerprint(&self) -> Result<String> {
119        self.cbox
120            .as_ref()
121            .map(|cbox| cbox.fingerprint())
122            .ok_or(eyre!("Cryptobox isn't initialized"))
123    }
124}