1use crate::attributes::{stunt_attribute, DecodeAttributeValue, EncodeAttributeValue};
2use crate::common::check_buffer_boundaries;
3use crate::context::{AttributeDecoderContext, AttributeEncoderContext};
4use crate::StunError;
5use crate::{Algorithm, AlgorithmId};
6use byteorder::{BigEndian, ByteOrder};
7use std::convert::TryInto;
8
9const PASSWORD_ALGORITHM: u16 = 0x001D;
18
19#[derive(Debug, Clone, PartialEq, Eq)]
40pub struct PasswordAlgorithm(Algorithm);
41
42impl PasswordAlgorithm {
43 pub fn new(algorithm: Algorithm) -> Self {
48 Self(algorithm)
49 }
50
51 pub fn algorithm(&self) -> AlgorithmId {
53 self.0.algorithm()
54 }
55
56 pub fn parameters(&self) -> Option<&[u8]> {
58 self.0.parameters()
59 }
60}
61
62impl AsRef<Algorithm> for PasswordAlgorithm {
63 fn as_ref(&self) -> &Algorithm {
64 &self.0
65 }
66}
67
68impl DecodeAttributeValue for PasswordAlgorithm {
69 fn decode(ctx: AttributeDecoderContext) -> Result<(Self, usize), StunError> {
70 let mut size: usize = 4;
72 let raw_value = ctx.raw_value();
73
74 check_buffer_boundaries(raw_value, size)?;
75
76 let algorithm = BigEndian::read_u16(&raw_value[..2]);
77 let param_length = BigEndian::read_u16(&raw_value[2..4]);
78
79 size += param_length as usize;
80 check_buffer_boundaries(raw_value, size)?;
81
82 let params = &raw_value[4..(param_length + 4).into()];
83
84 let algorithm_param = Algorithm::new(
85 AlgorithmId::from(algorithm),
86 (param_length > 0).then_some(params),
87 );
88 Ok((Self(algorithm_param), size))
89 }
90}
91
92impl EncodeAttributeValue for PasswordAlgorithm {
93 fn encode(&self, mut ctx: AttributeEncoderContext) -> Result<usize, StunError> {
94 let params_len = match self.0.parameters().as_ref() {
95 Some(buf) => buf.len(),
96 _ => 0,
97 };
98
99 let len = 4 + params_len;
101 let raw_value = ctx.raw_value_mut();
102
103 check_buffer_boundaries(raw_value, len)?;
104
105 BigEndian::write_u16(&mut raw_value[..2], self.0.algorithm().into());
106 BigEndian::write_u16(&mut raw_value[2..4], params_len.try_into()?);
107
108 if let Some(buf) = self.0.parameters() {
109 raw_value[4..params_len + 4].clone_from_slice(buf);
110 };
111
112 Ok(len)
113 }
114}
115
116impl crate::attributes::AsVerifiable for PasswordAlgorithm {}
117
118stunt_attribute!(PasswordAlgorithm, PASSWORD_ALGORITHM);
119
120#[cfg(test)]
121mod tests {
122 use super::*;
123 use crate::error::StunErrorType;
124 use crate::StunAttribute;
125
126 #[test]
127 fn password_algorithm() {
128 let algorithm = Algorithm::from(AlgorithmId::MD5);
129 let attr = PasswordAlgorithm::new(algorithm);
130
131 let algorithm = Algorithm::from(AlgorithmId::MD5);
132 assert_eq!(AlgorithmId::MD5, attr.algorithm());
133 assert_eq!(&algorithm, attr.as_ref());
134 assert!(attr.parameters().is_none());
135 }
136
137 #[test]
138 fn decode_password_algorithm() {
139 let dummy_msg: [u8; 0] = [0x0; 0];
140 let buffer = [0x00, 0x00, 0x00, 0x00];
141 let ctx = AttributeDecoderContext::new(None, &dummy_msg, &buffer);
142 let (attr, size) =
143 PasswordAlgorithm::decode(ctx).expect("Could not decode PasswordAlgorithm");
144 assert_eq!(size, 4);
145 assert_eq!(attr.algorithm(), AlgorithmId::Reserved);
146 assert_eq!(attr.parameters(), None);
147
148 let buffer = [0x00, 0x01, 0x00, 0x00];
149 let ctx = AttributeDecoderContext::new(None, &dummy_msg, &buffer);
150 let (attr, size) =
151 PasswordAlgorithm::decode(ctx).expect("Could not decode PasswordAlgorithm");
152 assert_eq!(size, 4);
153 assert_eq!(attr.algorithm(), AlgorithmId::MD5);
154 assert_eq!(attr.parameters(), None);
155
156 let buffer = [0x00, 0x02, 0x00, 0x00];
157 let ctx = AttributeDecoderContext::new(None, &dummy_msg, &buffer);
158 let (attr, size) =
159 PasswordAlgorithm::decode(ctx).expect("Could not decode PasswordAlgorithm");
160 assert_eq!(size, 4);
161 assert_eq!(attr.algorithm(), AlgorithmId::SHA256);
162 assert_eq!(attr.parameters(), None);
163
164 let buffer = [0x00, 0x03, 0x00, 0x02, 0x45, 0x23];
165 let ctx = AttributeDecoderContext::new(None, &dummy_msg, &buffer);
166 let (attr, size) =
167 PasswordAlgorithm::decode(ctx).expect("Could not decode PasswordAlgorithm");
168 assert_eq!(size, 6);
169 assert_eq!(attr.algorithm(), AlgorithmId::Unassigned(3));
170 assert_eq!(attr.parameters(), Some([0x45, 0x23].as_slice()));
171 }
172
173 #[test]
174 fn decode_password_algorithm_error() {
175 let dummy_msg: [u8; 0] = [0x0; 0];
176 let buffer = [];
177 let ctx = AttributeDecoderContext::new(None, &dummy_msg, &buffer);
178 let result = PasswordAlgorithm::decode(ctx);
179 assert_eq!(
180 result.expect_err("Error expected"),
181 StunErrorType::SmallBuffer
182 );
183
184 let buffer = [0x00, 0x01, 0x00];
185 let ctx = AttributeDecoderContext::new(None, &dummy_msg, &buffer);
186 let result = PasswordAlgorithm::decode(ctx);
187 assert_eq!(
188 result.expect_err("Error expected"),
189 StunErrorType::SmallBuffer
190 );
191
192 let buffer = [0x00, 0x03, 0x00, 0x02, 0x45];
193 let ctx = AttributeDecoderContext::new(None, &dummy_msg, &buffer);
194 let result = PasswordAlgorithm::decode(ctx);
195 assert_eq!(
196 result.expect_err("Error expected"),
197 StunErrorType::SmallBuffer
198 );
199 }
200
201 #[test]
202 fn encode_password_algorithm() {
203 let dummy_msg: [u8; 0] = [0x0; 0];
204 let algorithm = Algorithm::from(AlgorithmId::MD5);
205 let attr = PasswordAlgorithm::new(algorithm);
206 let mut buffer: [u8; 4] = [0x0; 4];
207 let ctx = AttributeEncoderContext::new(None, &dummy_msg, &mut buffer);
208 let result = attr.encode(ctx);
209 assert_eq!(result, Ok(4));
210 let expected_buffer = [0x00, 0x01, 0x00, 0x00];
211 assert_eq!(&buffer[..], &expected_buffer[..]);
212
213 let params = [1, 2, 3, 4, 5];
214 let algorithm = Algorithm::new(AlgorithmId::Unassigned(255), params.as_ref());
215 let attr = PasswordAlgorithm::new(algorithm);
216 let mut buffer: [u8; 9] = [0x0; 9];
217 let ctx = AttributeEncoderContext::new(None, &dummy_msg, &mut buffer);
218 let result = attr.encode(ctx);
219 assert_eq!(result, Ok(9));
220 let expected_buffer = [0x00, 0xFF, 0x00, 0x05, 0x01, 0x02, 0x03, 0x04, 0x05];
221 assert_eq!(&buffer[..], &expected_buffer[..]);
222 }
223
224 #[test]
225 fn encode_password_algorithm_error() {
226 let dummy_msg: [u8; 0] = [0x0; 0];
227 let algorithm = Algorithm::from(AlgorithmId::MD5);
228 let attr = PasswordAlgorithm::new(algorithm);
229
230 let mut buffer = [];
231 let ctx = AttributeEncoderContext::new(None, &dummy_msg, &mut buffer);
232 let result = attr.encode(ctx);
233 assert_eq!(
234 result.expect_err("Error expected"),
235 StunErrorType::SmallBuffer
236 );
237
238 let mut buffer: [u8; 3] = [0x0; 3];
239 let ctx = AttributeEncoderContext::new(None, &dummy_msg, &mut buffer);
240 let result = attr.encode(ctx);
241 assert_eq!(
242 result.expect_err("Error expected"),
243 StunErrorType::SmallBuffer
244 );
245
246 let params = [1, 2, 3];
247 let algorithm = Algorithm::new(AlgorithmId::Unassigned(255), params.as_ref());
248 let attr = PasswordAlgorithm::new(algorithm);
249 let mut buffer: [u8; 6] = [0x0; 6];
250 let ctx = AttributeEncoderContext::new(None, &dummy_msg, &mut buffer);
251 let result = attr.encode(ctx);
252 assert_eq!(
253 result.expect_err("Error expected"),
254 StunErrorType::SmallBuffer
255 );
256 }
257
258 #[test]
259 fn password_algorithm_stunt_attribute() {
260 let algorithm = Algorithm::from(AlgorithmId::MD5);
261 let attr = StunAttribute::PasswordAlgorithm(PasswordAlgorithm::new(algorithm));
262 assert!(attr.is_password_algorithm());
263 assert!(attr.as_password_algorithm().is_ok());
264 assert!(attr.as_unknown().is_err());
265
266 assert!(attr.attribute_type().is_comprehension_required());
267 assert!(!attr.attribute_type().is_comprehension_optional());
268
269 let dbg_fmt = format!("{:?}", attr);
270 assert_eq!(
271 "PasswordAlgorithm(PasswordAlgorithm(Algorithm { algorithm: MD5, params: None }))",
272 dbg_fmt
273 );
274 }
275}