pim_protocol/
handshake_frame.rs1use bytes::{Buf, BufMut, BytesMut};
4
5use pim_core::{FrameCodec, PimError};
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq)]
9#[repr(u8)]
10pub enum HandshakeFrameType {
11 Init = 0,
13 Response = 1,
15 Confirm = 2,
17}
18
19impl HandshakeFrameType {
20 pub fn from_u8(v: u8) -> Result<Self, PimError> {
22 match v {
23 0 => Ok(Self::Init),
24 1 => Ok(Self::Response),
25 2 => Ok(Self::Confirm),
26 other => Err(PimError::Protocol(format!(
27 "unknown handshake type: {other}"
28 ))),
29 }
30 }
31}
32
33#[derive(Debug, Clone, PartialEq, Eq)]
38pub enum HandshakeWireFrame {
39 InitOrResponse {
41 handshake_type: HandshakeFrameType,
43 sender_pub: [u8; 32],
45 ephemeral_pub: [u8; 32],
47 nonce: [u8; 32],
49 signature: [u8; 64],
51 },
52 Confirm {
54 hmac: [u8; 32],
56 },
57}
58
59const INIT_RESPONSE_SIZE: usize = 1 + 32 + 32 + 32 + 64; const CONFIRM_SIZE: usize = 1 + 32; impl FrameCodec for HandshakeWireFrame {
63 fn encode(&self, buf: &mut BytesMut) {
64 match self {
65 HandshakeWireFrame::InitOrResponse {
66 handshake_type,
67 sender_pub,
68 ephemeral_pub,
69 nonce,
70 signature,
71 } => {
72 buf.put_u8(*handshake_type as u8);
73 buf.put_slice(sender_pub);
74 buf.put_slice(ephemeral_pub);
75 buf.put_slice(nonce);
76 buf.put_slice(signature);
77 }
78 HandshakeWireFrame::Confirm { hmac } => {
79 buf.put_u8(HandshakeFrameType::Confirm as u8);
80 buf.put_slice(hmac);
81 }
82 }
83 }
84
85 fn decode(buf: &mut BytesMut) -> Result<Self, PimError> {
86 if buf.is_empty() {
87 return Err(PimError::Protocol("handshake frame empty".into()));
88 }
89
90 let handshake_type = HandshakeFrameType::from_u8(buf[0])?;
91
92 match handshake_type {
93 HandshakeFrameType::Init | HandshakeFrameType::Response => {
94 if buf.len() < INIT_RESPONSE_SIZE {
95 return Err(PimError::Protocol(format!(
96 "handshake init/response too short: need {INIT_RESPONSE_SIZE}, have {}",
97 buf.len()
98 )));
99 }
100 let mut sender_pub = [0u8; 32];
101 sender_pub.copy_from_slice(&buf[1..33]);
102 let mut ephemeral_pub = [0u8; 32];
103 ephemeral_pub.copy_from_slice(&buf[33..65]);
104 let mut nonce = [0u8; 32];
105 nonce.copy_from_slice(&buf[65..97]);
106 let mut signature = [0u8; 64];
107 signature.copy_from_slice(&buf[97..161]);
108
109 buf.advance(INIT_RESPONSE_SIZE);
110
111 Ok(HandshakeWireFrame::InitOrResponse {
112 handshake_type,
113 sender_pub,
114 ephemeral_pub,
115 nonce,
116 signature,
117 })
118 }
119 HandshakeFrameType::Confirm => {
120 if buf.len() < CONFIRM_SIZE {
121 return Err(PimError::Protocol(format!(
122 "handshake confirm too short: need {CONFIRM_SIZE}, have {}",
123 buf.len()
124 )));
125 }
126 let mut hmac = [0u8; 32];
127 hmac.copy_from_slice(&buf[1..33]);
128
129 buf.advance(CONFIRM_SIZE);
130
131 Ok(HandshakeWireFrame::Confirm { hmac })
132 }
133 }
134 }
135}
136
137#[cfg(test)]
138mod tests;