forked from RustCrypto/traits
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
…ustCrypto#182) Closes RustCrypto#179. This commit makes the `Params` struct always available regardless of enabled crate features, adding on functionality when the `password-hash` feature is enabled. Per the added TODOs in this commit, it really seems like in the next breaking release, `Argon2::new` should accept `Params` as an argument rather than duplicating all of the individual parameter fields and passing them in as arguments. After that, they can be validated and stored within the `Argon2` struct itself. But that would be a breaking change, so for now they're stored piecemeal. Additionally, this commit now ensures enough context is available in the `Argon2` struct in order to implement `hash_password_simple` that uses the configured params rather than the defaults, which addresses the aforementioned issue.
- Loading branch information
Showing
3 changed files
with
289 additions
and
182 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,137 @@ | ||
//! Argon2 algorithms (e.g. Argon2d, Argon2i, Argon2id). | ||
use crate::Error; | ||
use core::{ | ||
fmt::{self, Display}, | ||
str::FromStr, | ||
}; | ||
|
||
#[cfg(feature = "password-hash")] | ||
use {core::convert::TryFrom, password_hash::Ident}; | ||
|
||
/// Argon2d algorithm identifier | ||
#[cfg(feature = "password-hash")] | ||
#[cfg_attr(docsrs, doc(cfg(feature = "password-hash")))] | ||
pub const ARGON2D_IDENT: Ident<'_> = Ident::new("argon2d"); | ||
|
||
/// Argon2i algorithm identifier | ||
#[cfg(feature = "password-hash")] | ||
#[cfg_attr(docsrs, doc(cfg(feature = "password-hash")))] | ||
pub const ARGON2I_IDENT: Ident<'_> = Ident::new("argon2i"); | ||
|
||
/// Argon2id algorithm identifier | ||
#[cfg(feature = "password-hash")] | ||
#[cfg_attr(docsrs, doc(cfg(feature = "password-hash")))] | ||
pub const ARGON2ID_IDENT: Ident<'_> = Ident::new("argon2id"); | ||
|
||
/// Argon2 primitive type: variants of the algorithm. | ||
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] | ||
pub enum Algorithm { | ||
/// Optimizes against GPU cracking attacks but vulnerable to side-channels. | ||
/// | ||
/// Accesses the memory array in a password dependent order, reducing the | ||
/// possibility of time–memory tradeoff (TMTO) attacks. | ||
Argon2d = 0, | ||
|
||
/// Optimized to resist side-channel attacks. | ||
/// | ||
/// Accesses the memory array in a password independent order, increasing the | ||
/// possibility of time-memory tradeoff (TMTO) attacks. | ||
Argon2i = 1, | ||
|
||
/// Hybrid that mixes Argon2i and Argon2d passes (*default*). | ||
/// | ||
/// Uses the Argon2i approach for the first half pass over memory and | ||
/// Argon2d approach for subsequent passes. This effectively places it in | ||
/// the "middle" between the other two: it doesn't provide as good | ||
/// TMTO/GPU cracking resistance as Argon2d, nor as good of side-channel | ||
/// resistance as Argon2i, but overall provides the most well-rounded | ||
/// approach to both classes of attacks. | ||
Argon2id = 2, | ||
} | ||
|
||
impl Default for Algorithm { | ||
fn default() -> Algorithm { | ||
Algorithm::Argon2id | ||
} | ||
} | ||
|
||
impl Algorithm { | ||
/// Parse an [`Algorithm`] from the provided string. | ||
pub fn new(id: impl AsRef<str>) -> Result<Self, Error> { | ||
id.as_ref().parse() | ||
} | ||
|
||
/// Get the identifier string for this PBKDF2 [`Algorithm`]. | ||
pub fn as_str(&self) -> &str { | ||
match self { | ||
Algorithm::Argon2d => "argon2d", | ||
Algorithm::Argon2i => "argon2i", | ||
Algorithm::Argon2id => "argon2id", | ||
} | ||
} | ||
|
||
/// 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> { | ||
match self { | ||
Algorithm::Argon2d => ARGON2D_IDENT, | ||
Algorithm::Argon2i => ARGON2I_IDENT, | ||
Algorithm::Argon2id => ARGON2ID_IDENT, | ||
} | ||
} | ||
|
||
/// Serialize primitive type as little endian bytes | ||
pub(crate) fn to_le_bytes(self) -> [u8; 4] { | ||
(self as u32).to_le_bytes() | ||
} | ||
} | ||
|
||
impl AsRef<str> for Algorithm { | ||
fn as_ref(&self) -> &str { | ||
self.as_str() | ||
} | ||
} | ||
|
||
impl Display for Algorithm { | ||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
f.write_str(self.as_str()) | ||
} | ||
} | ||
|
||
impl FromStr for Algorithm { | ||
type Err = Error; | ||
|
||
fn from_str(s: &str) -> Result<Algorithm, Error> { | ||
match s { | ||
"argon2d" => Ok(Algorithm::Argon2d), | ||
"argon2i" => Ok(Algorithm::Argon2i), | ||
"argon2id" => Ok(Algorithm::Argon2id), | ||
_ => Err(Error::AlgorithmInvalid), | ||
} | ||
} | ||
} | ||
|
||
#[cfg(feature = "password-hash")] | ||
#[cfg_attr(docsrs, doc(cfg(feature = "password-hash")))] | ||
impl From<Algorithm> for Ident<'static> { | ||
fn from(alg: Algorithm) -> Ident<'static> { | ||
alg.ident() | ||
} | ||
} | ||
|
||
#[cfg(feature = "password-hash")] | ||
#[cfg_attr(docsrs, doc(cfg(feature = "password-hash")))] | ||
impl<'a> TryFrom<Ident<'a>> for Algorithm { | ||
type Error = password_hash::Error; | ||
|
||
fn try_from(ident: Ident<'a>) -> Result<Algorithm, password_hash::Error> { | ||
match ident { | ||
ARGON2D_IDENT => Ok(Algorithm::Argon2d), | ||
ARGON2I_IDENT => Ok(Algorithm::Argon2i), | ||
ARGON2ID_IDENT => Ok(Algorithm::Argon2id), | ||
_ => Err(password_hash::Error::Algorithm), | ||
} | ||
} | ||
} |
Oops, something went wrong.