Skip to main content

osdp/command/
keyset.rs

1//! `osdp_KEYSET` (`0x75`) — install encryption key.
2//!
3//! # Spec: §6.16
4//!
5//! Body layout:
6//!
7//! ```text
8//! +---------+---------+----------+
9//! | key_type| key_len | key data |
10//! +---------+---------+----------+
11//! ```
12//!
13//! `key_type` is currently always `0x01` (SCBK), `key_len` is the byte length
14//! of the key (16 for AES-128).
15
16use crate::error::Error;
17use crate::payload_util::require_at_least;
18use alloc::vec::Vec;
19
20/// `osdp_KEYSET` body.
21#[derive(Debug, Clone, PartialEq, Eq)]
22pub struct KeySet {
23    /// Key type (0x01 = SCBK).
24    pub key_type: u8,
25    /// Key bytes.
26    pub key: Vec<u8>,
27}
28
29impl KeySet {
30    /// Build with the standard `key_type = 0x01` (SCBK) and a 16-byte key.
31    pub fn scbk(key: [u8; 16]) -> Self {
32        Self {
33            key_type: 0x01,
34            key: key.to_vec(),
35        }
36    }
37
38    /// Encode.
39    pub fn encode(&self) -> Result<Vec<u8>, Error> {
40        if self.key.len() > u8::MAX as usize {
41            return Err(Error::MalformedPayload {
42                code: 0x75,
43                reason: "KEYSET key length exceeds 255",
44            });
45        }
46        let mut out = Vec::with_capacity(2 + self.key.len());
47        out.push(self.key_type);
48        out.push(self.key.len() as u8);
49        out.extend_from_slice(&self.key);
50        Ok(out)
51    }
52
53    /// Decode.
54    pub fn decode(data: &[u8]) -> Result<Self, Error> {
55        require_at_least(data, 2, 0x75)?;
56        let key_len = data[1] as usize;
57        if data.len() != 2 + key_len {
58            return Err(Error::MalformedPayload {
59                code: 0x75,
60                reason: "KEYSET key length disagrees with payload",
61            });
62        }
63        Ok(Self {
64            key_type: data[0],
65            key: data[2..2 + key_len].to_vec(),
66        })
67    }
68}
69
70#[cfg(test)]
71mod tests {
72    use super::*;
73
74    #[test]
75    fn scbk_roundtrip() {
76        let key = [0xAAu8; 16];
77        let body = KeySet::scbk(key);
78        let bytes = body.encode().unwrap();
79        assert_eq!(bytes[0], 0x01);
80        assert_eq!(bytes[1], 16);
81        assert_eq!(&bytes[2..], &key);
82        assert_eq!(KeySet::decode(&bytes).unwrap(), body);
83    }
84
85    #[test]
86    fn decode_rejects_short() {
87        assert!(matches!(
88            KeySet::decode(&[0x01]),
89            Err(Error::PayloadTooShort { code: 0x75, .. })
90        ));
91    }
92
93    #[test]
94    fn decode_rejects_length_mismatch() {
95        // key_len says 4 but only 2 key bytes follow.
96        assert!(matches!(
97            KeySet::decode(&[0x01, 0x04, 0xDE, 0xAD]),
98            Err(Error::MalformedPayload { code: 0x75, .. })
99        ));
100    }
101}