11#include "protocol.h"
2+ #include "../include/vp_types.h"
23#include <string.h>
4+ #include <stdlib.h>
35
46// --------------------------------------
5- // Helpers: fixed-endian (big endian) I/O
7+ // Helpers: fixed-endian I/O
68// --------------------------------------
79static void vp_write_u16_be (uint8_t * p , uint16_t v )
810{
@@ -31,6 +33,164 @@ static uint32_t vp_read_u32_be(const uint8_t *p)
3133 ((uint32_t )p [3 ]);
3234}
3335
36+ static void vp_write_u64_be (uint8_t * p , uint64_t v )
37+ {
38+ p [0 ] = (uint8_t )((v >> 56 ) & 0xFF );
39+ p [1 ] = (uint8_t )((v >> 48 ) & 0xFF );
40+ p [2 ] = (uint8_t )((v >> 40 ) & 0xFF );
41+ p [3 ] = (uint8_t )((v >> 32 ) & 0xFF );
42+ p [4 ] = (uint8_t )((v >> 24 ) & 0xFF );
43+ p [5 ] = (uint8_t )((v >> 16 ) & 0xFF );
44+ p [6 ] = (uint8_t )((v >> 8 ) & 0xFF );
45+ p [7 ] = (uint8_t )(v & 0xFF );
46+ }
47+
48+ static uint64_t vp_read_u64_be (const uint8_t * p )
49+ {
50+ return (((uint64_t )p [0 ]) << 56 ) |
51+ (((uint64_t )p [1 ]) << 48 ) |
52+ (((uint64_t )p [2 ]) << 40 ) |
53+ (((uint64_t )p [3 ]) << 32 ) |
54+ (((uint64_t )p [4 ]) << 24 ) |
55+ (((uint64_t )p [5 ]) << 16 ) |
56+ (((uint64_t )p [6 ]) << 8 ) |
57+ ((uint64_t )p [7 ]);
58+ }
59+
60+ // --------------------------------------
61+ // Simple keyed MAC (SipHash-2-4)
62+ // --------------------------------------
63+ static uint8_t g_vp_psk [16 ];
64+ static int g_vp_psk_loaded = 0 ;
65+
66+ static uint64_t vp_load_u64_le (const uint8_t * p )
67+ {
68+ return ((uint64_t )p [0 ]) |
69+ ((uint64_t )p [1 ] << 8 ) |
70+ ((uint64_t )p [2 ] << 16 ) |
71+ ((uint64_t )p [3 ] << 24 ) |
72+ ((uint64_t )p [4 ] << 32 ) |
73+ ((uint64_t )p [5 ] << 40 ) |
74+ ((uint64_t )p [6 ] << 48 ) |
75+ ((uint64_t )p [7 ] << 56 );
76+ }
77+
78+ static uint64_t vp_rotl64 (uint64_t x , int b )
79+ {
80+ return (x << b ) | (x >> (64 - b ));
81+ }
82+
83+ static void vp_sipround (uint64_t * v0 , uint64_t * v1 ,
84+ uint64_t * v2 , uint64_t * v3 )
85+ {
86+ * v0 += * v1 ;
87+ * v2 += * v3 ;
88+ * v1 = vp_rotl64 (* v1 , 13 );
89+ * v3 = vp_rotl64 (* v3 , 16 );
90+ * v1 ^= * v0 ;
91+ * v3 ^= * v2 ;
92+ * v0 = vp_rotl64 (* v0 , 32 );
93+ * v2 += * v1 ;
94+ * v0 += * v3 ;
95+ * v1 = vp_rotl64 (* v1 , 17 );
96+ * v3 = vp_rotl64 (* v3 , 21 );
97+ * v1 ^= * v2 ;
98+ * v3 ^= * v0 ;
99+ * v2 = vp_rotl64 (* v2 , 32 );
100+ }
101+
102+ static uint64_t vp_siphash24 (const uint8_t key [16 ],
103+ const uint8_t * data ,
104+ size_t len )
105+ {
106+ uint64_t k0 = vp_load_u64_le (key + 0 );
107+ uint64_t k1 = vp_load_u64_le (key + 8 );
108+
109+ uint64_t v0 = 0x736f6d6570736575ULL ^ k0 ;
110+ uint64_t v1 = 0x646f72616e646f6dULL ^ k1 ;
111+ uint64_t v2 = 0x6c7967656e657261ULL ^ k0 ;
112+ uint64_t v3 = 0x7465646279746573ULL ^ k1 ;
113+
114+ const uint8_t * end = data + len - (len % 8 );
115+ const uint8_t * p = data ;
116+
117+ while (p != end ) {
118+ uint64_t m = vp_load_u64_le (p );
119+ v3 ^= m ;
120+ vp_sipround (& v0 , & v1 , & v2 , & v3 );
121+ vp_sipround (& v0 , & v1 , & v2 , & v3 );
122+ v0 ^= m ;
123+ p += 8 ;
124+ }
125+
126+ uint64_t b = (uint64_t )len << 56 ;
127+ size_t left = len & 7 ;
128+ switch (left ) {
129+ case 7 : b |= ((uint64_t )p [6 ] << 48 );
130+ case 6 : b |= ((uint64_t )p [5 ] << 40 );
131+ case 5 : b |= ((uint64_t )p [4 ] << 32 );
132+ case 4 : b |= ((uint64_t )p [3 ] << 24 );
133+ case 3 : b |= ((uint64_t )p [2 ] << 16 );
134+ case 2 : b |= ((uint64_t )p [1 ] << 8 );
135+ case 1 : b |= ((uint64_t )p [0 ]);
136+ default : break ;
137+ }
138+
139+ v3 ^= b ;
140+ vp_sipround (& v0 , & v1 , & v2 , & v3 );
141+ vp_sipround (& v0 , & v1 , & v2 , & v3 );
142+ v0 ^= b ;
143+
144+ v2 ^= 0xff ;
145+ vp_sipround (& v0 , & v1 , & v2 , & v3 );
146+ vp_sipround (& v0 , & v1 , & v2 , & v3 );
147+ vp_sipround (& v0 , & v1 , & v2 , & v3 );
148+ vp_sipround (& v0 , & v1 , & v2 , & v3 );
149+
150+ return v0 ^ v1 ^ v2 ^ v3 ;
151+ }
152+
153+ static void vp_auth_load_key (void )
154+ {
155+ if (g_vp_psk_loaded )
156+ return ;
157+
158+ g_vp_psk_loaded = 1 ;
159+
160+ const char * env = getenv ("VP_PSK" );
161+ memset (g_vp_psk , 0 , sizeof (g_vp_psk ));
162+
163+ if (env && env [0 ]) {
164+ size_t n = strlen (env );
165+ if (n > sizeof (g_vp_psk ))
166+ n = sizeof (g_vp_psk );
167+ memcpy (g_vp_psk , env , n );
168+ } else {
169+ // Default key (should be overridden in production via VP_PSK).
170+ const uint8_t default_key [16 ] = {
171+ 0x56 , 0x50 , 0x4E , 0x32 , // "VPN2"
172+ 0x01 , 0x23 , 0x45 , 0x67 ,
173+ 0x89 , 0xAB , 0xCD , 0xEF ,
174+ 0x10 , 0x32 , 0x54 , 0x76
175+ };
176+ memcpy (g_vp_psk , default_key , sizeof (g_vp_psk ));
177+ }
178+ }
179+
180+ static void vp_pack_header (uint8_t * buf , const vp_header_t * hdr , uint64_t auth_tag )
181+ {
182+ vp_write_u32_be (buf + 0 , hdr -> magic );
183+ buf [4 ] = hdr -> version ;
184+ buf [5 ] = hdr -> type ;
185+ vp_write_u16_be (buf + 6 , (uint16_t )hdr -> header_len );
186+ vp_write_u16_be (buf + 8 , hdr -> payload_len );
187+ vp_write_u16_be (buf + 10 , hdr -> flags );
188+ vp_write_u32_be (buf + 12 , hdr -> client_id );
189+ vp_write_u32_be (buf + 16 , hdr -> seq );
190+ vp_write_u32_be (buf + 20 , hdr -> checksum );
191+ vp_write_u64_be (buf + 24 , auth_tag );
192+ }
193+
34194// --------------------------------------
35195// CRC32 IEEE (standard)
36196// --------------------------------------
@@ -52,26 +212,30 @@ int vp_encode_packet(uint8_t *buf, size_t buf_len,
52212 const vp_header_t * hdr ,
53213 const uint8_t * payload )
54214{
215+ vp_auth_load_key ();
216+
55217 size_t header_len = VP_HEADER_WIRE_LEN ;
56218 size_t payload_len = hdr -> payload_len ;
57219 size_t total_len = header_len + payload_len ;
58220 if (buf_len < total_len )
59221 return -1 ;
60222
61- // Serialize header in a stable, padding-independent way
62- vp_write_u32_be (buf + 0 , hdr -> magic );
63- buf [4 ] = hdr -> version ;
64- buf [5 ] = hdr -> type ;
65- vp_write_u16_be (buf + 6 , (uint16_t )header_len );
66- vp_write_u16_be (buf + 8 , hdr -> payload_len );
67- vp_write_u16_be (buf + 10 , hdr -> flags );
68- vp_write_u32_be (buf + 12 , hdr -> client_id );
69- vp_write_u32_be (buf + 16 , hdr -> seq );
70- vp_write_u32_be (buf + 20 , hdr -> checksum );
223+ // Serialize header with auth_tag=0 for MAC computation
224+ vp_header_t tmp = * hdr ;
225+ tmp .header_len = (uint16_t )header_len ;
226+ tmp .auth_tag = 0 ;
227+ vp_pack_header (buf , & tmp , 0 );
71228
72229 if (payload && payload_len > 0 )
73230 memcpy (buf + header_len , payload , payload_len );
74231
232+ // Compute MAC over header (with auth_tag=0) + payload
233+ uint64_t tag = vp_siphash24 (g_vp_psk , buf , total_len );
234+
235+ // Write final header including auth_tag
236+ tmp .auth_tag = tag ;
237+ vp_pack_header (buf , & tmp , tag );
238+
75239 return (int )total_len ;
76240}
77241
@@ -81,6 +245,8 @@ int vp_encode_packet(uint8_t *buf, size_t buf_len,
81245int vp_decode_header (const uint8_t * buf , size_t buf_len ,
82246 vp_header_t * hdr )
83247{
248+ vp_auth_load_key ();
249+
84250 if (buf_len < VP_HEADER_WIRE_LEN )
85251 return -1 ;
86252
@@ -99,6 +265,7 @@ int vp_decode_header(const uint8_t *buf, size_t buf_len,
99265 hdr -> client_id = vp_read_u32_be (buf + 12 );
100266 hdr -> seq = vp_read_u32_be (buf + 16 );
101267 hdr -> checksum = vp_read_u32_be (buf + 20 );
268+ hdr -> auth_tag = vp_read_u64_be (buf + 24 );
102269
103270 // Basic bounds validation
104271 size_t header_len = hdr -> header_len ;
@@ -110,5 +277,23 @@ int vp_decode_header(const uint8_t *buf, size_t buf_len,
110277 if (buf_len < header_len + payload_len )
111278 return -4 ;
112279
280+ // Verify MAC over header (with auth_tag=0) + payload
281+ vp_header_t tmp = * hdr ;
282+ tmp .auth_tag = 0 ;
283+
284+ uint8_t hdr_bytes [VP_HEADER_WIRE_LEN + VP_MAX_FRAME_LEN ];
285+ if (header_len > VP_HEADER_WIRE_LEN )
286+ return -5 ;
287+ if (payload_len > VP_MAX_FRAME_LEN )
288+ return -6 ;
289+
290+ vp_pack_header (hdr_bytes , & tmp , 0 );
291+ if (payload_len > 0 )
292+ memcpy (hdr_bytes + header_len , buf + header_len , payload_len );
293+
294+ uint64_t expected = vp_siphash24 (g_vp_psk , hdr_bytes , header_len + payload_len );
295+ if (expected != hdr -> auth_tag )
296+ return -7 ;
297+
113298 return 0 ;
114299}
0 commit comments