Struct bonsaidb::local::argon2::password_hash::Output
pub struct Output { /* private fields */ }
Expand description
Output from password hashing functions, i.e. the “hash” or “digest” as raw bytes.
The Output
type implements the RECOMMENDED best practices described in
the PHC string format specification, namely:
The hash output, for a verification, must be long enough to make preimage attacks at least as hard as password guessing. To promote wide acceptance, a default output size of 256 bits (32 bytes, encoded as 43 characters) is recommended. Function implementations SHOULD NOT allow outputs of less than 80 bits to be used for password verification.
Recommended length
Per the description above, the recommended default length for an Output
of a password hashing function is 32-bytes (256-bits).
Constraints
The above guidelines are interpreted into the following constraints:
- Minimum length: 10-bytes (80-bits)
- Maximum length: 64-bytes (512-bits)
The specific recommendation of a 64-byte maximum length is taken as a best practice from the hash output guidelines for Argon2 Encoding given in the same document:
The hash output…length shall be between 12 and 64 bytes (16 and 86 characters, respectively). The default output length is 32 bytes (43 characters).
Based on this guidance, this type enforces an upper bound of 64-bytes as a reasonable maximum, and recommends using 32-bytes.
Constant-time comparisons
The Output
type impls the ConstantTimeEq
trait from the subtle
crate and uses it to perform constant-time comparisons.
Additionally the PartialEq
and Eq
trait impls for Output
use
ConstantTimeEq
when performing comparisons.
Attacks on non-constant-time password hash comparisons
Comparing password hashes in constant-time is known to mitigate at least one poorly understood attack involving an adversary with the following knowledge/capabilities:
- full knowledge of what password hashing algorithm is being used including any relevant configurable parameters
- knowledge of the salt for a particular victim
- ability to accurately measure a timing side-channel on comparisons of the password hash over the network
An attacker with the above is able to perform an offline computation of the hash for any chosen password in such a way that it will match the hash computed by the server.
As noted above, they also measure timing variability in the server’s comparison of the hash it computes for a given password and a target hash the attacker is trying to learn.
When the attacker observes a hash comparison that takes longer than their previous attempts, they learn that they guessed another byte in the password hash correctly. They can leverage repeated measurements and observations with different candidate passwords to learn the password hash a byte-at-a-time in a manner similar to other such timing side-channel attacks.
The attack may seem somewhat counterintuitive since learning prefixes of a password hash does not reveal any additional information about the password itself. However, the above can be combined with an offline dictionary attack where the attacker is able to determine candidate passwords to send to the server by performing a brute force search offline and selecting candidate passwords whose hashes match the portion of the prefix they have learned so far.
As the attacker learns a longer and longer prefix of the password hash, they are able to more effectively eliminate candidate passwords offline as part of a dictionary attack, until they eventually guess the correct password or exhaust their set of candidate passwords.
Mitigations
While we have taken care to ensure password hashes are compared in constant time, we would also suggest preventing such attacks by using randomly generated salts and keeping those salts secret.
The SaltString::generate
function can be
used to generate random high-entropy salt values.
Implementations§
§impl Output
impl Output
pub const MIN_LENGTH: usize = 10usize
pub const MIN_LENGTH: usize = 10usize
Minimum length of a Output
string: 10-bytes.
pub const MAX_LENGTH: usize = 64usize
pub const MAX_LENGTH: usize = 64usize
pub const B64_MAX_LENGTH: usize = 86usize
pub const B64_MAX_LENGTH: usize = 86usize
Maximum length of Output
when encoded as B64 string: 86-bytes
(i.e. 86 ASCII characters)
pub fn new(input: &[u8]) -> Result<Output, Error>
pub fn new(input: &[u8]) -> Result<Output, Error>
Create a Output
from the given byte slice, validating it according
to Output::MIN_LENGTH
and Output::MAX_LENGTH
restrictions.
pub fn new_with_encoding(
input: &[u8],
encoding: Encoding
) -> Result<Output, Error>
pub fn new_with_encoding( input: &[u8], encoding: Encoding ) -> Result<Output, Error>
Create a Output
from the given byte slice and Encoding
,
validating it according to Output::MIN_LENGTH
and
Output::MAX_LENGTH
restrictions.
pub fn init_with<F>(output_size: usize, f: F) -> Result<Output, Error>where
F: FnOnce(&mut [u8]) -> Result<(), Error>,
pub fn init_with<F>(output_size: usize, f: F) -> Result<Output, Error>where F: FnOnce(&mut [u8]) -> Result<(), Error>,
Initialize an Output
using the provided method, which is given
a mutable byte slice into which it should write the output.
The output_size
(in bytes) must be known in advance, as well as at
least Output::MIN_LENGTH
bytes and at most Output::MAX_LENGTH
bytes.
pub fn b64_decode(input: &str) -> Result<Output, Error>
pub fn b64_decode(input: &str) -> Result<Output, Error>
Parse B64-encoded Output
, i.e. using the PHC string
specification’s restricted interpretation of Base64.
pub fn b64_encode<'a>(&self, out: &'a mut [u8]) -> Result<&'a str, Error>
pub fn b64_encode<'a>(&self, out: &'a mut [u8]) -> Result<&'a str, Error>
Write B64-encoded Output
to the provided buffer, returning
a sub-slice containing the encoded data.
Returns an error if the buffer is too short to contain the output.
pub fn decode(input: &str, encoding: Encoding) -> Result<Output, Error>
pub fn decode(input: &str, encoding: Encoding) -> Result<Output, Error>
Decode the given input string using the specified Encoding
.
Trait Implementations§
§impl ConstantTimeEq for Output
impl ConstantTimeEq for Output
impl Copy for Output
impl Eq for Output
impl StructuralEq for Output
Auto Trait Implementations§
impl RefUnwindSafe for Output
impl Send for Output
impl Sync for Output
impl Unpin for Output
impl UnwindSafe for Output
Blanket Implementations§
§impl<'a, T, E> AsTaggedExplicit<'a, E> for Twhere
T: 'a,
impl<'a, T, E> AsTaggedExplicit<'a, E> for Twhere T: 'a,
§impl<'a, T, E> AsTaggedImplicit<'a, E> for Twhere
T: 'a,
impl<'a, T, E> AsTaggedImplicit<'a, E> for Twhere T: 'a,
source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere T: ?Sized,
source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
source§impl<Q, K> Equivalent<K> for Qwhere
Q: Eq + ?Sized,
K: Borrow<Q> + ?Sized,
impl<Q, K> Equivalent<K> for Qwhere Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,
source§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
key
and return true
if they are equal.§impl<Q, K> Equivalent<K> for Qwhere
Q: Eq + ?Sized,
K: Borrow<Q> + ?Sized,
impl<Q, K> Equivalent<K> for Qwhere Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,
§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
§impl<Q, K> Equivalent<K> for Qwhere
Q: Eq + ?Sized,
K: Borrow<Q> + ?Sized,
impl<Q, K> Equivalent<K> for Qwhere Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,
§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
key
and return true
if they are equal.source§impl<T> Instrument for T
impl<T> Instrument for T
source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
source§impl<T> ToHex for Twhere
T: AsRef<[u8]>,
impl<T> ToHex for Twhere T: AsRef<[u8]>,
source§fn encode_hex<U>(&self) -> Uwhere
U: FromIterator<char>,
fn encode_hex<U>(&self) -> Uwhere U: FromIterator<char>,
self
into the result. Lower case
letters are used (e.g. f9b4ca
)source§fn encode_hex_upper<U>(&self) -> Uwhere
U: FromIterator<char>,
fn encode_hex_upper<U>(&self) -> Uwhere U: FromIterator<char>,
self
into the result. Upper case
letters are used (e.g. F9B4CA
)