psp_security/
lib.rs

1use std::{
2    fmt, io,
3    net::{ToSocketAddrs, UdpSocket},
4    str::FromStr,
5};
6
7use rand::RngCore;
8
9use aes::Aes256;
10use aws_lc_rs::{aead::{
11    nonce_sequence, Aad, BoundKey, OpeningKey, SealingKey, UnboundKey, AES_128_GCM, AES_256_GCM
12}, error};
13use bincode::Options;
14use bitfield::bitfield;
15use clap::ValueEnum;
16use derive_builder::Builder;
17use etherparse::{
18    ether_type, ip_number, Ethernet2Header, IpHeader, Ipv4Header, Ipv6Header, PacketHeaders,
19    SerializedSize, TransportHeader, UdpHeader,
20};
21use log::debug;
22use pnet_packet::Packet;
23
24use serde::{Deserialize, Serialize};
25
26mod packet;
27use packet::psp::PspPacket;
28
29pub const PSP_ICV_SIZE: usize = 16;
30const PSP_VC_SIZE: usize = 8;
31const PSP_MASTER_KEY_SIZE: usize = 32;
32const PSP_SPI_KEY_SELECTOR_BIT: u32 = 31;
33const PSP_CRYPT_OFFSET_UNITS: usize = 4;
34const PSP_UDP_PORT: u16 = 1000;
35const PSP_HDR_FIXED_LEN: u8 = 16;
36
37// An enumeration of the PSP versions.
38#[repr(u8)]
39#[derive(Debug, PartialEq)]
40enum PspVersion {
41    PspVer0 = 0, // AES-GCM-128
42    PspVer1 = 1, // AES-GCM-256
43}
44
45impl TryFrom<u8> for PspVersion {
46    type Error = PspError;
47
48    fn try_from(value: u8) -> Result<Self, Self::Error> {
49        match value {
50            0 => Ok(PspVersion::PspVer0),
51            1 => Ok(PspVersion::PspVer1),
52            _ => Err(PspError::InvalidPspVersion(value)),
53        }
54    }
55}
56
57// An enumeration of the PSP encapsulation types.
58#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize, clap::ValueEnum)]
59pub enum PspEncap {
60    #[default]
61    Transport,
62    Tunnel,
63}
64
65impl fmt::Display for PspEncap {
66    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
67        match self {
68            Self::Transport => write!(f, "transport"),
69            Self::Tunnel => write!(f, "tunnel"),
70        }
71    }
72}
73
74impl FromStr for PspEncap {
75    type Err = PspError;
76
77    fn from_str(s: &str) -> Result<PspEncap, Self::Err> {
78        match s {
79            "transport" => Ok(PspEncap::Transport),
80            "tunnel" => Ok(PspEncap::Tunnel),
81            _ => Err(PspError::InvalidPspEncap(s.to_string())),
82        }
83    }
84}
85
86// An enumeration of the supported crypto algorithms.
87#[derive(PartialEq, Eq, Copy, Clone, Debug, Default, Serialize, Deserialize, ValueEnum)]
88pub enum CryptoAlg {
89    AesGcm128,
90    #[default]
91    AesGcm256,
92}
93
94impl fmt::Display for CryptoAlg {
95    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
96        match self {
97            Self::AesGcm128 => write!(f, "aes-gcm-128"),
98            Self::AesGcm256 => write!(f, "aes-gcm-256"),
99        }
100    }
101}
102
103impl FromStr for CryptoAlg {
104    type Err = PspError;
105
106    fn from_str(s: &str) -> Result<CryptoAlg, Self::Err> {
107        match s {
108            "aes-gcm-128" => Ok(CryptoAlg::AesGcm128),
109            "aes-gcm-256" => Ok(CryptoAlg::AesGcm256),
110            _ => Err(PspError::InvalidCryptoAlg(s.to_string())),
111        }
112    }
113}
114
115// A bitfield representing the PSP header flags.
116bitfield! {
117    #[derive(Copy, Clone, Serialize, PartialEq, Eq)]
118    pub struct PspHeaderFlags(u8);
119    impl Debug;
120    r, set_r: 0;
121    v, set_v: 1;
122    version, set_version: 5, 2;
123    d, set_d: 6;
124    s, set_s: 7;
125}
126
127impl Default for PspHeaderFlags {
128    fn default() -> Self {
129        let mut flags = Self(0);
130        flags.set_r(true);
131        flags.set_v(false);
132        flags.set_version(PspVersion::PspVer0 as u8);
133        flags.set_d(false);
134        flags.set_s(false);
135        flags
136    }
137}
138
139#[derive(Builder, Serialize, Debug, Default)]
140#[builder(default)]
141pub struct PspHeader {
142    /// An IP protocol number, identifying the type of the next header.
143    /// For example:
144    /// - 6 for transport mode when next header is TCP
145    /// - 17 for transport mode when next header is UDP
146    /// - 4 for tunnel mode when next header is IPv4
147    /// - 41 for tunnel mode when next header is IPv6
148    next_hdr: u8,
149    hdr_ext_len: u8,
150    crypt_off: u8,
151    flags: PspHeaderFlags,
152    spi: u32,
153    iv: u64,
154}
155
156pub type PspMasterKey = [u8; PSP_MASTER_KEY_SIZE];
157
158type PspDerivedKey = Vec<u8>;
159
160/// A PSP configuration structure.
161#[derive(Clone, Debug, Default, Serialize, Deserialize)]
162pub struct PspConfig {
163    pub master_keys: [PspMasterKey; 2],
164    pub spi: u32,
165    pub psp_encap: PspEncap,
166    pub crypto_alg: CryptoAlg,
167    pub transport_crypt_off: u8,
168    pub ipv4_tunnel_crypt_off: u8,
169    pub ipv6_tunnel_crypt_off: u8,
170    pub include_vc: bool,
171}
172
173impl PspConfig {
174    /// Validates the PSP configuration for security and correctness.
175    pub fn validate(&self) -> Result<(), PspError> {
176        // Validate SPI is not reserved value
177        if self.spi == 0 {
178            return Err(PspError::InvalidSpi(self.spi));
179        }
180
181        // Check for weak keys (all zeros)
182        for (i, key) in self.master_keys.iter().enumerate() {
183            if key.iter().all(|&b| b == 0) {
184                return Err(PspError::WeakKey(format!("Master key {} is all zeros", i)));
185            }
186            
187            // Check for other weak patterns (all same byte)
188            let first_byte = key[0];
189            if key.iter().all(|&b| b == first_byte) {
190                return Err(PspError::WeakKey(format!(
191                    "Master key {} uses repeating pattern (0x{:02X})", i, first_byte
192                )));
193            }
194        }
195
196        // Validate crypto offset values are reasonable
197        if self.transport_crypt_off > 64 {
198            return Err(PspError::ConfigError(format!(
199                "Transport crypto offset too large: {}", self.transport_crypt_off
200            )));
201        }
202
203        if self.ipv4_tunnel_crypt_off > 64 {
204            return Err(PspError::ConfigError(format!(
205                "IPv4 tunnel crypto offset too large: {}", self.ipv4_tunnel_crypt_off
206            )));
207        }
208
209        if self.ipv6_tunnel_crypt_off > 64 {
210            return Err(PspError::ConfigError(format!(
211                "IPv6 tunnel crypto offset too large: {}", self.ipv6_tunnel_crypt_off
212            )));
213        }
214
215        Ok(())
216    }
217
218    /// Securely clears all cryptographic material from memory.
219    /// This should be called when the configuration is no longer needed
220    /// to prevent keys from remaining in memory.
221    pub fn secure_clear(&mut self) {
222        // Clear master keys with explicit write to prevent optimization
223        for key in &mut self.master_keys {
224            for byte in key.iter_mut() {
225                unsafe {
226                    std::ptr::write_volatile(byte, 0);
227                }
228            }
229        }
230        
231        // Clear SPI (though not as sensitive as keys)
232        unsafe {
233            std::ptr::write_volatile(&mut self.spi, 0);
234        }
235    }
236
237    /// Creates a new configuration with secure defaults and validation.
238    pub fn new_secure() -> Result<Self, PspError> {
239        let cfg = PspConfig {
240            master_keys: [
241                PktContext::generate_secure_key(),
242                PktContext::generate_secure_key(),
243            ],
244            spi: PktContext::generate_secure_spi(),
245            psp_encap: PspEncap::Transport,
246            crypto_alg: CryptoAlg::AesGcm256, // Use stronger default
247            transport_crypt_off: 0,
248            ipv4_tunnel_crypt_off: 0,
249            ipv6_tunnel_crypt_off: 0,
250            include_vc: false,
251        };
252
253        cfg.validate()?;
254        Ok(cfg)
255    }
256}
257
258#[derive(Debug, Clone)]
259pub struct PktContext {
260    pub psp_cfg: PspConfig,
261    pub key: PspDerivedKey,
262    pub iv: u64,
263    pub vc: u64,
264}
265
266impl PktContext {
267    /// Creates a new PktContext with secure random initialization.
268    /// WARNING: This generates random keys suitable for testing only.
269    /// In production, keys should be loaded from secure key management systems.
270    pub fn new() -> PktContext {
271        PktContext {
272            psp_cfg: PspConfig {
273                master_keys: [
274                    Self::generate_secure_key(),
275                    Self::generate_secure_key(),
276                ],
277                spi: Self::generate_secure_spi(),
278                psp_encap: PspEncap::Transport,
279                crypto_alg: CryptoAlg::AesGcm128,
280                transport_crypt_off: 0,
281                ipv4_tunnel_crypt_off: 0,
282                ipv6_tunnel_crypt_off: 0,
283                include_vc: false,
284            },
285            key: Self::generate_derived_key(16),
286            iv: Self::generate_secure_iv(),
287            vc: 0,
288        }
289    }
290
291    /// Generates a cryptographically secure 32-byte key
292    pub fn generate_secure_key() -> [u8; 32] {
293        let mut key = [0u8; 32];
294        rand::thread_rng().fill_bytes(&mut key);
295        key
296    }
297
298    /// Generates a cryptographically secure derived key of specified length
299    fn generate_derived_key(len: usize) -> Vec<u8> {
300        let mut key = vec![0u8; len];
301        rand::thread_rng().fill_bytes(&mut key);
302        key
303    }
304
305    /// Generates a secure random SPI (avoiding reserved values)
306    pub fn generate_secure_spi() -> u32 {
307        loop {
308            let mut spi_bytes = [0u8; 4];
309            rand::thread_rng().fill_bytes(&mut spi_bytes);
310            let spi = u32::from_be_bytes(spi_bytes);
311            // Ensure SPI is not 0 or 1 (reserved values)
312            if spi > 1 {
313                return spi;
314            }
315        }
316    }
317
318    /// Generates a secure random IV
319    fn generate_secure_iv() -> u64 {
320        let mut iv_bytes = [0u8; 8];
321        rand::thread_rng().fill_bytes(&mut iv_bytes);
322        u64::from_be_bytes(iv_bytes)
323    }
324
325    /// Securely clears all cryptographic material from memory.
326    /// This should be called when the context is no longer needed
327    /// to prevent keys and sensitive data from remaining in memory.
328    pub fn secure_clear(&mut self) {
329        // Clear the PSP configuration keys
330        self.psp_cfg.secure_clear();
331        
332        // Clear the derived key
333        for byte in &mut self.key {
334            unsafe {
335                std::ptr::write_volatile(byte, 0);
336            }
337        }
338        
339        // Clear IV and VC (though less sensitive than keys)
340        unsafe {
341            std::ptr::write_volatile(&mut self.iv, 0);
342            std::ptr::write_volatile(&mut self.vc, 0);
343        }
344    }
345
346    /// Creates a new PktContext for testing with predictable (insecure) values.
347    /// DO NOT USE IN PRODUCTION - This is only for unit tests.
348    #[cfg(test)]
349    pub fn new_for_testing() -> PktContext {
350        PktContext {
351            psp_cfg: PspConfig {
352                master_keys: [[0; 32], [0; 32]],
353                spi: 1,
354                psp_encap: PspEncap::Transport,
355                crypto_alg: CryptoAlg::AesGcm128,
356                transport_crypt_off: 0,
357                ipv4_tunnel_crypt_off: 0,
358                ipv6_tunnel_crypt_off: 0,
359                include_vc: false,
360            },
361            key: vec![0; 16],
362            iv: 1,
363            vc: 0,
364        }
365    }
366}
367
368impl Default for PktContext {
369    fn default() -> PktContext {
370        PktContext::new()
371    }
372}
373
374impl Drop for PktContext {
375    /// Automatically clear cryptographic material when the context is dropped.
376    /// This provides defense-in-depth against keys remaining in memory.
377    fn drop(&mut self) {
378        self.secure_clear();
379    }
380}
381
382impl Drop for PspConfig {
383    /// Automatically clear cryptographic material when the config is dropped.
384    /// This provides defense-in-depth against keys remaining in memory.
385    fn drop(&mut self) {
386        self.secure_clear();
387    }
388}
389
390/// PspError enumerates all possible errors returned by this library.
391#[derive(thiserror::Error, Debug)]
392pub enum PspError {
393    /// Represents a crypto error. Crypto errors can occur during PSP packet
394    /// encryption or decryption.
395    #[error("PSP Crypto Error: {}", .0)]
396    CryptoError(#[from] error::Unspecified),
397
398    /// Serialization errors occur when converting PSP headers into a byte
399    /// stream.
400    #[error("PSP Serialization Error")]
401    SerializeError(#[from] bincode::Error),
402
403    /// The PSP packet didn't contain any ciphertext payload.
404    #[error("PSP No Ciphertext In PSP Packet")]
405    NoCiphertext,
406
407    /// An error occurred when parsing a packet.
408    #[error("Packet Parse Error")]
409    PacketParseError(#[from] etherparse::ReadError),
410
411    /// Configuration validation errors
412    #[error("Invalid configuration: {0}")]
413    ConfigError(String),
414
415    /// Weak cryptographic key detected
416    #[error("Weak cryptographic key detected: {0}")]
417    WeakKey(String),
418
419    /// Invalid SPI value
420    #[error("Invalid SPI value: {0}")]
421    InvalidSpi(u32),
422
423    /// Invalid PSP encapsulation type string
424    #[error("Invalid PSP encapsulation type: {0}")]
425    InvalidPspEncap(String),
426
427    /// Invalid cryptographic algorithm string
428    #[error("Invalid cryptographic algorithm: {0}")]
429    InvalidCryptoAlg(String),
430
431
432    /// An error occurred when writing a packet.
433    #[error("Packet Write Error")]
434    PacketWriteError(#[from] etherparse::WriteError),
435
436    /// An error was encountered building the packet.
437    #[error("PSP Packet Build Error")]
438    PacketBuildError(#[from] io::Error),
439
440    /// The packet could not be encapsulated in PSP.
441    #[error("Packet Could not be encapsulated in PSP: {}", .0)]
442    PacketEncapError(String),
443
444    /// Packet could not be decapsulated. This could be caused by a number of reasons including the
445    /// packet not being a valid PSP packet or a combination of outer packet headers which are
446    /// unsupported by the library.
447    #[error("PSP Packet Decap Error: {}", .0)]
448    PacketDecapError(String),
449
450    /// Invalid PSP Version
451    #[error("Invalid PSP Version: {}", .0)]
452    InvalidPspVersion(u8),
453
454    /// Invalid PSP packet size. This can occur when parsing the packet if the length after the PSP
455    /// header is too short to hold the PSP ICV value.
456    #[error("Invalid PSP Packet Size")]
457    InvalidPspPacketSize,
458
459    // The implementation does not support a feature. The string describes what is not supported.
460    #[error("Unsupported Feature: {}", .0)]
461    Unsupported(String),
462}
463
464/// PspSocket is a socket that encapsulates and decapsulates packets in PSP.
465/// It is a wrapper around a UdpSocket.
466/// ```rust
467/// # use psp_security::*;
468/// # fn main() -> Result<(), PspError> {
469/// let spi = 1;
470/// let key = vec![0; 16];
471/// let opts = PspSocketOptions::new(spi, &key);
472/// let socket = PspSocket::bind("0.0.0.0:0", opts)?;
473/// #
474/// #   Ok(())
475/// # }
476/// ```
477/// # Errors
478/// This function may encounter several types of errors.
479/// Errors when trying to bind the socket are returned as an `io::Error`.
480/// Errors when trying to send or receive packets are returned as an `io::Error`.
481#[derive(Debug)]
482pub struct PspSocket {
483    options: PspSocketOptions,
484    udp_sock: Option<UdpSocket>,
485}
486
487impl PspSocket {
488    /// Bind a PSP socket to a given address.
489    pub fn bind<A: ToSocketAddrs>(addr: A, opts: PspSocketOptions) -> io::Result<PspSocket> {
490        let udp_sock = UdpSocket::bind(addr)?;
491        let psp_sock = PspSocket {
492            options: opts,
493            udp_sock: Some(udp_sock),
494        };
495
496        Ok(psp_sock)
497    }
498
499    /// Send a packet to a given address.
500    pub fn send_to<A: ToSocketAddrs>(&self, pkt: &[u8], addr: A) -> io::Result<()> {
501        let udp_sock = self
502            .udp_sock
503            .as_ref()
504            .ok_or(io::Error::new(io::ErrorKind::NotFound, "No UDP socket"))?;
505
506        let mut pkt_ctx = PktContext {
507            key: self.options.key.clone(),
508            psp_cfg: PspConfig {
509                spi: self.options.spi,
510                crypto_alg: self.options.algorithm,
511                transport_crypt_off: self.options.crypt_off,
512                ..Default::default()
513            },
514            ..Default::default()
515        };
516
517        let psp_pkt = psp_encap_pdu(&mut pkt_ctx, pkt, 0).map_err(|e| {
518            io::Error::new(
519                io::ErrorKind::Other,
520                format!("Error encapsulating packet: {:?}", e),
521            )
522        })?;
523        udp_sock.send_to(&psp_pkt, addr)?;
524        Ok(())
525    }
526
527    /// Receive a packet from the socket.
528    pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, String)> {
529        let udp_sock = self
530            .udp_sock
531            .as_ref()
532            .ok_or(io::Error::new(io::ErrorKind::NotFound, "No UDP socket"))?;
533        let (size, addr) = udp_sock.recv_from(buf)?;
534
535        let mut pkt_ctx = PktContext {
536            key: self.options.key.clone(),
537            psp_cfg: PspConfig {
538                spi: self.options.spi,
539                crypto_alg: self.options.algorithm,
540                transport_crypt_off: self.options.crypt_off,
541                ..Default::default()
542            },
543            ..Default::default()
544        };
545
546        let decrypted = psp_decap_pdu(&mut pkt_ctx, &buf[..size]).map_err(|e| {
547            io::Error::new(
548                io::ErrorKind::Other,
549                format!("Error decapsulating packet: {:?}", e),
550            )
551        })?;
552        buf[..decrypted.len()].copy_from_slice(&decrypted);
553        Ok((decrypted.len(), addr.to_string()))
554    }
555}
556
557/// Socket options for a PSP socket.
558#[derive(Debug, Clone, Serialize, Deserialize, Default)]
559pub struct PspSocketOptions {
560    /// The SPI value for the PSP socket.
561    spi: u32,
562    /// The PSP derived key for encrypting packets transmitted and received over the socket.
563    key: PspDerivedKey,
564    /// The cryptographic algorithm used for encryption.
565    algorithm: CryptoAlg,
566    /// The offset in the packet where encryption should start.
567    crypt_off: u8,
568}
569
570impl PspSocketOptions {
571    pub fn new(spi: u32, key: &PspDerivedKey) -> PspSocketOptions {
572        PspSocketOptions {
573            spi,
574            key: key.clone(),
575            algorithm: CryptoAlg::AesGcm256,
576            crypt_off: 0,
577        }
578    }
579}
580
581const fn get_psp_version(alg: CryptoAlg) -> PspVersion {
582    match alg {
583        CryptoAlg::AesGcm128 => PspVersion::PspVer0,
584        CryptoAlg::AesGcm256 => PspVersion::PspVer1,
585    }
586}
587
588const fn get_psp_crypto_alg(ver: PspVersion) -> CryptoAlg {
589    match ver {
590        PspVersion::PspVer0 => CryptoAlg::AesGcm128,
591        PspVersion::PspVer1 => CryptoAlg::AesGcm256,
592    }
593}
594
595const fn select_master_key(spi: u32, keys: &[PspMasterKey]) -> &PspMasterKey {
596    if (spi >> PSP_SPI_KEY_SELECTOR_BIT) & 0x01 == 0 {
597        return &keys[0];
598    }
599    &keys[1]
600}
601
602fn derive_psp_key_128(
603    spi: u32,
604    crypto_alg: CryptoAlg,
605    master_keys: &[PspMasterKey],
606    counter: u8,
607) -> Vec<u8> {
608    use cmac::{Cmac, Mac};
609
610    let mut input_block: [u8; 16] = [0; 16];
611    input_block[3] = counter;
612    input_block[4] = 0x50;
613    input_block[5] = 0x76;
614
615    match crypto_alg {
616        CryptoAlg::AesGcm128 => {
617            input_block[6] = 0x30;
618            input_block[15] = 0x80;
619        }
620        CryptoAlg::AesGcm256 => {
621            input_block[6] = 0x31;
622            input_block[14] = 0x01;
623            input_block[15] = 0x00;
624        }
625    }
626
627    input_block[8] = ((spi >> 24) & 0xff) as u8;
628    input_block[9] = ((spi >> 16) & 0xff) as u8;
629    input_block[10] = ((spi >> 8) & 0xff) as u8;
630    input_block[11] = (spi & 0xff) as u8;
631
632    let key = select_master_key(spi, master_keys);
633
634    let mut mac = Cmac::<Aes256>::new(key.into());
635    mac.update(&input_block);
636    let result = mac.finalize();
637    result.into_bytes().to_vec()
638}
639
640/// Derive a PSP key using the `spi`, and the `master_keys`.
641pub fn derive_psp_key(spi: u32, crypto_alg: CryptoAlg, master_keys: &[PspMasterKey]) -> Vec<u8> {
642    let mut key = derive_psp_key_128(spi, crypto_alg, master_keys, 1);
643    if crypto_alg == CryptoAlg::AesGcm256 {
644        key.extend(derive_psp_key_128(spi, crypto_alg, master_keys, 2));
645    }
646    key
647}
648
649/// Use the PSP packet SPI and IV fields, build an IV for use with AES-GCM.
650fn get_aesgcm_iv(spi: u32, iv: u64) -> [u8; 12] {
651    let mut gcm_iv: [u8; 12] = [0; 12];
652    gcm_iv[0..4].copy_from_slice(&spi.to_be_bytes());
653    gcm_iv[4..12].copy_from_slice(&iv.to_be_bytes());
654    gcm_iv
655}
656
657/// Encrypt a PSP packet given the PSP header and the payload buffer. The
658/// encryption is an out-of-place operation with the ciphertext and the ICV tag
659/// returned in the same buffer.
660///
661/// ```rust
662/// # use psp_security::*;
663/// # fn main() -> Result<(), PspError> {
664/// let algo = CryptoAlg::AesGcm128;
665/// let key: [u8; 16] = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
666///                      0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00];
667/// let iv: [u8; 12] = [0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB];
668/// let aad = [0xCA, 0xFE, 0xFA, 0xCE];
669/// let cleartext = vec![0u8; 64];
670/// let mut ciphertext = vec![0u8; cleartext.len() + PSP_ICV_SIZE];
671/// psp_encrypt(algo, &key, &iv, &aad, &cleartext, &mut ciphertext)?;
672/// #
673/// #   Ok(())
674/// # }
675/// ```
676///
677/// # Errors
678///
679/// If this function encounters any errors, a PspError::CryptoError will be returned. The contents
680/// of the ciphertext slice are only valid if no errors occur.
681pub fn psp_encrypt(
682    algo: CryptoAlg,
683    key: &[u8],
684    iv: &[u8],
685    aad: &[u8],
686    cleartext: &[u8],
687    ciphertext: &mut [u8],
688) -> Result<(), PspError> {
689    debug!("psp_encrypt(): Key: {:02X?}", key);
690    debug!("psp_encrypt(): IV:  {:02X?}", iv);
691    debug!("psp_encrypt(): AAD: {:02X?}", aad);
692    debug!("psp_encrypt(): Cleartext len:  {}", cleartext.len());
693    debug!("psp_encrypt(): Ciphertext len: {}", ciphertext.len());
694
695    let mut in_out_buf = Vec::from(cleartext);
696
697    let unbound_key = match algo {
698        CryptoAlg::AesGcm128 => {
699            UnboundKey::new(&AES_128_GCM, key).map_err(|e| PspError::CryptoError(e))?
700        }
701        CryptoAlg::AesGcm256 => {
702            UnboundKey::new(&AES_256_GCM, key).map_err(|e| PspError::CryptoError(e))?
703        }
704    };
705    let counter = u64::from_be_bytes(iv[4..12].try_into().unwrap());
706    let nonce_seq = nonce_sequence::Counter64Builder::new()
707        .identifier(<[u8; 4]>::try_from(&iv[..4]).unwrap())
708        .counter(counter)
709        .build();
710    let mut sealing_key = SealingKey::new(unbound_key, nonce_seq);
711    let aad_content = Aad::from(aad);
712    sealing_key
713        .seal_in_place_append_tag(aad_content, &mut in_out_buf)
714        .map_err(|e| PspError::CryptoError(e))?;
715
716    ciphertext.copy_from_slice(&in_out_buf);
717
718    Ok(())
719}
720
721/// Decrypt a PSP packet. The decryption is an out-of-place operation returned
722/// in separate buffers. On input, the ciphertext buffer must also contain the icv.
723///
724/// ```rust
725/// # use psp_security::*;
726/// # fn main() -> Result<(), psp_security::PspError> {
727/// let algo = CryptoAlg::AesGcm128;
728/// let key: [u8; 16] = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
729///                      0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00];
730/// let iv: [u8; 12] = [0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB];
731/// let aad = [0xCA, 0xFE, 0xFA, 0xCE];
732/// let cleartext = vec![0u8; 64];
733/// let mut ciphertext = vec![0u8; cleartext.len() + PSP_ICV_SIZE];
734/// psp_encrypt(algo, &key, &iv, &aad, &cleartext, &mut ciphertext)?;
735/// let mut decrypted = vec![0u8; cleartext.len()];
736/// psp_decrypt(algo, &key, &iv, &aad, &ciphertext, &mut decrypted)?;
737/// #
738/// #   Ok(())
739/// # }
740/// ```
741///
742/// # Errors
743///
744/// If this function encounters any errors, a PspError::CryptoError will be returned. The contents
745/// of the ciphertext slice are only valid if no errors occur.
746pub fn psp_decrypt(
747    algo: CryptoAlg,
748    key: &[u8],
749    iv: &[u8],
750    aad: &[u8],
751    ciphertext: &[u8],
752    cleartext: &mut [u8],
753) -> Result<(), PspError> {
754    debug!("psp_decrypt(): Key: {:02X?}", key);
755    debug!("psp_decrypt(): IV:  {:02X?}", iv);
756    debug!("psp_decrypt(): AAD: {:02X?}", aad);
757    debug!("psp_encrypt(): Ciphertext len: {}", ciphertext.len());
758    debug!("psp_encrypt(): Cleartext len:  {}", cleartext.len());
759
760    if ciphertext.is_empty() {
761        return Err(PspError::NoCiphertext);
762    }
763
764    let mut in_out_buf = Vec::from(ciphertext);
765
766    let unbound_key = match algo {
767        CryptoAlg::AesGcm128 => {
768            UnboundKey::new(&AES_128_GCM, key).map_err(|e| PspError::CryptoError(e))?
769        }
770        CryptoAlg::AesGcm256 => {
771            UnboundKey::new(&AES_256_GCM, key).map_err(|e| PspError::CryptoError(e))?
772        }
773    };
774    let counter = u64::from_be_bytes(iv[4..12].try_into().unwrap());
775    let nonce_seq = nonce_sequence::Counter64Builder::new()
776        .identifier(<[u8; 4]>::try_from(&iv[..4]).unwrap())
777        .counter(counter)
778        .build();
779    let mut opening_key = OpeningKey::new(unbound_key, nonce_seq);
780    let aad_content = Aad::from(aad);
781    opening_key
782        .open_in_place(aad_content, &mut in_out_buf)
783        .map_err(|e| PspError::CryptoError(e))?;
784
785    // Not all of the decrypted content needs to be copied. e.g. when an encrypted vc is present.
786    // let drop_offset = pt.len() - cleartext.len();
787    // cleartext.copy_from_slice(&pt[drop_offset..]);
788    let pt_len = in_out_buf.len() - PSP_ICV_SIZE;
789    let drop_offset = pt_len - cleartext.len();
790    cleartext.copy_from_slice(&in_out_buf[drop_offset..ciphertext.len() - PSP_ICV_SIZE]);
791
792    Ok(())
793}
794
795/// Encapsulate a PDU in PSP.
796///
797/// Input PDU:
798///     +---------+
799///     | Payload |
800///     +---------+
801///
802/// Output PDU:
803///     +---------+---------+-------------+
804///     | PSP Hdr | Payload | PSP Trailer |
805///     +---------+---------+-------------+
806///
807/// ```rust
808/// # use psp_security::*;
809/// # use etherparse::PacketBuilder;
810/// # fn main() -> Result<(), PspError> {
811/// let pkt = [1, 2, 3, 4, 5, 6, 7, 8];
812///
813/// let mut pkt_ctx = PktContext::default();
814/// pkt_ctx.key = derive_psp_key(pkt_ctx.psp_cfg.spi, pkt_ctx.psp_cfg.crypto_alg, &pkt_ctx.psp_cfg.master_keys);
815/// let encap_pkt = psp_encap_pdu(&mut pkt_ctx, &pkt, 17)?;
816/// #
817/// #   Ok(())
818/// # }
819/// ```
820/// # Errors
821///
822/// This function may encounter several types of errors.
823/// Errors when trying to encapsulate the packet are returned as a `PspError::PacketEncapError`.
824/// Errors when encrypting the packet are reurned as a `PspError::CryptoError`.
825pub fn psp_encap_pdu(
826    pkt_ctx: &mut PktContext,
827    in_pdu: &[u8],
828    next_protocol: u8,
829) -> Result<Vec<u8>, PspError> {
830    let crypt_off = usize::from(pkt_ctx.psp_cfg.transport_crypt_off) * PSP_CRYPT_OFFSET_UNITS;
831    let mut payload_crypt_off = crypt_off;
832    let mut encrypted_vc = false;
833
834    if pkt_ctx.psp_cfg.include_vc {
835        if crypt_off >= PSP_VC_SIZE {
836            payload_crypt_off -= PSP_VC_SIZE;
837        } else {
838            encrypted_vc = true;
839            payload_crypt_off = 0;
840        }
841    }
842    if crypt_off > in_pdu.len() {
843        return Err(PspError::PacketEncapError(
844            "Crypt offset too big".to_string(),
845        ));
846    }
847    debug!("encap: crypt_off: {crypt_off}");
848    debug!("encap: payload_crypt_off: {payload_crypt_off}");
849
850    // Build the PSP encapsulated packet
851    //   - insert the PSP header
852    //   - Copy crypt_off bytes from input packet
853    //   - Compute ICV and insert encrypted data
854    //   - Insert ICV as the PSP trailer
855
856    let mut psp_encap_len = PspPacket::minimum_packet_size() + PSP_ICV_SIZE;
857    if pkt_ctx.psp_cfg.include_vc {
858        psp_encap_len += PSP_VC_SIZE;
859    }
860    let out_pkt_len = psp_encap_len + in_pdu.len();
861    let mut out_pkt = Vec::<u8>::with_capacity(out_pkt_len);
862
863    let mut flags = PspHeaderFlags::default();
864    flags.set_version(get_psp_version(pkt_ctx.psp_cfg.crypto_alg) as u8);
865    flags.set_v(pkt_ctx.psp_cfg.include_vc);
866
867    let psp_hdr = &PspHeader {
868        next_hdr: next_protocol,
869        hdr_ext_len: match pkt_ctx.psp_cfg.include_vc {
870            true => 2,
871            false => 1,
872        },
873        crypt_off: pkt_ctx.psp_cfg.transport_crypt_off,
874        flags,
875        spi: pkt_ctx.psp_cfg.spi,
876        iv: pkt_ctx.iv,
877    };
878
879    let start_of_psp_hdr = out_pkt.len();
880    let encoder = bincode::DefaultOptions::new()
881        .with_big_endian()
882        .with_fixint_encoding();
883    let psp_buf = encoder.serialize(psp_hdr)?;
884    out_pkt.extend_from_slice(&psp_buf);
885
886    let end_of_iv = out_pkt.len();
887    let start_of_crypto_region = end_of_iv + crypt_off;
888
889    if flags.v() {
890        out_pkt.extend_from_slice(&encoder.serialize(&pkt_ctx.vc)?);
891    }
892    let start_of_payload_region = out_pkt.len();
893
894    let gcm_iv = get_aesgcm_iv(pkt_ctx.psp_cfg.spi, pkt_ctx.iv);
895    pkt_ctx.iv += 1;
896
897    out_pkt.extend_from_slice(&in_pdu[..payload_crypt_off]);
898    out_pkt.resize(out_pkt_len, 0);
899    let aad = out_pkt[start_of_psp_hdr..start_of_crypto_region].to_vec();
900
901    if encrypted_vc {
902        let mut cleartext: Vec<u8> = Vec::with_capacity(in_pdu.len() + PSP_VC_SIZE);
903        cleartext.extend_from_slice(&out_pkt[start_of_crypto_region..start_of_payload_region]);
904        cleartext.extend_from_slice(in_pdu);
905
906        let ciphertext = &mut out_pkt[start_of_crypto_region..];
907
908        psp_encrypt(
909            pkt_ctx.psp_cfg.crypto_alg,
910            &pkt_ctx.key,
911            &gcm_iv,
912            &aad,
913            &cleartext,
914            ciphertext,
915        )?;
916    } else {
917        // Simpler case, no need to copy
918        let cleartext = &in_pdu[payload_crypt_off..];
919
920        let ciphertext = &mut out_pkt[start_of_crypto_region..];
921
922        psp_encrypt(
923            pkt_ctx.psp_cfg.crypto_alg,
924            &pkt_ctx.key,
925            &gcm_iv,
926            &aad,
927            cleartext,
928            ciphertext,
929        )?;
930    }
931
932    Ok(out_pkt)
933}
934
935/// Encapsulate a packet in transport mode.
936///
937/// Input packet:
938///     +---------+--------+---------+
939///     | Eth Hdr | IP Hdr | Payload |
940///     +---------+--------+---------+
941///
942/// Output packet:
943///     +---------+--------+---------+---------+---------+-------------+
944///     | Eth Hdr | IP Hdr ] UDP Hdr | PSP Hdr | Payload | PSP Trailer |
945///     +---------+--------+---------+---------+---------+-------------+
946///
947/// ```rust
948/// # use psp_security::*;
949/// # use etherparse::PacketBuilder;
950/// # fn main() -> Result<(), PspError> {
951/// let builder = PacketBuilder::ethernet2([1, 2, 3, 4, 5, 6], [7, 8, 9, 10, 11, 12])
952///     .ipv4([192, 168, 1, 1], [192, 168, 1, 2], 32)
953///     .udp(21, 1234);
954/// let payload = [1, 2, 3, 4, 5, 6, 7, 8];
955/// let mut pkt = Vec::<u8>::with_capacity(builder.size(payload.len()));
956/// builder.write(&mut pkt, &payload).unwrap();
957///
958/// let mut pkt_ctx = PktContext::default();
959/// pkt_ctx.psp_cfg.psp_encap = PspEncap::Transport;
960/// pkt_ctx.key = derive_psp_key(pkt_ctx.psp_cfg.spi, pkt_ctx.psp_cfg.crypto_alg, &pkt_ctx.psp_cfg.master_keys);
961/// let encap_pkt = psp_transport_encap(&mut pkt_ctx, &pkt)?;
962/// #
963/// #   Ok(())
964/// # }
965/// ```
966/// # Errors
967///
968/// This function may encounter several types of errors.
969/// Errors when trying to encapsulate the packet are returned as a `PspError::PacketEncapError`.
970/// Errors when encrypting the packet are reurned as a `PspError::CryptoError`.
971pub fn psp_transport_encap(pkt_ctx: &mut PktContext, in_pkt: &[u8]) -> Result<Vec<u8>, PspError> {
972    let (in_eth, in_eth_payload) = Ethernet2Header::from_slice(in_pkt)?;
973    match in_eth.ether_type {
974        ether_type::IPV4 => (),
975        ether_type::IPV6 => (),
976        _ => {
977            return Err(PspError::PacketEncapError(
978                "Unsupported input packet type".to_string(),
979            ))
980        }
981    }
982
983    let (in_ip, next_protocol, in_ip_payload) = IpHeader::from_slice(in_eth_payload)?;
984
985    let crypt_off = usize::from(pkt_ctx.psp_cfg.transport_crypt_off) * PSP_CRYPT_OFFSET_UNITS;
986    let mut payload_crypt_off = crypt_off;
987    let mut encrypted_vc = false;
988
989    if pkt_ctx.psp_cfg.include_vc {
990        if crypt_off >= PSP_VC_SIZE {
991            payload_crypt_off -= PSP_VC_SIZE;
992        } else {
993            encrypted_vc = true;
994            payload_crypt_off = 0;
995        }
996    }
997    if crypt_off > in_ip_payload.len() {
998        return Err(PspError::PacketEncapError(
999            "Crypt offset too big".to_string(),
1000        ));
1001    }
1002    debug!("transport_encap: crypt_off: {crypt_off}");
1003    debug!("transport_encap: payload_crypt_off: {payload_crypt_off}");
1004
1005    // Build the PSP encapsulated packet
1006    //   - copy the Ethernet and IP headers of the input packet.
1007    //   - insert the PSP UDP header
1008    //   - insert the PSP header
1009    //   - Copy crypt_off bytes from input packet starting at the L4 header
1010    //   - Compute ICV and insert encrypted data
1011    //   - Insert ICV as the PSP trailer
1012
1013    let mut psp_encap_len = PspPacket::minimum_packet_size() + PSP_ICV_SIZE;
1014    if pkt_ctx.psp_cfg.include_vc {
1015        psp_encap_len += PSP_VC_SIZE;
1016    }
1017    let psp_udp_encap_len = psp_encap_len + UdpHeader::SERIALIZED_SIZE;
1018    let out_pkt_len = in_pkt.len() + psp_udp_encap_len;
1019    let mut out_pkt = Vec::<u8>::with_capacity(out_pkt_len);
1020
1021    in_eth.write(&mut out_pkt)?;
1022
1023    let mut out_ip = in_ip;
1024    out_ip.set_next_headers(ip_number::UDP);
1025    out_ip
1026        .set_payload_len(in_ip_payload.len() + psp_udp_encap_len)
1027        .map_err(|err| PspError::PacketEncapError(format!("Failed to encapsulate packet: {}", err)))?;
1028    out_ip.write(&mut out_pkt)?;
1029
1030    let out_udp = UdpHeader::without_ipv4_checksum(
1031        PSP_UDP_PORT,
1032        PSP_UDP_PORT,
1033        in_ip_payload.len() + psp_encap_len,
1034    )
1035    .map_err(|err| PspError::PacketEncapError(format!("Failed to encapsulate packet: {}", err)))?;
1036
1037    out_udp.write(&mut out_pkt)?;
1038
1039    let mut flags = PspHeaderFlags::default();
1040    flags.set_version(get_psp_version(pkt_ctx.psp_cfg.crypto_alg) as u8);
1041    flags.set_v(pkt_ctx.psp_cfg.include_vc);
1042
1043    let psp_hdr = &PspHeader {
1044        next_hdr: next_protocol,
1045        hdr_ext_len: match pkt_ctx.psp_cfg.include_vc {
1046            true => 2,
1047            false => 1,
1048        },
1049        crypt_off: pkt_ctx.psp_cfg.transport_crypt_off,
1050        flags,
1051        spi: pkt_ctx.psp_cfg.spi,
1052        iv: pkt_ctx.iv,
1053    };
1054
1055    let start_of_psp_hdr = out_pkt.len();
1056    let encoder = bincode::DefaultOptions::new()
1057        .with_big_endian()
1058        .with_fixint_encoding();
1059    let psp_buf = encoder.serialize(psp_hdr)?;
1060    out_pkt.extend_from_slice(&psp_buf);
1061
1062    let end_of_iv = out_pkt.len();
1063    let start_of_crypto_region = end_of_iv + crypt_off;
1064
1065    if flags.v() {
1066        out_pkt.extend_from_slice(&encoder.serialize(&pkt_ctx.vc)?);
1067    }
1068    let start_of_payload_region = out_pkt.len();
1069
1070    let gcm_iv = get_aesgcm_iv(pkt_ctx.psp_cfg.spi, pkt_ctx.iv);
1071    pkt_ctx.iv += 1;
1072
1073    out_pkt.extend_from_slice(&in_ip_payload[..payload_crypt_off]);
1074    out_pkt.resize(out_pkt_len, 0);
1075    let aad = out_pkt[start_of_psp_hdr..start_of_crypto_region].to_vec();
1076
1077    if encrypted_vc {
1078        let mut cleartext: Vec<u8> = Vec::with_capacity(in_ip_payload.len() + PSP_VC_SIZE);
1079        cleartext.extend_from_slice(&out_pkt[start_of_crypto_region..start_of_payload_region]);
1080        cleartext.extend_from_slice(in_ip_payload);
1081
1082        let ciphertext = &mut out_pkt[start_of_crypto_region..];
1083
1084        psp_encrypt(
1085            pkt_ctx.psp_cfg.crypto_alg,
1086            &pkt_ctx.key,
1087            &gcm_iv,
1088            &aad,
1089            &cleartext,
1090            ciphertext,
1091        )?;
1092    } else {
1093        // Simpler case, no need to copy
1094        let cleartext = &in_ip_payload[payload_crypt_off..];
1095
1096        let ciphertext = &mut out_pkt[start_of_crypto_region..];
1097
1098        psp_encrypt(
1099            pkt_ctx.psp_cfg.crypto_alg,
1100            &pkt_ctx.key,
1101            &gcm_iv,
1102            &aad,
1103            cleartext,
1104            ciphertext,
1105        )?;
1106    }
1107
1108    Ok(out_pkt)
1109}
1110
1111/// Encapsulate a packet in tunnel mode.
1112///
1113/// Input packet:
1114///     +---------+--------+---------+
1115///     | Eth Hdr | IP Hdr | Payload |
1116///     +---------+--------+---------+
1117///
1118/// Output packet:
1119///     +---------+--------+---------+---------+--------+---------+-------------+
1120///     | Eth Hdr | IP Hdr ] UDP Hdr | PSP Hdr | IP Hdr | Payload | PSP Trailer |
1121///     +---------+--------+---------+---------+--------+---------+-------------+
1122///
1123/// ```rust
1124/// # use psp_security::*;
1125/// # use etherparse::PacketBuilder;
1126/// # fn main() -> Result<(), PspError> {
1127/// let builder = PacketBuilder::ethernet2([1, 2, 3, 4, 5, 6], [7, 8, 9, 10, 11, 12])
1128///     .ipv4([192, 168, 1, 1], [192, 168, 1, 2], 32)
1129///     .udp(21, 1234);
1130/// let payload = [1, 2, 3, 4, 5, 6, 7, 8];
1131/// let mut pkt = Vec::<u8>::with_capacity(builder.size(payload.len()));
1132/// builder.write(&mut pkt, &payload).unwrap();
1133///
1134/// let mut pkt_ctx = PktContext::default();
1135/// pkt_ctx.psp_cfg.psp_encap = PspEncap::Tunnel;
1136/// pkt_ctx.key = derive_psp_key(pkt_ctx.psp_cfg.spi, pkt_ctx.psp_cfg.crypto_alg, &pkt_ctx.psp_cfg.master_keys);
1137/// let encap_pkt = psp_tunnel_encap(&mut pkt_ctx, &pkt)?;
1138/// #
1139/// #   Ok(())
1140/// # }
1141/// ```
1142/// # Errors
1143///
1144/// This function may encounter several types of errors.
1145/// Errors when trying to encapsulate the packet are returned as a `PspError::PacketEncapError`.
1146/// Errors when encrypting the packet are reurned as a `PspError::CryptoError`.
1147pub fn psp_tunnel_encap(pkt_ctx: &mut PktContext, in_pkt: &[u8]) -> Result<Vec<u8>, PspError> {
1148    let (in_eth, in_eth_payload) = Ethernet2Header::from_slice(in_pkt)?;
1149    let (psp_next_protocol, tun_hdr_size) = match in_eth.ether_type {
1150        ether_type::IPV4 => (ip_number::IPV4, Ipv4Header::SERIALIZED_SIZE),
1151        ether_type::IPV6 => (ip_number::IPV6, Ipv6Header::SERIALIZED_SIZE),
1152        _ => {
1153            return Err(PspError::PacketEncapError(
1154                "Unsupported input packet type".to_string(),
1155            ))
1156        }
1157    };
1158
1159    let psp_payload = in_eth_payload;
1160    let psp_payload_len = psp_payload.len();
1161
1162    let (in_ip, _, _) = IpHeader::from_slice(in_eth_payload)?;
1163
1164    let crypt_off_cfg_val = match psp_next_protocol {
1165        ip_number::IPV4 => usize::from(pkt_ctx.psp_cfg.ipv4_tunnel_crypt_off),
1166        ip_number::IPV6 => usize::from(pkt_ctx.psp_cfg.ipv6_tunnel_crypt_off),
1167        _ => 0,
1168    };
1169    let crypt_off = crypt_off_cfg_val * PSP_CRYPT_OFFSET_UNITS;
1170    let mut payload_crypt_off = crypt_off;
1171    let mut encrypted_vc = false;
1172    if pkt_ctx.psp_cfg.include_vc {
1173        if crypt_off >= PSP_VC_SIZE {
1174            payload_crypt_off -= PSP_VC_SIZE;
1175        } else {
1176            encrypted_vc = true;
1177        }
1178    }
1179    if payload_crypt_off > in_eth_payload.len() {
1180        return Err(PspError::PacketEncapError(
1181            "Crypto offset too big".to_string(),
1182        ));
1183    }
1184
1185    // Build the PSP encapsulated packet
1186    //   - copy the Ethernet and IP headers of the input packet.
1187    //   - insert the outer ip header based on ip header of input packet.
1188    //   - insert the PSP UDP header
1189    //   - insert the PSP header
1190    //   - Copy crypt_off bytes from input packet starting at the IP header
1191    //   - Compute ICV and insert encrypted data
1192    //   - Insert ICV as the PSP trailer
1193
1194    let mut psp_encap_len = PspPacket::minimum_packet_size() + PSP_ICV_SIZE;
1195    if pkt_ctx.psp_cfg.include_vc {
1196        psp_encap_len += PSP_VC_SIZE;
1197    }
1198    let psp_udp_encap_len = psp_encap_len + UdpHeader::SERIALIZED_SIZE;
1199    let psp_udp_ip_encap_len = psp_udp_encap_len + tun_hdr_size;
1200    let out_pkt_len = in_pkt.len() + psp_udp_ip_encap_len;
1201    let mut out_pkt = Vec::<u8>::with_capacity(out_pkt_len);
1202
1203    in_eth.write(&mut out_pkt)?;
1204
1205    let mut out_ip = in_ip;
1206    out_ip.set_next_headers(ip_number::UDP);
1207    out_ip
1208        .set_payload_len(psp_payload_len + psp_udp_encap_len)
1209        .map_err(|err| PspError::PacketEncapError(format!("Failed to encapsulate packet: {}", err)))?;
1210    out_ip.write(&mut out_pkt)?;
1211
1212    let out_udp = UdpHeader::without_ipv4_checksum(
1213        PSP_UDP_PORT,
1214        PSP_UDP_PORT,
1215        psp_payload_len + psp_encap_len,
1216    )
1217    .map_err(|err| PspError::PacketEncapError(format!("Failed to encapsulate packet: {}", err)))?;
1218
1219    out_udp.write(&mut out_pkt)?;
1220
1221    let mut flags = PspHeaderFlags::default();
1222    flags.set_version(get_psp_version(pkt_ctx.psp_cfg.crypto_alg) as u8);
1223    flags.set_v(pkt_ctx.psp_cfg.include_vc);
1224
1225    let psp_hdr = &PspHeader {
1226        next_hdr: psp_next_protocol,
1227        hdr_ext_len: match pkt_ctx.psp_cfg.include_vc {
1228            true => 2,
1229            false => 1,
1230        },
1231        crypt_off: crypt_off_cfg_val as u8,
1232        flags,
1233        spi: pkt_ctx.psp_cfg.spi,
1234        iv: pkt_ctx.iv,
1235    };
1236
1237    let start_of_psp_hdr = out_pkt.len();
1238
1239    let encoder = bincode::DefaultOptions::new()
1240        .with_big_endian()
1241        .with_fixint_encoding();
1242    let psp_buf = encoder.serialize(psp_hdr)?;
1243    out_pkt.extend_from_slice(&psp_buf);
1244
1245    let end_of_iv = out_pkt.len();
1246    let start_of_crypto_region = end_of_iv + crypt_off;
1247
1248    if flags.v() {
1249        out_pkt.extend_from_slice(&encoder.serialize(&pkt_ctx.vc)?);
1250    }
1251
1252    let start_of_payload_region = out_pkt.len();
1253
1254    let gcm_iv = get_aesgcm_iv(pkt_ctx.psp_cfg.spi, pkt_ctx.iv);
1255    pkt_ctx.iv += 1;
1256
1257    out_pkt.extend_from_slice(&psp_payload[..payload_crypt_off]);
1258    out_pkt.resize(out_pkt_len, 0);
1259    let aad = out_pkt[start_of_psp_hdr..start_of_crypto_region].to_vec();
1260
1261    if encrypted_vc {
1262        let mut cleartext: Vec<u8> = Vec::with_capacity(psp_payload.len() + PSP_VC_SIZE);
1263        cleartext.extend_from_slice(&out_pkt[start_of_crypto_region..start_of_payload_region]);
1264        cleartext.extend_from_slice(psp_payload);
1265
1266        let ciphertext = &mut out_pkt[start_of_crypto_region..];
1267
1268        psp_encrypt(
1269            pkt_ctx.psp_cfg.crypto_alg,
1270            &pkt_ctx.key,
1271            &gcm_iv,
1272            &aad,
1273            &cleartext,
1274            ciphertext,
1275        )?;
1276    } else {
1277        // Simpler case, no need to copy
1278        let cleartext = &psp_payload[payload_crypt_off..];
1279
1280        let ciphertext = &mut out_pkt[start_of_crypto_region..];
1281
1282        psp_encrypt(
1283            pkt_ctx.psp_cfg.crypto_alg,
1284            &pkt_ctx.key,
1285            &gcm_iv,
1286            &aad,
1287            cleartext,
1288            ciphertext,
1289        )?;
1290    }
1291
1292    Ok(out_pkt)
1293}
1294
1295/// Decapsulate a PSP packet.
1296/// If the PSP header Next Header field indicates an IPv4 or IPv6 header, tunnel mode decapsulation
1297/// will be used, otherwise, transport mode decapsulation will be used.
1298pub fn psp_decap_eth(pkt_ctx: &mut PktContext, in_pkt: &[u8]) -> Result<Vec<u8>, PspError> {
1299    let parsed_pkt = PacketHeaders::from_ethernet_slice(in_pkt)?;
1300    match parsed_pkt.transport {
1301        None => Err(PspError::PacketDecapError("No UDP header".to_string())),
1302        _ => Ok(()),
1303    }?;
1304
1305    let psp_buf = parsed_pkt.payload;
1306
1307    let in_psp = PspPacket::new(psp_buf).ok_or(PspError::PacketDecapError(
1308        "Error parsing PSP header".to_string(),
1309    ))?;
1310
1311    match in_psp.get_next_hdr() {
1312        ip_number::IPV4 | ip_number::IPV6 => psp_tunnel_decap(pkt_ctx, in_pkt),
1313        _ => psp_transport_decap(pkt_ctx, in_pkt),
1314    }
1315}
1316
1317/// Decapsulate a PSP transport mode packet.
1318///
1319/// Input packet:
1320///     +---------+--------+---------+---------+---------+-------------+
1321///     | Eth Hdr | IP Hdr | UDP Hdr | PSP Hdr | Payload | PSP Trailer |
1322///     +---------+--------+---------+---------+---------+-------------+
1323///
1324/// Output packet:
1325///     +---------+--------+---------+
1326///     | Eth Hdr | IP Hdr | Payload |
1327///     +---------+--------+---------+
1328///
1329/// ```rust
1330/// # use psp_security::*;
1331/// # use etherparse::PacketBuilder;
1332/// # fn main() -> Result<(), PspError> {
1333/// let builder = PacketBuilder::ethernet2([1, 2, 3, 4, 5, 6], [7, 8, 9, 10, 11, 12])
1334///     .ipv4([192, 168, 1, 1], [192, 168, 1, 2], 32)
1335///     .udp(21, 1234);
1336/// let payload = [1, 2, 3, 4, 5, 6, 7, 8];
1337/// let mut pkt = Vec::<u8>::with_capacity(builder.size(payload.len()));
1338/// builder.write(&mut pkt, &payload).unwrap();
1339///
1340/// let mut pkt_ctx = PktContext::default();
1341/// pkt_ctx.psp_cfg.psp_encap = PspEncap::Transport;
1342/// let mut decrypt_pkt_ctx = pkt_ctx.clone();
1343///
1344/// pkt_ctx.key = derive_psp_key(pkt_ctx.psp_cfg.spi, pkt_ctx.psp_cfg.crypto_alg, &pkt_ctx.psp_cfg.master_keys);
1345/// let encap_pkt = psp_transport_encap(&mut pkt_ctx, &pkt)?;
1346/// let decap_pkt = psp_transport_decap(&mut decrypt_pkt_ctx, &encap_pkt)?;
1347/// #
1348/// #   Ok(())
1349/// # }
1350/// ```
1351/// # Errors
1352///
1353/// This function may encounter several types of errors.
1354/// Errors when trying to encapsulate the packet are returned as a `PspError::PacketDecapError`.
1355/// Errors when encrypting the packet are reurned as a `PspError::CryptoError`.
1356pub fn psp_transport_decap(pkt_ctx: &mut PktContext, in_pkt: &[u8]) -> Result<Vec<u8>, PspError> {
1357    let parsed_pkt = PacketHeaders::from_ethernet_slice(in_pkt)?;
1358    match parsed_pkt.transport {
1359        None => Err(PspError::PacketDecapError("No UDP header".to_string())),
1360        _ => Ok(()),
1361    }?;
1362
1363    let psp_buf = parsed_pkt.payload;
1364
1365    let in_psp = PspPacket::new(psp_buf).ok_or(PspError::PacketDecapError(
1366        "Error parsing PSP header".to_string(),
1367    ))?;
1368
1369    let payload = in_psp.payload();
1370    if payload.len() < PSP_ICV_SIZE {
1371        return Err(PspError::InvalidPspPacketSize);
1372    }
1373
1374    let crypt_off = usize::from(in_psp.get_crypt_offset()) * PSP_CRYPT_OFFSET_UNITS;
1375    debug!("transport_decap: crypt_off: {crypt_off}");
1376    let mut payload_crypt_off = crypt_off;
1377    if in_psp.get_v() == 1 {
1378        if crypt_off >= PSP_VC_SIZE {
1379            payload_crypt_off -= PSP_VC_SIZE;
1380        } else {
1381            payload_crypt_off = 0;
1382        }
1383    }
1384    if payload_crypt_off > payload.len() {
1385        return Err(PspError::PacketDecapError(
1386            "Invalid crypto offset".to_string(),
1387        ));
1388    }
1389
1390    // Build the PSP deencapsulated packet
1391    //   - copy the Ethernet and IP headers of the input packet.
1392    //   - Skip the PSP UDP header
1393    //   - Skip the PSP header
1394    //   - Copy crypt_off bytes from input packet starting at the L4 header
1395
1396    let vc_len = match in_psp.get_v() {
1397        0 => 0,
1398        _ => PSP_VC_SIZE,
1399    };
1400    let psp_encap_len = PspPacket::minimum_packet_size() + vc_len + PSP_ICV_SIZE;
1401    let psp_and_udp_encap_len = UdpHeader::SERIALIZED_SIZE + psp_encap_len;
1402    let out_pkt_len = in_pkt.len() - psp_and_udp_encap_len;
1403    let mut out_pkt = Vec::<u8>::with_capacity(out_pkt_len);
1404
1405    if let Some(eth) = parsed_pkt.link {
1406        eth.write(&mut out_pkt)?;
1407    }
1408    if let Some(ip) = parsed_pkt.ip {
1409        let mut out_ip = ip;
1410        let out_ip_len = parsed_pkt.payload.len() - psp_encap_len;
1411        out_ip
1412            .set_payload_len(out_ip_len)
1413            .map_err(|err| PspError::PacketDecapError(format!("Failed to decapsulate packet: {}", err)))?;
1414        out_ip.set_next_headers(in_psp.get_next_hdr());
1415        out_ip.write(&mut out_pkt)?;
1416    }
1417
1418    pkt_ctx.psp_cfg.crypto_alg = get_psp_crypto_alg(in_psp.get_version().try_into()?);
1419
1420    let aad_len: usize = usize::from(PSP_HDR_FIXED_LEN) + crypt_off;
1421    let aad = parsed_pkt.payload[..aad_len].to_vec();
1422
1423    let spi = in_psp.get_spi();
1424    pkt_ctx.psp_cfg.spi = spi;
1425    let gcm_iv = get_aesgcm_iv(spi, in_psp.get_iv());
1426
1427    pkt_ctx.key = derive_psp_key(
1428        pkt_ctx.psp_cfg.spi,
1429        pkt_ctx.psp_cfg.crypto_alg,
1430        &pkt_ctx.psp_cfg.master_keys,
1431    );
1432
1433    let ciphertext = &parsed_pkt.payload[aad_len..];
1434    out_pkt.extend_from_slice(&in_psp.payload()[..payload_crypt_off]);
1435
1436    let start_of_decrypt_region = out_pkt.len();
1437    out_pkt.resize(out_pkt_len, 0);
1438    let cleartext = &mut out_pkt[start_of_decrypt_region..];
1439
1440    psp_decrypt(
1441        pkt_ctx.psp_cfg.crypto_alg,
1442        &pkt_ctx.key,
1443        &gcm_iv,
1444        &aad,
1445        ciphertext,
1446        cleartext,
1447    )?;
1448
1449    Ok(out_pkt)
1450}
1451
1452/// Decapsulate a PSP tunnel mode packet.
1453///
1454/// Input packet:
1455///     +---------+--------+---------+---------+--------+---------+-------------+
1456///     | Eth Hdr | IP Hdr ] UDP Hdr | PSP Hdr | IP Hdr | Payload | PSP Trailer |
1457///     +---------+--------+---------+---------+--------+---------+-------------+
1458///
1459/// Output packet:
1460///     +---------+--------+---------+
1461///     | Eth Hdr | IP Hdr | Payload |
1462///     +---------+--------+---------+
1463///
1464/// ```rust
1465/// # use psp_security::*;
1466/// # use etherparse::PacketBuilder;
1467/// # fn main() -> Result<(), PspError> {
1468/// let builder = PacketBuilder::ethernet2([1, 2, 3, 4, 5, 6], [7, 8, 9, 10, 11, 12])
1469///     .ipv4([192, 168, 1, 1], [192, 168, 1, 2], 32)
1470///     .udp(21, 1234);
1471/// let payload = [1, 2, 3, 4, 5, 6, 7, 8];
1472/// let mut pkt = Vec::<u8>::with_capacity(builder.size(payload.len()));
1473/// builder.write(&mut pkt, &payload).unwrap();
1474///
1475/// let mut pkt_ctx = PktContext::default();
1476/// pkt_ctx.psp_cfg.psp_encap = PspEncap::Tunnel;
1477/// let mut decrypt_pkt_ctx = pkt_ctx.clone();
1478///
1479/// pkt_ctx.key = derive_psp_key(pkt_ctx.psp_cfg.spi, pkt_ctx.psp_cfg.crypto_alg, &pkt_ctx.psp_cfg.master_keys);
1480/// let encap_pkt = psp_tunnel_encap(&mut pkt_ctx, &pkt)?;
1481/// let decap_pkt = psp_tunnel_decap(&mut decrypt_pkt_ctx, &encap_pkt)?;
1482/// #
1483/// #   Ok(())
1484/// # }
1485/// ```
1486/// # Errors
1487///
1488/// This function may encounter several types of errors.
1489/// Errors when trying to encapsulate the packet are returned as a `PspError::PacketDecapError`.
1490/// Errors when encrypting the packet are reurned as a `PspError::CryptoError`.
1491pub fn psp_tunnel_decap(pkt_ctx: &mut PktContext, in_pkt: &[u8]) -> Result<Vec<u8>, PspError> {
1492    let parsed_pkt = PacketHeaders::from_ethernet_slice(in_pkt)?;
1493
1494    let eth = parsed_pkt.link.ok_or(PspError::PacketDecapError(
1495        "Unsupported packet type".to_string(),
1496    ))?;
1497
1498    let ip_hdr = parsed_pkt.ip.ok_or(PspError::PacketDecapError(
1499        "Unsupported packet type".to_string(),
1500    ))?;
1501    let ip_hdr_size = ip_hdr.header_len();
1502
1503    match parsed_pkt.transport {
1504        Some(TransportHeader::Udp(_)) => Ok(()),
1505        _ => Err(PspError::PacketDecapError("No UDP header".to_string())),
1506    }?;
1507
1508    let psp_buf = parsed_pkt.payload;
1509    let in_psp = PspPacket::new(psp_buf).ok_or(PspError::PacketDecapError(
1510        "Error parsing PSP header".to_string(),
1511    ))?;
1512
1513    let payload = in_psp.payload();
1514    if payload.len() < PSP_ICV_SIZE {
1515        return Err(PspError::InvalidPspPacketSize);
1516    }
1517
1518    let crypt_off = usize::from(in_psp.get_crypt_offset()) * PSP_CRYPT_OFFSET_UNITS;
1519    let mut payload_crypt_off = crypt_off;
1520    if in_psp.get_v() == 1 {
1521        if crypt_off >= PSP_VC_SIZE {
1522            payload_crypt_off -= PSP_VC_SIZE;
1523        } else {
1524            payload_crypt_off = 0;
1525        }
1526    }
1527    if payload_crypt_off > payload.len() {
1528        return Err(PspError::PacketDecapError(
1529            "Invalid crypto offset".to_string(),
1530        ));
1531    }
1532
1533    // Build the PSP deencapsulated packet
1534    //   - copy the Ethernet header of the input packet.
1535    //   - Skip the outer IP header
1536    //   - Skip the PSP UDP header
1537    //   - Skip the PSP header
1538    //   - Copy crypt_off bytes from input packet starting at the L4 header
1539    //   - Decrypt the remainder of the input packet and write the decrypted content to the output
1540    //     packet.
1541
1542    let vc_len = match in_psp.get_v() {
1543        0 => 0,
1544        _ => PSP_VC_SIZE,
1545    };
1546    let psp_encap_len = PspPacket::minimum_packet_size() + vc_len + PSP_ICV_SIZE;
1547    let psp_udp_encap_len = UdpHeader::SERIALIZED_SIZE + psp_encap_len;
1548    let psp_udp_ip_encap_len = ip_hdr_size + psp_udp_encap_len;
1549    let out_pkt_len = in_pkt.len() - psp_udp_ip_encap_len;
1550    let mut out_pkt = Vec::<u8>::with_capacity(out_pkt_len);
1551
1552    eth.write(&mut out_pkt)?;
1553
1554    pkt_ctx.psp_cfg.crypto_alg = get_psp_crypto_alg(in_psp.get_version().try_into()?);
1555
1556    // crypt_off already incorporates vc len
1557    let aad_len: usize = usize::from(PSP_HDR_FIXED_LEN) + crypt_off;
1558    let aad = parsed_pkt.payload[..aad_len].to_vec();
1559
1560    let spi = in_psp.get_spi();
1561    pkt_ctx.psp_cfg.spi = spi;
1562    let gcm_iv = get_aesgcm_iv(spi, in_psp.get_iv());
1563
1564    pkt_ctx.key = derive_psp_key(
1565        pkt_ctx.psp_cfg.spi,
1566        pkt_ctx.psp_cfg.crypto_alg,
1567        &pkt_ctx.psp_cfg.master_keys,
1568    );
1569
1570    let ciphertext = &parsed_pkt.payload[aad_len..];
1571    out_pkt.extend_from_slice(&in_psp.payload()[..payload_crypt_off]);
1572
1573    let start_of_decrypt_region = out_pkt.len();
1574    out_pkt.resize(out_pkt_len, 0);
1575    let cleartext = &mut out_pkt[start_of_decrypt_region..];
1576
1577    psp_decrypt(
1578        pkt_ctx.psp_cfg.crypto_alg,
1579        &pkt_ctx.key,
1580        &gcm_iv,
1581        &aad,
1582        ciphertext,
1583        cleartext,
1584    )?;
1585
1586    Ok(out_pkt)
1587}
1588
1589/// Decapsulate a PSP encapsulated PDU.
1590///
1591/// Input PDU:
1592///     +---------+---------+-------------+
1593///     | PSP Hdr | Payload | PSP Trailer |
1594///     +---------+---------+-------------+
1595///
1596/// Output PDU:
1597///     +---------+
1598///     | Payload |
1599///     +---------+
1600///
1601/// ```rust
1602/// # use psp_security::*;
1603/// # fn main() -> Result<(), PspError> {
1604/// let pkt = [1, 2, 3, 4, 5, 6, 7, 8];
1605///
1606/// let mut pkt_ctx = PktContext::default();
1607/// pkt_ctx.key = derive_psp_key(pkt_ctx.psp_cfg.spi, pkt_ctx.psp_cfg.crypto_alg, &pkt_ctx.psp_cfg.master_keys);
1608/// let encap_pkt = psp_encap_pdu(&mut pkt_ctx, &pkt, 17)?;
1609/// let decap_pdu = psp_decap_pdu(&mut pkt_ctx, &encap_pkt)?;
1610/// #
1611/// #   Ok(())
1612/// # }
1613/// ```
1614/// # Errors
1615///
1616/// This function may encounter several types of errors.
1617/// Errors when trying to encapsulate the packet are returned as a `PspError::PacketDecapError
1618/// Errors when encrypting the packet are reurned as a `PspError::CryptoError`.
1619/// Decapsulate a PSP PDU
1620pub fn psp_decap_pdu(pkt_ctx: &mut PktContext, in_pdu: &[u8]) -> Result<Vec<u8>, PspError> {
1621    let in_psp = PspPacket::new(in_pdu).ok_or(PspError::PacketDecapError(
1622        "Error parsing PSP header".to_string(),
1623    ))?;
1624
1625    let payload = in_psp.payload();
1626    if payload.len() < PSP_ICV_SIZE {
1627        return Err(PspError::InvalidPspPacketSize);
1628    }
1629
1630    let crypt_off = usize::from(in_psp.get_crypt_offset()) * PSP_CRYPT_OFFSET_UNITS;
1631    debug!("transport_decap: crypt_off: {crypt_off}");
1632    let mut payload_crypt_off = crypt_off;
1633    if in_psp.get_v() == 1 {
1634        if crypt_off >= PSP_VC_SIZE {
1635            payload_crypt_off -= PSP_VC_SIZE;
1636        } else {
1637            payload_crypt_off = 0;
1638        }
1639    }
1640    if payload_crypt_off > payload.len() {
1641        return Err(PspError::PacketDecapError(
1642            "Invalid crypto offset".to_string(),
1643        ));
1644    }
1645
1646    // Build the PSP deencapsulated packet
1647    //   - Copy crypt_off bytes from input packet starting at the L4 header
1648
1649    let vc_len = match in_psp.get_v() {
1650        0 => 0,
1651        _ => PSP_VC_SIZE,
1652    };
1653    let psp_encap_len = PspPacket::minimum_packet_size() + vc_len + PSP_ICV_SIZE;
1654    let out_pkt_len = in_pdu.len() - psp_encap_len;
1655    let mut out_pkt = Vec::<u8>::with_capacity(out_pkt_len);
1656
1657    pkt_ctx.psp_cfg.crypto_alg = get_psp_crypto_alg(in_psp.get_version().try_into()?);
1658
1659    let aad_len: usize = usize::from(PSP_HDR_FIXED_LEN) + crypt_off;
1660    let aad = in_pdu[..aad_len].to_vec();
1661
1662    let spi = in_psp.get_spi();
1663    pkt_ctx.psp_cfg.spi = spi;
1664    let gcm_iv = get_aesgcm_iv(spi, in_psp.get_iv());
1665
1666    debug!("decap_pdu: spi: {:08X}", pkt_ctx.psp_cfg.spi);
1667    debug!("decap_pdu: crypto_alg: {}", pkt_ctx.psp_cfg.crypto_alg);
1668    debug!("decap_pdu: iv: {}", pkt_ctx.iv);
1669    debug!("decap_pdu: key: {:?}", &pkt_ctx.key);
1670
1671    // pkt_ctx.key = derive_psp_key(
1672    //     pkt_ctx.psp_cfg.spi,
1673    //     pkt_ctx.psp_cfg.crypto_alg,
1674    //     &pkt_ctx.psp_cfg.master_keys,
1675    // );
1676
1677    let ciphertext = &in_pdu[aad_len..];
1678    out_pkt.extend_from_slice(&in_psp.payload()[..payload_crypt_off]);
1679
1680    let start_of_decrypt_region = out_pkt.len();
1681    out_pkt.resize(out_pkt_len, 0);
1682    let cleartext = &mut out_pkt[start_of_decrypt_region..];
1683
1684    psp_decrypt(
1685        pkt_ctx.psp_cfg.crypto_alg,
1686        &pkt_ctx.key,
1687        &gcm_iv,
1688        &aad,
1689        ciphertext,
1690        cleartext,
1691    )?;
1692
1693    Ok(out_pkt)
1694}
1695
1696#[cfg(test)]
1697mod tests {
1698    use super::*;
1699    use crate::packet::psp::PspPacket;
1700    use etherparse::{EtherType, IpNumber, PacketBuilder, TransportHeader};
1701
1702    #[test]
1703    fn test_psp_version_try_from() {
1704        assert!(PspVersion::try_from(0).is_ok());
1705        assert!(PspVersion::try_from(1).is_ok());
1706        assert!(PspVersion::try_from(2).is_err());
1707    }
1708
1709    #[test]
1710    fn check_psp_header_builder() {
1711        let hdr = PspHeaderBuilder::default()
1712            .next_hdr(17)
1713            .spi(0x12345678)
1714            .iv(0x12345678_9ABCDEF0)
1715            .build()
1716            .unwrap();
1717
1718        assert_eq!(hdr.spi, 0x12345678);
1719        assert_eq!(hdr.iv, 0x12345678_9ABCDEF0);
1720        assert_eq!(hdr.next_hdr, 17);
1721        assert_eq!(hdr.flags.0, 0x01u8);
1722    }
1723
1724    #[test]
1725    fn test_derive_psp_key_128() {
1726        let mut master_keys = [[0u8; PSP_MASTER_KEY_SIZE]; 2];
1727        master_keys[0] = [
1728            0x34, 0x44, 0x8A, 0x06, 0x42, 0x92, 0x60, 0x1B, 0x11, 0xA0, 0x97, 0x8F, 0x56, 0xA2,
1729            0xd3, 0x4c, 0xf3, 0xfc, 0x35, 0xed, 0xe1, 0xa6, 0xbc, 0x04, 0xf8, 0xdb, 0x3e, 0x52,
1730            0x43, 0xa2, 0xb0, 0xca,
1731        ];
1732        master_keys[1] = [
1733            0x56, 0x39, 0x52, 0x56, 0x5d, 0x3a, 0x78, 0xae, 0x77, 0x3e, 0xc1, 0xb7, 0x79, 0xf2,
1734            0xf2, 0xd9, 0x9f, 0x4a, 0x7f, 0x53, 0xa6, 0xfb, 0xb9, 0xb0, 0x7d, 0x5b, 0x71, 0xf3,
1735            0x93, 0x64, 0xd7, 0x39,
1736        ];
1737
1738        let spi = 0x12345678;
1739        let expected: [u8; 16] = [
1740            0x96, 0xc2, 0x2d, 0xc7, 0x99, 0x19, 0x80, 0x90, 0xb7, 0x4b, 0x70, 0xae, 0x46, 0x8e,
1741            0x4e, 0x30,
1742        ];
1743
1744        let derived_key = derive_psp_key_128(spi, CryptoAlg::AesGcm128, &master_keys, 1);
1745        assert_eq!(expected.to_vec(), derived_key);
1746
1747        let spi = 0x9A345678;
1748        let expected: [u8; 16] = [
1749            0x39, 0x46, 0xda, 0x25, 0x54, 0xea, 0xe4, 0x6a, 0xd1, 0xef, 0x77, 0xa6, 0x43, 0x72,
1750            0xed, 0xc4,
1751        ];
1752
1753        let derived_key = derive_psp_key_128(spi, CryptoAlg::AesGcm128, &master_keys, 1);
1754        assert_eq!(expected.to_vec(), derived_key);
1755    }
1756
1757    #[test]
1758    fn test_derive_psp_key() {
1759        let mut master_keys = [[0u8; PSP_MASTER_KEY_SIZE]; 2];
1760        master_keys[0] = [
1761            0x34, 0x44, 0x8A, 0x06, 0x42, 0x92, 0x60, 0x1B, 0x11, 0xA0, 0x97, 0x8F, 0x56, 0xA2,
1762            0xd3, 0x4c, 0xf3, 0xfc, 0x35, 0xed, 0xe1, 0xa6, 0xbc, 0x04, 0xf8, 0xdb, 0x3e, 0x52,
1763            0x43, 0xa2, 0xb0, 0xca,
1764        ];
1765        let spi = 0x12345678;
1766        let crypto_alg = CryptoAlg::AesGcm128;
1767        let expected: [u8; 16] = [
1768            0x96, 0xc2, 0x2d, 0xc7, 0x99, 0x19, 0x80, 0x90, 0xb7, 0x4b, 0x70, 0xae, 0x46, 0x8e,
1769            0x4e, 0x30,
1770        ];
1771        let derived_key = derive_psp_key(spi, crypto_alg, &master_keys);
1772        assert_eq!(derived_key.len(), 16);
1773        assert_eq!(derived_key, expected);
1774
1775        let crypto_alg = CryptoAlg::AesGcm256;
1776        let expected: [u8; 32] = [
1777            0x2b, 0x7d, 0x72, 0x07, 0x4e, 0x42, 0xca, 0x33, 0x44, 0x87, 0xf2, 0x99, 0x0e, 0x3f,
1778            0x8c, 0x40, 0x37, 0xe4, 0x36, 0xf3, 0x82, 0x83, 0x44, 0x9b, 0x76, 0x46, 0x3e, 0x9b,
1779            0x7f, 0xb2, 0xe3, 0xde,
1780        ];
1781        let derived_key = derive_psp_key(spi, crypto_alg, &master_keys);
1782        assert_eq!(derived_key.len(), 32);
1783        assert_eq!(derived_key, expected);
1784    }
1785
1786    #[test]
1787    fn test_psp_encrypt() -> Result<(), Box<dyn std::error::Error>> {
1788        let mut pkt_ctx = PktContext::new();
1789        pkt_ctx.psp_cfg.crypto_alg = CryptoAlg::AesGcm128;
1790        pkt_ctx.key = vec![
1791            0x96, 0xc2, 0x2d, 0xc7, 0x99, 0x19, 0x80, 0x90, 0xb7, 0x4b, 0x70, 0xae, 0x46, 0x8e,
1792            0x4e, 0x30,
1793        ];
1794        let mut psp_hdr = PspHeader::default();
1795        psp_hdr.next_hdr = 6;
1796        psp_hdr.spi = 0x12345678;
1797        psp_hdr.iv = 0x12345678_9ABCDEFF;
1798        let aad = bincode::DefaultOptions::new()
1799            .with_fixint_encoding()
1800            .with_big_endian()
1801            .serialize(&psp_hdr)?;
1802
1803        let gcm_iv = get_aesgcm_iv(psp_hdr.spi, psp_hdr.iv);
1804
1805        let cleartext = vec![0u8; 256];
1806        let mut ciphertext = vec![0u8; 256 + PSP_ICV_SIZE];
1807
1808        let res = psp_encrypt(
1809            pkt_ctx.psp_cfg.crypto_alg,
1810            &pkt_ctx.key,
1811            &gcm_iv,
1812            &aad,
1813            &cleartext,
1814            &mut ciphertext,
1815        );
1816        assert!(res.is_ok());
1817        assert_ne!(ciphertext, cleartext);
1818
1819        Ok(())
1820    }
1821
1822    #[test]
1823    fn check_transport_encap() -> Result<(), Box<dyn std::error::Error>> {
1824        let builder = PacketBuilder::ethernet2([1, 2, 3, 4, 5, 6], [7, 8, 9, 10, 11, 12])
1825            .ipv4([192, 168, 1, 1], [192, 168, 1, 2], 32)
1826            .udp(21, 1234);
1827        let payload = [1, 2, 3, 4, 5, 6, 7, 8];
1828        let mut in_pkt = Vec::<u8>::with_capacity(builder.size(payload.len()));
1829        builder.write(&mut in_pkt, &payload)?;
1830
1831        let out_pkt_len = in_pkt.len()
1832            + UdpHeader::SERIALIZED_SIZE
1833            + PspPacket::minimum_packet_size()
1834            + PSP_ICV_SIZE;
1835        let mut pkt_ctx = PktContext::default();
1836        pkt_ctx.psp_cfg.spi = 1;
1837        pkt_ctx.psp_cfg.transport_crypt_off = 1;
1838
1839        let out_pkt = psp_transport_encap(&mut pkt_ctx, &in_pkt)?;
1840        assert_eq!(out_pkt_len, out_pkt.len());
1841
1842        let pkt = PacketHeaders::from_ethernet_slice(&out_pkt)?;
1843        assert!(pkt.link.is_some());
1844        assert_eq!(pkt.link.unwrap().ether_type, EtherType::Ipv4 as u16);
1845        assert!(pkt.ip.is_some());
1846        match pkt.ip.unwrap() {
1847            IpHeader::Version4(ip, _) => {
1848                assert_eq!(ip.source, [192, 168, 1, 1]);
1849                assert_eq!(ip.destination, [192, 168, 1, 2]);
1850                assert_eq!(ip.protocol, IpNumber::Udp as u8);
1851            }
1852            _ => assert!(false),
1853        };
1854        assert!(pkt.transport.is_some());
1855        match pkt.transport.unwrap() {
1856            TransportHeader::Udp(udp) => {
1857                assert_eq!(udp.destination_port, PSP_UDP_PORT);
1858            }
1859            _ => assert!(false),
1860        }
1861        let psp = PspPacket::new(pkt.payload).unwrap();
1862        assert_eq!(psp.get_spi(), pkt_ctx.psp_cfg.spi);
1863        assert_eq!(psp.get_version(), PspVersion::PspVer0 as u8);
1864
1865        Ok(())
1866    }
1867
1868    #[test]
1869    fn check_transport_vc_encap() -> Result<(), Box<dyn std::error::Error>> {
1870        let builder = PacketBuilder::ethernet2([1, 2, 3, 4, 5, 6], [7, 8, 9, 10, 11, 12])
1871            .ipv4([192, 168, 1, 1], [192, 168, 1, 2], 32)
1872            .udp(21, 1234);
1873        let payload = [1, 2, 3, 4, 5, 6, 7, 8];
1874        let mut in_pkt = Vec::<u8>::with_capacity(builder.size(payload.len()));
1875        builder.write(&mut in_pkt, &payload)?;
1876
1877        let out_pkt_len = in_pkt.len()
1878            + UdpHeader::SERIALIZED_SIZE
1879            + PspPacket::minimum_packet_size()
1880            + PSP_VC_SIZE
1881            + PSP_ICV_SIZE;
1882        let mut pkt_ctx = PktContext::default();
1883        pkt_ctx.psp_cfg.spi = 1;
1884        pkt_ctx.psp_cfg.include_vc = true;
1885        pkt_ctx.vc = 0xCAFE;
1886        pkt_ctx.psp_cfg.transport_crypt_off = 4;
1887
1888        let out_pkt = psp_transport_encap(&mut pkt_ctx, &in_pkt)?;
1889        assert_eq!(out_pkt_len, out_pkt.len());
1890
1891        let pkt = PacketHeaders::from_ethernet_slice(&out_pkt)?;
1892        assert!(pkt.link.is_some());
1893        assert_eq!(pkt.link.unwrap().ether_type, EtherType::Ipv4 as u16);
1894        assert!(pkt.ip.is_some());
1895        match pkt.ip.unwrap() {
1896            IpHeader::Version4(ip, _) => {
1897                assert_eq!(ip.source, [192, 168, 1, 1]);
1898                assert_eq!(ip.destination, [192, 168, 1, 2]);
1899                assert_eq!(ip.protocol, IpNumber::Udp as u8);
1900            }
1901            _ => assert!(false),
1902        };
1903        assert!(pkt.transport.is_some());
1904        match pkt.transport.unwrap() {
1905            TransportHeader::Udp(udp) => {
1906                assert_eq!(udp.destination_port, PSP_UDP_PORT);
1907            }
1908            _ => assert!(false),
1909        }
1910        let psp = PspPacket::new(pkt.payload).unwrap();
1911        assert_eq!(psp.get_spi(), pkt_ctx.psp_cfg.spi);
1912        assert_eq!(psp.get_version(), PspVersion::PspVer0 as u8);
1913        assert_eq!(psp.get_v(), 1);
1914        assert_eq!(psp.get_vc(), vec![0xCAFE]);
1915
1916        Ok(())
1917    }
1918
1919    fn get_pkt_ctx(ver: PspVersion) -> PktContext {
1920        let mut pkt_ctx = PktContext::new();
1921        match ver {
1922            PspVersion::PspVer0 => {
1923                pkt_ctx.psp_cfg.crypto_alg = CryptoAlg::AesGcm128;
1924                pkt_ctx.key = vec![
1925                    0x96, 0xc2, 0x2d, 0xc7, 0x99, 0x19, 0x80, 0x90, 0xb7, 0x4b, 0x70, 0xae, 0x46,
1926                    0x8e, 0x4e, 0x30,
1927                ];
1928                pkt_ctx.iv = 0x12345678_9ABCDEFF;
1929                pkt_ctx.psp_cfg.spi = 0x12345678;
1930                pkt_ctx.psp_cfg.transport_crypt_off = 1;
1931                pkt_ctx.psp_cfg.ipv4_tunnel_crypt_off = 6;
1932                pkt_ctx.psp_cfg.ipv6_tunnel_crypt_off = 11;
1933            }
1934            PspVersion::PspVer1 => {
1935                pkt_ctx.psp_cfg.crypto_alg = CryptoAlg::AesGcm256;
1936                pkt_ctx.key = vec![
1937                    0x96, 0xc2, 0x2d, 0xc7, 0x99, 0x19, 0x80, 0x90, 0xb7, 0x4b, 0x70, 0xae, 0x46,
1938                    0x8e, 0x4e, 0x30, 0xab, 0xcd, 0xef, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
1939                    0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd,
1940                ];
1941                pkt_ctx.iv = 0x12345678_9ABCDEFF;
1942                pkt_ctx.psp_cfg.spi = 0x82345678;
1943            }
1944        }
1945        pkt_ctx
1946    }
1947
1948    fn get_ipv4_test_pkt() -> Vec<u8> {
1949        // Build a cleartext packet
1950        let builder = PacketBuilder::ethernet2([1, 2, 3, 4, 5, 6], [7, 8, 9, 10, 11, 12])
1951            .ipv4([192, 168, 1, 1], [192, 168, 1, 2], 32)
1952            .udp(21, 1234);
1953        let payload = [1, 2, 3, 4, 5, 6, 7, 8];
1954        let mut orig_pkt = Vec::<u8>::with_capacity(builder.size(payload.len()));
1955        builder.write(&mut orig_pkt, &payload).unwrap();
1956        orig_pkt
1957    }
1958
1959    fn get_ipv4_empty_test_pkt() -> Vec<u8> {
1960        // Build a cleartext packet
1961        let builder = PacketBuilder::ethernet2([1, 2, 3, 4, 5, 6], [7, 8, 9, 10, 11, 12])
1962            .ipv4([192, 168, 1, 1], [192, 168, 1, 2], 32)
1963            .udp(21, 1234);
1964        let payload = [0u8; 0];
1965        let mut orig_pkt = Vec::<u8>::with_capacity(builder.size(payload.len()));
1966        builder.write(&mut orig_pkt, &payload).unwrap();
1967        orig_pkt
1968    }
1969
1970    fn get_ipv6_test_pkt() -> Vec<u8> {
1971        // Build a cleartext packet
1972        let builder = PacketBuilder::ethernet2([1, 2, 3, 4, 5, 6], [7, 8, 9, 10, 11, 12])
1973            .ipv6(
1974                [
1975                    11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
1976                ],
1977                [
1978                    31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46,
1979                ],
1980                32,
1981            )
1982            .udp(21, 1234);
1983        let payload = [1, 2, 3, 4, 5, 6, 7, 8];
1984        let mut orig_pkt = Vec::<u8>::with_capacity(builder.size(payload.len()));
1985        builder.write(&mut orig_pkt, &payload).unwrap();
1986        orig_pkt
1987    }
1988
1989    #[test]
1990    fn test_pspv0_encrypt_decrypt() -> Result<(), Box<dyn std::error::Error>> {
1991        let mut pkt_ctx = get_pkt_ctx(PspVersion::PspVer0);
1992
1993        let mut psp_hdr = PspHeader::default();
1994        psp_hdr.next_hdr = 6;
1995        psp_hdr.spi = pkt_ctx.psp_cfg.spi;
1996        psp_hdr.iv = pkt_ctx.iv;
1997        let aad = bincode::DefaultOptions::new()
1998            .with_fixint_encoding()
1999            .with_big_endian()
2000            .serialize(&psp_hdr)?;
2001
2002        pkt_ctx.key = derive_psp_key(
2003            pkt_ctx.psp_cfg.spi,
2004            pkt_ctx.psp_cfg.crypto_alg,
2005            &pkt_ctx.psp_cfg.master_keys,
2006        );
2007        let gcm_iv = get_aesgcm_iv(pkt_ctx.psp_cfg.spi, pkt_ctx.iv);
2008
2009        let cleartext = vec![0u8; 256];
2010        let mut ciphertext = vec![0u8; cleartext.len() + PSP_ICV_SIZE];
2011
2012        let rc = psp_encrypt(
2013            pkt_ctx.psp_cfg.crypto_alg,
2014            &pkt_ctx.key,
2015            &gcm_iv,
2016            &aad,
2017            &cleartext,
2018            &mut ciphertext,
2019        );
2020        assert!(rc.is_ok());
2021        let mut decrypted = vec![1u8; cleartext.len()];
2022        let rc = psp_decrypt(
2023            pkt_ctx.psp_cfg.crypto_alg,
2024            &pkt_ctx.key,
2025            &gcm_iv,
2026            &aad,
2027            &ciphertext,
2028            &mut decrypted,
2029        );
2030        assert!(rc.is_ok());
2031        assert_eq!(cleartext.len(), decrypted.len());
2032        assert_eq!(cleartext, decrypted);
2033
2034        Ok(())
2035    }
2036
2037    #[test]
2038    fn test_pspv1_encrypt_decrypt() -> Result<(), Box<dyn std::error::Error>> {
2039        let mut pkt_ctx = get_pkt_ctx(PspVersion::PspVer1);
2040
2041        let mut psp_hdr = PspHeader::default();
2042        psp_hdr.next_hdr = 6;
2043        psp_hdr.spi = pkt_ctx.psp_cfg.spi;
2044        psp_hdr.iv = pkt_ctx.iv;
2045        let aad = bincode::DefaultOptions::new()
2046            .with_fixint_encoding()
2047            .with_big_endian()
2048            .serialize(&psp_hdr)?;
2049
2050        pkt_ctx.key = derive_psp_key(
2051            pkt_ctx.psp_cfg.spi,
2052            pkt_ctx.psp_cfg.crypto_alg,
2053            &pkt_ctx.psp_cfg.master_keys,
2054        );
2055        let gcm_iv = get_aesgcm_iv(pkt_ctx.psp_cfg.spi, pkt_ctx.iv);
2056
2057        let cleartext = vec![0u8; 256];
2058        let mut ciphertext = vec![0u8; cleartext.len() + PSP_ICV_SIZE];
2059
2060        let rc = psp_encrypt(
2061            pkt_ctx.psp_cfg.crypto_alg,
2062            &pkt_ctx.key,
2063            &gcm_iv,
2064            &aad,
2065            &cleartext,
2066            &mut ciphertext,
2067        );
2068        assert!(rc.is_ok());
2069        let mut decrypted = vec![1u8; cleartext.len()];
2070        let rc = psp_decrypt(
2071            pkt_ctx.psp_cfg.crypto_alg,
2072            &pkt_ctx.key,
2073            &gcm_iv,
2074            &aad,
2075            &ciphertext,
2076            &mut decrypted,
2077        );
2078        assert!(rc.is_ok());
2079        assert_eq!(cleartext.len(), decrypted.len());
2080        assert_eq!(cleartext, decrypted);
2081
2082        Ok(())
2083    }
2084
2085    #[test_log::test]
2086    fn test_pspv0_transport_encap_decap_ipv4() -> Result<(), PspError> {
2087        let mut pkt_ctx = get_pkt_ctx(PspVersion::PspVer0);
2088        let mut decap_pkt_ctx = pkt_ctx.clone();
2089        let orig_pkt = get_ipv4_test_pkt();
2090
2091        pkt_ctx.key = derive_psp_key(
2092            pkt_ctx.psp_cfg.spi,
2093            pkt_ctx.psp_cfg.crypto_alg,
2094            &pkt_ctx.psp_cfg.master_keys,
2095        );
2096
2097        let encap_pkt = psp_transport_encap(&mut pkt_ctx, &orig_pkt)?;
2098        let decap_pkt = psp_transport_decap(&mut decap_pkt_ctx, &encap_pkt)?;
2099        assert_eq!(orig_pkt, decap_pkt);
2100
2101        Ok(())
2102    }
2103
2104    #[test_log::test]
2105    fn test_pspv0_transport_encap_decap_crypt_off() -> Result<(), PspError> {
2106        let mut pkt_ctx = get_pkt_ctx(PspVersion::PspVer0);
2107        pkt_ctx.psp_cfg.transport_crypt_off = 1;
2108        let mut decap_pkt_ctx = pkt_ctx.clone();
2109        let orig_pkt = get_ipv4_test_pkt();
2110
2111        pkt_ctx.key = derive_psp_key(
2112            pkt_ctx.psp_cfg.spi,
2113            pkt_ctx.psp_cfg.crypto_alg,
2114            &pkt_ctx.psp_cfg.master_keys,
2115        );
2116
2117        let encap_pkt = psp_transport_encap(&mut pkt_ctx, &orig_pkt)?;
2118        let decap_pkt = psp_transport_decap(&mut decap_pkt_ctx, &encap_pkt)?;
2119        assert_eq!(orig_pkt, decap_pkt);
2120
2121        Ok(())
2122    }
2123
2124    #[test_log::test]
2125    fn test_pspv1_transport_encap_decap_ipv4() -> Result<(), PspError> {
2126        let mut pkt_ctx = get_pkt_ctx(PspVersion::PspVer1);
2127        let mut decap_pkt_ctx = pkt_ctx.clone();
2128        let orig_pkt = get_ipv4_test_pkt();
2129
2130        pkt_ctx.key = derive_psp_key(
2131            pkt_ctx.psp_cfg.spi,
2132            pkt_ctx.psp_cfg.crypto_alg,
2133            &pkt_ctx.psp_cfg.master_keys,
2134        );
2135
2136        let encap_pkt = psp_transport_encap(&mut pkt_ctx, &orig_pkt)?;
2137        let decap_pkt = psp_transport_decap(&mut decap_pkt_ctx, &encap_pkt)?;
2138        assert_eq!(orig_pkt, decap_pkt);
2139
2140        Ok(())
2141    }
2142
2143    #[test_log::test]
2144    fn test_pspv0_transport_encap_decap_ipv6() -> Result<(), PspError> {
2145        let mut pkt_ctx = get_pkt_ctx(PspVersion::PspVer0);
2146        let mut decap_pkt_ctx = pkt_ctx.clone();
2147        let orig_pkt = get_ipv6_test_pkt();
2148
2149        pkt_ctx.key = derive_psp_key(
2150            pkt_ctx.psp_cfg.spi,
2151            pkt_ctx.psp_cfg.crypto_alg,
2152            &pkt_ctx.psp_cfg.master_keys,
2153        );
2154
2155        let encap_pkt = psp_transport_encap(&mut pkt_ctx, &orig_pkt)?;
2156        let decap_pkt = psp_transport_decap(&mut decap_pkt_ctx, &encap_pkt)?;
2157        assert_eq!(orig_pkt, decap_pkt);
2158
2159        Ok(())
2160    }
2161
2162    #[test_log::test]
2163    fn test_pspv1_transport_encap_decap_ipv6() -> Result<(), PspError> {
2164        let mut pkt_ctx = get_pkt_ctx(PspVersion::PspVer1);
2165        let mut decap_pkt_ctx = pkt_ctx.clone();
2166        let orig_pkt = get_ipv6_test_pkt();
2167
2168        pkt_ctx.key = derive_psp_key(
2169            pkt_ctx.psp_cfg.spi,
2170            pkt_ctx.psp_cfg.crypto_alg,
2171            &pkt_ctx.psp_cfg.master_keys,
2172        );
2173
2174        let encap_pkt = psp_transport_encap(&mut pkt_ctx, &orig_pkt)?;
2175        let decap_pkt = psp_transport_decap(&mut decap_pkt_ctx, &encap_pkt)?;
2176        assert_eq!(orig_pkt, decap_pkt);
2177
2178        Ok(())
2179    }
2180
2181    #[test_log::test]
2182    fn test_pspv0_tunnel_encap_decap_ipv4() -> Result<(), PspError> {
2183        let mut pkt_ctx = get_pkt_ctx(PspVersion::PspVer0);
2184        let mut decap_pkt_ctx = pkt_ctx.clone();
2185        let orig_pkt = get_ipv4_test_pkt();
2186
2187        pkt_ctx.key = derive_psp_key(
2188            pkt_ctx.psp_cfg.spi,
2189            pkt_ctx.psp_cfg.crypto_alg,
2190            &pkt_ctx.psp_cfg.master_keys,
2191        );
2192
2193        let encap_pkt = psp_tunnel_encap(&mut pkt_ctx, &orig_pkt)?;
2194        let decap_pkt = psp_tunnel_decap(&mut decap_pkt_ctx, &encap_pkt)?;
2195        assert_eq!(orig_pkt, decap_pkt);
2196
2197        Ok(())
2198    }
2199
2200    #[test_log::test]
2201    fn test_pspv0_tunnel_encap_decap_crypt_off() -> Result<(), PspError> {
2202        let mut pkt_ctx = get_pkt_ctx(PspVersion::PspVer0);
2203        pkt_ctx.psp_cfg.ipv4_tunnel_crypt_off = 2;
2204        let mut decap_pkt_ctx = pkt_ctx.clone();
2205        let orig_pkt = get_ipv4_test_pkt();
2206
2207        pkt_ctx.key = derive_psp_key(
2208            pkt_ctx.psp_cfg.spi,
2209            pkt_ctx.psp_cfg.crypto_alg,
2210            &pkt_ctx.psp_cfg.master_keys,
2211        );
2212
2213        let encap_pkt = psp_tunnel_encap(&mut pkt_ctx, &orig_pkt)?;
2214        let decap_pkt = psp_tunnel_decap(&mut decap_pkt_ctx, &encap_pkt)?;
2215        assert_eq!(orig_pkt, decap_pkt);
2216
2217        Ok(())
2218    }
2219
2220    #[test_log::test]
2221    fn test_pspv1_tunnel_encap_decap_ipv4() -> Result<(), PspError> {
2222        let mut pkt_ctx = get_pkt_ctx(PspVersion::PspVer1);
2223        let mut decap_pkt_ctx = pkt_ctx.clone();
2224        let orig_pkt = get_ipv4_test_pkt();
2225
2226        pkt_ctx.key = derive_psp_key(
2227            pkt_ctx.psp_cfg.spi,
2228            pkt_ctx.psp_cfg.crypto_alg,
2229            &pkt_ctx.psp_cfg.master_keys,
2230        );
2231
2232        let encap_pkt = psp_tunnel_encap(&mut pkt_ctx, &orig_pkt)?;
2233        let decap_pkt = psp_tunnel_decap(&mut decap_pkt_ctx, &encap_pkt)?;
2234        assert_eq!(orig_pkt, decap_pkt);
2235
2236        Ok(())
2237    }
2238
2239    #[test_log::test]
2240    fn test_pspv0_tunnel_encap_decap_ipv6() -> Result<(), PspError> {
2241        let mut pkt_ctx = get_pkt_ctx(PspVersion::PspVer0);
2242        let mut decap_pkt_ctx = pkt_ctx.clone();
2243        let orig_pkt = get_ipv6_test_pkt();
2244
2245        pkt_ctx.key = derive_psp_key(
2246            pkt_ctx.psp_cfg.spi,
2247            pkt_ctx.psp_cfg.crypto_alg,
2248            &pkt_ctx.psp_cfg.master_keys,
2249        );
2250
2251        let encap_pkt = psp_tunnel_encap(&mut pkt_ctx, &orig_pkt)?;
2252        let decap_pkt = psp_tunnel_decap(&mut decap_pkt_ctx, &encap_pkt)?;
2253        assert_eq!(orig_pkt, decap_pkt);
2254
2255        Ok(())
2256    }
2257
2258    #[test_log::test]
2259    fn test_pspv1_tunnel_encap_decap_ipv6() -> Result<(), PspError> {
2260        let mut pkt_ctx = get_pkt_ctx(PspVersion::PspVer1);
2261        let mut decap_pkt_ctx = pkt_ctx.clone();
2262        let orig_pkt = get_ipv6_test_pkt();
2263
2264        pkt_ctx.key = derive_psp_key(
2265            pkt_ctx.psp_cfg.spi,
2266            pkt_ctx.psp_cfg.crypto_alg,
2267            &pkt_ctx.psp_cfg.master_keys,
2268        );
2269
2270        let encap_pkt = psp_tunnel_encap(&mut pkt_ctx, &orig_pkt)?;
2271        let decap_pkt = psp_tunnel_decap(&mut decap_pkt_ctx, &encap_pkt)?;
2272        assert_eq!(orig_pkt, decap_pkt);
2273
2274        Ok(())
2275    }
2276
2277    #[test_log::test]
2278    fn test_tunnel_encap_decap_ipv6_vc() -> Result<(), PspError> {
2279        let mut pkt_ctx = get_pkt_ctx(PspVersion::PspVer0);
2280        pkt_ctx.psp_cfg.include_vc = true;
2281        let mut decap_pkt_ctx = pkt_ctx.clone();
2282        let orig_pkt = get_ipv6_test_pkt();
2283
2284        pkt_ctx.key = derive_psp_key(
2285            pkt_ctx.psp_cfg.spi,
2286            pkt_ctx.psp_cfg.crypto_alg,
2287            &pkt_ctx.psp_cfg.master_keys,
2288        );
2289
2290        let encap_pkt = psp_tunnel_encap(&mut pkt_ctx, &orig_pkt)?;
2291        let decap_pkt = psp_tunnel_decap(&mut decap_pkt_ctx, &encap_pkt)?;
2292        assert_eq!(orig_pkt, decap_pkt);
2293
2294        Ok(())
2295    }
2296
2297    #[test_log::test]
2298    fn test_tunnel_encap_decap_ipv6_vc_no_co() -> Result<(), PspError> {
2299        let mut pkt_ctx = get_pkt_ctx(PspVersion::PspVer0);
2300        pkt_ctx.psp_cfg.include_vc = true;
2301        pkt_ctx.psp_cfg.ipv6_tunnel_crypt_off = 0;
2302        let mut decap_pkt_ctx = pkt_ctx.clone();
2303        let orig_pkt = get_ipv6_test_pkt();
2304
2305        pkt_ctx.key = derive_psp_key(
2306            pkt_ctx.psp_cfg.spi,
2307            pkt_ctx.psp_cfg.crypto_alg,
2308            &pkt_ctx.psp_cfg.master_keys,
2309        );
2310
2311        let encap_pkt = psp_tunnel_encap(&mut pkt_ctx, &orig_pkt)?;
2312        let decap_pkt = psp_tunnel_decap(&mut decap_pkt_ctx, &encap_pkt)?;
2313        assert_eq!(orig_pkt, decap_pkt);
2314
2315        Ok(())
2316    }
2317
2318    #[test_log::test]
2319    fn test_tunnel_encap_decap_ipv6_vc_partial_enc() -> Result<(), PspError> {
2320        let mut pkt_ctx = get_pkt_ctx(PspVersion::PspVer0);
2321        pkt_ctx.psp_cfg.include_vc = true;
2322        pkt_ctx.psp_cfg.ipv6_tunnel_crypt_off = 1;
2323        let mut decap_pkt_ctx = pkt_ctx.clone();
2324        let orig_pkt = get_ipv6_test_pkt();
2325
2326        pkt_ctx.key = derive_psp_key(
2327            pkt_ctx.psp_cfg.spi,
2328            pkt_ctx.psp_cfg.crypto_alg,
2329            &pkt_ctx.psp_cfg.master_keys,
2330        );
2331
2332        let encap_pkt = psp_tunnel_encap(&mut pkt_ctx, &orig_pkt)?;
2333        let decap_pkt = psp_tunnel_decap(&mut decap_pkt_ctx, &encap_pkt)?;
2334        assert_eq!(orig_pkt, decap_pkt);
2335
2336        Ok(())
2337    }
2338
2339    #[test_log::test]
2340    fn test_pspv1_transport_ipv4_empty() -> Result<(), PspError> {
2341        let mut pkt_ctx = get_pkt_ctx(PspVersion::PspVer1);
2342        let mut decap_pkt_ctx = pkt_ctx.clone();
2343        let orig_pkt = get_ipv4_empty_test_pkt();
2344
2345        pkt_ctx.key = derive_psp_key(
2346            pkt_ctx.psp_cfg.spi,
2347            pkt_ctx.psp_cfg.crypto_alg,
2348            &pkt_ctx.psp_cfg.master_keys,
2349        );
2350
2351        let encap_pkt = psp_transport_encap(&mut pkt_ctx, &orig_pkt)?;
2352        let decap_pkt = psp_transport_decap(&mut decap_pkt_ctx, &encap_pkt)?;
2353        assert_eq!(orig_pkt, decap_pkt);
2354
2355        Ok(())
2356    }
2357
2358    #[test_log::test]
2359    fn test_pspv1_tunnel_ipv4_empty() -> Result<(), PspError> {
2360        let mut pkt_ctx = get_pkt_ctx(PspVersion::PspVer1);
2361        let mut decap_pkt_ctx = pkt_ctx.clone();
2362        let orig_pkt = get_ipv4_empty_test_pkt();
2363
2364        pkt_ctx.key = derive_psp_key(
2365            pkt_ctx.psp_cfg.spi,
2366            pkt_ctx.psp_cfg.crypto_alg,
2367            &pkt_ctx.psp_cfg.master_keys,
2368        );
2369
2370        let encap_pkt = psp_tunnel_encap(&mut pkt_ctx, &orig_pkt)?;
2371        let decap_pkt = psp_tunnel_decap(&mut decap_pkt_ctx, &encap_pkt)?;
2372        assert_eq!(orig_pkt, decap_pkt);
2373
2374        Ok(())
2375    }
2376
2377    // Security-focused tests
2378    mod security_tests {
2379        use super::*;
2380
2381        #[test]
2382        fn test_no_zero_keys_in_new_context() {
2383            let ctx = PktContext::new();
2384            
2385            // Ensure no all-zero keys in secure initialization
2386            assert!(
2387                !ctx.psp_cfg.master_keys[0].iter().all(|&b| b == 0),
2388                "Master key 0 should not be all zeros"
2389            );
2390            assert!(
2391                !ctx.psp_cfg.master_keys[1].iter().all(|&b| b == 0),
2392                "Master key 1 should not be all zeros"
2393            );
2394            
2395            // Ensure derived key is not all zeros
2396            assert!(
2397                !ctx.key.iter().all(|&b| b == 0),
2398                "Derived key should not be all zeros"
2399            );
2400            
2401            // Ensure IV is not predictable
2402            assert_ne!(ctx.iv, 1, "IV should not be predictable value 1");
2403            assert_ne!(ctx.iv, 0, "IV should not be zero");
2404        }
2405
2406        #[test]
2407        fn test_secure_spi_generation() {
2408            let spi1 = PktContext::generate_secure_spi();
2409            let spi2 = PktContext::generate_secure_spi();
2410            
2411            // SPI should not be reserved values
2412            assert_ne!(spi1, 0, "SPI should not be 0");
2413            assert_ne!(spi1, 1, "SPI should not be 1");
2414            assert_ne!(spi2, 0, "SPI should not be 0");
2415            assert_ne!(spi2, 1, "SPI should not be 1");
2416            
2417            // SPIs should be different (highly likely)
2418            assert_ne!(spi1, spi2, "Generated SPIs should be different");
2419        }
2420
2421        #[test]
2422        fn test_config_validation_rejects_zero_keys() {
2423            let mut cfg = PspConfig::default();
2424            
2425            // Set keys to all zeros (weak)
2426            cfg.master_keys[0] = [0u8; 32];
2427            cfg.master_keys[1] = [0u8; 32];
2428            cfg.spi = 123; // Valid SPI
2429            
2430            // Should reject weak keys
2431            assert!(
2432                cfg.validate().is_err(),
2433                "Validation should reject all-zero keys"
2434            );
2435        }
2436
2437        #[test]
2438        fn test_config_validation_rejects_repeating_patterns() {
2439            let mut cfg = PspConfig::default();
2440            
2441            // Set keys to repeating patterns (weak)
2442            cfg.master_keys[0] = [0xAA; 32];
2443            cfg.master_keys[1] = [0x11; 32];
2444            cfg.spi = 123; // Valid SPI
2445            
2446            // Should reject weak patterns
2447            assert!(
2448                cfg.validate().is_err(),
2449                "Validation should reject repeating key patterns"
2450            );
2451        }
2452
2453        #[test]
2454        fn test_config_validation_rejects_zero_spi() {
2455            let mut cfg = PspConfig::default();
2456            
2457            // Use secure keys but invalid SPI
2458            cfg.master_keys[0] = PktContext::generate_secure_key();
2459            cfg.master_keys[1] = PktContext::generate_secure_key();
2460            cfg.spi = 0; // Invalid SPI
2461            
2462            // Should reject zero SPI
2463            assert!(
2464                cfg.validate().is_err(),
2465                "Validation should reject SPI value of 0"
2466            );
2467        }
2468
2469        #[test]
2470        fn test_config_validation_rejects_large_crypto_offsets() {
2471            let mut cfg = PspConfig::default();
2472            
2473            // Use secure keys and valid SPI
2474            cfg.master_keys[0] = PktContext::generate_secure_key();
2475            cfg.master_keys[1] = PktContext::generate_secure_key();
2476            cfg.spi = 123;
2477            
2478            // Test various large offset values
2479            cfg.transport_crypt_off = 65; // Too large
2480            assert!(
2481                cfg.validate().is_err(),
2482                "Validation should reject large transport crypto offset"
2483            );
2484            
2485            cfg.transport_crypt_off = 0; // Reset to valid
2486            cfg.ipv4_tunnel_crypt_off = 65; // Too large
2487            assert!(
2488                cfg.validate().is_err(),
2489                "Validation should reject large IPv4 tunnel crypto offset"
2490            );
2491            
2492            cfg.ipv4_tunnel_crypt_off = 0; // Reset to valid
2493            cfg.ipv6_tunnel_crypt_off = 65; // Too large
2494            assert!(
2495                cfg.validate().is_err(),
2496                "Validation should reject large IPv6 tunnel crypto offset"
2497            );
2498        }
2499
2500        #[test]
2501        fn test_secure_config_passes_validation() {
2502            // Create secure config
2503            let cfg = PspConfig::new_secure().expect("Should create secure config");
2504            
2505            // Should pass validation
2506            assert!(
2507                cfg.validate().is_ok(),
2508                "Secure configuration should pass validation"
2509            );
2510            
2511            // Verify it uses stronger defaults
2512            assert_eq!(cfg.crypto_alg, CryptoAlg::AesGcm256, "Should default to AES-GCM-256");
2513        }
2514
2515        #[test]
2516        fn test_key_uniqueness() {
2517            let key1 = PktContext::generate_secure_key();
2518            let key2 = PktContext::generate_secure_key();
2519            
2520            // Keys should be different
2521            assert_ne!(key1, key2, "Generated keys should be unique");
2522            
2523            // No obvious patterns
2524            assert!(!key1.iter().all(|&b| b == key1[0]), "Key should not be all same byte");
2525            assert!(!key2.iter().all(|&b| b == key2[0]), "Key should not be all same byte");
2526        }
2527
2528        #[test]
2529        fn test_testing_context_has_predictable_values() {
2530            let ctx = PktContext::new_for_testing();
2531            
2532            // Testing context should have predictable (insecure) values
2533            assert_eq!(ctx.psp_cfg.master_keys[0], [0u8; 32], "Test key 0 should be all zeros");
2534            assert_eq!(ctx.psp_cfg.master_keys[1], [0u8; 32], "Test key 1 should be all zeros");
2535            assert_eq!(ctx.psp_cfg.spi, 1, "Test SPI should be 1");
2536            assert_eq!(ctx.iv, 1, "Test IV should be 1");
2537        }
2538    }
2539}