argonautica/
hasher.rs

1use futures::Future;
2use futures_cpupool::CpuPool;
3use scopeguard;
4
5use config::defaults::{default_cpu_pool, default_lanes};
6use config::{Backend, HasherConfig, Variant, Version};
7use input::{AdditionalData, Container, Password, Salt, SecretKey};
8use output::HashRaw;
9use {Error, ErrorKind};
10
11impl<'a> Default for Hasher<'a> {
12    /// Same as the [`new`](struct.Hasher.html#method.new) method
13    fn default() -> Hasher<'static> {
14        Hasher {
15            additional_data: None,
16            config: HasherConfig::default(),
17            password: None,
18            salt: Salt::default(),
19            secret_key: None,
20        }
21    }
22}
23
24/// <b><u>One of the two main structs.</u></b> Use it to turn passwords into hashes
25#[derive(Debug)]
26#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
27#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
28pub struct Hasher<'a> {
29    pub(crate) additional_data: Option<AdditionalData>,
30    pub(crate) config: HasherConfig,
31    #[cfg_attr(feature = "serde", serde(skip_serializing, skip_deserializing))]
32    pub(crate) password: Option<Password<'a>>,
33    pub(crate) salt: Salt,
34    #[cfg_attr(feature = "serde", serde(skip_serializing, skip_deserializing))]
35    pub(crate) secret_key: Option<SecretKey<'a>>,
36}
37
38impl<'a> Hasher<'a> {
39    /// Creates a new [`Hasher`](struct.Hasher.html) with a sensible default configuration
40    /// for the average machine (e.g. an early-2014 MacBook Air).
41    ///
42    /// <b>Note: If you are using this library to hash user passwords for storage in a database,
43    /// it is recommended that you adjust these settings for your machine (primarily `iterations`,
44    /// and `memory_size`) until the time it takes to hash a password is approximately 300-500
45    /// milliseconds</b>.
46    ///
47    /// There is a script in the examples directory that will show you the various configuration
48    /// options for your machine that produce hashing times between 300 and 500 milliseconds
49    /// (Don't forget to run it with the `--release` and `--features="simd"` flags). Alternatively,
50    /// you can clone the repository and run the benchmark suite with
51    /// `cargo bench --features="benches simd" -- inputs`, which will take longer but which runs
52    /// many iterations for each configuration scenario; so it provides information about
53    /// distributions of running time (e.g. mean, 95% confidence intervals, etc.) as opposed
54    /// to just point estimates.
55    ///
56    /// Here are the default configuration options:
57    /// * `backend`: [`Backend::C`](config/enum.Backend.html#variant.C)
58    /// * `cpu_pool`: A [`CpuPool`](https://docs.rs/futures-cpupool/0.1.8/futures_cpupool/struct.CpuPool.html) ...
59    ///     * with threads equal to the number of logical cores on your machine
60    ///     * that is lazily created, i.e. created only if / when you call the methods
61    ///       that need it ([`hash_non_blocking`](struct.Hasher.html#method.hash_non_blocking) or
62    ///       [`hash_raw_non_blocking`](struct.Hasher.html#method.hash_raw_non_blocking))
63    /// * `hash_len`: `32` bytes
64    /// * `iterations`: `192`
65    /// * `lanes`: The number of logical cores on your machine
66    /// * `memory_size`: `4096` kibibytes
67    /// * `opt_out_of_secret_key`: `false`
68    /// * `password_clearing`: `false`
69    /// * `salt`: random [`Salt`](input/struct.Salt.html) of length 32 bytes that renews with every hash
70    /// * `secret_key_clearing`: `false`
71    /// * `threads`: The number of logical cores on your machine
72    /// * `variant`: [`Variant::Argon2id`](config/enum.Variant.html#variant.Argon2id)
73    /// * `version`: [`Version::_0x13`](config/enum.Verion.html#variant._0x13)
74    pub fn new() -> Hasher<'static> {
75        Hasher::default()
76    }
77    /// Creates a new [`Hasher`](struct.Hasher.html) that is <b>fast but <u>highly</u> insecure</b>.
78    /// If for some reason you'd like to use Argon2 for hashing where security is not an issue,
79    /// you can use this configuration. It sets hash length to 32 bytes (256 bits), uses only
80    /// 1 iteration, sets memory size to the minimum of 8 * the number of lanes, uses a
81    /// deterministic salt of the minimum length of 8 bytes, and opts out of a secret key.
82    /// All other configuration options are the same as the defaults. On the developer's
83    /// early-2014 Macbook Air, this configuration hashes the full text of Shakespear's Hamlet
84    /// in approximately 1 millisecond (on average). [MD5](https://github.com/stainless-steel/md5)
85    /// does it in about half the time and [sha2](https://github.com/RustCrypto/hashes) with the
86    /// SHA-256 algorithm performs about the same as `argonautica`
87    pub fn fast_but_insecure() -> Hasher<'a> {
88        fn memory_size(lanes: u32) -> u32 {
89            let mut counter = 1;
90            let memory_size = loop {
91                if 2u32.pow(counter) < 8 * lanes {
92                    counter += 1;
93                    continue;
94                } else {
95                    break 2u32.pow(counter);
96                }
97            };
98            memory_size
99        }
100        let lanes = default_lanes();
101        let mut hasher = Hasher::default();
102        hasher
103            .configure_hash_len(32)
104            .configure_iterations(1)
105            .configure_lanes(lanes)
106            .configure_memory_size(memory_size(lanes))
107            .configure_password_clearing(false)
108            .configure_secret_key_clearing(false)
109            .configure_threads(lanes)
110            .opt_out_of_secret_key(true)
111            .with_salt(&[0u8; 8][..]);
112        hasher
113    }
114    /// Allows you to configure [`Hasher`](struct.Hasher.html) with a custom backend. The
115    /// default backend is [`Backend::C`](config/enum.Backend.html#variant.C), <i>which is
116    /// currently the only backend supported. A Rust backend is planned, but is not currently
117    /// available. If you configure a [`Hasher`](struct.Hasher.html) with
118    /// [`Backend::Rust`](config/enum.Backend.html#variant.Rust) it will error when you
119    /// call [`hash`](struct.Hasher.html#method.hash),
120    /// [`hash_raw`](struct.Hasher.html#method.hash_raw) or their non-blocking equivalents</i>
121    pub fn configure_backend(&mut self, backend: Backend) -> &mut Hasher<'a> {
122        self.config.set_backend(backend);
123        self
124    }
125    /// Allows you to configure [`Hasher`](struct.Hasher.html) with a custom
126    /// [`CpuPool`](https://docs.rs/futures-cpupool/0.1.8/futures_cpupool/struct.CpuPool.html).
127    /// The default [`Hasher`](struct.Hasher.html) does not have a cpu pool, which is
128    /// only needed for the [`hash_non_blocking`](struct.Hasher.html#method.hash_non_blocking)
129    /// and [`hash_raw_non_blocking`](struct.Hasher.html#method.hash_raw_non_blocking) methods.
130    /// If you call either of these methods without a cpu pool, a default cpu pool will be created
131    /// for you on the fly; so even if you never configure [`Hasher`](struct.Hasher.html) with
132    /// this method you can still use the non-blocking hashing methods.
133    /// The default cpu pool has as many threads as the number of logical cores on your machine
134    pub fn configure_cpu_pool(&mut self, cpu_pool: CpuPool) -> &mut Hasher<'a> {
135        self.config.set_cpu_pool(cpu_pool);
136        self
137    }
138    /// Allows you to configure [`Hasher`](struct.Hasher.html) to use a custom hash length
139    /// (in number of bytes). The default is `32`.
140    ///
141    /// See [configuration example](index.html#configuration) for a more detailed discussion
142    /// of this parameter
143    pub fn configure_hash_len(&mut self, hash_len: u32) -> &mut Hasher<'a> {
144        self.config.set_hash_len(hash_len);
145        self
146    }
147    /// Allows you to configure [`Hasher`](struct.Hasher.html) to use a custom number of
148    /// iterations. The default is `192`.
149    ///
150    /// See [configuration example](index.html#configuration) for a more details on this parameter
151    pub fn configure_iterations(&mut self, iterations: u32) -> &mut Hasher<'a> {
152        self.config.set_iterations(iterations);
153        self
154    }
155    /// Allows you to configure [`Hasher`](struct.Hasher.html) to use a custom number of
156    /// lanes. The default is the number of physical cores on your machine.
157    ///
158    /// See [configuration example](index.html#configuration) for a more details on this parameter
159    pub fn configure_lanes(&mut self, lanes: u32) -> &mut Hasher<'a> {
160        self.config.set_lanes(lanes);
161        self
162    }
163    /// Allows you to configure [`Hasher`](struct.Hasher.html) to use a custom memory size
164    /// (in kibibytes). The default is `4096`.
165    ///
166    /// See [configuration example](index.html#configuration) for a more details on this parameter
167    pub fn configure_memory_size(&mut self, memory_size: u32) -> &mut Hasher<'a> {
168        self.config.set_memory_size(memory_size);
169        self
170    }
171    /// Allows you to configure [`Hasher`](struct.Hasher.html) to erase the password bytes
172    /// after each call to [`hash`](struct.Hasher.html#method.hash),
173    /// [`hash_raw`](struct.Hasher#method.hash_raw), or their non-blocking equivalents.
174    /// The default is to <b>not</b> clear out the password
175    /// bytes (i.e. `false`). If you set this option to `true`, you must provide
176    /// [`Hasher`](struct.Hasher.html) with a mutable password, e.g. a password
177    /// constructed from a `String`, `Vec<u8>`, `&mut str`, `&mut [u8]`, etc. as opposed to
178    /// one constructed from a `&str`, `&[u8]`, etc., or else hashing will return an
179    /// [`Error`](struct.Error.html).
180    ///
181    /// See [configuration example](index.html#configuration) for a more details on this parameter
182    pub fn configure_password_clearing(&mut self, boolean: bool) -> &mut Hasher<'a> {
183        self.config.set_password_clearing(boolean);
184        self
185    }
186    /// Allows you to configure [`Hasher`](struct.Hasher.html) to erase the secret key bytes
187    /// after each call to [`hash`](struct.Hasher.html#method.hash),
188    /// [`hash_raw`](struct.Hasher#method.hash_raw), or their non-blocking equivalents.
189    /// The default is to <b>not</b> clear out the secret key
190    /// bytes (i.e. `false`). If you set this option to `true`, you must provide
191    /// [`Hasher`](struct.Hasher.html) with a mutable secret key, e.g. a secret key
192    /// constructed from a `String`, `Vec<u8>`, `&mut str`, `&mut [u8]`, etc. as opposed to
193    /// one constructed from a `&str`, `&[u8]`, etc., or else hashing will return an
194    /// [`Error`](struct.Error.html).
195    ///
196    /// See [configuration example](index.html#configuration) for a more details on this parameter
197    pub fn configure_secret_key_clearing(&mut self, boolean: bool) -> &mut Hasher<'a> {
198        self.config.set_secret_key_clearing(boolean);
199        self
200    }
201    /// Allows you to configure [`Hasher`](struct.Hasher.html) to use a custom number of
202    /// threads. The default is the number of physical cores on your machine. If you choose
203    /// a number of threads that is greater than the lanes configuration,
204    /// [`Hasher`](struct.Hasher.html) will use the minimum of the two.
205    ///
206    /// See [configuration example](index.html#configuration) for a more details on this parameter
207    pub fn configure_threads(&mut self, threads: u32) -> &mut Hasher<'a> {
208        self.config.set_threads(threads);
209        self
210    }
211    /// Allows you to configure [`Hasher`](struct.Hasher.html) to use a custom Argon2
212    /// variant. The default is [`Variant::Argon2id`](config/enum.Variant.html#variant.Argon2id).
213    /// Do <b>not</b> use a different variant unless you have a specific reason to do so.
214    ///
215    /// See [configuration example](index.html#configuration) for a more details on this parameter
216    pub fn configure_variant(&mut self, variant: Variant) -> &mut Hasher<'a> {
217        self.config.set_variant(variant);
218        self
219    }
220    /// Allows you to configure [`Hasher`](struct.Hasher.html) to use a custom Argon2 version.
221    /// The default and latest (as of 5/18) is
222    /// [`Version::_0x13`](config/enum.Version.html#variant._0x13).
223    /// Do <b>not</b> use a different version unless you have a specific reason to do so.
224    ///
225    /// See [configuration example](index.html#configuration) for a more details on this parameter
226    pub fn configure_version(&mut self, version: Version) -> &mut Hasher<'a> {
227        self.config.set_version(version);
228        self
229    }
230    /// <b><u>The primary method (blocking version).</u></b>
231    ///
232    /// After you have configured a [`Hasher`](struct.Hasher.html) to your liking and provided
233    /// it will all the data you would like to hash, e.g.
234    /// * a [`Password`](input/struct.Password.html),
235    /// * a [`Salt`](input/struct.Password.html) (note: it is recommened you use the default random salt),
236    /// * a [`SecretKey`](input/struct.SecretKey.html),
237    /// * [`AdditionalData`](input/struct.AdditionalData.html) (optional),
238    ///
239    /// call this method in order to produce a string-encoded hash, which is safe to store in a
240    /// database and against which you can verify passwords later
241    pub fn hash(&mut self) -> Result<String, Error> {
242        let hash_raw = self.hash_raw()?;
243        let hash = hash_raw.encode_rust();
244        Ok(hash)
245    }
246    /// <b><u>The primary method (non-blocking version).</u></b>
247    ///
248    /// Same as [`hash`](struct.Hasher.html#method.hash) except it returns a
249    /// [`Future`](https://docs.rs/futures/0.1.21/futures/future/trait.Future.html)
250    /// instead of a [`Result`](https://doc.rust-lang.org/std/result/enum.Result.html)
251    pub fn hash_non_blocking(&mut self) -> impl Future<Item = String, Error = Error> {
252        self.hash_raw_non_blocking().and_then(|hash_raw| {
253            let hash = hash_raw.encode_rust();
254            Ok::<_, Error>(hash)
255        })
256    }
257    /// Like the [`hash`](struct.Hasher.html#method.hash) method, but instead of producing
258    /// an string-encoded hash, it produces a [`HashRaw`](output/struct.HashRaw.html) struct
259    /// that contains all the components of the string-encoded version, including the raw
260    /// hash bytes and the raw salt bytes. In general, you should prefer to use the
261    /// [`hash`](struct.Hasher.html#method.hash) method instead of this method
262    pub fn hash_raw(&mut self) -> Result<HashRaw, Error> {
263        let mut hasher = scopeguard::guard(self, |hasher| {
264            hasher.clear();
265        });
266        hasher.validate()?;
267        hasher.salt.update()?;
268        let hash_raw = match hasher.config.backend() {
269            Backend::C => hasher.hash_raw_c()?,
270            Backend::Rust => return Err(Error::new(ErrorKind::BackendUnsupportedError)),
271        };
272        Ok(hash_raw)
273    }
274    /// Same as [`hash_raw`](struct.Hasher.html#method.hash) except it returns a
275    /// [`Future`](https://docs.rs/futures/0.1.21/futures/future/trait.Future.html)
276    /// instead of a [`Result`](https://doc.rust-lang.org/std/result/enum.Result.html)
277    pub fn hash_raw_non_blocking(&mut self) -> impl Future<Item = HashRaw, Error = Error> {
278        let hasher = scopeguard::guard(self, |hasher| {
279            hasher.clear();
280        });
281        let mut hasher = hasher.to_owned();
282        match hasher.config.cpu_pool() {
283            Some(cpu_pool) => cpu_pool.spawn_fn(move || hasher.hash_raw()),
284            None => {
285                let cpu_pool = default_cpu_pool();
286                hasher.config.set_cpu_pool(cpu_pool.clone());
287                cpu_pool.spawn_fn(move || hasher.hash_raw())
288            }
289        }
290    }
291    /// As an extra security measure, if you want to hash without a secret key, which
292    /// is not recommended, you must explicitly declare that this is your intention
293    /// by calling this method and setting the `opt_out_of_secret_key` configuration to
294    /// `true` (by default, it is set to `false`); otherwise hashing will return an error
295    /// when you fail to provide a secret key
296    pub fn opt_out_of_secret_key(&mut self, boolean: bool) -> &mut Hasher<'a> {
297        self.config.set_opt_out_of_secret_key(boolean);
298        self
299    }
300    /// Clones the [`Hasher`](struct.Hasher.html), returning a new
301    /// [`Hasher`](struct.Hasher.html) with a `static` lifetime. Use this method if you
302    /// would like to move a [`Hasher`](struct.Hasher.html) to another thread
303    pub fn to_owned(&self) -> Hasher<'static> {
304        let password = self.password.as_ref().map(|password| password.to_owned());
305        let secret_key = self
306            .secret_key
307            .as_ref()
308            .map(|secret_key| secret_key.to_owned());
309        Hasher {
310            additional_data: self.additional_data.clone(),
311            config: self.config.clone(),
312            password,
313            salt: self.salt.clone(),
314            secret_key,
315        }
316    }
317    /// Allows you to add some additional data to the [`Hasher`](struct.Hasher.html)
318    /// that will be hashed alongside the [`Password`](input/struct.Password.html) and
319    /// other pieces of data you would like to hash (i.e. the [`Salt`](input/struct.Salt.html) and
320    /// an optional [`SecretKey`](input/struct.SecretKey.html)).
321    ///
322    /// Including additional data in your hash is not very common; so it is unlikely you will
323    /// need to use this method. If, however, you do add additional data, note that it is like
324    /// a secret key in that it will be required later in order to verify passwords, and
325    /// it is not stored in the string-encoded version of the hash, meaning you will have to
326    /// provide it manually to a [`Verifier`](struct.Verifier.html)
327    pub fn with_additional_data<AD>(&mut self, additional_data: AD) -> &mut Hasher<'a>
328    where
329        AD: Into<AdditionalData>,
330    {
331        self.additional_data = Some(additional_data.into());
332        self
333    }
334    /// Allows you to provide a [`Hasher`](struct.Hasher.html) with the password you would like
335    /// to hash. Hashing requires a password; so you must call this method before calling
336    /// [`hash`](struct.Hasher.html#method.hash), [`hash_raw`](struct.Hasher.html#method.hash_raw),
337    /// or their non-blocking version
338    pub fn with_password<P>(&mut self, password: P) -> &mut Hasher<'a>
339    where
340        P: Into<Password<'a>>,
341    {
342        self.password = Some(password.into());
343        self
344    }
345    /// Allows you to provide [`Hasher`](struct.Hasher.html) with a custom
346    /// [`Salt`](input/struct.Salt.html) to include in the hash. The default
347    /// [`Hasher`](struct.Hasher.html) is configured to use a random
348    /// [`Salt`](input/struct.Salt.html) of 32 bytes; so there is no need
349    /// to call this method. If you would like to use a random
350    /// [`Salt`](input/struct.Salt.html) of different length, you can call this method with
351    /// `Salt::random(your_custom_length_in_bytes)`. Using a deterministic
352    /// [`Salt`](input/struct.Salt.html) is possible, but discouraged
353    pub fn with_salt<S>(&mut self, salt: S) -> &mut Hasher<'a>
354    where
355        S: Into<Salt>,
356    {
357        self.salt = salt.into();
358        self
359    }
360    /// Allows you to provide [`Hasher`](struct.Hasher.html) with a secret key that will be used
361    /// to create the hash. The secret key will not be included in the hash output, meaning you
362    /// must save it somewhere (ideally outside your code) to use later, as the only way to
363    /// verify passwords against the hash later is to know the secret key. This library
364    /// encourages the use of a secret key
365    pub fn with_secret_key<SK>(&mut self, secret_key: SK) -> &mut Hasher<'a>
366    where
367        SK: Into<SecretKey<'a>>,
368    {
369        self.secret_key = Some(secret_key.into());
370        self
371    }
372    /// Read-only access to the [`Hasher`](struct.Hasher.html)'s
373    /// [`AdditionalData`](input/struct.AdditionalData.html), if any
374    pub fn additional_data(&self) -> Option<&AdditionalData> {
375        self.additional_data.as_ref()
376    }
377    /// Read-only access to the [`Hasher`](struct.Hasher.html)'s
378    /// [`HasherConfig`](config/struct.HasherConfig.html)
379    pub fn config(&self) -> &HasherConfig {
380        &self.config
381    }
382    /// Read-only access to the [`Hasher`](struct.Hasher.html)'s
383    /// [`Password`](input/struct.Password.html), if any
384    pub fn password(&self) -> Option<&Password<'a>> {
385        self.password.as_ref()
386    }
387    /// Read-only access to the [`Hasher`](struct.Hasher.html)'s [`Salt`](input/struct.Salt.html)
388    pub fn salt(&self) -> &Salt {
389        &self.salt
390    }
391    /// Read-only access to the [`Hasher`](struct.Hasher.html)'s
392    /// [`SecretKey`](input/struct.SecretKey.html), if any
393    pub fn secret_key(&self) -> Option<&SecretKey<'a>> {
394        self.secret_key.as_ref()
395    }
396}
397
398impl<'a> Hasher<'a> {
399    pub(crate) fn clear(&mut self) {
400        if self.password.is_some() && self.config.password_clearing() {
401            {
402                let password_mut_ref = self.password.as_mut().unwrap();
403                match password_mut_ref.inner {
404                    Container::Borrowed(_) => (),
405                    Container::BorrowedMut(ref mut bytes) => {
406                        unsafe { ::std::ptr::write_bytes(bytes.as_mut_ptr(), 0, bytes.len()) };
407                    }
408                    Container::Owned(ref mut bytes) => {
409                        unsafe { ::std::ptr::write_bytes(bytes.as_mut_ptr(), 0, bytes.len()) };
410                    }
411                }
412            }
413            self.password = None;
414        }
415        if self.secret_key.is_some() && self.config.secret_key_clearing() {
416            {
417                let secret_key_mut_ref = self.secret_key.as_mut().unwrap();
418                match secret_key_mut_ref.inner {
419                    Container::Borrowed(_) => (),
420                    Container::BorrowedMut(ref mut bytes) => {
421                        unsafe { ::std::ptr::write_bytes(bytes.as_mut_ptr(), 0, bytes.len()) };
422                    }
423                    Container::Owned(ref mut bytes) => {
424                        unsafe { ::std::ptr::write_bytes(bytes.as_mut_ptr(), 0, bytes.len()) };
425                    }
426                }
427            }
428            self.secret_key = None;
429        }
430    }
431    pub(crate) fn validate(&self) -> Result<(), Error> {
432        self.config.validate()?;
433        if let Some(ref additional_data) = self.additional_data {
434            additional_data.validate()?;
435        }
436        match self.password {
437            Some(ref password) => {
438                password.validate()?;
439                if self.config.password_clearing() && !password.is_mutable() {
440                    return Err(Error::new(ErrorKind::PasswordImmutableError));
441                }
442            }
443            None => return Err(Error::new(ErrorKind::PasswordMissingError)),
444        }
445        self.salt.validate()?;
446        match self.secret_key {
447            Some(ref secret_key) => {
448                secret_key.validate()?;
449                if self.config.secret_key_clearing() && !secret_key.is_mutable() {
450                    return Err(Error::new(ErrorKind::SecretKeyImmutableError));
451                }
452            }
453            None => {
454                if !self.config.opt_out_of_secret_key() {
455                    return Err(Error::new(ErrorKind::SecretKeyMissingError));
456                }
457            }
458        }
459        Ok(())
460    }
461}
462
463#[cfg(test)]
464mod tests {
465    use super::*;
466    use config::{Variant, Version};
467
468    struct Test {
469        variant: Variant,
470        version: Version,
471        expected: Vec<u8>,
472    }
473
474    impl Test {
475        fn run(&self) {
476            let mut hasher = Hasher::default();
477            let raw_hash = hasher
478                .configure_hash_len(32)
479                .configure_iterations(3)
480                .configure_lanes(4)
481                .configure_memory_size(32)
482                .configure_threads(4)
483                .configure_variant(self.variant)
484                .configure_version(self.version)
485                .with_additional_data(vec![4; 12])
486                .with_password(vec![1; 32])
487                .with_salt(vec![2; 16])
488                .with_secret_key(vec![3; 8])
489                .hash_raw()
490                .unwrap();
491            assert_eq!(raw_hash.raw_hash_bytes(), self.expected.as_slice());
492        }
493    }
494
495    #[test]
496    fn test_hasher_0x10_2d() {
497        Test {
498            variant: Variant::Argon2d,
499            version: Version::_0x10,
500            expected: vec![
501                0x96, 0xa9, 0xd4, 0xe5, 0xa1, 0x73, 0x40, 0x92, 0xc8, 0x5e, 0x29, 0xf4, 0x10, 0xa4,
502                0x59, 0x14, 0xa5, 0xdd, 0x1f, 0x5c, 0xbf, 0x08, 0xb2, 0x67, 0x0d, 0xa6, 0x8a, 0x02,
503                0x85, 0xab, 0xf3, 0x2b,
504            ],
505        }.run();
506    }
507
508    #[test]
509    fn test_hasher_0x10_2i() {
510        Test {
511            variant: Variant::Argon2i,
512            version: Version::_0x10,
513            expected: vec![
514                0x87, 0xae, 0xed, 0xd6, 0x51, 0x7a, 0xb8, 0x30, 0xcd, 0x97, 0x65, 0xcd, 0x82, 0x31,
515                0xab, 0xb2, 0xe6, 0x47, 0xa5, 0xde, 0xe0, 0x8f, 0x7c, 0x05, 0xe0, 0x2f, 0xcb, 0x76,
516                0x33, 0x35, 0xd0, 0xfd,
517            ],
518        }.run();
519    }
520
521    #[test]
522    fn test_hasher_0x10_2id() {
523        Test {
524            variant: Variant::Argon2id,
525            version: Version::_0x10,
526            expected: vec![
527                0xb6, 0x46, 0x15, 0xf0, 0x77, 0x89, 0xb6, 0x6b, 0x64, 0x5b, 0x67, 0xee, 0x9e, 0xd3,
528                0xb3, 0x77, 0xae, 0x35, 0x0b, 0x6b, 0xfc, 0xbb, 0x0f, 0xc9, 0x51, 0x41, 0xea, 0x8f,
529                0x32, 0x26, 0x13, 0xc0,
530            ],
531        }.run();
532    }
533
534    #[test]
535    fn test_hasher_0x13_2d() {
536        Test {
537            variant: Variant::Argon2d,
538            version: Version::_0x13,
539            expected: vec![
540                0x51, 0x2b, 0x39, 0x1b, 0x6f, 0x11, 0x62, 0x97, 0x53, 0x71, 0xd3, 0x09, 0x19, 0x73,
541                0x42, 0x94, 0xf8, 0x68, 0xe3, 0xbe, 0x39, 0x84, 0xf3, 0xc1, 0xa1, 0x3a, 0x4d, 0xb9,
542                0xfa, 0xbe, 0x4a, 0xcb,
543            ],
544        }.run();
545    }
546
547    #[test]
548    fn test_hasher_0x13_2i() {
549        Test {
550            variant: Variant::Argon2i,
551            version: Version::_0x13,
552            expected: vec![
553                0xc8, 0x14, 0xd9, 0xd1, 0xdc, 0x7f, 0x37, 0xaa, 0x13, 0xf0, 0xd7, 0x7f, 0x24, 0x94,
554                0xbd, 0xa1, 0xc8, 0xde, 0x6b, 0x01, 0x6d, 0xd3, 0x88, 0xd2, 0x99, 0x52, 0xa4, 0xc4,
555                0x67, 0x2b, 0x6c, 0xe8,
556            ],
557        }.run();
558    }
559
560    #[test]
561    fn test_hasher_0x13_2id() {
562        Test {
563            variant: Variant::Argon2id,
564            version: Version::_0x13,
565            expected: vec![
566                0x0d, 0x64, 0x0d, 0xf5, 0x8d, 0x78, 0x76, 0x6c, 0x08, 0xc0, 0x37, 0xa3, 0x4a, 0x8b,
567                0x53, 0xc9, 0xd0, 0x1e, 0xf0, 0x45, 0x2d, 0x75, 0xb6, 0x5e, 0xb5, 0x25, 0x20, 0xe9,
568                0x6b, 0x01, 0xe6, 0x59,
569            ],
570        }.run();
571    }
572
573    #[test]
574    fn test_hasher_clearing() {
575        // Password is cleared and secret key remains
576        let mut hasher = Hasher::default();
577        let hash = hasher
578            .configure_password_clearing(true)
579            .configure_secret_key_clearing(false)
580            .with_password("password")
581            .with_secret_key("secret")
582            .hash();
583        match hash {
584            Ok(_) => panic!("Should return an error"),
585            Err(e) => assert_eq!(e, Error::new(ErrorKind::PasswordImmutableError)),
586        }
587        assert!(hasher.password().is_none());
588        assert!(hasher.secret_key().is_some());
589
590        // Secret key is cleared and password remains
591        let mut hasher = Hasher::default();
592        let hash = hasher
593            .configure_password_clearing(false)
594            .configure_secret_key_clearing(true)
595            .with_password("password")
596            .with_secret_key("secret")
597            .hash();
598        match hash {
599            Ok(_) => panic!("Should return an error"),
600            Err(e) => assert_eq!(e, Error::new(ErrorKind::SecretKeyImmutableError)),
601        }
602        assert!(hasher.password().is_some());
603        assert!(hasher.secret_key().is_none());
604    }
605
606    #[test]
607    fn test_hasher_fast_but_insecure() {
608        let mut hasher = Hasher::fast_but_insecure();
609        let _ = hasher.with_password("P@ssw0rd").hash().unwrap();
610    }
611
612    #[cfg(feature = "serde")]
613    #[test]
614    fn test_hasher_serialization() {
615        use serde_json;
616
617        let password = "P@ssw0rd";
618        let secret_key = "secret";
619
620        let mut hasher1 = Hasher::default();
621        hasher1
622            .configure_password_clearing(false)
623            .with_additional_data("additional data")
624            .with_password(password)
625            .with_secret_key(secret_key)
626            .with_salt("somesalt");
627        let hash1 = hasher1.hash().expect("failed to hash");
628        let hash_raw1 = hasher1.hash_raw().expect("failed to hash_raw");
629
630        // Serialize Hasher
631        let j = serde_json::to_string_pretty(&hasher1).expect("failed to serialize hasher");
632        // Deserialize Hasher
633        let mut hasher2: Hasher = serde_json::from_str(&j).expect("failed to deserialize hasher");
634        // Assert that password and secret key have been erased
635        assert_eq!(hasher2.password(), None);
636        assert_eq!(hasher2.secret_key(), None);
637        // Assert that calling hash or hash_raw produces an error
638        assert!(hasher2.hash().is_err());
639        assert!(hasher2.hash_raw().is_err());
640        // Add a password and secret key and ensure hash and hash_raw now work
641        hasher2.with_password(password).with_secret_key(secret_key);
642        let hash2 = hasher2.hash().expect("failed to hash");
643        let hash_raw2 = hasher2.hash_raw().expect("failed to hash_raw");
644        // Assert hashes match originals
645        assert_eq!(hash1, hash2);
646        assert_eq!(hash_raw1, hash_raw2);
647    }
648
649    #[test]
650    fn test_send() {
651        fn assert_send<T: Send>() {}
652        assert_send::<Hasher>();
653    }
654
655    #[test]
656    fn test_sync() {
657        fn assert_sync<T: Sync>() {}
658        assert_sync::<Hasher>();
659    }
660
661    #[cfg(feature = "serde")]
662    #[test]
663    fn test_serialize() {
664        use serde;
665        fn assert_serialize<T: serde::Serialize>() {}
666        assert_serialize::<Hasher>();
667    }
668
669    #[cfg(feature = "serde")]
670    #[test]
671    fn test_deserialize() {
672        use serde;
673        fn assert_deserialize<'de, T: serde::Deserialize<'de>>() {}
674        assert_deserialize::<Hasher>();
675    }
676}