stun_types/attribute/
fingerprint.rs1use std::convert::TryFrom;
10
11use crate::message::StunParseError;
12
13use super::{
14 Attribute, AttributeStaticType, AttributeType, AttributeWrite, AttributeWriteExt, RawAttribute,
15};
16
17#[derive(Debug, Clone, PartialEq, Eq)]
19pub struct Fingerprint {
20 fingerprint: [u8; 4],
21}
22
23impl AttributeStaticType for Fingerprint {
24 const TYPE: AttributeType = AttributeType(0x8028);
25}
26
27impl Attribute for Fingerprint {
28 fn get_type(&self) -> AttributeType {
29 Self::TYPE
30 }
31
32 fn length(&self) -> u16 {
33 4
34 }
35}
36
37impl AttributeWrite for Fingerprint {
38 fn to_raw(&self) -> RawAttribute {
39 let buf = bytewise_xor!(4, self.fingerprint, Fingerprint::XOR_CONSTANT, 0);
40 RawAttribute::new(Fingerprint::TYPE, &buf).into_owned()
41 }
42
43 fn write_into_unchecked(&self, dest: &mut [u8]) {
44 let offset = self.write_header_unchecked(dest);
45 let buf = bytewise_xor!(4, self.fingerprint, Fingerprint::XOR_CONSTANT, 0);
46 dest[offset..offset + 4].copy_from_slice(&buf);
47 }
48}
49impl<'a> TryFrom<&RawAttribute<'a>> for Fingerprint {
50 type Error = StunParseError;
51
52 fn try_from(raw: &RawAttribute) -> Result<Self, Self::Error> {
53 raw.check_type_and_len(Self::TYPE, 4..=4)?;
54 let boxed: [u8; 4] = (&*raw.value).try_into().unwrap();
56 let fingerprint = bytewise_xor!(4, boxed, Fingerprint::XOR_CONSTANT, 0);
57 Ok(Self { fingerprint })
58 }
59}
60
61impl Fingerprint {
62 const XOR_CONSTANT: [u8; 4] = [0x53, 0x54, 0x55, 0x4E];
63
64 pub fn new(fingerprint: [u8; 4]) -> Self {
75 Self { fingerprint }
76 }
77
78 pub fn fingerprint(&self) -> &[u8; 4] {
89 &self.fingerprint
90 }
91
92 pub fn compute(data: &[u8]) -> [u8; 4] {
101 use crc::{Crc, CRC_32_ISO_HDLC};
102 const CRC_ALGO: Crc<u32> = Crc::<u32>::new(&CRC_32_ISO_HDLC);
103 CRC_ALGO.checksum(data).to_be_bytes()
104 }
105}
106
107impl std::fmt::Display for Fingerprint {
108 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
109 write!(f, "{}: 0x", Self::TYPE)?;
110 for val in self.fingerprint.iter() {
111 write!(f, "{:02x}", val)?;
112 }
113 Ok(())
114 }
115}
116
117#[cfg(test)]
118mod tests {
119 use crate::prelude::AttributeExt;
120
121 use super::*;
122 use byteorder::{BigEndian, ByteOrder};
123 use tracing::trace;
124
125 #[test]
126 fn fingerprint() {
127 let _log = crate::tests::test_init_log();
128 let val = [1; 4];
129 let attr = Fingerprint::new(val);
130 trace!("{attr}");
131 assert_eq!(attr.fingerprint(), &val);
132 assert_eq!(attr.length(), 4);
133 let raw = RawAttribute::from(&attr);
134 trace!("{raw}");
135 assert_eq!(raw.get_type(), Fingerprint::TYPE);
136 let mapped2 = Fingerprint::try_from(&raw).unwrap();
137 assert_eq!(mapped2.fingerprint(), &val);
138 let mut data: Vec<_> = raw.clone().into();
140 let len = data.len();
141 BigEndian::write_u16(&mut data[2..4], len as u16 - 4 - 1);
142 assert!(matches!(
143 Fingerprint::try_from(&RawAttribute::from_bytes(data[..len - 1].as_ref()).unwrap()),
144 Err(StunParseError::Truncated {
145 expected: 4,
146 actual: 3
147 })
148 ));
149 let mut data: Vec<_> = raw.clone().into();
151 BigEndian::write_u16(&mut data[0..2], 0);
152 assert!(matches!(
153 Fingerprint::try_from(&RawAttribute::from_bytes(data.as_ref()).unwrap()),
154 Err(StunParseError::WrongAttributeImplementation)
155 ));
156
157 let mut dest = vec![0; raw.padded_len()];
158 attr.write_into(&mut dest).unwrap();
159 let raw = RawAttribute::from_bytes(&dest).unwrap();
160 let attr2 = Fingerprint::try_from(&raw).unwrap();
161 assert_eq!(attr2.fingerprint(), &val);
162 }
163}