Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .clippy.toml
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
allow-unwrap-in-consts = true
allow-unwrap-in-tests = true
doc-valid-idents = ["BLAKE2b", ".."]
67 changes: 56 additions & 11 deletions argon2/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -309,8 +309,30 @@ impl<'key> Argon2<'key> {
pwd: &[u8],
salt: &[u8],
out: &mut [u8],
mut memory_blocks: impl AsMut<[Block]>,
memory_blocks: impl AsMut<[Block]>,
) -> Result<()> {
self.hash_password_into_block(pwd, salt, out, memory_blocks)?;
Ok(())
}

/// Hash a password and associated parameters, returning the final reduced internal block.
///
/// This method performs the full Argon2 execution phase but returns the raw computed block
/// matrix result prior to the final BLAKE2b variable-length extraction layout.
///
/// # Errors
/// - Returns [`Error::PwdTooLong`] if `pwd` is longer than `MAX_PWD_LEN`.
/// - Returns [`Error::SaltTooShort`] if `salt` is shorter than `MIN_SALT_LEN`.
/// - Returns [`Error::SaltTooLong`] if `salt` is longer than `MAX_SALT_LEN`.
/// - Returns [`Error::OutputTooShort`] if `out` is too short.
/// - Returns [`Error::OutputTooLong`] if `out` is too long.
pub fn hash_password_into_block(
&self,
pwd: &[u8],
salt: &[u8],
out: &mut [u8],
mut memory_blocks: impl AsMut<[Block]>,
) -> Result<Block> {
// Validate output length
if out.len() < self.params.output_len().unwrap_or(Params::MIN_OUTPUT_LEN) {
return Err(Error::OutputTooShort);
Expand Down Expand Up @@ -547,18 +569,21 @@ impl<'key> Argon2<'key> {
&self.params
}

fn finalize(&self, memory_blocks: &[Block], out: &mut [u8]) -> Result<()> {
let lane_length = self.params.lane_length();

let mut blockhash = memory_blocks[lane_length - 1];
/// Finalize a raw structural block hash computed from [`Argon2::hash_password_into_block`]
/// down into a target variable-length byte destination buffer.
///
/// # Errors
/// - Returns [`Error::OutputTooShort`] if `out` is too short.
/// - Returns [`Error::OutputTooLong`] if `out` is too long.
pub fn finalize_block(&self, blockhash: &Block, out: &mut [u8]) -> Result<()> {
if out.len() < self.params.output_len().unwrap_or(Params::MIN_OUTPUT_LEN) {
return Err(Error::OutputTooShort);
}

// XOR the last blocks
for l in 1..self.params.lanes() {
let last_block_in_lane = l * lane_length + (lane_length - 1);
blockhash ^= &memory_blocks[last_block_in_lane];
if out.len() > self.params.output_len().unwrap_or(Params::MAX_OUTPUT_LEN) {
return Err(Error::OutputTooLong);
}

// Hash the result
let mut blockhash_bytes = [0u8; Block::SIZE];

for (chunk, v) in blockhash_bytes.chunks_mut(8).zip(blockhash.iter()) {
Expand All @@ -569,13 +594,33 @@ impl<'key> Argon2<'key> {

#[cfg(feature = "zeroize")]
{
blockhash.zeroize();
blockhash_bytes.zeroize();
}

Ok(())
}

fn finalize(&self, memory_blocks: &[Block], out: &mut [u8]) -> Result<Block> {
let lane_length = self.params.lane_length();

let mut blockhash = memory_blocks[lane_length - 1];

// XOR the last blocks
for l in 1..self.params.lanes() {
let last_block_in_lane = l * lane_length + (lane_length - 1);
blockhash ^= &memory_blocks[last_block_in_lane];
}

self.finalize_block(&blockhash, out)?;

#[cfg(feature = "zeroize")]
{
blockhash.zeroize();
}

Ok(blockhash)
}

fn update_address_block(
&self,
address_block: &mut Block,
Expand Down