Skip to content
Merged
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
2 changes: 2 additions & 0 deletions .github/workflows/argon2.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ jobs:
# target: ${{ matrix.target }}
# override: true
# - run: cargo build --target ${{ matrix.target }} --release --no-default-features
# - run: cargo build --target ${{ matrix.target }} --release --no-default-features --features password-hash
# - run: cargo build --target ${{ matrix.target }} --release
# - run: cargo build --target ${{ matrix.target }} --release --features zeroize

Expand All @@ -55,5 +56,6 @@ jobs:
toolchain: ${{ matrix.rust }}
override: true
- run: cargo test --release --no-default-features
- run: cargo test --release --no-default-features --features password-hash
- run: cargo test --release
- run: cargo test --release --all-features
5 changes: 3 additions & 2 deletions argon2/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,11 @@ hex-literal = "0.3"
password-hash = { version = "=0.3.0-pre.1", features = ["rand_core"] }

[features]
default = ["password-hash", "rand"]
default = ["alloc", "password-hash", "rand"]
alloc = []
parallel = ["rayon", "std"]
rand = ["password-hash/rand_core"]
std = ["password-hash/std"]
std = ["alloc", "password-hash/std"]

[package.metadata.docs.rs]
all-features = true
Expand Down
10 changes: 5 additions & 5 deletions argon2/src/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use zeroize::Zeroize;

/// Structure for the (1KB) memory block implemented as 128 64-bit words.
#[derive(Copy, Clone, Debug)]
pub(crate) struct Block([u64; Self::SIZE / 8]);
pub struct Block([u64; Self::SIZE / 8]);

