/rust/registry/src/index.crates.io-1949cf8c6b5b557f/argon2-0.5.3/src/blake2b_long.rs
Line | Count | Source |
1 | | //! The variable length hash function used in the Argon2 algorithm. |
2 | | |
3 | | use crate::{Error, Result}; |
4 | | |
5 | | use blake2::{ |
6 | | digest::{self, Digest, VariableOutput}, |
7 | | Blake2b512, Blake2bVar, |
8 | | }; |
9 | | |
10 | | use core::convert::TryFrom; |
11 | | |
12 | 0 | pub fn blake2b_long(inputs: &[&[u8]], out: &mut [u8]) -> Result<()> { |
13 | 0 | if out.is_empty() { |
14 | 0 | return Err(Error::OutputTooShort); |
15 | 0 | } |
16 | | |
17 | 0 | let len_bytes = u32::try_from(out.len()) |
18 | 0 | .map(|v| v.to_le_bytes()) |
19 | 0 | .map_err(|_| Error::OutputTooLong)?; |
20 | | |
21 | | // Use blake2b directly if the output is small enough. |
22 | 0 | if out.len() <= Blake2b512::output_size() { |
23 | 0 | let mut digest = Blake2bVar::new(out.len()).map_err(|_| Error::OutputTooLong)?; |
24 | | |
25 | | // Conflicting method name from `Digest` and `Update` traits |
26 | 0 | digest::Update::update(&mut digest, &len_bytes); |
27 | | |
28 | 0 | for input in inputs { |
29 | 0 | digest::Update::update(&mut digest, input); |
30 | 0 | } |
31 | | |
32 | 0 | digest |
33 | 0 | .finalize_variable(out) |
34 | 0 | .map_err(|_| Error::OutputTooLong)?; |
35 | | |
36 | 0 | return Ok(()); |
37 | 0 | } |
38 | | |
39 | | // Calculate longer hashes by first calculating a full 64 byte hash |
40 | 0 | let half_hash_len = Blake2b512::output_size() / 2; |
41 | 0 | let mut digest = Blake2b512::new(); |
42 | | |
43 | 0 | digest.update(len_bytes); |
44 | 0 | for input in inputs { |
45 | 0 | digest.update(input); |
46 | 0 | } |
47 | 0 | let mut last_output = digest.finalize(); |
48 | | |
49 | | // Then we write the first 32 bytes of this hash to the output |
50 | 0 | out[..half_hash_len].copy_from_slice(&last_output[..half_hash_len]); |
51 | | |
52 | | // Next, we write a number of 32 byte blocks to the output. |
53 | | // Each block is the first 32 bytes of the hash of the last block. |
54 | | // The very last block of the output is excluded, and has a variable |
55 | | // length in range [1, 32]. |
56 | 0 | let mut counter = 0; |
57 | 0 | let out_len = out.len(); |
58 | 0 | for chunk in out[half_hash_len..] |
59 | 0 | .chunks_exact_mut(half_hash_len) |
60 | 0 | .take_while(|_| { |
61 | 0 | counter += half_hash_len; |
62 | 0 | out_len - counter > 64 |
63 | 0 | }) |
64 | 0 | { |
65 | 0 | last_output = Blake2b512::digest(last_output); |
66 | 0 | chunk.copy_from_slice(&last_output[..half_hash_len]); |
67 | 0 | } |
68 | | |
69 | | // Calculate the last block with VarBlake2b. |
70 | 0 | let last_block_size = out.len() - counter; |
71 | 0 | let mut digest = Blake2bVar::new(last_block_size).map_err(|_| Error::OutputTooLong)?; |
72 | | |
73 | 0 | digest::Update::update(&mut digest, &last_output); |
74 | 0 | digest |
75 | 0 | .finalize_variable(&mut out[counter..]) |
76 | 0 | .expect("invalid Blake2bVar out length"); |
77 | | |
78 | 0 | Ok(()) |
79 | 0 | } |