1use serde::{Deserialize, Serialize};
43use serde::de::DeserializeOwned;
44use serde_bytes::ByteBuf;
45use flate2::write::DeflateEncoder;
46use flate2::read::DeflateDecoder;
47use flate2::Compression;
48use std::io::{Write, Read};
49use hkdf::Hkdf;
50use sha2::Sha256;
51use crate::tools::helper::hmac;
52use crate::tools::crypt::{aes_encrypt, aes_decrypt};
53use x25519_dalek::{EphemeralSecret, PublicKey as X25519PublicKey};
54use rand_core::{RngCore, OsRng};
55
56pub const REPLAY_WINDOW_SECS: i64 = 30;
58
59pub const MAX_DECOMPRESSED_SIZE: usize = 10 * 1024 * 1024; pub fn derive_wrap_key(
69 shared_secret: &[u8; 32],
70 client_pk: &[u8; 32],
71 server_pk: &[u8; 32],
72) -> [u8; 32] {
73 let mut salt = [0u8; 64];
74 salt[..32].copy_from_slice(client_pk);
75 salt[32..].copy_from_slice(server_pk);
76 let hk = Hkdf::<Sha256>::new(Some(&salt), shared_secret);
77 let mut key = [0u8; 32];
78 hk.expand(b"alterion-wrap", &mut key).expect("HKDF expand failed");
79 key
80}
81
82fn derive_response_mac_key(enc_key: &[u8; 32]) -> [u8; 32] {
87 let hk = Hkdf::<Sha256>::new(None, enc_key);
88 let mut mac_key = [0u8; 32];
89 hk.expand(b"alterion-response-mac", &mut mac_key).expect("HKDF expand failed");
90 mac_key
91}
92
93#[derive(Debug, Serialize, Deserialize)]
99pub struct Request {
100 pub data: ByteBuf,
101 pub kx: ByteBuf,
102 pub client_pk: ByteBuf,
103 pub key_id: String,
104 pub ts: i64,
105}
106
107#[derive(Debug, Serialize, Deserialize)]
113pub struct Response {
114 pub payload: ByteBuf,
115 pub hmac: ByteBuf,
116}
117
118#[derive(Debug, thiserror::Error)]
119pub enum SerializerError {
120 #[error("serialize error: {0}")]
121 Serialize(String),
122 #[error("deserialize error: {0}")]
123 Deserialize(String),
124 #[error("compress error: {0}")]
125 Compress(String),
126 #[error("decompress error: {0}")]
127 Decompress(String),
128}
129
130impl From<SerializerError> for actix_web::Error {
131 fn from(e: SerializerError) -> Self {
132 actix_web::error::ErrorInternalServerError(e.to_string())
133 }
134}
135
136pub fn serialize<T: Serialize>(value: &T) -> Result<Vec<u8>, SerializerError> {
138 rmp_serde::to_vec_named(value)
139 .map_err(|e| SerializerError::Serialize(e.to_string()))
140}
141
142pub fn deserialize<T: DeserializeOwned>(data: &[u8]) -> Result<T, SerializerError> {
144 rmp_serde::from_slice(data)
145 .map_err(|e| SerializerError::Deserialize(e.to_string()))
146}
147
148pub fn compress(data: &[u8]) -> Result<Vec<u8>, SerializerError> {
150 let mut encoder = DeflateEncoder::new(Vec::new(), Compression::default());
151 encoder.write_all(data)
152 .map_err(|e: std::io::Error| SerializerError::Compress(e.to_string()))?;
153 encoder.finish()
154 .map_err(|e: std::io::Error| SerializerError::Compress(e.to_string()))
155}
156
157pub fn decompress(data: &[u8], max_size: usize) -> Result<Vec<u8>, SerializerError> {
162 let mut decoder = DeflateDecoder::new(data);
163 let mut out = Vec::new();
164 decoder
165 .by_ref()
166 .take(max_size as u64 + 1)
167 .read_to_end(&mut out)
168 .map_err(|e: std::io::Error| SerializerError::Decompress(e.to_string()))?;
169 if out.len() > max_size {
170 return Err(SerializerError::Decompress(
171 "decompressed payload exceeds size limit".into(),
172 ));
173 }
174 Ok(out)
175}
176
177pub fn deserialize_packet(data: &[u8]) -> Result<Request, SerializerError> {
182 let packet = deserialize::<Request>(data)?;
183 let now = std::time::SystemTime::now()
184 .duration_since(std::time::UNIX_EPOCH)
185 .map_err(|e| SerializerError::Deserialize(format!("system clock error: {e}")))?
186 .as_secs() as i64;
187 if (packet.ts - now).abs() > REPLAY_WINDOW_SECS {
188 return Err(SerializerError::Deserialize(
189 format!("timestamp out of window: skew={}s", packet.ts - now)
190 ));
191 }
192 Ok(packet)
193}
194
195
196pub fn decode_request_payload<T: DeserializeOwned>(
199 decrypted_data: &[u8],
200) -> Result<T, SerializerError> {
201 let compressed: ByteBuf = deserialize(decrypted_data)?;
202 let json_bytes = decompress(&compressed, MAX_DECOMPRESSED_SIZE)?;
203 serde_json::from_slice(&json_bytes)
204 .map_err(|e| SerializerError::Deserialize(e.to_string()))
205}
206
207pub fn build_signed_response<T: Serialize>(
209 value: &T,
210 enc_key: &[u8; 32],
211) -> Result<Vec<u8>, SerializerError> {
212 let json_bytes = serde_json::to_vec(value)
213 .map_err(|e| SerializerError::Serialize(e.to_string()))?;
214 build_signed_response_raw(&json_bytes, enc_key)
215}
216
217pub fn build_signed_response_raw(
220 json_bytes: &[u8],
221 enc_key: &[u8; 32],
222) -> Result<Vec<u8>, SerializerError> {
223 let compressed = compress(json_bytes)?;
224 let msgpacked = serialize(&ByteBuf::from(compressed))?;
225 let encrypted = aes_encrypt(&msgpacked, enc_key)
226 .map_err(|e| SerializerError::Serialize(e.to_string()))?;
227 let mac_key = derive_response_mac_key(enc_key);
228 let sig = hmac::sign(&encrypted, &mac_key);
229 let response = Response {
230 payload: ByteBuf::from(encrypted),
231 hmac: ByteBuf::from(sig),
232 };
233 serialize(&response)
234}
235
236pub fn build_request_packet<T: Serialize>(
256 value: &T,
257 server_pk: &[u8; 32],
258 key_id: String,
259) -> Result<(Vec<u8>, [u8; 32]), SerializerError> {
260 let json_bytes = serde_json::to_vec(value)
261 .map_err(|e| SerializerError::Serialize(e.to_string()))?;
262 let compressed = compress(&json_bytes)?;
263 let msgpacked = serialize(&ByteBuf::from(compressed))?;
264
265 let mut enc_key = [0u8; 32];
266 OsRng.fill_bytes(&mut enc_key);
267
268 let encrypted = aes_encrypt(&msgpacked, &enc_key)
269 .map_err(|e| SerializerError::Serialize(e.to_string()))?;
270
271 let client_sk = EphemeralSecret::random_from_rng(OsRng);
272 let client_pk = X25519PublicKey::from(&client_sk);
273 let server_pub = X25519PublicKey::from(*server_pk);
274 let shared = client_sk.diffie_hellman(&server_pub);
275 let client_pk_bytes = client_pk.to_bytes();
276
277 let wrap_key = derive_wrap_key(shared.as_bytes(), &client_pk_bytes, server_pk);
278 let kx = aes_encrypt(&enc_key, &wrap_key)
279 .map_err(|e| SerializerError::Serialize(e.to_string()))?;
280
281 let ts = std::time::SystemTime::now()
282 .duration_since(std::time::UNIX_EPOCH)
283 .map_err(|e| SerializerError::Serialize(format!("system clock error: {e}")))?
284 .as_secs() as i64;
285
286 let packet = Request {
287 data: ByteBuf::from(encrypted),
288 kx: ByteBuf::from(kx),
289 client_pk: ByteBuf::from(client_pk_bytes.to_vec()),
290 key_id,
291 ts,
292 };
293 let wire_bytes = serialize(&packet)?;
294
295 Ok((wire_bytes, enc_key))
296}
297
298pub fn decode_response_packet<T: DeserializeOwned>(
306 data: &[u8],
307 enc_key: &[u8; 32],
308) -> Result<T, SerializerError> {
309 let signed: Response = deserialize(data)?;
310 let mac_key = derive_response_mac_key(enc_key);
311
312 if !hmac::verify(signed.payload.as_ref(), &mac_key, signed.hmac.as_ref()) {
313 return Err(SerializerError::Deserialize("response HMAC invalid".into()));
314 }
315
316 let decrypted = aes_decrypt(signed.payload.as_ref(), enc_key)
317 .map_err(|e| SerializerError::Deserialize(e.to_string()))?;
318 let compressed: ByteBuf = deserialize(&decrypted)?;
319 let json_bytes = decompress(&compressed, MAX_DECOMPRESSED_SIZE)?;
320
321 serde_json::from_slice(&json_bytes)
322 .map_err(|e| SerializerError::Deserialize(e.to_string()))
323}
324
325#[cfg(test)]
326mod tests {
327 use super::*;
328 use serde::{Deserialize, Serialize};
329 use crate::tools::crypt::aes_decrypt;
330
331 #[derive(Debug, PartialEq, Serialize, Deserialize)]
332 struct TestPayload { id: u32, name: String, flag: bool }
333
334 fn sample() -> TestPayload { TestPayload { id: 42, name: "alterion".into(), flag: true } }
335
336 fn test_enc_key() -> [u8; 32] { [0x42u8; 32] }
337
338 #[test]
339 fn compress_decompress_roundtrip() {
340 let data = b"hello alterion enc pipeline payload";
341 assert_eq!(decompress(&compress(data).unwrap(), MAX_DECOMPRESSED_SIZE).unwrap(), data);
342 }
343
344 #[test]
345 fn decode_request_payload_roundtrip() {
346 let original = sample();
347 let json_bytes = serde_json::to_vec(&original).unwrap();
348 let compressed = compress(&json_bytes).unwrap();
349 let msgpacked = serialize(&ByteBuf::from(compressed)).unwrap();
350 let decoded: TestPayload = decode_request_payload(&msgpacked).unwrap();
351 assert_eq!(original, decoded);
352 }
353
354 #[test]
355 fn derive_wrap_key_bound_to_public_keys() {
356 let shared = [0x42u8; 32];
357 let client_pk = [0x01u8; 32];
358 let server_pk = [0x02u8; 32];
359 let k1 = derive_wrap_key(&shared, &client_pk, &server_pk);
360 let k2 = derive_wrap_key(&shared, &server_pk, &client_pk);
361 assert_ne!(k1, k2);
362 }
363
364 #[test]
365 fn build_signed_response_roundtrip() {
366 let enc_key = test_enc_key();
367 let payload = sample();
368 let bytes = build_signed_response(&payload, &enc_key).unwrap();
369 let signed: Response = deserialize(&bytes).unwrap();
370
371 let mac_key = derive_response_mac_key(&enc_key);
372 assert_eq!(signed.hmac.as_ref(), hmac::sign(&signed.payload, &mac_key).as_slice());
373
374 let decrypted: Vec<u8> = aes_decrypt(&signed.payload, &enc_key).unwrap();
375 let compressed: ByteBuf = deserialize(&decrypted).unwrap();
376 let json_bytes = decompress(&compressed, MAX_DECOMPRESSED_SIZE).unwrap();
377 let decoded: TestPayload = serde_json::from_slice(&json_bytes).unwrap();
378 assert_eq!(payload, decoded);
379 }
380
381 #[test]
382 fn decompress_garbage_returns_error() {
383 assert!(decompress(b"not compressed", MAX_DECOMPRESSED_SIZE).is_err());
384 }
385
386 #[test]
389 fn request_response_full_roundtrip() {
390 let server_sk = EphemeralSecret::random_from_rng(OsRng);
391 let server_pk = X25519PublicKey::from(&server_sk);
392 let server_pk_bytes: [u8; 32] = server_pk.to_bytes();
393
394 let (wire, client_enc_key) =
395 build_request_packet(&sample(), &server_pk_bytes, "test-key".to_string()).unwrap();
396
397 let packet: Request = deserialize(&wire).unwrap();
398 let client_pk_bytes: [u8; 32] = packet.client_pk.as_ref().try_into().unwrap();
399 let client_pub = X25519PublicKey::from(client_pk_bytes);
400 let shared = server_sk.diffie_hellman(&client_pub);
401 let wrap_key = derive_wrap_key(shared.as_bytes(), &client_pk_bytes, &server_pk_bytes);
402
403 let enc_key_bytes = aes_decrypt(packet.kx.as_ref(), &wrap_key).unwrap();
404 let srv_enc_key: [u8; 32] = enc_key_bytes.as_slice().try_into().unwrap();
405 assert_eq!(client_enc_key, srv_enc_key);
406
407 let decrypted: TestPayload = decode_request_payload(
408 &aes_decrypt(packet.data.as_ref(), &srv_enc_key).unwrap()
409 ).unwrap();
410 assert_eq!(decrypted, sample());
411
412 let response_bytes = build_signed_response(&sample(), &srv_enc_key).unwrap();
413 let decoded: TestPayload =
414 decode_response_packet(&response_bytes, &client_enc_key).unwrap();
415 assert_eq!(decoded, sample());
416 }
417
418 #[test]
419 fn decode_response_packet_rejects_tampered_hmac() {
420 let enc_key = test_enc_key();
421 let mut bytes = build_signed_response(&sample(), &enc_key).unwrap();
422 let last = bytes.len() - 1;
423 bytes[last] ^= 0xFF;
424 assert!(decode_response_packet::<TestPayload>(&bytes, &enc_key).is_err());
425 }
426
427 #[test]
428 fn decode_response_packet_rejects_wrong_key() {
429 let enc_key = test_enc_key();
430 let bytes = build_signed_response(&sample(), &enc_key).unwrap();
431 let wrong_key = [0x00u8; 32];
432 assert!(decode_response_packet::<TestPayload>(&bytes, &wrong_key).is_err());
433 }
434}