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 fn derive_wrap_key(
64 shared_secret: &[u8; 32],
65 client_pk: &[u8; 32],
66 server_pk: &[u8; 32],
67) -> [u8; 32] {
68 let mut salt = [0u8; 64];
69 salt[..32].copy_from_slice(client_pk);
70 salt[32..].copy_from_slice(server_pk);
71 let hk = Hkdf::<Sha256>::new(Some(&salt), shared_secret);
72 let mut key = [0u8; 32];
73 hk.expand(b"alterion-wrap", &mut key).expect("HKDF expand failed");
74 key
75}
76
77fn derive_response_mac_key(enc_key: &[u8; 32]) -> [u8; 32] {
82 let hk = Hkdf::<Sha256>::new(None, enc_key);
83 let mut mac_key = [0u8; 32];
84 hk.expand(b"alterion-response-mac", &mut mac_key).expect("HKDF expand failed");
85 mac_key
86}
87
88#[derive(Debug, Serialize, Deserialize)]
94pub struct Request {
95 pub data: ByteBuf,
96 pub kx: ByteBuf,
97 pub client_pk: ByteBuf,
98 pub key_id: String,
99 pub ts: i64,
100}
101
102#[derive(Debug, Serialize, Deserialize)]
108pub struct Response {
109 pub payload: ByteBuf,
110 pub hmac: ByteBuf,
111}
112
113#[derive(Debug, thiserror::Error)]
114pub enum SerializerError {
115 #[error("serialize error: {0}")]
116 Serialize(String),
117 #[error("deserialize error: {0}")]
118 Deserialize(String),
119 #[error("compress error: {0}")]
120 Compress(String),
121 #[error("decompress error: {0}")]
122 Decompress(String),
123}
124
125impl From<SerializerError> for actix_web::Error {
126 fn from(e: SerializerError) -> Self {
127 actix_web::error::ErrorInternalServerError(e.to_string())
128 }
129}
130
131pub fn serialize<T: Serialize>(value: &T) -> Result<Vec<u8>, SerializerError> {
133 rmp_serde::to_vec_named(value)
134 .map_err(|e| SerializerError::Serialize(e.to_string()))
135}
136
137pub fn deserialize<T: DeserializeOwned>(data: &[u8]) -> Result<T, SerializerError> {
139 rmp_serde::from_slice(data)
140 .map_err(|e| SerializerError::Deserialize(e.to_string()))
141}
142
143pub fn compress(data: &[u8]) -> Result<Vec<u8>, SerializerError> {
145 let mut encoder = DeflateEncoder::new(Vec::new(), Compression::default());
146 encoder.write_all(data)
147 .map_err(|e: std::io::Error| SerializerError::Compress(e.to_string()))?;
148 encoder.finish()
149 .map_err(|e: std::io::Error| SerializerError::Compress(e.to_string()))
150}
151
152pub fn decompress(data: &[u8]) -> Result<Vec<u8>, SerializerError> {
154 let mut decoder = DeflateDecoder::new(data);
155 let mut out = Vec::new();
156 decoder.read_to_end(&mut out)
157 .map_err(|e: std::io::Error| SerializerError::Decompress(e.to_string()))?;
158 Ok(out)
159}
160
161pub fn deserialize_packet(data: &[u8]) -> Result<Request, SerializerError> {
166 let packet = deserialize::<Request>(data)?;
167 let now = std::time::SystemTime::now()
168 .duration_since(std::time::UNIX_EPOCH)
169 .map_err(|e| SerializerError::Deserialize(format!("system clock error: {e}")))?
170 .as_secs() as i64;
171 if (packet.ts - now).abs() > REPLAY_WINDOW_SECS {
172 return Err(SerializerError::Deserialize(
173 format!("timestamp out of window: skew={}s", packet.ts - now)
174 ));
175 }
176 Ok(packet)
177}
178
179
180pub fn decode_request_payload<T: DeserializeOwned>(
183 decrypted_data: &[u8],
184) -> Result<T, SerializerError> {
185 let compressed: ByteBuf = deserialize(decrypted_data)?;
186 let json_bytes = decompress(&compressed)?;
187 serde_json::from_slice(&json_bytes)
188 .map_err(|e| SerializerError::Deserialize(e.to_string()))
189}
190
191pub fn build_signed_response<T: Serialize>(
193 value: &T,
194 enc_key: &[u8; 32],
195) -> Result<Vec<u8>, SerializerError> {
196 let json_bytes = serde_json::to_vec(value)
197 .map_err(|e| SerializerError::Serialize(e.to_string()))?;
198 build_signed_response_raw(&json_bytes, enc_key)
199}
200
201pub fn build_signed_response_raw(
204 json_bytes: &[u8],
205 enc_key: &[u8; 32],
206) -> Result<Vec<u8>, SerializerError> {
207 let compressed = compress(json_bytes)?;
208 let msgpacked = serialize(&ByteBuf::from(compressed))?;
209 let encrypted = aes_encrypt(&msgpacked, enc_key)
210 .map_err(|e| SerializerError::Serialize(e.to_string()))?;
211 let mac_key = derive_response_mac_key(enc_key);
212 let sig = hmac::sign(&encrypted, &mac_key);
213 let response = Response {
214 payload: ByteBuf::from(encrypted),
215 hmac: ByteBuf::from(sig),
216 };
217 serialize(&response)
218}
219
220pub fn build_request_packet<T: Serialize>(
240 value: &T,
241 server_pk: &[u8; 32],
242 key_id: String,
243) -> Result<(Vec<u8>, [u8; 32]), SerializerError> {
244 let json_bytes = serde_json::to_vec(value)
245 .map_err(|e| SerializerError::Serialize(e.to_string()))?;
246 let compressed = compress(&json_bytes)?;
247 let msgpacked = serialize(&ByteBuf::from(compressed))?;
248
249 let mut enc_key = [0u8; 32];
250 OsRng.fill_bytes(&mut enc_key);
251
252 let encrypted = aes_encrypt(&msgpacked, &enc_key)
253 .map_err(|e| SerializerError::Serialize(e.to_string()))?;
254
255 let client_sk = EphemeralSecret::random_from_rng(OsRng);
256 let client_pk = X25519PublicKey::from(&client_sk);
257 let server_pub = X25519PublicKey::from(*server_pk);
258 let shared = client_sk.diffie_hellman(&server_pub);
259 let client_pk_bytes = client_pk.to_bytes();
260
261 let wrap_key = derive_wrap_key(shared.as_bytes(), &client_pk_bytes, server_pk);
262 let kx = aes_encrypt(&enc_key, &wrap_key)
263 .map_err(|e| SerializerError::Serialize(e.to_string()))?;
264
265 let ts = std::time::SystemTime::now()
266 .duration_since(std::time::UNIX_EPOCH)
267 .map_err(|e| SerializerError::Serialize(format!("system clock error: {e}")))?
268 .as_secs() as i64;
269
270 let packet = Request {
271 data: ByteBuf::from(encrypted),
272 kx: ByteBuf::from(kx),
273 client_pk: ByteBuf::from(client_pk_bytes.to_vec()),
274 key_id,
275 ts,
276 };
277 let wire_bytes = serialize(&packet)?;
278
279 Ok((wire_bytes, enc_key))
280}
281
282pub fn decode_response_packet<T: DeserializeOwned>(
290 data: &[u8],
291 enc_key: &[u8; 32],
292) -> Result<T, SerializerError> {
293 let signed: Response = deserialize(data)?;
294 let mac_key = derive_response_mac_key(enc_key);
295
296 if !hmac::verify(signed.payload.as_ref(), &mac_key, signed.hmac.as_ref()) {
297 return Err(SerializerError::Deserialize("response HMAC invalid".into()));
298 }
299
300 let decrypted = aes_decrypt(signed.payload.as_ref(), enc_key)
301 .map_err(|e| SerializerError::Deserialize(e.to_string()))?;
302 let compressed: ByteBuf = deserialize(&decrypted)?;
303 let json_bytes = decompress(&compressed)?;
304
305 serde_json::from_slice(&json_bytes)
306 .map_err(|e| SerializerError::Deserialize(e.to_string()))
307}
308
309#[cfg(test)]
310mod tests {
311 use super::*;
312 use serde::{Deserialize, Serialize};
313 use crate::tools::crypt::aes_decrypt;
314
315 #[derive(Debug, PartialEq, Serialize, Deserialize)]
316 struct TestPayload { id: u32, name: String, flag: bool }
317
318 fn sample() -> TestPayload { TestPayload { id: 42, name: "alterion".into(), flag: true } }
319
320 fn test_enc_key() -> [u8; 32] { [0x42u8; 32] }
321
322 #[test]
323 fn compress_decompress_roundtrip() {
324 let data = b"hello alterion enc pipeline payload";
325 assert_eq!(decompress(&compress(data).unwrap()).unwrap(), data);
326 }
327
328 #[test]
329 fn decode_request_payload_roundtrip() {
330 let original = sample();
331 let json_bytes = serde_json::to_vec(&original).unwrap();
332 let compressed = compress(&json_bytes).unwrap();
333 let msgpacked = serialize(&ByteBuf::from(compressed)).unwrap();
334 let decoded: TestPayload = decode_request_payload(&msgpacked).unwrap();
335 assert_eq!(original, decoded);
336 }
337
338 #[test]
339 fn derive_wrap_key_bound_to_public_keys() {
340 let shared = [0x42u8; 32];
341 let client_pk = [0x01u8; 32];
342 let server_pk = [0x02u8; 32];
343 let k1 = derive_wrap_key(&shared, &client_pk, &server_pk);
344 let k2 = derive_wrap_key(&shared, &server_pk, &client_pk);
345 assert_ne!(k1, k2);
346 }
347
348 #[test]
349 fn build_signed_response_roundtrip() {
350 let enc_key = test_enc_key();
351 let payload = sample();
352 let bytes = build_signed_response(&payload, &enc_key).unwrap();
353 let signed: Response = deserialize(&bytes).unwrap();
354
355 let mac_key = derive_response_mac_key(&enc_key);
356 assert_eq!(signed.hmac.as_ref(), hmac::sign(&signed.payload, &mac_key).as_slice());
357
358 let decrypted: Vec<u8> = aes_decrypt(&signed.payload, &enc_key).unwrap();
359 let compressed: ByteBuf = deserialize(&decrypted).unwrap();
360 let json_bytes = decompress(&compressed).unwrap();
361 let decoded: TestPayload = serde_json::from_slice(&json_bytes).unwrap();
362 assert_eq!(payload, decoded);
363 }
364
365 #[test]
366 fn decompress_garbage_returns_error() {
367 assert!(decompress(b"not compressed").is_err());
368 }
369
370 #[test]
373 fn request_response_full_roundtrip() {
374 let server_sk = EphemeralSecret::random_from_rng(OsRng);
375 let server_pk = X25519PublicKey::from(&server_sk);
376 let server_pk_bytes: [u8; 32] = server_pk.to_bytes();
377
378 let (wire, client_enc_key) =
379 build_request_packet(&sample(), &server_pk_bytes, "test-key".to_string()).unwrap();
380
381 let packet: Request = deserialize(&wire).unwrap();
382 let client_pk_bytes: [u8; 32] = packet.client_pk.as_ref().try_into().unwrap();
383 let client_pub = X25519PublicKey::from(client_pk_bytes);
384 let shared = server_sk.diffie_hellman(&client_pub);
385 let wrap_key = derive_wrap_key(shared.as_bytes(), &client_pk_bytes, &server_pk_bytes);
386
387 let enc_key_bytes = aes_decrypt(packet.kx.as_ref(), &wrap_key).unwrap();
388 let srv_enc_key: [u8; 32] = enc_key_bytes.as_slice().try_into().unwrap();
389 assert_eq!(client_enc_key, srv_enc_key);
390
391 let decrypted: TestPayload = decode_request_payload(
392 &aes_decrypt(packet.data.as_ref(), &srv_enc_key).unwrap()
393 ).unwrap();
394 assert_eq!(decrypted, sample());
395
396 let response_bytes = build_signed_response(&sample(), &srv_enc_key).unwrap();
397 let decoded: TestPayload =
398 decode_response_packet(&response_bytes, &client_enc_key).unwrap();
399 assert_eq!(decoded, sample());
400 }
401
402 #[test]
403 fn decode_response_packet_rejects_tampered_hmac() {
404 let enc_key = test_enc_key();
405 let mut bytes = build_signed_response(&sample(), &enc_key).unwrap();
406 let last = bytes.len() - 1;
407 bytes[last] ^= 0xFF;
408 assert!(decode_response_packet::<TestPayload>(&bytes, &enc_key).is_err());
409 }
410
411 #[test]
412 fn decode_response_packet_rejects_wrong_key() {
413 let enc_key = test_enc_key();
414 let bytes = build_signed_response(&sample(), &enc_key).unwrap();
415 let wrong_key = [0x00u8; 32];
416 assert!(decode_response_packet::<TestPayload>(&bytes, &wrong_key).is_err());
417 }
418}