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
11pub 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
44fn 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}