Skip to main content

leodos_protocols/datalink/security/sdls/
security_header.rs

1//! SDLS Security Header and Trailer parsing (CCSDS 355.0-B-2 Section 4.1).
2
3use super::{Error, SecurityAssociation};
4
5/// A parsed view over a Security Header in a byte buffer.
6///
7/// The Security Header consists of:
8/// - SPI (16 bits, mandatory)
9/// - Initialization Vector (0-32 bytes, optional)
10/// - Sequence Number (0-8 bytes, optional)
11/// - Pad Length (0-2 bytes, optional)
12///
13/// All field lengths are determined by the Security Association.
14#[derive(Debug)]
15pub struct SecurityHeader<'a> {
16    spi: u16,
17    iv: &'a [u8],
18    sn: &'a [u8],
19    pl: &'a [u8],
20}
21
22impl<'a> SecurityHeader<'a> {
23    /// Parse a Security Header from the given bytes using the SA
24    /// to determine field lengths.
25    pub fn parse(
26        sa: &SecurityAssociation,
27        bytes: &'a [u8],
28    ) -> Result<Self, Error> {
29        let hdr_size = sa.header_size();
30        if bytes.len() < hdr_size {
31            return Err(Error::FrameTooShort);
32        }
33
34        let spi =
35            u16::from_be_bytes([bytes[0], bytes[1]]);
36        let mut pos = 2;
37
38        let iv_len = sa.iv_len as usize;
39        let iv = &bytes[pos..pos + iv_len];
40        pos += iv_len;
41
42        let sn_len = sa.sn_len as usize;
43        let sn = &bytes[pos..pos + sn_len];
44        pos += sn_len;
45
46        let pl_len = sa.pl_len as usize;
47        let pl = &bytes[pos..pos + pl_len];
48
49        Ok(Self { spi, iv, sn, pl })
50    }
51
52    /// Returns the Security Parameter Index.
53    pub fn spi(&self) -> u16 {
54        self.spi
55    }
56
57    /// Returns the Initialization Vector bytes.
58    pub fn iv(&self) -> &[u8] {
59        self.iv
60    }
61
62    /// Returns the Sequence Number bytes.
63    pub fn sequence_number(&self) -> &[u8] {
64        self.sn
65    }
66
67    /// Returns the Sequence Number as a u64 value.
68    pub fn sequence_number_value(&self) -> u64 {
69        let mut buf = [0u8; 8];
70        let len = self.sn.len();
71        if len > 0 {
72            let start = 8 - len;
73            buf[start..].copy_from_slice(self.sn);
74        }
75        u64::from_be_bytes(buf)
76    }
77
78    /// Returns the Pad Length value.
79    pub fn pad_length(&self) -> u16 {
80        let len = self.pl.len();
81        if len == 0 {
82            return 0;
83        }
84        let mut buf = [0u8; 2];
85        let start = 2 - len;
86        buf[start..].copy_from_slice(self.pl);
87        u16::from_be_bytes(buf)
88    }
89}
90
91/// A parsed view over a Security Trailer in a byte buffer.
92///
93/// The Security Trailer consists of a single optional MAC field.
94#[derive(Debug)]
95pub struct SecurityTrailer<'a> {
96    mac: &'a [u8],
97}
98
99impl<'a> SecurityTrailer<'a> {
100    /// Parse a Security Trailer from the given bytes.
101    pub fn parse(
102        sa: &SecurityAssociation,
103        bytes: &'a [u8],
104    ) -> Result<Self, Error> {
105        let mac_len = sa.mac_len as usize;
106        if bytes.len() < mac_len {
107            return Err(Error::FrameTooShort);
108        }
109        Ok(Self {
110            mac: &bytes[..mac_len],
111        })
112    }
113
114    /// Returns the MAC bytes.
115    pub fn mac(&self) -> &[u8] {
116        self.mac
117    }
118}