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}