sbd_e2e_crypto_client/
sodoken_crypto.rs

1use crate::*;
2
3/// Secret stream encryptor.
4pub struct Encryptor {
5    sk: sodoken::SizedLockedArray<32>,
6    state: sodoken::secretstream::State,
7}
8
9impl Encryptor {
10    /// Initialize a new encryptor.
11    fn init(&mut self) -> Result<[u8; 24]> {
12        let mut header = [0; 24];
13        sodoken::secretstream::init_push(
14            &mut self.state,
15            &mut header,
16            &self.sk.lock(),
17        )?;
18        Ok(header)
19    }
20
21    /// Encrypt a new message. This version saves a copy by putting the
22    /// encrypted data directly into a protocol message.
23    pub fn encrypt(
24        &mut self,
25        pub_key: &[u8],
26        msg: &[u8],
27    ) -> Result<protocol::Protocol> {
28        let mut out = bytes::BytesMut::zeroed(
29            32 + 1 + msg.len() + sodoken::secretstream::ABYTES,
30        );
31        out[..32].copy_from_slice(&pub_key[..32]);
32        out[32] = protocol::T_MESSAGE;
33
34        sodoken::secretstream::push(
35            &mut self.state,
36            &mut out[33..],
37            msg,
38            None,
39            sodoken::secretstream::Tag::Message,
40        )?;
41
42        // unwrap okay since we are constructing this
43        Ok(protocol::Protocol::from_full(out.freeze()).unwrap())
44    }
45}
46
47/// Secret stream decryptor.
48pub struct Decryptor {
49    state: sodoken::secretstream::State,
50}
51
52impl Decryptor {
53    /// Decrypt a new message into [bytes::Bytes].
54    pub fn decrypt(&mut self, msg: &[u8]) -> Result<bytes::Bytes> {
55        let mut out =
56            bytes::BytesMut::zeroed(msg.len() - sodoken::secretstream::ABYTES);
57        sodoken::secretstream::pull(&mut self.state, &mut out[..], msg, None)?;
58        Ok(out.freeze())
59    }
60}
61
62/// Crypto based on sodoken(libsodium).
63pub struct SodokenCrypto {
64    sign_pk: [u8; 32],
65    sign_sk: Mutex<sodoken::SizedLockedArray<64>>,
66    enc_pk: [u8; 32],
67    enc_sk: Mutex<sodoken::SizedLockedArray<32>>,
68}
69
70impl SodokenCrypto {
71    /// Construct a new crypto instance.
72    pub fn new() -> Result<Self> {
73        loop {
74            let mut sign_pk = [0; 32];
75            let mut sign_sk = sodoken::SizedLockedArray::new()?;
76
77            sodoken::sign::keypair(&mut sign_pk, &mut sign_sk.lock())?;
78
79            if sign_pk[..28] == [0; 28] {
80                continue;
81            }
82
83            let mut enc_pk = [0; 32];
84            sodoken::sign::pk_to_curve25519(&mut enc_pk, &sign_pk)?;
85
86            let mut enc_sk = sodoken::SizedLockedArray::new()?;
87            sodoken::sign::sk_to_curve25519(
88                &mut enc_sk.lock(),
89                &sign_sk.lock(),
90            )?;
91
92            return Ok(Self {
93                sign_pk,
94                sign_sk: Mutex::new(sign_sk),
95                enc_pk,
96                enc_sk: Mutex::new(enc_sk),
97            });
98        }
99    }
100
101    /// Derive session keys for a peer connection.
102    fn session(
103        &self,
104        peer_sign_pk: &[u8; 32],
105    ) -> Result<(sodoken::SizedLockedArray<32>, sodoken::SizedLockedArray<32>)>
106    {
107        let mut peer_enc_pk = [0; 32];
108        sodoken::sign::pk_to_curve25519(&mut peer_enc_pk, peer_sign_pk)?;
109
110        let mut rx = sodoken::SizedLockedArray::new()?;
111        let mut tx = sodoken::SizedLockedArray::new()?;
112
113        // determine the "server" by ordering
114        if peer_enc_pk > self.enc_pk {
115            sodoken::kx::client_session_keys(
116                &mut rx.lock(),
117                &mut tx.lock(),
118                &self.enc_pk,
119                &self.enc_sk.lock().unwrap().lock(),
120                &peer_enc_pk,
121            )?;
122        } else {
123            sodoken::kx::server_session_keys(
124                &mut rx.lock(),
125                &mut tx.lock(),
126                &self.enc_pk,
127                &self.enc_sk.lock().unwrap().lock(),
128                &peer_enc_pk,
129            )?;
130        }
131
132        Ok((rx, tx))
133    }
134
135    /// Construct a new encryptor for a peer connection.
136    pub fn new_enc(
137        &self,
138        peer_sign_pk: &[u8; 32],
139    ) -> Result<(Encryptor, [u8; 24])> {
140        let (_rx, tx) = self.session(peer_sign_pk)?;
141
142        let mut enc = Encryptor {
143            sk: tx,
144            state: sodoken::secretstream::State::default(),
145        };
146
147        let hdr = enc.init()?;
148
149        Ok((enc, hdr))
150    }
151
152    /// Construct a new decryptor for a peer connection.
153    pub fn new_dec(
154        &self,
155        peer_sign_pk: &[u8],
156        hdr: &[u8],
157    ) -> Result<Decryptor> {
158        let mut pk = [0; 32];
159        pk.copy_from_slice(&peer_sign_pk[..32]);
160        let (mut rx, _tx) = self.session(&pk)?;
161
162        let mut state = sodoken::secretstream::State::default();
163
164        let mut header = [0; 24];
165        header.copy_from_slice(&hdr[..24]);
166
167        sodoken::secretstream::init_pull(&mut state, &header, &rx.lock())?;
168
169        Ok(Decryptor { state })
170    }
171}
172
173impl sbd_client::Crypto for SodokenCrypto {
174    fn pub_key(&self) -> &[u8; 32] {
175        &self.sign_pk
176    }
177
178    fn sign(&self, nonce: &[u8]) -> Result<[u8; 64]> {
179        let mut sig = [0; 64];
180        sodoken::sign::sign_detached(
181            &mut sig,
182            nonce,
183            &self.sign_sk.lock().unwrap().lock(),
184        )?;
185        Ok(sig)
186    }
187}