sha_crypt/
params.rs

1//! Algorithm parameters.
2
3use crate::{Error, Result};
4use core::{
5    default::Default,
6    fmt::{self, Display},
7    str::FromStr,
8};
9
10/// Name of the parameter when serialized in an MCF string.
11const ROUNDS_PARAM: &str = "rounds=";
12
13/// Algorithm parameters.
14#[derive(Clone, Copy, Debug, Eq, PartialEq)]
15pub struct Params {
16    /// Number of times to apply the digest function
17    pub(crate) rounds: u32,
18}
19
20impl Params {
21    /// Recommended parameters.
22    pub const RECOMMENDED: Self = Self {
23        rounds: Self::RECOMMENDED_ROUNDS,
24    };
25
26    /// Recommended number of rounds.
27    pub const RECOMMENDED_ROUNDS: u32 = 5_000;
28
29    /// Minimum number of rounds allowed.
30    pub const ROUNDS_MIN: u32 = 1_000;
31
32    /// Maximum number of rounds allowed.
33    pub const ROUNDS_MAX: u32 = 999_999_999;
34
35    /// Create new algorithm parameters.
36    pub fn new(rounds: u32) -> Result<Params> {
37        match rounds {
38            Self::ROUNDS_MIN..=Self::ROUNDS_MAX => Ok(Params { rounds }),
39            _ => Err(Error::RoundsInvalid),
40        }
41    }
42}
43
44impl Default for Params {
45    fn default() -> Self {
46        Params::RECOMMENDED
47    }
48}
49
50impl Display for Params {
51    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
52        write!(f, "rounds={}", self.rounds)
53    }
54}
55
56impl FromStr for Params {
57    type Err = Error;
58
59    fn from_str(s: &str) -> Result<Self> {
60        if s.is_empty() {
61            return Ok(Self::default());
62        }
63
64        if let Some(rounds_str) = s.strip_prefix(ROUNDS_PARAM) {
65            Self::new(rounds_str.parse().map_err(|_| Error::RoundsInvalid)?)
66        } else {
67            Err(Error::ParamsInvalid)
68        }
69    }
70}
71
72#[cfg(test)]
73mod tests {
74    use super::Params;
75
76    #[test]
77    fn test_sha256_crypt_invalid_rounds() {
78        let params = Params::new(Params::ROUNDS_MAX + 1);
79        assert!(params.is_err());
80
81        let params = Params::new(Params::ROUNDS_MIN - 1);
82        assert!(params.is_err());
83    }
84
85    #[test]
86    fn test_sha512_crypt_invalid_rounds() {
87        let params = Params::new(Params::ROUNDS_MAX + 1);
88        assert!(params.is_err());
89
90        let params = Params::new(Params::ROUNDS_MIN - 1);
91        assert!(params.is_err());
92    }
93}