df_share/
client.rs

1use super::shared::{derive_aes_key, ecdh_compute_shared_secret, EphemeralKeyPair};
2use crate::server::ServerEncryptedRes;
3use aes_gcm::{
4    aead::{Aead, KeyInit},
5    Aes256Gcm, Nonce,
6};
7use ring::agreement::EphemeralPrivateKey;
8use ring::error::Unspecified;
9use serde::{Deserialize, Serialize};
10
11/// Generate per request. Do not reuse.
12pub struct EphemeralClient {
13    pair: EphemeralKeyPair,
14}
15
16impl EphemeralClient {
17    pub fn new() -> Result<Self, Unspecified> {
18        Ok(Self {
19            pair: EphemeralKeyPair::new()?,
20        })
21    }
22    pub fn sendable(self) -> (ClientReq, ResponseDecryptor) {
23        (
24            ClientReq {
25                pubk: self.pair.pubk.as_ref().to_vec(),
26            },
27            ResponseDecryptor { _pk: self.pair._pk },
28        )
29    }
30}
31
32pub struct ResponseDecryptor {
33    _pk: EphemeralPrivateKey,
34}
35
36impl ResponseDecryptor {
37    pub fn decrypt(self, res: &ServerEncryptedRes) -> Result<Vec<u8>, Unspecified> {
38        let shared_secret = ecdh_compute_shared_secret(self._pk, &res.pubk)?;
39        let aes_key = derive_aes_key(res.salt, &shared_secret);
40        Ok(aes_gcm_decrypt(&aes_key, &res.nonce, &res.ciphertext))
41    }
42}
43
44/// Decrypt with AES-256-GCM.
45fn aes_gcm_decrypt(key: &[u8], nonce: &[u8], ciphertext: &[u8]) -> Vec<u8> {
46    let cipher = Aes256Gcm::new(key.into());
47    let nonce = Nonce::from_slice(nonce);
48    cipher
49        .decrypt(nonce, ciphertext)
50        .expect("AES-GCM decryption failed")
51}
52
53#[derive(Debug, Clone, Deserialize, Serialize)]
54pub struct ClientReq {
55    #[serde(with = "crate::shared::bytes_hex")]
56    pub pubk: Vec<u8>,
57}
58
59#[cfg(test)]
60mod test {
61    use super::*;
62
63    #[test]
64    fn test_ser_client_pubk() {
65        let client = ClientReq {
66            pubk: vec![1, 2, 3],
67        };
68        let ser = serde_json::to_string(&client).unwrap();
69        println!("{}", ser);
70        let deser: ClientReq = serde_json::from_str(&ser).unwrap();
71        assert_eq!(client.pubk, deser.pubk);
72    }
73}