1use serde::{Deserialize, Serialize};
3use serde::de::DeserializeOwned;
4use serde_bytes::ByteBuf;
5use flate2::write::DeflateEncoder;
6use flate2::read::DeflateDecoder;
7use flate2::Compression;
8use std::io::{Write, Read};
9use hkdf::Hkdf;
10use sha2::Sha256;
11use crate::tools::helper::hmac;
12use crate::tools::crypt::{aes_encrypt, aes_decrypt};
13use x25519_dalek::{EphemeralSecret, PublicKey as X25519PublicKey};
14use rand_core::{RngCore, OsRng};
15
16const REPLAY_WINDOW_SECS: i64 = 30;
18
19pub fn derive_wrap_key(
24 shared_secret: &[u8; 32],
25 client_pk: &[u8; 32],
26 server_pk: &[u8; 32],
27) -> [u8; 32] {
28 let mut salt = [0u8; 64];
29 salt[..32].copy_from_slice(client_pk);
30 salt[32..].copy_from_slice(server_pk);
31 let hk = Hkdf::<Sha256>::new(Some(&salt), shared_secret);
32 let mut key = [0u8; 32];
33 hk.expand(b"alterion-wrap", &mut key).expect("HKDF expand failed");
34 key
35}
36
37fn derive_response_mac_key(enc_key: &[u8; 32]) -> [u8; 32] {
42 let hk = Hkdf::<Sha256>::new(None, enc_key);
43 let mut mac_key = [0u8; 32];
44 hk.expand(b"alterion-response-mac", &mut mac_key).expect("HKDF expand failed");
45 mac_key
46}
47
48#[derive(Debug, Serialize, Deserialize)]
54pub struct Request {
55 pub data: ByteBuf,
56 pub kx: ByteBuf,
57 pub client_pk: ByteBuf,
58 pub key_id: String,
59 pub ts: i64,
60}
61
62#[derive(Debug, Serialize, Deserialize)]
68pub struct Response {
69 pub payload: ByteBuf,
70 pub hmac: ByteBuf,
71}
72
73#[derive(Debug, thiserror::Error)]
74pub enum SerializerError {
75 #[error("serialize error: {0}")]
76 Serialize(String),
77 #[error("deserialize error: {0}")]
78 Deserialize(String),
79 #[error("compress error: {0}")]
80 Compress(String),
81 #[error("decompress error: {0}")]
82 Decompress(String),
83}
84
85impl From<SerializerError> for actix_web::Error {
86 fn from(e: SerializerError) -> Self {
87 actix_web::error::ErrorInternalServerError(e.to_string())
88 }
89}
90
91pub fn serialize<T: Serialize>(value: &T) -> Result<Vec<u8>, SerializerError> {
93 rmp_serde::to_vec_named(value)
94 .map_err(|e| SerializerError::Serialize(e.to_string()))
95}
96
97pub fn deserialize<T: DeserializeOwned>(data: &[u8]) -> Result<T, SerializerError> {
99 rmp_serde::from_slice(data)
100 .map_err(|e| SerializerError::Deserialize(e.to_string()))
101}
102
103pub fn compress(data: &[u8]) -> Result<Vec<u8>, SerializerError> {
105 let mut encoder = DeflateEncoder::new(Vec::new(), Compression::default());
106 encoder.write_all(data)
107 .map_err(|e: std::io::Error| SerializerError::Compress(e.to_string()))?;
108 encoder.finish()
109 .map_err(|e: std::io::Error| SerializerError::Compress(e.to_string()))
110}
111
112pub fn decompress(data: &[u8]) -> Result<Vec<u8>, SerializerError> {
114 let mut decoder = DeflateDecoder::new(data);
115 let mut out = Vec::new();
116 decoder.read_to_end(&mut out)
117 .map_err(|e: std::io::Error| SerializerError::Decompress(e.to_string()))?;
118 Ok(out)
119}
120
121pub fn deserialize_packet(data: &[u8]) -> Result<Request, SerializerError> {
126 let packet = deserialize::<Request>(data)?;
127 let now = std::time::SystemTime::now()
128 .duration_since(std::time::UNIX_EPOCH)
129 .map_err(|e| SerializerError::Deserialize(format!("system clock error: {e}")))?
130 .as_secs() as i64;
131 if (packet.ts - now).abs() > REPLAY_WINDOW_SECS {
132 return Err(SerializerError::Deserialize(
133 format!("timestamp out of window: skew={}s", packet.ts - now)
134 ));
135 }
136 Ok(packet)
137}
138
139
140pub fn decode_request_payload<T: DeserializeOwned>(
143 decrypted_data: &[u8],
144) -> Result<T, SerializerError> {
145 let compressed: ByteBuf = deserialize(decrypted_data)?;
146 let json_bytes = decompress(&compressed)?;
147 serde_json::from_slice(&json_bytes)
148 .map_err(|e| SerializerError::Deserialize(e.to_string()))
149}
150
151pub fn build_signed_response<T: Serialize>(
153 value: &T,
154 enc_key: &[u8; 32],
155) -> Result<Vec<u8>, SerializerError> {
156 let json_bytes = serde_json::to_vec(value)
157 .map_err(|e| SerializerError::Serialize(e.to_string()))?;
158 build_signed_response_raw(&json_bytes, enc_key)
159}
160
161pub fn build_signed_response_raw(
164 json_bytes: &[u8],
165 enc_key: &[u8; 32],
166) -> Result<Vec<u8>, SerializerError> {
167 let compressed = compress(json_bytes)?;
168 let msgpacked = serialize(&ByteBuf::from(compressed))?;
169 let encrypted = aes_encrypt(&msgpacked, enc_key)
170 .map_err(|e| SerializerError::Serialize(e.to_string()))?;
171 let mac_key = derive_response_mac_key(enc_key);
172 let sig = hmac::sign(&encrypted, &mac_key);
173 let response = Response {
174 payload: ByteBuf::from(encrypted),
175 hmac: ByteBuf::from(sig),
176 };
177 serialize(&response)
178}
179
180pub fn build_request_packet<T: Serialize>(
200 value: &T,
201 server_pk: &[u8; 32],
202 key_id: String,
203) -> Result<(Vec<u8>, [u8; 32]), SerializerError> {
204 let json_bytes = serde_json::to_vec(value)
205 .map_err(|e| SerializerError::Serialize(e.to_string()))?;
206 let compressed = compress(&json_bytes)?;
207 let msgpacked = serialize(&ByteBuf::from(compressed))?;
208
209 let mut enc_key = [0u8; 32];
210 OsRng.fill_bytes(&mut enc_key);
211
212 let encrypted = aes_encrypt(&msgpacked, &enc_key)
213 .map_err(|e| SerializerError::Serialize(e.to_string()))?;
214
215 let client_sk = EphemeralSecret::random_from_rng(OsRng);
216 let client_pk = X25519PublicKey::from(&client_sk);
217 let server_pub = X25519PublicKey::from(*server_pk);
218 let shared = client_sk.diffie_hellman(&server_pub);
219 let client_pk_bytes = client_pk.to_bytes();
220
221 let wrap_key = derive_wrap_key(shared.as_bytes(), &client_pk_bytes, server_pk);
222 let kx = aes_encrypt(&enc_key, &wrap_key)
223 .map_err(|e| SerializerError::Serialize(e.to_string()))?;
224
225 let ts = std::time::SystemTime::now()
226 .duration_since(std::time::UNIX_EPOCH)
227 .map_err(|e| SerializerError::Serialize(format!("system clock error: {e}")))?
228 .as_secs() as i64;
229
230 let packet = Request {
231 data: ByteBuf::from(encrypted),
232 kx: ByteBuf::from(kx),
233 client_pk: ByteBuf::from(client_pk_bytes.to_vec()),
234 key_id,
235 ts,
236 };
237 let wire_bytes = serialize(&packet)?;
238
239 Ok((wire_bytes, enc_key))
240}
241
242pub fn decode_response_packet<T: DeserializeOwned>(
250 data: &[u8],
251 enc_key: &[u8; 32],
252) -> Result<T, SerializerError> {
253 let signed: Response = deserialize(data)?;
254 let mac_key = derive_response_mac_key(enc_key);
255
256 if !hmac::verify(signed.payload.as_ref(), &mac_key, signed.hmac.as_ref()) {
257 return Err(SerializerError::Deserialize("response HMAC invalid".into()));
258 }
259
260 let decrypted = aes_decrypt(signed.payload.as_ref(), enc_key)
261 .map_err(|e| SerializerError::Deserialize(e.to_string()))?;
262 let compressed: ByteBuf = deserialize(&decrypted)?;
263 let json_bytes = decompress(&compressed)?;
264
265 serde_json::from_slice(&json_bytes)
266 .map_err(|e| SerializerError::Deserialize(e.to_string()))
267}
268
269#[cfg(test)]
270mod tests {
271 use super::*;
272 use serde::{Deserialize, Serialize};
273 use crate::tools::crypt::aes_decrypt;
274
275 #[derive(Debug, PartialEq, Serialize, Deserialize)]
276 struct TestPayload { id: u32, name: String, flag: bool }
277
278 fn sample() -> TestPayload { TestPayload { id: 42, name: "alterion".into(), flag: true } }
279
280 fn test_enc_key() -> [u8; 32] { [0x42u8; 32] }
281
282 #[test]
283 fn compress_decompress_roundtrip() {
284 let data = b"hello alterion enc pipeline payload";
285 assert_eq!(decompress(&compress(data).unwrap()).unwrap(), data);
286 }
287
288 #[test]
289 fn decode_request_payload_roundtrip() {
290 let original = sample();
291 let json_bytes = serde_json::to_vec(&original).unwrap();
292 let compressed = compress(&json_bytes).unwrap();
293 let msgpacked = serialize(&ByteBuf::from(compressed)).unwrap();
294 let decoded: TestPayload = decode_request_payload(&msgpacked).unwrap();
295 assert_eq!(original, decoded);
296 }
297
298 #[test]
299 fn derive_wrap_key_bound_to_public_keys() {
300 let shared = [0x42u8; 32];
301 let client_pk = [0x01u8; 32];
302 let server_pk = [0x02u8; 32];
303 let k1 = derive_wrap_key(&shared, &client_pk, &server_pk);
304 let k2 = derive_wrap_key(&shared, &server_pk, &client_pk);
305 assert_ne!(k1, k2);
306 }
307
308 #[test]
309 fn build_signed_response_roundtrip() {
310 let enc_key = test_enc_key();
311 let payload = sample();
312 let bytes = build_signed_response(&payload, &enc_key).unwrap();
313 let signed: Response = deserialize(&bytes).unwrap();
314
315 let mac_key = derive_response_mac_key(&enc_key);
316 assert_eq!(signed.hmac.as_ref(), hmac::sign(&signed.payload, &mac_key).as_slice());
317
318 let decrypted: Vec<u8> = aes_decrypt(&signed.payload, &enc_key).unwrap();
319 let compressed: ByteBuf = deserialize(&decrypted).unwrap();
320 let json_bytes = decompress(&compressed).unwrap();
321 let decoded: TestPayload = serde_json::from_slice(&json_bytes).unwrap();
322 assert_eq!(payload, decoded);
323 }
324
325 #[test]
326 fn decompress_garbage_returns_error() {
327 assert!(decompress(b"not compressed").is_err());
328 }
329
330 #[test]
333 fn request_response_full_roundtrip() {
334 use x25519_dalek::{EphemeralSecret, PublicKey as X25519PublicKey};
335
336 let server_sk = EphemeralSecret::random_from_rng(OsRng);
337 let server_pk = X25519PublicKey::from(&server_sk);
338 let server_pk_bytes: [u8; 32] = server_pk.to_bytes();
339
340 let (wire, client_enc_key) =
341 build_request_packet(&sample(), &server_pk_bytes, "test-key".to_string()).unwrap();
342
343 let packet: Request = deserialize(&wire).unwrap();
344 let client_pk_bytes: [u8; 32] = packet.client_pk.as_ref().try_into().unwrap();
345 let client_pub = X25519PublicKey::from(client_pk_bytes);
346 let shared = server_sk.diffie_hellman(&client_pub);
347 let wrap_key = derive_wrap_key(shared.as_bytes(), &client_pk_bytes, &server_pk_bytes);
348
349 let enc_key_bytes = aes_decrypt(packet.kx.as_ref(), &wrap_key).unwrap();
350 let srv_enc_key: [u8; 32] = enc_key_bytes.as_slice().try_into().unwrap();
351 assert_eq!(client_enc_key, srv_enc_key);
352
353 let decrypted: TestPayload = decode_request_payload(
354 &aes_decrypt(packet.data.as_ref(), &srv_enc_key).unwrap()
355 ).unwrap();
356 assert_eq!(decrypted, sample());
357
358 let response_bytes = build_signed_response(&sample(), &srv_enc_key).unwrap();
359 let decoded: TestPayload =
360 decode_response_packet(&response_bytes, &client_enc_key).unwrap();
361 assert_eq!(decoded, sample());
362 }
363
364 #[test]
365 fn decode_response_packet_rejects_tampered_hmac() {
366 let enc_key = test_enc_key();
367 let mut bytes = build_signed_response(&sample(), &enc_key).unwrap();
368 let last = bytes.len() - 1;
369 bytes[last] ^= 0xFF;
370 assert!(decode_response_packet::<TestPayload>(&bytes, &enc_key).is_err());
371 }
372
373 #[test]
374 fn decode_response_packet_rejects_wrong_key() {
375 let enc_key = test_enc_key();
376 let bytes = build_signed_response(&sample(), &enc_key).unwrap();
377 let wrong_key = [0x00u8; 32];
378 assert!(decode_response_packet::<TestPayload>(&bytes, &wrong_key).is_err());
379 }
380}