faster_stun/util.rs
1use crc::{Crc, CRC_32_ISO_HDLC};
2use hmac::{digest::CtOutput, Hmac, Mac};
3use md5::{Digest, Md5};
4
5use crate::StunError;
6
7/// compute padding size.
8///
9/// RFC5766 stipulates that the attribute
10/// content is a multiple of 4.
11///
12/// # Unit Test
13///
14/// ```
15/// assert_eq!(faster_stun::util::pad_size(4), 0);
16/// assert_eq!(faster_stun::util::pad_size(0), 0);
17/// assert_eq!(faster_stun::util::pad_size(5), 3);
18/// ```
19#[inline(always)]
20pub fn pad_size(size: usize) -> usize {
21 let range = size % 4;
22 if size == 0 || range == 0 {
23 return 0;
24 }
25
26 4 - range
27}
28
29/// create long key.
30///
31/// > key = MD5(username ":" OpaqueString(realm) ":" OpaqueString(password))
32///
33/// ```
34/// let buffer = [
35/// 0x3eu8, 0x2f, 0x79, 0x1e, 0x1f, 0x14, 0xd1, 0x73, 0xfc, 0x91, 0xff,
36/// 0x2f, 0x59, 0xb5, 0x0f, 0xd1,
37/// ];
38///
39/// let key = faster_stun::util::long_key("panda", "panda", "raspberry");
40/// assert_eq!(key, buffer);
41/// ```
42pub fn long_key(username: &str, key: &str, realm: &str) -> [u8; 16] {
43 let mut hasher = Md5::new();
44 hasher.update([username, realm, key].join(":"));
45 hasher.finalize().into()
46}
47
48/// HMAC SHA1 digest.
49///
50/// # Unit Test
51///
52/// ```
53/// let buffer = [
54/// 0x00u8, 0x03, 0x00, 0x50, 0x21, 0x12, 0xa4, 0x42, 0x64, 0x4f, 0x5a,
55/// 0x78, 0x6a, 0x56, 0x33, 0x62, 0x4b, 0x52, 0x33, 0x31, 0x00, 0x19, 0x00,
56/// 0x04, 0x11, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x05, 0x70, 0x61, 0x6e,
57/// 0x64, 0x61, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x09, 0x72, 0x61, 0x73,
58/// 0x70, 0x62, 0x65, 0x72, 0x72, 0x79, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00,
59/// 0x10, 0x31, 0x63, 0x31, 0x33, 0x64, 0x32, 0x62, 0x32, 0x34, 0x35, 0x62,
60/// 0x33, 0x61, 0x37, 0x33, 0x34,
61/// ];
62///
63/// let key = [
64/// 0x3eu8, 0x2f, 0x79, 0x1e, 0x1f, 0x14, 0xd1, 0x73, 0xfc, 0x91, 0xff,
65/// 0x2f, 0x59, 0xb5, 0x0f, 0xd1,
66/// ];
67///
68/// let sign = [
69/// 0xd6u8, 0x78, 0x26, 0x99, 0x0e, 0x15, 0x56, 0x15, 0xe5, 0xf4, 0x24,
70/// 0x74, 0xe2, 0x3c, 0x26, 0xc5, 0xb1, 0x03, 0xb2, 0x6d,
71/// ];
72///
73/// let hmac_output = faster_stun::util::hmac_sha1(&key, vec![&buffer])
74/// .unwrap()
75/// .into_bytes();
76/// assert_eq!(hmac_output.as_slice(), &sign);
77/// ```
78pub fn hmac_sha1(key: &[u8], source: Vec<&[u8]>) -> Result<CtOutput<Hmac<sha1::Sha1>>, StunError> {
79 match Hmac::<sha1::Sha1>::new_from_slice(key) {
80 Err(_) => Err(StunError::ShaFailed),
81 Ok(mut mac) => {
82 for buf in source {
83 mac.update(buf);
84 }
85
86 Ok(mac.finalize())
87 }
88 }
89}
90
91/// CRC32 Fingerprint.
92///
93/// # Unit Test
94///
95/// ```
96/// assert_eq!(faster_stun::util::fingerprint(b"1"), 3498621689);
97/// ```
98pub fn fingerprint(buffer: &[u8]) -> u32 {
99 Crc::<u32>::new(&CRC_32_ISO_HDLC).checksum(buffer) ^ 0x5354_554e
100}
101
102/// slice as u16.
103///
104/// # Unit Test
105///
106/// ```
107/// let int = faster_stun::util::as_u16(&[0x00, 0x04]);
108/// assert_eq!(int, 4);
109/// ```
110#[rustfmt::skip]
111#[inline(always)]
112pub fn as_u16(buf: &[u8]) -> u16 {
113 assert!(buf.len() >= 2);
114 u16::from_be_bytes([
115 buf[0],
116 buf[1]
117 ])
118}
119
120/// slice as u32.
121///
122/// # Unit Test
123///
124/// ```
125/// let int = faster_stun::util::as_u32(&[0x00, 0x00, 0x00, 0x04]);
126///
127/// assert_eq!(int, 4);
128/// ```
129#[rustfmt::skip]
130#[inline(always)]
131pub fn as_u32(buf: &[u8]) -> u32 {
132 assert!(buf.len() >= 4);
133 u32::from_be_bytes([
134 buf[0],
135 buf[1],
136 buf[2],
137 buf[3]
138 ])
139}
140
141/// slice as u64.
142///
143/// # Unit Test
144///
145/// ```
146/// let int =
147/// faster_stun::util::as_u64(&[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04]);
148///
149/// assert_eq!(int, 4);
150/// ```
151#[rustfmt::skip]
152#[inline(always)]
153pub fn as_u64(buf: &[u8]) -> u64 {
154 assert!(buf.len() >= 8);
155 u64::from_be_bytes([
156 buf[0],
157 buf[1],
158 buf[2],
159 buf[3],
160 buf[4],
161 buf[5],
162 buf[6],
163 buf[7],
164 ])
165}