impl Default for Block {
fn default() -> Self {
Expand All @@ -25,7 +25,7 @@ impl Block {
pub const SIZE: usize = 1024;

/// Load a block from a block-sized byte slice
pub fn load(&mut self, input: &[u8]) {
pub(crate) fn load(&mut self, input: &[u8]) {
debug_assert_eq!(input.len(), Block::SIZE);

for (i, chunk) in input.chunks(8).enumerate() {
Expand All @@ -34,18 +34,18 @@ impl Block {
}

/// Iterate over the `u64` values contained in this block
pub fn iter(&self) -> slice::Iter<'_, u64> {
pub(crate) fn iter(&self) -> slice::Iter<'_, u64> {
self.0.iter()
}

/// Iterate mutably over the `u64` values contained in this block
pub fn iter_mut(&mut self) -> slice::IterMut<'_, u64> {
pub(crate) fn iter_mut(&mut self) -> slice::IterMut<'_, u64> {
self.0.iter_mut()
}

/// Function fills a new memory block and optionally XORs the old block over the new one.
// TODO(tarcieri): optimized implementation (i.e. from opt.c instead of ref.c)
pub fn fill_block(&mut self, prev_block: Block, ref_block: Block, with_xor: bool) {
pub(crate) fn fill_block(&mut self, prev_block: Block, ref_block: Block, with_xor: bool) {
let mut block_r = ref_block ^ prev_block;
let mut block_tmp = block_r;

Expand Down
2 changes: 1 addition & 1 deletion argon2/src/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ impl<'a> Instance<'a> {
memory,
passes: context.params.t_cost(),
lane_length,
lanes: context.lanes(),
lanes: context.params.lanes(),
threads: context.params.t_cost(),
alg,
};
Expand Down
58 changes: 40 additions & 18 deletions argon2/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
//! - **Argon2i**: optimized to resist side-channel attacks
//! - **Argon2id**: (default) hybrid version combining both Argon2i and Argon2d
//!
//! Support is provided for embedded (i.e. `no_std`) environments, including
//! ones without `alloc` support.
//!
//! # Usage (simple with default params)
//!
//! Note: this example requires the `rand_core` crate with the `std` feature
Expand Down Expand Up @@ -72,6 +75,7 @@
)]
#![warn(rust_2018_idioms, missing_docs)]

#[cfg(feature = "alloc")]
#[macro_use]
extern crate alloc;

Expand All @@ -88,6 +92,7 @@ mod version;

pub use crate::{
algorithm::Algorithm,
block::Block,
error::{Error, Result},
params::{Params, ParamsBuilder},
version::Version,
Expand All @@ -101,13 +106,12 @@ pub use {
};

use crate::{
block::Block,
instance::Instance,
memory::{Memory, SYNC_POINTS},
};
use blake2::{digest, Blake2b, Digest};

#[cfg(feature = "password-hash")]
#[cfg(all(feature = "alloc", feature = "password-hash"))]
use {
core::convert::{TryFrom, TryInto},
password_hash::{Decimal, Ident, Salt},
Expand Down Expand Up @@ -208,12 +212,35 @@ impl<'key> Argon2<'key> {
}

/// Hash a password and associated parameters into the provided output buffer.
#[cfg(feature = "alloc")]
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
pub fn hash_password_into(
&self,
pwd: &[u8],
salt: &[u8],
ad: &[u8],
out: &mut [u8],
) -> Result<()> {
let mut blocks = vec![Block::default(); self.params.block_count()];
self.hash_password_into_with_memory(pwd, salt, ad, out, &mut blocks)
}

/// Hash a password and associated parameters into the provided output buffer.
///
/// This method takes an explicit `memory_blocks` parameter which allows
/// the caller to provide the backing storage for the algorithm's state:
///
/// - Users with the `alloc` feature enabled can use [`Argon2::hash_password_into`]
/// to have it allocated for them.
/// - `no_std` users on "heapless" targets can use an array of the [`Block`] type
/// to stack allocate this buffer.
pub fn hash_password_into_with_memory(
&self,
pwd: &[u8],
salt: &[u8],
ad: &[u8],
out: &mut [u8],
mut memory_blocks: impl AsMut<[Block]>,
) -> Result<()> {
// Validate output length
if out.len()
Expand Down Expand Up @@ -255,15 +282,14 @@ impl<'key> Argon2<'key> {
// Hashing all inputs
let initial_hash = self.initial_hash(pwd, salt, ad, out);

let segment_length =
Memory::segment_length_for_params(self.params.m_cost(), self.params.p_cost());

let blocks_count = (segment_length * self.params.p_cost() * SYNC_POINTS) as usize;
let segment_length = self.params.segment_length();
let block_count = self.params.block_count();
let memory_blocks = memory_blocks
.as_mut()
.get_mut(..block_count)
.ok_or(Error::MemoryTooLittle)?;

// TODO(tarcieri): support for stack-allocated memory blocks (i.e. no alloc)
let mut blocks = vec![Block::default(); blocks_count];

let memory = Memory::new(&mut blocks, segment_length);
let memory = Memory::new(memory_blocks, segment_length);
Instance::hash(self, self.algorithm, initial_hash, memory, out)
}

Expand All @@ -272,11 +298,6 @@ impl<'key> Argon2<'key> {
&self.params
}

/// Get the number of lanes.
pub(crate) fn lanes(&self) -> u32 {
self.params.p_cost()
}

/// Hashes all the inputs into `blockhash[PREHASH_DIGEST_LENGTH]`.
pub(crate) fn initial_hash(
&self,
Expand All @@ -286,7 +307,7 @@ impl<'key> Argon2<'key> {
out: &[u8],
) -> digest::Output<Blake2b> {
let mut digest = Blake2b::new();
digest.update(&self.lanes().to_le_bytes());
digest.update(&self.params.lanes().to_le_bytes());
digest.update(&(out.len() as u32).to_le_bytes());
digest.update(&self.params.m_cost().to_le_bytes());
digest.update(&self.params.t_cost().to_le_bytes());
Expand All @@ -310,7 +331,8 @@ impl<'key> Argon2<'key> {
}
}

#[cfg(feature = "password-hash")]
#[cfg(all(feature = "alloc", feature = "password-hash"))]
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
#[cfg_attr(docsrs, doc(cfg(feature = "password-hash")))]
impl PasswordHasher for Argon2<'_> {
type Params = Params;
Expand Down Expand Up @@ -389,7 +411,7 @@ impl<'key> From<&Params> for Argon2<'key> {
}
}

#[cfg(all(test, feature = "password-hash"))]
#[cfg(all(test, feature = "alloc", feature = "password-hash"))]
mod tests {
use crate::{Algorithm, Argon2, Params, PasswordHasher, Salt, Version};

Expand Down
13 changes: 0 additions & 13 deletions argon2/src/memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,6 @@ pub(crate) struct Memory<'a> {
}

impl<'a> Memory<'a> {
/// Align memory size.
///
/// Minimum memory_blocks = 8*`L` blocks, where `L` is the number of lanes.
pub(crate) fn segment_length_for_params(m_cost: u32, lanes: u32) -> u32 {
let memory_blocks = if m_cost < 2 * SYNC_POINTS * lanes {
2 * SYNC_POINTS * lanes
} else {
m_cost
};

memory_blocks / (lanes * SYNC_POINTS)
}

/// Instantiate a new memory struct
pub(crate) fn new(data: &'a mut [Block], segment_length: u32) -> Self {
Self {
Expand Down
23 changes: 23 additions & 0 deletions argon2/src/params.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,29 @@ impl Params {
pub fn output_len(self) -> Option<usize> {
self.output_len
}

/// Get the number of lanes.
pub(crate) fn lanes(self) -> u32 {
self.p_cost
}

/// Get the segment length given the configured `m_cost` and `p_cost`.
///
/// Minimum memory_blocks = 8*`L` blocks, where `L` is the number of lanes.
pub(crate) fn segment_length(self) -> u32 {
let memory_blocks = if self.m_cost < 2 * SYNC_POINTS * self.lanes() {
2 * SYNC_POINTS * self.lanes()
} else {
self.m_cost
};

memory_blocks / (self.lanes() * SYNC_POINTS)
}

/// Get the number of blocks required given the configured `m_cost` and `p_cost`.
pub(crate) fn block_count(self) -> usize {
(self.segment_length() * self.p_cost * SYNC_POINTS) as usize
}
}

impl Default for Params {
Expand Down
2 changes: 2 additions & 0 deletions argon2/tests/kat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
//! `draft-irtf-cfrg-argon2-12` Section 5:
//! <https://datatracker.ietf.org/doc/draft-irtf-cfrg-argon2/>

#![cfg(feature = "alloc")]

// TODO(tarcieri): test full set of vectors from the reference implementation:
// https://github.com/P-H-C/phc-winner-argon2/blob/master/src/test.c

Expand Down
2 changes: 1 addition & 1 deletion argon2/tests/phc_strings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
//!
//! Adapted from: <https://github.com/P-H-C/phc-winner-argon2/blob/master/src/test.c>

#![cfg(feature = "password-hash")]
#![cfg(all(feature = "alloc", feature = "password-hash"))]

use argon2::{Argon2, PasswordHash, PasswordVerifier};

Expand Down