1use crate::attributes::{stunt_attribute, DecodeAttributeValue, EncodeAttributeValue};
2use crate::common::{check_buffer_boundaries, sha256};
3use crate::context::{AttributeDecoderContext, AttributeEncoderContext};
4use crate::error::{StunError, StunErrorType};
5use crate::strings;
6use std::convert::TryInto;
7use std::ops::Deref;
8use std::sync::Arc;
9
10const USER_HASH: u16 = 0x001E;
11const USER_HASH_LEN: usize = 32;
12
13#[derive(Debug, PartialEq, Eq, Clone)]
37pub struct UserHash(Arc<[u8; USER_HASH_LEN]>);
38
39impl UserHash {
40 pub fn new<A, B>(name: A, realm: B) -> Result<Self, StunError>
48 where
49 A: AsRef<str>,
50 B: AsRef<str>,
51 {
52 let vec = do_sha256(name.as_ref(), realm.as_ref())?;
53 Ok(Self(Arc::new(vec.try_into().map_err(|_v| {
54 StunError::new(StunErrorType::InvalidParam, "Can not create user hash")
55 })?)))
56 }
57
58 pub fn hash(&self) -> &[u8] {
60 self.0.as_slice()
61 }
62}
63
64impl Deref for UserHash {
65 type Target = [u8];
66
67 fn deref(&self) -> &[u8] {
68 self.0.as_slice()
69 }
70}
71
72impl DecodeAttributeValue for UserHash {
73 fn decode(ctx: AttributeDecoderContext) -> Result<(Self, usize), StunError> {
74 let raw_value = ctx.raw_value();
75 (raw_value.len() == USER_HASH_LEN)
76 .then(|| {
77 let mut vec: [u8; USER_HASH_LEN] = [0x0; USER_HASH_LEN];
78 vec.clone_from_slice(raw_value);
79 (Self(Arc::new(vec)), raw_value.len())
80 })
81 .ok_or_else(|| {
82 StunError::new(
83 StunErrorType::InvalidParam,
84 format!(
85 "Unexpected buffer size: {}, user hash legnth {}",
86 raw_value.len(),
87 USER_HASH_LEN
88 ),
89 )
90 })
91 }
92}
93
94impl EncodeAttributeValue for UserHash {
95 fn encode(&self, mut ctx: AttributeEncoderContext) -> Result<usize, StunError> {
96 let len = self.0.len();
97 let raw_value = ctx.raw_value_mut();
98 check_buffer_boundaries(raw_value, len)?;
99 raw_value[..len].clone_from_slice(self.0.as_slice());
100
101 Ok(len)
102 }
103}
104
105fn do_sha256(name: &str, realm: &str) -> Result<Vec<u8>, StunError> {
106 let name = strings::opaque_string_prepapre(name)?;
107 let realm = strings::opaque_string_prepapre(realm)?;
108 let val = format!("{}:{}", name, realm);
109 let val = sha256(val.as_str());
110 let val_len = val.len();
111
112 (val_len == USER_HASH_LEN).then_some(val).ok_or_else(|| {
113 StunError::new(
114 StunErrorType::InvalidParam,
115 format!(
116 "Unexpected buffer size: {}, user hash legnth {}",
117 val_len, USER_HASH_LEN
118 ),
119 )
120 })
121}
122
123impl crate::attributes::AsVerifiable for UserHash {}
124
125stunt_attribute!(UserHash, USER_HASH);
126
127#[cfg(test)]
128mod tests {
129 use super::*;
130 use crate::attributes::stun::{Realm, UserName};
131 use crate::error::StunErrorType;
132 use crate::StunAttribute;
133 use std::convert::TryFrom;
134
135 #[test]
136 fn constructor() {
137 let username = UserName::try_from("username").unwrap();
138 let realm = Realm::try_from("realm").unwrap();
139 let attr = UserHash::new(username, realm).expect("Can not create UserHas attribute");
140
141 let slice: &[u8] = &attr;
143 assert_eq!(slice, attr.hash());
144
145 let error = UserHash::new("user\u{0009}name", "realm").expect_err("Error expected");
147 assert_eq!(error, StunErrorType::InvalidParam);
148 }
149
150 #[test]
151 fn decode_user_hash() {
152 let dummy_msg = [];
153 let buffer = [
156 0x4a, 0x3c, 0xf3, 0x8f, 0xef, 0x69, 0x92, 0xbd, 0xa9, 0x52, 0xc6, 0x78, 0x04, 0x17,
157 0xda, 0x0f, 0x24, 0x81, 0x94, 0x15, 0x56, 0x9e, 0x60, 0xb2, 0x05, 0xc4, 0x6e, 0x41,
158 0x40, 0x7f, 0x17, 0x04,
159 ];
160 let ctx = AttributeDecoderContext::new(None, &dummy_msg, &buffer);
161
162 let (user_hash, size) = UserHash::decode(ctx).expect("Can not decode USER-HASH");
163 assert_eq!(size, 32);
164 assert_eq!(&buffer[..], user_hash.hash());
165 }
166
167 #[test]
168 fn decode_user_hash_error() {
169 let dummy_msg = [];
170 let buffer = [];
171 let ctx = AttributeDecoderContext::new(None, &dummy_msg, &buffer);
172 let result = UserHash::decode(ctx);
173 assert_eq!(
174 result.expect_err("Error expected"),
175 StunErrorType::InvalidParam
176 );
177
178 let buffer = [
179 0x4a, 0x3c, 0xf3, 0x8f, 0xef, 0x69, 0x92, 0xbd, 0xa9, 0x52, 0xc6, 0x78, 0x04, 0x17,
180 0xda, 0x0f, 0x24,
181 ];
182 let ctx = AttributeDecoderContext::new(None, &dummy_msg, &buffer);
183 let result = UserHash::decode(ctx);
184 assert_eq!(
185 result.expect_err("Error expected"),
186 StunErrorType::InvalidParam
187 );
188
189 let buffer = [
190 0x4a, 0x3c, 0xf3, 0x8f, 0xef, 0x69, 0x92, 0xbd, 0xa9, 0x52, 0xc6, 0x78, 0x04, 0x17,
191 0xda, 0x0f, 0x24, 0x81, 0x94, 0x15, 0x56, 0x9e, 0x60, 0xb2, 0x05, 0xc4, 0x6e, 0x41,
192 0x40, 0x7f, 0x17, 0x04, 0x03,
193 ];
194 let ctx = AttributeDecoderContext::new(None, &dummy_msg, &buffer);
195 let result = UserHash::decode(ctx);
196 assert_eq!(
197 result.expect_err("Error expected"),
198 StunErrorType::InvalidParam
199 );
200 }
201
202 #[test]
203 fn encode_user_hash() {
204 let dummy_msg: [u8; 0] = [0x0; 0];
205 let username =
206 UserName::try_from("\u{30de}\u{30c8}\u{30ea}\u{30c3}\u{30af}\u{30b9}").unwrap();
207 let realm = Realm::try_from("example.org").unwrap();
208 let result = UserHash::new(username, realm);
209 assert!(result.is_ok());
210 let user_hash = result.unwrap();
211
212 let mut buffer: [u8; 32] = [0x0; 32];
213 let ctx = AttributeEncoderContext::new(None, &dummy_msg, &mut buffer);
214 let result = user_hash.encode(ctx);
215 assert_eq!(result, Ok(32));
216
217 let expected_buffer = [
220 0x4a, 0x3c, 0xf3, 0x8f, 0xef, 0x69, 0x92, 0xbd, 0xa9, 0x52, 0xc6, 0x78, 0x04, 0x17,
221 0xda, 0x0f, 0x24, 0x81, 0x94, 0x15, 0x56, 0x9e, 0x60, 0xb2, 0x05, 0xc4, 0x6e, 0x41,
222 0x40, 0x7f, 0x17, 0x04,
223 ];
224 assert_eq!(&buffer[..], &expected_buffer[..]);
225 }
226
227 #[test]
228 fn encode_user_hash_error() {
229 let dummy_msg: [u8; 0] = [0x0; 0];
230 let username = UserName::try_from("username").unwrap();
231 let realm = Realm::try_from("realm").unwrap();
232 let result = UserHash::new(username, realm);
233 assert!(result.is_ok());
234 let user_hash = result.unwrap();
235
236 let mut buffer = [];
237 let ctx = AttributeEncoderContext::new(None, &dummy_msg, &mut buffer);
238 let result = user_hash.encode(ctx);
239 assert_eq!(
240 result.expect_err("Error expected"),
241 StunErrorType::SmallBuffer
242 );
243
244 let mut buffer: [u8; 31] = [0x0; 31];
245 let ctx = AttributeEncoderContext::new(None, &dummy_msg, &mut buffer);
246 let result = user_hash.encode(ctx);
247 assert_eq!(
248 result.expect_err("Error expected"),
249 StunErrorType::SmallBuffer
250 );
251 }
252
253 #[test]
254 fn user_hash_stunt_attribute() {
255 let user_hash = UserHash::new("a", "b").expect("Can not create user hash");
256 let attr = StunAttribute::UserHash(user_hash);
257 assert!(attr.is_user_hash());
258 assert!(attr.as_user_hash().is_ok());
259 assert!(attr.as_unknown().is_err());
260
261 assert!(attr.attribute_type().is_comprehension_required());
262 assert!(!attr.attribute_type().is_comprehension_optional());
263
264 let dbg_fmt = format!("{:?}", attr);
265 assert_eq!("UserHash(UserHash([103, 131, 163, 30, 171, 246, 140, 204, 6, 96, 249, 53, 192, 130, 98, 130, 189, 210, 36, 31, 58, 128, 169, 242, 209, 13, 89, 174, 169, 235, 181, 216]))", dbg_fmt);
266 }
267}