Skip to main content

argon2/
context.rs

1// Copyright (c) 2017 Martijn Rijkeboer <mrr@sru-systems.com>
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
9use crate::common;
10use crate::config::Config;
11use crate::error::Error;
12use crate::result::Result;
13
14/// Structure containing settings for the Argon2 algorithm. A combination of
15/// the original argon2_context and argon2_instance_t.
16#[derive(Debug, PartialEq)]
17pub struct Context<'a> {
18    /// The config for this context.
19    pub config: Config<'a>,
20
21    /// The length of a lane.
22    pub lane_length: u32,
23
24    /// The number of memory blocks.
25    pub memory_blocks: u32,
26
27    /// The password.
28    pub pwd: &'a [u8],
29
30    /// The salt.
31    pub salt: &'a [u8],
32
33    /// The length of a segment.
34    pub segment_length: u32,
35}
36
37impl<'a> Context<'a> {
38    /// Attempts to create a new context.
39    pub fn new(config: Config<'a>, pwd: &'a [u8], salt: &'a [u8]) -> Result<Context<'a>> {
40        if config.lanes < common::MIN_LANES {
41            return Err(Error::LanesTooFew);
42        } else if config.lanes > common::MAX_LANES {
43            return Err(Error::LanesTooMany);
44        }
45
46        let lanes = config.lanes;
47        if config.mem_cost < common::MIN_MEMORY {
48            return Err(Error::MemoryTooLittle);
49        } else if config.mem_cost > common::MAX_MEMORY {
50            return Err(Error::MemoryTooMuch);
51        } else if config.mem_cost < 8 * lanes {
52            return Err(Error::MemoryTooLittle);
53        }
54
55        if config.time_cost < common::MIN_TIME {
56            return Err(Error::TimeTooSmall);
57        } else if config.time_cost > common::MAX_TIME {
58            return Err(Error::TimeTooLarge);
59        }
60
61        let pwd_len = pwd.len();
62        if pwd_len < common::MIN_PWD_LENGTH as usize {
63            return Err(Error::PwdTooShort);
64        } else if pwd_len > common::MAX_PWD_LENGTH as usize {
65            return Err(Error::PwdTooLong);
66        }
67
68        let salt_len = salt.len();
69        if salt_len < common::MIN_SALT_LENGTH as usize {
70            return Err(Error::SaltTooShort);
71        } else if salt_len > common::MAX_SALT_LENGTH as usize {
72            return Err(Error::SaltTooLong);
73        }
74
75        let secret_len = config.secret.len();
76        if secret_len < common::MIN_SECRET_LENGTH as usize {
77            return Err(Error::SecretTooShort);
78        } else if secret_len > common::MAX_SECRET_LENGTH as usize {
79            return Err(Error::SecretTooLong);
80        }
81
82        let ad_len = config.ad.len();
83        if ad_len < common::MIN_AD_LENGTH as usize {
84            return Err(Error::AdTooShort);
85        } else if ad_len > common::MAX_AD_LENGTH as usize {
86            return Err(Error::AdTooLong);
87        }
88
89        if config.hash_length < common::MIN_HASH_LENGTH {
90            return Err(Error::OutputTooShort);
91        } else if config.hash_length > common::MAX_HASH_LENGTH {
92            return Err(Error::OutputTooLong);
93        }
94
95        let mut memory_blocks = config.mem_cost;
96        if memory_blocks < 2 * common::SYNC_POINTS * lanes {
97            memory_blocks = 2 * common::SYNC_POINTS * lanes;
98        }
99
100        let segment_length = memory_blocks / (lanes * common::SYNC_POINTS);
101        let memory_blocks = segment_length * (lanes * common::SYNC_POINTS);
102        let lane_length = segment_length * common::SYNC_POINTS;
103
104        Ok(Context {
105            config,
106            lane_length,
107            memory_blocks,
108            pwd,
109            salt,
110            segment_length,
111        })
112    }
113}
114
115#[cfg(test)]
116mod tests {
117
118    use crate::config::Config;
119    use crate::context::Context;
120    use crate::error::Error;
121    use crate::variant::Variant;
122    use crate::version::Version;
123
124    #[test]
125    fn new_returns_correct_instance() {
126        let config = Config {
127            ad: b"additionaldata",
128            hash_length: 32,
129            lanes: 4,
130            mem_cost: 4096,
131            secret: b"secret",
132            time_cost: 3,
133            variant: Variant::Argon2i,
134            version: Version::Version13,
135        };
136        let pwd = b"password";
137        let salt = b"somesalt";
138        let result = Context::new(config.clone(), pwd, salt);
139        assert!(result.is_ok());
140
141        let context = result.unwrap();
142        assert_eq!(context.config, config);
143        assert_eq!(context.pwd, pwd);
144        assert_eq!(context.salt, salt);
145        assert_eq!(context.memory_blocks, 4096);
146        assert_eq!(context.segment_length, 256);
147        assert_eq!(context.lane_length, 1024);
148    }
149
150    #[test]
151    fn new_with_too_little_mem_cost_returns_correct_error() {
152        let config = Config {
153            mem_cost: 7,
154            ..Default::default()
155        };
156        assert_eq!(
157            Context::new(config, &[0u8; 8], &[0u8; 8]),
158            Err(Error::MemoryTooLittle)
159        );
160    }
161
162    #[test]
163    fn new_with_less_than_8_x_lanes_mem_cost_returns_correct_error() {
164        let config = Config {
165            lanes: 4,
166            mem_cost: 31,
167            ..Default::default()
168        };
169        assert_eq!(
170            Context::new(config, &[0u8; 8], &[0u8; 8]),
171            Err(Error::MemoryTooLittle)
172        );
173    }
174
175    #[test]
176    fn new_with_too_small_time_cost_returns_correct_error() {
177        let config = Config {
178            time_cost: 0,
179            ..Default::default()
180        };
181        assert_eq!(
182            Context::new(config, &[0u8; 8], &[0u8; 8]),
183            Err(Error::TimeTooSmall)
184        );
185    }
186
187    #[test]
188    fn new_with_too_few_lanes_returns_correct_error() {
189        let config = Config {
190            lanes: 0,
191            ..Default::default()
192        };
193        assert_eq!(
194            Context::new(config, &[0u8; 8], &[0u8; 8]),
195            Err(Error::LanesTooFew)
196        );
197    }
198
199    #[test]
200    fn new_with_too_many_lanes_returns_correct_error() {
201        let config = Config {
202            lanes: 1 << 24,
203            ..Default::default()
204        };
205        assert_eq!(
206            Context::new(config, &[0u8; 8], &[0u8; 8]),
207            Err(Error::LanesTooMany)
208        );
209    }
210
211    #[test]
212    fn new_with_too_short_salt_returns_correct_error() {
213        let config = Default::default();
214        let salt = [0u8; 7];
215        assert_eq!(
216            Context::new(config, &[0u8; 8], &salt),
217            Err(Error::SaltTooShort)
218        );
219    }
220
221    #[test]
222    fn new_with_too_short_hash_length_returns_correct_error() {
223        let config = Config {
224            hash_length: 3,
225            ..Default::default()
226        };
227        assert_eq!(
228            Context::new(config, &[0u8; 8], &[0u8; 8]),
229            Err(Error::OutputTooShort)
230        );
231    }
232}