1pub mod auth;
13mod engine;
14mod privacy;
15mod usm;
16
17pub use auth::{LocalizedKey, MasterKey, MasterKeys};
18pub use engine::report_oids;
19pub use engine::{
20 DEFAULT_MSG_MAX_SIZE, EngineCache, EngineState, MAX_ENGINE_TIME, TIME_WINDOW,
21 parse_discovery_response, parse_discovery_response_with_limits,
22};
23pub use engine::{
24 is_decryption_error_report, is_not_in_time_window_report, is_unknown_engine_id_report,
25 is_unknown_user_name_report, is_unsupported_sec_level_report, is_wrong_digest_report,
26};
27pub use privacy::{PrivKey, PrivacyError, PrivacyResult, SaltCounter};
28pub use usm::UsmSecurityParams;
29
30#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
36pub(crate) enum KeyExtension {
37 #[default]
39 None,
40 Blumenthal,
42 Reeder,
44}
45
46#[derive(Debug, Clone, PartialEq, Eq)]
48pub struct ParseProtocolError {
49 input: String,
50 kind: ProtocolKind,
51}
52
53#[derive(Debug, Clone, Copy, PartialEq, Eq)]
54enum ProtocolKind {
55 Auth,
56 Priv,
57}
58
59impl std::fmt::Display for ParseProtocolError {
60 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
61 match self.kind {
62 ProtocolKind::Auth => write!(
63 f,
64 "unknown authentication protocol '{}'; expected one of: MD5, SHA, SHA-224, SHA-256, SHA-384, SHA-512",
65 self.input
66 ),
67 ProtocolKind::Priv => write!(
68 f,
69 "unknown privacy protocol '{}'; expected one of: DES, AES, AES-128, AES-192, AES-256",
70 self.input
71 ),
72 }
73 }
74}
75
76impl std::error::Error for ParseProtocolError {}
77
78#[derive(Debug, Clone, Copy, PartialEq, Eq)]
80pub enum AuthProtocol {
81 Md5,
83 Sha1,
85 Sha224,
87 Sha256,
89 Sha384,
91 Sha512,
93}
94
95impl std::fmt::Display for AuthProtocol {
96 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
97 match self {
98 Self::Md5 => write!(f, "MD5"),
99 Self::Sha1 => write!(f, "SHA"),
100 Self::Sha224 => write!(f, "SHA-224"),
101 Self::Sha256 => write!(f, "SHA-256"),
102 Self::Sha384 => write!(f, "SHA-384"),
103 Self::Sha512 => write!(f, "SHA-512"),
104 }
105 }
106}
107
108impl std::str::FromStr for AuthProtocol {
109 type Err = ParseProtocolError;
110
111 fn from_str(s: &str) -> Result<Self, Self::Err> {
112 match s.to_ascii_uppercase().as_str() {
113 "MD5" => Ok(Self::Md5),
114 "SHA" | "SHA1" | "SHA-1" => Ok(Self::Sha1),
115 "SHA224" | "SHA-224" => Ok(Self::Sha224),
116 "SHA256" | "SHA-256" => Ok(Self::Sha256),
117 "SHA384" | "SHA-384" => Ok(Self::Sha384),
118 "SHA512" | "SHA-512" => Ok(Self::Sha512),
119 _ => Err(ParseProtocolError {
120 input: s.to_string(),
121 kind: ProtocolKind::Auth,
122 }),
123 }
124 }
125}
126
127impl AuthProtocol {
128 pub fn digest_len(self) -> usize {
133 match self {
134 Self::Md5 => 16,
135 Self::Sha1 => 20,
136 Self::Sha224 => 28,
137 Self::Sha256 => 32,
138 Self::Sha384 => 48,
139 Self::Sha512 => 64,
140 }
141 }
142
143 pub fn mac_len(self) -> usize {
145 match self {
146 Self::Md5 | Self::Sha1 => 12, Self::Sha224 => 16, Self::Sha256 => 24, Self::Sha384 => 32, Self::Sha512 => 48, }
152 }
153}
154
155#[derive(Debug, Clone, Copy, PartialEq, Eq)]
157pub enum PrivProtocol {
158 Des,
163 Des3,
168 Aes128,
170 Aes192,
172 Aes256,
174}
175
176impl std::fmt::Display for PrivProtocol {
177 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
178 match self {
179 Self::Des => write!(f, "DES"),
180 Self::Des3 => write!(f, "3DES"),
181 Self::Aes128 => write!(f, "AES"),
182 Self::Aes192 => write!(f, "AES-192"),
183 Self::Aes256 => write!(f, "AES-256"),
184 }
185 }
186}
187
188impl std::str::FromStr for PrivProtocol {
189 type Err = ParseProtocolError;
190
191 fn from_str(s: &str) -> Result<Self, Self::Err> {
192 match s.to_ascii_uppercase().as_str() {
193 "DES" => Ok(Self::Des),
194 "3DES" | "3DES-EDE" | "DES3" | "TDES" => Ok(Self::Des3),
195 "AES" | "AES128" | "AES-128" => Ok(Self::Aes128),
196 "AES192" | "AES-192" => Ok(Self::Aes192),
197 "AES256" | "AES-256" => Ok(Self::Aes256),
198 _ => Err(ParseProtocolError {
199 input: s.to_string(),
200 kind: ProtocolKind::Priv,
201 }),
202 }
203 }
204}
205
206impl PrivProtocol {
207 pub fn key_len(self) -> usize {
209 match self {
210 Self::Des => 16, Self::Des3 => 32, Self::Aes128 => 16,
213 Self::Aes192 => 24,
214 Self::Aes256 => 32,
215 }
216 }
217
218 pub fn salt_len(self) -> usize {
220 8 }
222
223 pub(crate) fn key_extension_for(self, auth_protocol: AuthProtocol) -> KeyExtension {
232 let auth_len = auth_protocol.digest_len();
233 let priv_len = self.key_len();
234
235 if auth_len >= priv_len {
236 return KeyExtension::None;
237 }
238
239 match self {
240 Self::Des3 => KeyExtension::Reeder,
241 Self::Aes192 | Self::Aes256 => KeyExtension::Blumenthal,
242 Self::Des | Self::Aes128 => KeyExtension::None, }
244 }
245}
246
247#[cfg(test)]
248mod tests {
249 use super::*;
250
251 #[test]
252 fn test_auth_protocol_display() {
253 assert_eq!(format!("{}", AuthProtocol::Md5), "MD5");
254 assert_eq!(format!("{}", AuthProtocol::Sha1), "SHA");
255 assert_eq!(format!("{}", AuthProtocol::Sha224), "SHA-224");
256 assert_eq!(format!("{}", AuthProtocol::Sha256), "SHA-256");
257 assert_eq!(format!("{}", AuthProtocol::Sha384), "SHA-384");
258 assert_eq!(format!("{}", AuthProtocol::Sha512), "SHA-512");
259 }
260
261 #[test]
262 fn test_auth_protocol_from_str() {
263 assert_eq!("MD5".parse::<AuthProtocol>().unwrap(), AuthProtocol::Md5);
264 assert_eq!("md5".parse::<AuthProtocol>().unwrap(), AuthProtocol::Md5);
265 assert_eq!("SHA".parse::<AuthProtocol>().unwrap(), AuthProtocol::Sha1);
266 assert_eq!("sha1".parse::<AuthProtocol>().unwrap(), AuthProtocol::Sha1);
267 assert_eq!("SHA-1".parse::<AuthProtocol>().unwrap(), AuthProtocol::Sha1);
268 assert_eq!(
269 "sha-224".parse::<AuthProtocol>().unwrap(),
270 AuthProtocol::Sha224
271 );
272 assert_eq!(
273 "SHA256".parse::<AuthProtocol>().unwrap(),
274 AuthProtocol::Sha256
275 );
276 assert_eq!(
277 "SHA-256".parse::<AuthProtocol>().unwrap(),
278 AuthProtocol::Sha256
279 );
280 assert_eq!(
281 "sha384".parse::<AuthProtocol>().unwrap(),
282 AuthProtocol::Sha384
283 );
284 assert_eq!(
285 "SHA-512".parse::<AuthProtocol>().unwrap(),
286 AuthProtocol::Sha512
287 );
288
289 assert!("invalid".parse::<AuthProtocol>().is_err());
290 }
291
292 #[test]
293 fn test_priv_protocol_display() {
294 assert_eq!(format!("{}", PrivProtocol::Des), "DES");
295 assert_eq!(format!("{}", PrivProtocol::Des3), "3DES");
296 assert_eq!(format!("{}", PrivProtocol::Aes128), "AES");
297 assert_eq!(format!("{}", PrivProtocol::Aes192), "AES-192");
298 assert_eq!(format!("{}", PrivProtocol::Aes256), "AES-256");
299 }
300
301 #[test]
302 fn test_priv_protocol_from_str() {
303 assert_eq!("DES".parse::<PrivProtocol>().unwrap(), PrivProtocol::Des);
304 assert_eq!("des".parse::<PrivProtocol>().unwrap(), PrivProtocol::Des);
305 assert_eq!("3DES".parse::<PrivProtocol>().unwrap(), PrivProtocol::Des3);
306 assert_eq!("3des".parse::<PrivProtocol>().unwrap(), PrivProtocol::Des3);
307 assert_eq!(
308 "3DES-EDE".parse::<PrivProtocol>().unwrap(),
309 PrivProtocol::Des3
310 );
311 assert_eq!("DES3".parse::<PrivProtocol>().unwrap(), PrivProtocol::Des3);
312 assert_eq!("TDES".parse::<PrivProtocol>().unwrap(), PrivProtocol::Des3);
313 assert_eq!("AES".parse::<PrivProtocol>().unwrap(), PrivProtocol::Aes128);
314 assert_eq!("aes".parse::<PrivProtocol>().unwrap(), PrivProtocol::Aes128);
315 assert_eq!(
316 "AES128".parse::<PrivProtocol>().unwrap(),
317 PrivProtocol::Aes128
318 );
319 assert_eq!(
320 "AES-128".parse::<PrivProtocol>().unwrap(),
321 PrivProtocol::Aes128
322 );
323 assert_eq!(
324 "aes192".parse::<PrivProtocol>().unwrap(),
325 PrivProtocol::Aes192
326 );
327 assert_eq!(
328 "AES-192".parse::<PrivProtocol>().unwrap(),
329 PrivProtocol::Aes192
330 );
331 assert_eq!(
332 "aes256".parse::<PrivProtocol>().unwrap(),
333 PrivProtocol::Aes256
334 );
335 assert_eq!(
336 "AES-256".parse::<PrivProtocol>().unwrap(),
337 PrivProtocol::Aes256
338 );
339
340 assert!("invalid".parse::<PrivProtocol>().is_err());
341 }
342
343 #[test]
344 fn test_parse_protocol_error_display() {
345 let err = "bogus".parse::<AuthProtocol>().unwrap_err();
346 assert!(err.to_string().contains("bogus"));
347 assert!(err.to_string().contains("authentication protocol"));
348
349 let err = "bogus".parse::<PrivProtocol>().unwrap_err();
350 assert!(err.to_string().contains("bogus"));
351 assert!(err.to_string().contains("privacy protocol"));
352 }
353}