Skip to content

Commit

Permalink
argon2: more const-ness (#450)
Browse files Browse the repository at this point in the history
  • Loading branch information
C0D3-M4513R authored Aug 26, 2023
1 parent 0e32400 commit d25ea61
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 78 deletions.
6 changes: 3 additions & 3 deletions argon2/src/algorithm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ impl Algorithm {
}

/// Get the identifier string for this PBKDF2 [`Algorithm`].
pub fn as_str(&self) -> &'static str {
pub const fn as_str(&self) -> &'static str {
match self {
Algorithm::Argon2d => "argon2d",
Algorithm::Argon2i => "argon2i",
Expand All @@ -69,7 +69,7 @@ impl Algorithm {
/// Get the [`Ident`] that corresponds to this Argon2 [`Algorithm`].
#[cfg(feature = "password-hash")]
#[cfg_attr(docsrs, doc(cfg(feature = "password-hash")))]
pub fn ident(&self) -> Ident<'static> {
pub const fn ident(&self) -> Ident<'static> {
match self {
Algorithm::Argon2d => ARGON2D_IDENT,
Algorithm::Argon2i => ARGON2I_IDENT,
Expand All @@ -78,7 +78,7 @@ impl Algorithm {
}

/// Serialize primitive type as little endian bytes
pub(crate) fn to_le_bytes(self) -> [u8; 4] {
pub(crate) const fn to_le_bytes(self) -> [u8; 4] {
(self as u32).to_le_bytes()
}
}
Expand Down
4 changes: 2 additions & 2 deletions argon2/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -470,7 +470,7 @@ impl<'key> Argon2<'key> {
}

/// Get default configured [`Params`].
pub fn params(&self) -> &Params {
pub const fn params(&self) -> &Params {
&self.params
}

Expand Down Expand Up @@ -531,7 +531,7 @@ impl<'key> Argon2<'key> {
digest.finalize()
}

fn verify_inputs(pwd: &[u8], salt: &[u8]) -> Result<()> {
const fn verify_inputs(pwd: &[u8], salt: &[u8]) -> Result<()> {
if pwd.len() > MAX_PWD_LEN {
return Err(Error::PwdTooLong);
}
Expand Down
144 changes: 79 additions & 65 deletions argon2/src/params.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,36 +104,74 @@ impl Params {
/// - `t_cost`: number of iterations. Between 1 and (2^32)-1.
/// - `p_cost`: degree of parallelism. Between 1 and 255.
/// - `output_len`: size of the KDF output in bytes. Default 32.
pub fn new(m_cost: u32, t_cost: u32, p_cost: u32, output_len: Option<usize>) -> Result<Self> {
let mut builder = ParamsBuilder::new();
pub const fn new(
m_cost: u32,
t_cost: u32,
p_cost: u32,
output_len: Option<usize>,
) -> Result<Self> {
if m_cost < Params::MIN_M_COST {
return Err(Error::MemoryTooLittle);
}

builder.m_cost(m_cost).t_cost(t_cost).p_cost(p_cost);
// Note: we don't need to check `MAX_M_COST`, since it's `u32::MAX`

if m_cost < p_cost * 8 {
return Err(Error::MemoryTooLittle);
}

if t_cost < Params::MIN_T_COST {
return Err(Error::TimeTooSmall);
}

// Note: we don't need to check `MAX_T_COST`, since it's `u32::MAX`

if p_cost < Params::MIN_P_COST {
return Err(Error::ThreadsTooFew);
}

if p_cost > Params::MAX_P_COST {
return Err(Error::ThreadsTooMany);
}

if let Some(len) = output_len {
builder.output_len(len);
if len < Params::MIN_OUTPUT_LEN {
return Err(Error::OutputTooShort);
}

if len > Params::MAX_OUTPUT_LEN {
return Err(Error::OutputTooLong);
}
}

builder.build()
Ok(Params {
m_cost,
t_cost,
p_cost,
keyid: KeyId::EMPTY,
data: AssociatedData::EMPTY,
output_len,
})
}

/// Memory size, expressed in kibibytes. Between 1 and (2^32)-1.
///
/// Value is an integer in decimal (1 to 10 digits).
pub fn m_cost(&self) -> u32 {
pub const fn m_cost(&self) -> u32 {
self.m_cost
}

/// Number of iterations. Between 1 and (2^32)-1.
///
/// Value is an integer in decimal (1 to 10 digits).
pub fn t_cost(&self) -> u32 {
pub const fn t_cost(&self) -> u32 {
self.t_cost
}

/// Degree of parallelism. Between 1 and 255.
///
/// Value is an integer in decimal (1 to 3 digits).
pub fn p_cost(&self) -> u32 {
pub const fn p_cost(&self) -> u32 {
self.p_cost
}

Expand Down Expand Up @@ -164,25 +202,25 @@ impl Params {
}

/// Length of the output (in bytes).
pub fn output_len(&self) -> Option<usize> {
pub const fn output_len(&self) -> Option<usize> {
self.output_len
}

/// Get the number of lanes.
#[allow(clippy::cast_possible_truncation)]
pub(crate) fn lanes(&self) -> usize {
pub(crate) const fn lanes(&self) -> usize {
self.p_cost as usize
}

/// Get the number of blocks in a lane.
pub(crate) fn lane_length(&self) -> usize {
pub(crate) const fn lane_length(&self) -> usize {
self.segment_length() * SYNC_POINTS
}

/// 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) -> usize {
pub(crate) const fn segment_length(&self) -> usize {
let m_cost = self.m_cost as usize;

let memory_blocks = if m_cost < 2 * SYNC_POINTS * self.lanes() {
Expand All @@ -195,7 +233,7 @@ impl Params {
}

/// Get the number of blocks required given the configured `m_cost` and `p_cost`.
pub fn block_count(&self) -> usize {
pub const fn block_count(&self) -> usize {
self.segment_length() * self.lanes() * SYNC_POINTS
}
}
Expand Down Expand Up @@ -233,6 +271,12 @@ macro_rules! param_buf {
Ok(Self { bytes, len })
}

/// Empty value.
pub const EMPTY: Self = Self {
bytes: [0u8; Self::MAX_LEN],
len: 0,
};

#[doc = "Decode"]
#[doc = $name]
#[doc = " from a B64 string"]
Expand All @@ -249,12 +293,12 @@ macro_rules! param_buf {
}

/// Get the length in bytes.
pub fn len(&self) -> usize {
pub const fn len(&self) -> usize {
self.len
}

/// Is this value empty?
pub fn is_empty(&self) -> bool {
pub const fn is_empty(&self) -> bool {
self.len() == 0
}
}
Expand Down Expand Up @@ -384,8 +428,8 @@ pub struct ParamsBuilder {

impl ParamsBuilder {
/// Create a new builder with the default parameters.
pub fn new() -> Self {
Self::default()
pub const fn new() -> Self {
Self::DEFAULT
}

/// Set memory size, expressed in kibibytes, between 1 and (2^32)-1.
Expand Down Expand Up @@ -428,52 +472,18 @@ impl ParamsBuilder {
///
/// This performs validations to ensure that the given parameters are valid
/// and compatible with each other, and will return an error if they are not.
pub fn build(&self) -> Result<Params> {
if self.m_cost < Params::MIN_M_COST {
return Err(Error::MemoryTooLittle);
}

// Note: we don't need to check `MAX_M_COST`, since it's `u32::MAX`

if self.m_cost < self.p_cost * 8 {
return Err(Error::MemoryTooLittle);
}

if self.t_cost < Params::MIN_T_COST {
return Err(Error::TimeTooSmall);
}

// Note: we don't need to check `MAX_T_COST`, since it's `u32::MAX`

if self.p_cost < Params::MIN_P_COST {
return Err(Error::ThreadsTooFew);
}

if self.p_cost > Params::MAX_P_COST {
return Err(Error::ThreadsTooMany);
}

if let Some(len) = self.output_len {
if len < Params::MIN_OUTPUT_LEN {
return Err(Error::OutputTooShort);
}
pub const fn build(&self) -> Result<Params> {
let mut params = match Params::new(self.m_cost, self.t_cost, self.p_cost, self.output_len) {
Ok(params) => params,
Err(err) => return Err(err),
};

if len > Params::MAX_OUTPUT_LEN {
return Err(Error::OutputTooLong);
}
if let Some(keyid) = self.keyid {
params.keyid = keyid;
}

let keyid = self.keyid.unwrap_or_default();

let data = self.data.unwrap_or_default();

let params = Params {
m_cost: self.m_cost,
t_cost: self.t_cost,
p_cost: self.p_cost,
keyid,
data,
output_len: self.output_len,
if let Some(data) = self.data {
params.data = data;
};

Ok(params)
Expand All @@ -483,11 +493,9 @@ impl ParamsBuilder {
pub fn context(&self, algorithm: Algorithm, version: Version) -> Result<Argon2<'_>> {
Ok(Argon2::new(algorithm, version, self.build()?))
}
}

impl Default for ParamsBuilder {
fn default() -> Self {
let params = Params::default();
/// Default parameters (recommended).
pub const DEFAULT: ParamsBuilder = {
let params = Params::DEFAULT;
Self {
m_cost: params.m_cost,
t_cost: params.t_cost,
Expand All @@ -496,6 +504,12 @@ impl Default for ParamsBuilder {
data: None,
output_len: params.output_len,
}
};
}

impl Default for ParamsBuilder {
fn default() -> Self {
Self::DEFAULT
}
}

Expand Down
11 changes: 3 additions & 8 deletions argon2/src/version.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
use crate::{Error, Result};

/// Version of the algorithm.
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq, PartialOrd, Ord)]
#[repr(u32)]
pub enum Version {
/// Version 16 (0x10 in hex)
Expand All @@ -14,22 +14,17 @@ pub enum Version {
/// Version 19 (0x13 in hex, default)
///
/// Performs XOR internally
#[default]
V0x13 = 0x13,
}

impl Version {
/// Serialize version as little endian bytes
pub(crate) fn to_le_bytes(self) -> [u8; 4] {
pub(crate) const fn to_le_bytes(self) -> [u8; 4] {
(self as u32).to_le_bytes()
}
}

impl Default for Version {
fn default() -> Self {
Self::V0x13
}
}

impl From<Version> for u32 {
fn from(version: Version) -> u32 {
version as u32
Expand Down

0 comments on commit d25ea61

Please sign in to comment.