diff options
Diffstat (limited to '')
-rw-r--r-- | third_party/rust/rust-argon2/src/argon2.rs | 717 | ||||
-rw-r--r-- | third_party/rust/rust-argon2/src/block.rs | 142 | ||||
-rw-r--r-- | third_party/rust/rust-argon2/src/common.rs | 92 | ||||
-rw-r--r-- | third_party/rust/rust-argon2/src/config.rs | 105 | ||||
-rw-r--r-- | third_party/rust/rust-argon2/src/context.rs | 213 | ||||
-rw-r--r-- | third_party/rust/rust-argon2/src/core.rs | 474 | ||||
-rw-r--r-- | third_party/rust/rust-argon2/src/decoded.rs | 35 | ||||
-rw-r--r-- | third_party/rust/rust-argon2/src/encoding.rs | 401 | ||||
-rw-r--r-- | third_party/rust/rust-argon2/src/error.rs | 119 | ||||
-rw-r--r-- | third_party/rust/rust-argon2/src/lib.rs | 103 | ||||
-rw-r--r-- | third_party/rust/rust-argon2/src/memory.rs | 120 | ||||
-rw-r--r-- | third_party/rust/rust-argon2/src/result.rs | 13 | ||||
-rw-r--r-- | third_party/rust/rust-argon2/src/thread_mode.rs | 56 | ||||
-rw-r--r-- | third_party/rust/rust-argon2/src/variant.rs | 159 | ||||
-rw-r--r-- | third_party/rust/rust-argon2/src/version.rs | 97 |
15 files changed, 2846 insertions, 0 deletions
diff --git a/third_party/rust/rust-argon2/src/argon2.rs b/third_party/rust/rust-argon2/src/argon2.rs new file mode 100644 index 0000000000..d16f3487a4 --- /dev/null +++ b/third_party/rust/rust-argon2/src/argon2.rs @@ -0,0 +1,717 @@ +// Copyright (c) 2017 Martijn Rijkeboer <mrr@sru-systems.com> +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use super::context::Context; +use super::config::Config; +use super::core; +use super::encoding; +use super::memory::Memory; +use super::result::Result; +use super::thread_mode::ThreadMode; +use super::variant::Variant; +use super::version::Version; + +/// Returns the length of the encoded string. +/// +/// # Remarks +/// +/// The length is **one** less that the original C version, since no null +/// terminator is used. +/// +/// # Examples +/// +/// ```rust +/// use argon2::{self, Variant}; +/// +/// let variant = Variant::Argon2i; +/// let mem = 4096; +/// let time = 10; +/// let parallelism = 10; +/// let salt_len = 8; +/// let hash_len = 32; +/// let enc_len = argon2::encoded_len(variant, mem, time, parallelism, salt_len, hash_len); +/// assert_eq!(enc_len, 86); +/// ``` +#[cfg_attr(rustfmt, rustfmt_skip)] +pub fn encoded_len( + variant: Variant, + mem_cost: u32, + time_cost: u32, + parallelism: u32, + salt_len: u32, + hash_len: u32 +) -> u32 { + ("$$v=$m=,t=,p=$$".len() as u32) + + (variant.as_lowercase_str().len() as u32) + + encoding::num_len(Version::default().as_u32()) + + encoding::num_len(mem_cost) + + encoding::num_len(time_cost) + + encoding::num_len(parallelism) + + encoding::base64_len(salt_len) + + encoding::base64_len(hash_len) +} + +/// Hashes the password and returns the encoded hash. +/// +/// # Examples +/// +/// Create an encoded hash with the default configuration: +/// +/// ``` +/// use argon2::{self, Config}; +/// +/// let pwd = b"password"; +/// let salt = b"somesalt"; +/// let config = Config::default(); +/// let encoded = argon2::hash_encoded(pwd, salt, &config).unwrap(); +/// ``` +/// +/// +/// Create an Argon2d encoded hash with 4 lanes and parallel execution: +/// +/// ``` +/// use argon2::{self, Config, ThreadMode, Variant}; +/// +/// let pwd = b"password"; +/// let salt = b"somesalt"; +/// let mut config = Config::default(); +/// config.variant = Variant::Argon2d; +/// config.lanes = 4; +/// config.thread_mode = ThreadMode::Parallel; +/// let encoded = argon2::hash_encoded(pwd, salt, &config).unwrap(); +/// ``` +pub fn hash_encoded(pwd: &[u8], salt: &[u8], config: &Config) -> Result<String> { + let context = Context::new(config.clone(), pwd, salt)?; + let hash = run(&context); + let encoded = encoding::encode_string(&context, &hash); + Ok(encoded) +} + +/// Hashes the password using default settings and returns the encoded hash. +/// +/// # Examples +/// +/// ``` +/// use argon2; +/// +/// let pwd = b"password"; +/// let salt = b"somesalt"; +/// let encoded = argon2::hash_encoded_defaults(pwd, salt).unwrap(); +/// ``` +/// +/// The above rewritten using `hash_encoded`: +/// +/// ``` +/// use argon2::{self, Config}; +/// +/// let pwd = b"password"; +/// let salt = b"somesalt"; +/// let config = Config::default(); +/// let encoded = argon2::hash_encoded(pwd, salt, &config).unwrap(); +/// ``` +#[deprecated(since = "0.2.0", note = "please use `hash_encoded` instead")] +pub fn hash_encoded_defaults(pwd: &[u8], salt: &[u8]) -> Result<String> { + hash_encoded(pwd, salt, &Config::default()) +} + +/// Hashes the password and returns the encoded hash (pre 0.2.0 `hash_encoded`). +/// +/// # Examples +/// +/// +/// ``` +/// use argon2::{self, Variant, Version}; +/// +/// let pwd = b"password"; +/// let salt = b"somesalt"; +/// let mem_cost = 4096; +/// let time_cost = 10; +/// let lanes = 1; +/// let threads = 1; +/// let secret = b"secret value"; +/// let ad = b"associated data"; +/// let hash_len = 32; +/// let encoded = argon2::hash_encoded_old(Variant::Argon2i, +/// Version::Version13, +/// mem_cost, +/// time_cost, +/// lanes, +/// threads, +/// pwd, +/// salt, +/// secret, +/// ad, +/// hash_len).unwrap(); +/// ``` +/// +/// The above rewritten using the new `hash_encoded`: +/// +/// ``` +/// use argon2::{self, Config, ThreadMode, Variant, Version}; +/// +/// let pwd = b"password"; +/// let salt = b"somesalt"; +/// let config = Config { +/// variant: Variant::Argon2i, +/// version: Version::Version13, +/// mem_cost: 4096, +/// time_cost: 10, +/// lanes: 1, +/// thread_mode: ThreadMode::Sequential, +/// secret: b"secret value", +/// ad: b"associated data", +/// hash_length: 32, +/// }; +/// let encoded = argon2::hash_encoded(pwd, salt, &config).unwrap(); +/// ``` +#[deprecated(since = "0.2.0", note = "please use new `hash_encoded` instead")] +pub fn hash_encoded_old( + variant: Variant, + version: Version, + mem_cost: u32, + time_cost: u32, + lanes: u32, + threads: u32, + pwd: &[u8], + salt: &[u8], + secret: &[u8], + ad: &[u8], + hash_len: u32, +) -> Result<String> { + let config = Config { + variant: variant, + version: version, + mem_cost: mem_cost, + time_cost: time_cost, + lanes: lanes, + thread_mode: ThreadMode::from_threads(threads), + secret: secret, + ad: ad, + hash_length: hash_len, + }; + hash_encoded(pwd, salt, &config) +} + +/// Hashes the password and returns the encoded hash (standard). +/// +/// # Examples +/// +/// +/// ``` +/// use argon2::{self, Variant, Version}; +/// +/// let pwd = b"password"; +/// let salt = b"somesalt"; +/// let mem_cost = 4096; +/// let time_cost = 10; +/// let parallelism = 1; +/// let hash_len = 32; +/// let encoded = argon2::hash_encoded_std(Variant::Argon2i, +/// Version::Version13, +/// mem_cost, +/// time_cost, +/// parallelism, +/// pwd, +/// salt, +/// hash_len).unwrap(); +/// ``` +/// +/// The above rewritten using `hash_encoded`: +/// +/// ``` +/// use argon2::{self, Config, ThreadMode, Variant, Version}; +/// +/// let pwd = b"password"; +/// let salt = b"somesalt"; +/// let config = Config { +/// variant: Variant::Argon2i, +/// version: Version::Version13, +/// mem_cost: 4096, +/// time_cost: 10, +/// lanes: 1, +/// thread_mode: ThreadMode::Sequential, +/// secret: &[], +/// ad: &[], +/// hash_length: 32, +/// }; +/// let encoded = argon2::hash_encoded(pwd, salt, &config).unwrap(); +/// ``` +#[deprecated(since = "0.2.0", note = "please use `hash_encoded` instead")] +pub fn hash_encoded_std( + variant: Variant, + version: Version, + mem_cost: u32, + time_cost: u32, + parallelism: u32, + pwd: &[u8], + salt: &[u8], + hash_len: u32, +) -> Result<String> { + let config = Config { + variant: variant, + version: version, + mem_cost: mem_cost, + time_cost: time_cost, + lanes: parallelism, + thread_mode: ThreadMode::from_threads(parallelism), + secret: &[], + ad: &[], + hash_length: hash_len, + }; + hash_encoded(pwd, salt, &config) +} + +/// Hashes the password and returns the hash as a vector. +/// +/// # Examples +/// +/// Create a hash with the default configuration: +/// +/// ``` +/// use argon2::{self, Config}; +/// +/// let pwd = b"password"; +/// let salt = b"somesalt"; +/// let config = Config::default(); +/// let vec = argon2::hash_raw(pwd, salt, &config).unwrap(); +/// ``` +/// +/// +/// Create an Argon2d hash with 4 lanes and parallel execution: +/// +/// ``` +/// use argon2::{self, Config, ThreadMode, Variant}; +/// +/// let pwd = b"password"; +/// let salt = b"somesalt"; +/// let mut config = Config::default(); +/// config.variant = Variant::Argon2d; +/// config.lanes = 4; +/// config.thread_mode = ThreadMode::Parallel; +/// let vec = argon2::hash_raw(pwd, salt, &config).unwrap(); +/// ``` +pub fn hash_raw(pwd: &[u8], salt: &[u8], config: &Config) -> Result<Vec<u8>> { + let context = Context::new(config.clone(), pwd, salt)?; + let hash = run(&context); + Ok(hash) +} + +/// Hashes the password using default settings and returns the hash as a vector. +/// +/// # Examples +/// +/// ``` +/// use argon2; +/// +/// let pwd = b"password"; +/// let salt = b"somesalt"; +/// let vec = argon2::hash_raw_defaults(pwd, salt).unwrap(); +/// ``` +/// +/// The above rewritten using `hash_raw`: +/// +/// ``` +/// use argon2::{self, Config}; +/// +/// let pwd = b"password"; +/// let salt = b"somesalt"; +/// let config = Config::default(); +/// let vec = argon2::hash_raw(pwd, salt, &config).unwrap(); +/// ``` +#[deprecated(since = "0.2.0", note = "please use `hash_raw` instead")] +pub fn hash_raw_defaults(pwd: &[u8], salt: &[u8]) -> Result<Vec<u8>> { + hash_raw(pwd, salt, &Config::default()) +} + +/// Hashes the password and returns the hash as a vector (pre 0.2.0 `hash_raw`). +/// +/// # Examples +/// +/// +/// ``` +/// use argon2::{self, Variant, Version}; +/// +/// let mem_cost = 4096; +/// let time_cost = 10; +/// let lanes = 1; +/// let threads = 1; +/// let pwd = b"password"; +/// let salt = b"somesalt"; +/// let secret = b"secret value"; +/// let ad = b"associated data"; +/// let hash_len = 32; +/// let vec = argon2::hash_raw_old(Variant::Argon2i, +/// Version::Version13, +/// mem_cost, +/// time_cost, +/// lanes, +/// threads, +/// pwd, +/// salt, +/// secret, +/// ad, +/// hash_len).unwrap(); +/// ``` +/// +/// The above rewritten using the new `hash_raw`: +/// +/// ``` +/// use argon2::{self, Config, ThreadMode, Variant, Version}; +/// +/// let pwd = b"password"; +/// let salt = b"somesalt"; +/// let config = Config { +/// variant: Variant::Argon2i, +/// version: Version::Version13, +/// mem_cost: 4096, +/// time_cost: 10, +/// lanes: 1, +/// thread_mode: ThreadMode::Sequential, +/// secret: b"secret value", +/// ad: b"associated data", +/// hash_length: 32, +/// }; +/// let vec = argon2::hash_raw(pwd, salt, &config); +/// ``` +#[deprecated(since = "0.2.0", note = "please use new `hash_raw` instead")] +pub fn hash_raw_old( + variant: Variant, + version: Version, + mem_cost: u32, + time_cost: u32, + lanes: u32, + threads: u32, + pwd: &[u8], + salt: &[u8], + secret: &[u8], + ad: &[u8], + hash_len: u32, +) -> Result<Vec<u8>> { + let config = Config { + variant: variant, + version: version, + mem_cost: mem_cost, + time_cost: time_cost, + lanes: lanes, + thread_mode: ThreadMode::from_threads(threads), + secret: secret, + ad: ad, + hash_length: hash_len, + }; + hash_raw(pwd, salt, &config) +} + +/// Hashes the password and returns the hash as a vector (standard). +/// +/// # Examples +/// +/// +/// ``` +/// use argon2::{self, Variant, Version}; +/// +/// let pwd = b"password"; +/// let salt = b"somesalt"; +/// let mem_cost = 4096; +/// let time_cost = 10; +/// let parallelism = 1; +/// let hash_len = 32; +/// let vec = argon2::hash_raw_std(Variant::Argon2i, +/// Version::Version13, +/// mem_cost, +/// time_cost, +/// parallelism, +/// pwd, +/// salt, +/// hash_len).unwrap(); +/// ``` +/// +/// The above rewritten using `hash_raw`: +/// +/// ``` +/// use argon2::{self, Config, ThreadMode, Variant, Version}; +/// +/// let pwd = b"password"; +/// let salt = b"somesalt"; +/// let config = Config { +/// variant: Variant::Argon2i, +/// version: Version::Version13, +/// mem_cost: 4096, +/// time_cost: 10, +/// lanes: 1, +/// thread_mode: ThreadMode::Sequential, +/// secret: &[], +/// ad: &[], +/// hash_length: 32, +/// }; +/// let vec = argon2::hash_raw(pwd, salt, &config); +/// ``` +#[deprecated(since = "0.2.0", note = "please use `hash_raw` instead")] +pub fn hash_raw_std( + variant: Variant, + version: Version, + mem_cost: u32, + time_cost: u32, + parallelism: u32, + pwd: &[u8], + salt: &[u8], + hash_len: u32, +) -> Result<Vec<u8>> { + let config = Config { + variant: variant, + version: version, + mem_cost: mem_cost, + time_cost: time_cost, + lanes: parallelism, + thread_mode: ThreadMode::from_threads(parallelism), + secret: &[], + ad: &[], + hash_length: hash_len, + }; + hash_raw(pwd, salt, &config) +} + +/// Verifies the password with the encoded hash. +/// +/// # Examples +/// +/// ``` +/// use argon2; +/// +/// let enc = "$argon2i$v=19$m=4096,t=3,p=1$c29tZXNhbHQ\ +/// $iWh06vD8Fy27wf9npn6FXWiCX4K6pW6Ue1Bnzz07Z8A"; +/// let pwd = b"password"; +/// let res = argon2::verify_encoded(enc, pwd).unwrap(); +/// assert!(res); +/// ``` +pub fn verify_encoded(encoded: &str, pwd: &[u8]) -> Result<bool> { + verify_encoded_ext(encoded, pwd, &[], &[]) +} + +/// Verifies the password with the encoded hash, secret and associated data. +/// +/// # Examples +/// +/// ``` +/// use argon2; +/// +/// let enc = "$argon2i$v=19$m=4096,t=3,p=1$c29tZXNhbHQ\ +/// $OlcSvlN20Lz43sK3jhCJ9K04oejhiY0AmI+ck6nuETo"; +/// let pwd = b"password"; +/// let secret = b"secret"; +/// let ad = b"ad"; +/// let res = argon2::verify_encoded_ext(enc, pwd, secret, ad).unwrap(); +/// assert!(res); +/// ``` +pub fn verify_encoded_ext(encoded: &str, pwd: &[u8], secret: &[u8], ad: &[u8]) -> Result<bool> { + let decoded = encoding::decode_string(encoded)?; + let config = Config { + variant: decoded.variant, + version: decoded.version, + mem_cost: decoded.mem_cost, + time_cost: decoded.time_cost, + lanes: decoded.parallelism, + thread_mode: ThreadMode::from_threads(decoded.parallelism), + secret: secret, + ad: ad, + hash_length: decoded.hash.len() as u32, + }; + verify_raw(pwd, &decoded.salt, &decoded.hash, &config) +} + +/// Verifies the password with the supplied configuration. +/// +/// # Examples +/// +/// +/// ``` +/// use argon2::{self, Config}; +/// +/// let pwd = b"password"; +/// let salt = b"somesalt"; +/// let hash = &[137, 104, 116, 234, 240, 252, 23, 45, 187, 193, 255, 103, 166, +/// 126, 133, 93, 104, 130, 95, 130, 186, 165, 110, 148, 123, 80, +/// 103, 207, 61, 59, 103, 192]; +/// let config = Config::default(); +/// let res = argon2::verify_raw(pwd, salt, hash, &config).unwrap(); +/// assert!(res); +/// ``` +pub fn verify_raw(pwd: &[u8], salt: &[u8], hash: &[u8], config: &Config) -> Result<bool> { + let config = Config { + hash_length: hash.len() as u32, + ..config.clone() + }; + let context = Context::new(config, pwd, salt)?; + Ok(run(&context) == hash) +} + +/// Verifies the password with the supplied settings (pre 0.2.0 `verify_raw`). +/// +/// # Examples +/// +/// ``` +/// use argon2::{self, Variant, Version}; +/// +/// let pwd = b"password"; +/// let salt = b"somesalt"; +/// let hash = &[137, 104, 116, 234, 240, 252, 23, 45, 187, 193, 255, 103, 166, +/// 126, 133, 93, 104, 130, 95, 130, 186, 165, 110, 148, 123, 80, +/// 103, 207, 61, 59, 103, 192]; +/// let mem_cost = 4096; +/// let time_cost = 3; +/// let lanes = 1; +/// let threads = 1; +/// let secret = &[]; +/// let ad = &[]; +/// let res = argon2::verify_raw_old(Variant::Argon2i, +/// Version::Version13, +/// mem_cost, +/// time_cost, +/// lanes, +/// threads, +/// pwd, +/// salt, +/// secret, +/// ad, +/// hash).unwrap(); +/// assert!(res); +/// ``` +/// +/// The above rewritten using the new `verify_raw`: +/// +/// ``` +/// use argon2::{self, Config, ThreadMode, Variant, Version}; +/// +/// let pwd = b"password"; +/// let salt = b"somesalt"; +/// let hash = &[137, 104, 116, 234, 240, 252, 23, 45, 187, 193, 255, 103, 166, +/// 126, 133, 93, 104, 130, 95, 130, 186, 165, 110, 148, 123, 80, +/// 103, 207, 61, 59, 103, 192]; +/// let config = Config { +/// variant: Variant::Argon2i, +/// version: Version::Version13, +/// mem_cost: 4096, +/// time_cost: 3, +/// lanes: 1, +/// thread_mode: ThreadMode::Sequential, +/// secret: &[], +/// ad: &[], +/// hash_length: hash.len() as u32, +/// }; +/// let res = argon2::verify_raw(pwd, salt, hash, &config).unwrap(); +/// assert!(res); +/// ``` +#[deprecated(since = "0.2.0", note = "please use new `verify_raw` instead")] +pub fn verify_raw_old( + variant: Variant, + version: Version, + mem_cost: u32, + time_cost: u32, + lanes: u32, + threads: u32, + pwd: &[u8], + salt: &[u8], + secret: &[u8], + ad: &[u8], + hash: &[u8], +) -> Result<bool> { + let config = Config { + variant: variant, + version: version, + mem_cost: mem_cost, + time_cost: time_cost, + lanes: lanes, + thread_mode: ThreadMode::from_threads(threads), + secret: secret, + ad: ad, + hash_length: hash.len() as u32, + }; + verify_raw(pwd, salt, hash, &config) +} + +/// Verifies the password with the supplied settings (standard). +/// +/// # Examples +/// +/// +/// ``` +/// use argon2::{self, Variant, Version}; +/// +/// let pwd = b"password"; +/// let salt = b"somesalt"; +/// let hash = &[137, 104, 116, 234, 240, 252, 23, 45, 187, 193, 255, 103, 166, +/// 126, 133, 93, 104, 130, 95, 130, 186, 165, 110, 148, 123, 80, +/// 103, 207, 61, 59, 103, 192]; +/// let mem_cost = 4096; +/// let time_cost = 3; +/// let parallelism = 1; +/// let res = argon2::verify_raw_std(Variant::Argon2i, +/// Version::Version13, +/// mem_cost, +/// time_cost, +/// parallelism, +/// pwd, +/// salt, +/// hash).unwrap(); +/// assert!(res); +/// ``` +/// +/// The above rewritten using `verify_raw`: +/// +/// ``` +/// use argon2::{self, Config, ThreadMode, Variant, Version}; +/// +/// let pwd = b"password"; +/// let salt = b"somesalt"; +/// let hash = &[137, 104, 116, 234, 240, 252, 23, 45, 187, 193, 255, 103, 166, +/// 126, 133, 93, 104, 130, 95, 130, 186, 165, 110, 148, 123, 80, +/// 103, 207, 61, 59, 103, 192]; +/// let config = Config { +/// variant: Variant::Argon2i, +/// version: Version::Version13, +/// mem_cost: 4096, +/// time_cost: 3, +/// lanes: 1, +/// thread_mode: ThreadMode::Sequential, +/// secret: &[], +/// ad: &[], +/// hash_length: hash.len() as u32, +/// }; +/// let res = argon2::verify_raw(pwd, salt, hash, &config).unwrap(); +/// assert!(res); +/// ``` +#[deprecated(since = "0.2.0", note = "please use `verify_raw` instead")] +pub fn verify_raw_std( + variant: Variant, + version: Version, + mem_cost: u32, + time_cost: u32, + parallelism: u32, + pwd: &[u8], + salt: &[u8], + hash: &[u8], +) -> Result<bool> { + let config = Config { + variant: variant, + version: version, + mem_cost: mem_cost, + time_cost: time_cost, + lanes: parallelism, + thread_mode: ThreadMode::from_threads(parallelism), + secret: &[], + ad: &[], + hash_length: hash.len() as u32, + }; + verify_raw(pwd, salt, hash, &config) +} + +fn run(context: &Context) -> Vec<u8> { + let mut memory = Memory::new(context.config.lanes, context.lane_length); + core::initialize(context, &mut memory); + core::fill_memory_blocks(context, &mut memory); + core::finalize(context, &memory) +} diff --git a/third_party/rust/rust-argon2/src/block.rs b/third_party/rust/rust-argon2/src/block.rs new file mode 100644 index 0000000000..134bb4b66f --- /dev/null +++ b/third_party/rust/rust-argon2/src/block.rs @@ -0,0 +1,142 @@ +// Copyright (c) 2017 Martijn Rijkeboer <mrr@sru-systems.com> +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::{fmt, mem}; +use std::fmt::Debug; +use std::ops::{BitXorAssign, Index, IndexMut}; +use super::common; + +/// Structure for the (1KB) memory block implemented as 128 64-bit words. +pub struct Block([u64; common::QWORDS_IN_BLOCK]); + +impl Block { + /// Gets the byte slice representation of the block. + pub fn as_u8(&self) -> &[u8] { + let bytes: &[u8; common::BLOCK_SIZE] = unsafe { mem::transmute(&self.0) }; + bytes + } + + /// Gets the mutable byte slice representation of the block. + pub fn as_u8_mut(&mut self) -> &mut [u8] { + let bytes: &mut [u8; common::BLOCK_SIZE] = unsafe { mem::transmute(&mut self.0) }; + bytes + } + + /// Copies self to destination. + pub fn copy_to(&self, dst: &mut Block) { + for (d, s) in dst.0.iter_mut().zip(self.0.iter()) { + *d = *s + } + } + + /// Creates a new block filled with zeros. + pub fn zero() -> Block { + Block([0u64; common::QWORDS_IN_BLOCK]) + } +} + +impl<'a> BitXorAssign<&'a Block> for Block { + fn bitxor_assign(&mut self, rhs: &Block) { + for (s, r) in self.0.iter_mut().zip(rhs.0.iter()) { + *s ^= *r + } + } +} + +impl Clone for Block { + fn clone(&self) -> Block { + Block(self.0) + } +} + +impl Debug for Block { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.debug_list().entries(self.0.iter()).finish() + } +} + +impl Eq for Block {} + +impl Index<usize> for Block { + type Output = u64; + fn index(&self, index: usize) -> &u64 { + &self.0[index] + } +} + +impl IndexMut<usize> for Block { + fn index_mut(&mut self, index: usize) -> &mut u64 { + &mut self.0[index] + } +} + +impl PartialEq for Block { + fn eq(&self, other: &Block) -> bool { + let mut equal = true; + for (s, o) in self.0.iter().zip(other.0.iter()) { + if s != o { + equal = false; + } + } + equal + } +} + + +#[cfg(test)] +mod tests { + + use common; + use super::*; + + #[test] + fn as_u8_returns_correct_slice() { + let block = Block::zero(); + let expected = vec![0u8; 1024]; + let actual = block.as_u8(); + assert_eq!(actual, expected.as_slice()); + } + + #[test] + fn as_u8_mut_returns_correct_slice() { + let mut block = Block::zero(); + let mut expected = vec![0u8; 1024]; + let actual = block.as_u8_mut(); + assert_eq!(actual, expected.as_mut_slice()); + } + + #[test] + fn bitxor_assign_updates_lhs() { + let mut lhs = Block([0u64; common::QWORDS_IN_BLOCK]); + let rhs = Block([1u64; common::QWORDS_IN_BLOCK]); + lhs ^= &rhs; + assert_eq!(lhs, rhs); + } + + #[test] + fn copy_to_copies_block() { + let src = Block([1u64; common::QWORDS_IN_BLOCK]); + let mut dst = Block([0u64; common::QWORDS_IN_BLOCK]); + src.copy_to(&mut dst); + assert_eq!(dst, src); + } + + #[test] + fn clone_clones_block() { + let orig = Block([1u64; common::QWORDS_IN_BLOCK]); + let copy = orig.clone(); + assert_eq!(copy, orig); + } + + #[test] + fn zero_creates_block_will_all_zeros() { + let expected = Block([0u64; common::QWORDS_IN_BLOCK]); + let actual = Block::zero(); + assert_eq!(actual, expected); + } +} diff --git a/third_party/rust/rust-argon2/src/common.rs b/third_party/rust/rust-argon2/src/common.rs new file mode 100644 index 0000000000..dffcac7916 --- /dev/null +++ b/third_party/rust/rust-argon2/src/common.rs @@ -0,0 +1,92 @@ +// Copyright (c) 2017 Martijn Rijkeboer <mrr@sru-systems.com> +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +/// Default number of lanes (degree of parallelism). +pub const DEF_LANES: u32 = 1; + +/// Minimum number of lanes (degree of parallelism). +pub const MIN_LANES: u32 = 1; + +/// Maximum number of lanes (degree of parallelism). +pub const MAX_LANES: u32 = 0x00FFFFFF; + +/// Number of synchronization points between lanes per pass. +pub const SYNC_POINTS: u32 = 4; + +/// Default digest size in bytes. +pub const DEF_HASH_LENGTH: u32 = 32; + +/// Minimum digest size in bytes. +pub const MIN_HASH_LENGTH: u32 = 4; + +/// Maximum digest size in bytes. +pub const MAX_HASH_LENGTH: u32 = 0xFFFFFFFF; + +/// Default number of memory blocks (2^12). +pub const DEF_MEMORY: u32 = 4096; + +/// Minimum number of memory blocks (each of BLOCK_SIZE bytes). +pub const MIN_MEMORY: u32 = 2 * SYNC_POINTS; + +/// Maximum number of memory blocks (each of BLOCK_SIZE bytes). +#[cfg(target_pointer_width = "32")] +pub const MAX_MEMORY: u32 = 0x200000; +#[cfg(target_pointer_width = "64")] +pub const MAX_MEMORY: u32 = 0xFFFFFFFF; + +/// Default number of passes. +pub const DEF_TIME: u32 = 3; + +/// Minimum number of passes +pub const MIN_TIME: u32 = 1; + +/// Maximum number of passes. +pub const MAX_TIME: u32 = 0xFFFFFFFF; + +/// Minimum password length in bytes. +pub const MIN_PWD_LENGTH: u32 = 0; + +/// Maximum password length in bytes. +pub const MAX_PWD_LENGTH: u32 = 0xFFFFFFFF; + +/// Minimum associated data length in bytes. +pub const MIN_AD_LENGTH: u32 = 0; + +/// Maximum associated data length in bytes. +pub const MAX_AD_LENGTH: u32 = 0xFFFFFFFF; + +/// Minimum salt length in bytes. +pub const MIN_SALT_LENGTH: u32 = 8; + +/// Maximum salt length in bytes. +pub const MAX_SALT_LENGTH: u32 = 0xFFFFFFFF; + +/// Minimum key length in bytes. +pub const MIN_SECRET_LENGTH: u32 = 0; + +/// Maximum key length in bytes. +pub const MAX_SECRET_LENGTH: u32 = 0xFFFFFFFF; + +/// Memory block size in bytes. +pub const BLOCK_SIZE: usize = 1024; + +/// Number of quad words in a block. +pub const QWORDS_IN_BLOCK: usize = BLOCK_SIZE / 8; + +/// Number of pseudo-random values generated by one call to Blake in Argon2i +/// to generate reference block positions. +pub const ADDRESSES_IN_BLOCK: u32 = 128; + +/// Pre-hashing digest length. +pub const PREHASH_DIGEST_LENGTH: usize = 64; + +/// Pre-hashing digest length with extension. +pub const PREHASH_SEED_LENGTH: usize = 72; + +/// Blake2b output length in bytes. +pub const BLAKE2B_OUT_LENGTH: usize = 64; diff --git a/third_party/rust/rust-argon2/src/config.rs b/third_party/rust/rust-argon2/src/config.rs new file mode 100644 index 0000000000..c63cecc43a --- /dev/null +++ b/third_party/rust/rust-argon2/src/config.rs @@ -0,0 +1,105 @@ +// Copyright (c) 2017 Martijn Rijkeboer <mrr@sru-systems.com> +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use super::common; +use super::thread_mode::ThreadMode; +use super::variant::Variant; +use super::version::Version; + +/// Structure containing configuration settings. +/// +/// # Examples +/// +/// ``` +/// use argon2::{Config, ThreadMode, Variant, Version}; +/// +/// let config = Config::default(); +/// assert_eq!(config.ad, &[]); +/// assert_eq!(config.hash_length, 32); +/// assert_eq!(config.lanes, 1); +/// assert_eq!(config.mem_cost, 4096); +/// assert_eq!(config.secret, &[]); +/// assert_eq!(config.thread_mode, ThreadMode::Sequential); +/// assert_eq!(config.time_cost, 3); +/// assert_eq!(config.variant, Variant::Argon2i); +/// assert_eq!(config.version, Version::Version13); +/// ``` +#[derive(Clone, Debug, PartialEq)] +pub struct Config<'a> { + /// The associated data. + pub ad: &'a [u8], + + /// The length of the resulting hash. + pub hash_length: u32, + + /// The number of lanes. + pub lanes: u32, + + /// The amount of memory requested (KB). + pub mem_cost: u32, + + /// The key. + pub secret: &'a [u8], + + /// The thread mode. + pub thread_mode: ThreadMode, + + /// The number of passes. + pub time_cost: u32, + + /// The variant. + pub variant: Variant, + + /// The version number. + pub version: Version, +} + +impl<'a> Config<'a> { + pub fn uses_sequential(&self) -> bool { + self.thread_mode == ThreadMode::Sequential || self.lanes == 1 + } +} + +impl<'a> Default for Config<'a> { + fn default() -> Config<'a> { + Config { + ad: &[], + hash_length: common::DEF_HASH_LENGTH, + lanes: common::DEF_LANES, + mem_cost: common::DEF_MEMORY, + secret: &[], + thread_mode: ThreadMode::default(), + time_cost: common::DEF_TIME, + variant: Variant::default(), + version: Version::default(), + } + } +} + + +#[cfg(test)] +mod tests { + + use super::*; + use variant::Variant; + use version::Version; + + #[test] + fn default_returns_correct_instance() { + let config = Config::default(); + assert_eq!(config.ad, &[]); + assert_eq!(config.hash_length, 32); + assert_eq!(config.lanes, 1); + assert_eq!(config.mem_cost, 4096); + assert_eq!(config.secret, &[]); + assert_eq!(config.thread_mode, ThreadMode::Sequential); + assert_eq!(config.time_cost, 3); + assert_eq!(config.variant, Variant::Argon2i); + assert_eq!(config.version, Version::Version13); + } +} diff --git a/third_party/rust/rust-argon2/src/context.rs b/third_party/rust/rust-argon2/src/context.rs new file mode 100644 index 0000000000..34eb076d1e --- /dev/null +++ b/third_party/rust/rust-argon2/src/context.rs @@ -0,0 +1,213 @@ +// Copyright (c) 2017 Martijn Rijkeboer <mrr@sru-systems.com> +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use super::common; +use super::config::Config; +use super::error::Error; +use super::result::Result; + +/// Structure containing settings for the Argon2 algorithm. A combination of +/// the original argon2_context and argon2_instance_t. +#[derive(Debug, PartialEq)] +pub struct Context<'a> { + /// The config for this context. + pub config: Config<'a>, + + /// The length of a lane. + pub lane_length: u32, + + /// The number of memory blocks. + pub memory_blocks: u32, + + /// The password. + pub pwd: &'a [u8], + + /// The salt. + pub salt: &'a [u8], + + /// The length of a segment. + pub segment_length: u32, +} + +impl<'a> Context<'a> { + /// Attempts to create a new context. + pub fn new(config: Config<'a>, pwd: &'a [u8], salt: &'a [u8]) -> Result<Context<'a>> { + if config.lanes < common::MIN_LANES { + return Err(Error::LanesTooFew); + } else if config.lanes > common::MAX_LANES { + return Err(Error::LanesTooMany); + } + + let lanes = config.lanes; + if config.mem_cost < common::MIN_MEMORY { + return Err(Error::MemoryTooLittle); + } else if config.mem_cost > common::MAX_MEMORY { + return Err(Error::MemoryTooMuch); + } else if config.mem_cost < 8 * lanes { + return Err(Error::MemoryTooLittle); + } + + if config.time_cost < common::MIN_TIME { + return Err(Error::TimeTooSmall); + } else if config.time_cost > common::MAX_TIME { + return Err(Error::TimeTooLarge); + } + + let pwd_len = pwd.len(); + if pwd_len < common::MIN_PWD_LENGTH as usize { + return Err(Error::PwdTooShort); + } else if pwd_len > common::MAX_PWD_LENGTH as usize { + return Err(Error::PwdTooLong); + } + + let salt_len = salt.len(); + if salt_len < common::MIN_SALT_LENGTH as usize { + return Err(Error::SaltTooShort); + } else if salt_len > common::MAX_SALT_LENGTH as usize { + return Err(Error::SaltTooLong); + } + + let secret_len = config.secret.len(); + if secret_len < common::MIN_SECRET_LENGTH as usize { + return Err(Error::SecretTooShort); + } else if secret_len > common::MAX_SECRET_LENGTH as usize { + return Err(Error::SecretTooLong); + } + + let ad_len = config.ad.len(); + if ad_len < common::MIN_AD_LENGTH as usize { + return Err(Error::AdTooShort); + } else if ad_len > common::MAX_AD_LENGTH as usize { + return Err(Error::AdTooLong); + } + + if config.hash_length < common::MIN_HASH_LENGTH { + return Err(Error::OutputTooShort); + } else if config.hash_length > common::MAX_HASH_LENGTH { + return Err(Error::OutputTooLong); + } + + let mut memory_blocks = config.mem_cost; + if memory_blocks < 2 * common::SYNC_POINTS * lanes { + memory_blocks = 2 * common::SYNC_POINTS * lanes; + } + + let segment_length = memory_blocks / (lanes * common::SYNC_POINTS); + let memory_blocks = segment_length * (lanes * common::SYNC_POINTS); + let lane_length = segment_length * common::SYNC_POINTS; + + Ok(Context { + config: config, + lane_length: lane_length, + memory_blocks: memory_blocks, + pwd: pwd, + salt: salt, + segment_length: segment_length, + }) + } +} + + +#[cfg(test)] +mod tests { + + use error::Error; + use super::*; + use thread_mode::ThreadMode; + use variant::Variant; + use version::Version; + + #[test] + fn new_returns_correct_instance() { + let config = Config { + ad: b"additionaldata", + hash_length: 32, + lanes: 4, + mem_cost: 4096, + secret: b"secret", + thread_mode: ThreadMode::Sequential, + time_cost: 3, + variant: Variant::Argon2i, + version: Version::Version13, + }; + let pwd = b"password"; + let salt = b"somesalt"; + let result = Context::new(config.clone(), pwd, salt); + assert!(result.is_ok()); + + let context = result.unwrap(); + assert_eq!(context.config, config); + assert_eq!(context.pwd, pwd); + assert_eq!(context.salt, salt); + assert_eq!(context.memory_blocks, 4096); + assert_eq!(context.segment_length, 256); + assert_eq!(context.lane_length, 1024); + } + + #[test] + fn new_with_too_little_mem_cost_returns_correct_error() { + let config = Config { + mem_cost: 7, + ..Default::default() + }; + assert_eq!(Context::new(config, &[0u8; 8], &[0u8; 8]), Err(Error::MemoryTooLittle)); + } + + #[test] + fn new_with_less_than_8_x_lanes_mem_cost_returns_correct_error() { + let config = Config { + lanes: 4, + mem_cost: 31, + ..Default::default() + }; + assert_eq!(Context::new(config, &[0u8; 8], &[0u8; 8]), Err(Error::MemoryTooLittle)); + } + + #[test] + fn new_with_too_small_time_cost_returns_correct_error() { + let config = Config { + time_cost: 0, + ..Default::default() + }; + assert_eq!(Context::new(config, &[0u8; 8], &[0u8; 8]), Err(Error::TimeTooSmall)); + } + + #[test] + fn new_with_too_few_lanes_returns_correct_error() { + let config = Config { + lanes: 0, + ..Default::default() + }; + assert_eq!(Context::new(config, &[0u8; 8], &[0u8; 8]), Err(Error::LanesTooFew)); + } + + #[test] + fn new_with_too_many_lanes_returns_correct_error() { + let config = Config { + lanes: 1 << 24, + ..Default::default() + }; + assert_eq!(Context::new(config, &[0u8; 8], &[0u8; 8]), Err(Error::LanesTooMany)); + } + + #[test] + fn new_with_too_short_salt_returns_correct_error() { + let config = Default::default(); + let salt = [0u8; 7]; + assert_eq!(Context::new(config, &[0u8; 8], &salt), Err(Error::SaltTooShort)); + } + + #[test] + fn new_with_too_short_hash_length_returns_correct_error() { + let config = Config { + hash_length: 3, + ..Default::default() + }; + assert_eq!(Context::new(config, &[0u8; 8], &[0u8; 8]), Err(Error::OutputTooShort)); + } +} diff --git a/third_party/rust/rust-argon2/src/core.rs b/third_party/rust/rust-argon2/src/core.rs new file mode 100644 index 0000000000..383b392e63 --- /dev/null +++ b/third_party/rust/rust-argon2/src/core.rs @@ -0,0 +1,474 @@ +// Copyright (c) 2017 Martijn Rijkeboer <mrr@sru-systems.com> +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use super::block::Block; +use super::common; +use super::context::Context; +use super::memory::Memory; +use super::variant::Variant; +use super::version::Version; +use blake2b_simd::Params; +use crossbeam_utils::thread::scope; +use std::mem; + +/// Position of the block currently being operated on. +#[derive(Clone, Debug)] +struct Position { + pass: u32, + lane: u32, + slice: u32, + index: u32, +} + +/// Initializes the memory. +pub fn initialize(context: &Context, memory: &mut Memory) { + fill_first_blocks(context, memory, &mut h0(context)); +} + +/// Fills all the memory blocks. +pub fn fill_memory_blocks(context: &Context, memory: &mut Memory) { + if context.config.uses_sequential() { + fill_memory_blocks_st(context, memory); + } else { + fill_memory_blocks_mt(context, memory); + } +} + +/// Calculates the final hash and returns it. +pub fn finalize(context: &Context, memory: &Memory) -> Vec<u8> { + let mut blockhash = memory[context.lane_length - 1].clone(); + for l in 1..context.config.lanes { + let last_block_in_lane = l * context.lane_length + (context.lane_length - 1); + blockhash ^= &memory[last_block_in_lane]; + } + + let mut hash = vec![0u8; context.config.hash_length as usize]; + hprime(hash.as_mut_slice(), blockhash.as_u8()); + hash +} + +fn blake2b(out: &mut [u8], input: &[&[u8]]) { + let mut blake = Params::new().hash_length(out.len()).to_state(); + for slice in input { + blake.update(slice); + } + out.copy_from_slice(blake.finalize().as_bytes()); +} + +fn f_bla_mka(x: u64, y: u64) -> u64 { + let m = 0xFFFFFFFFu64; + let xy = (x & m) * (y & m); + x.wrapping_add(y.wrapping_add(xy.wrapping_add(xy))) +} + +fn fill_block(prev_block: &Block, ref_block: &Block, next_block: &mut Block, with_xor: bool) { + let mut block_r = ref_block.clone(); + block_r ^= prev_block; + let mut block_tmp = block_r.clone(); + + // Now block_r = ref_block + prev_block and block_tmp = ref_block + prev_block + if with_xor { + // Saving the next block contents for XOR over + block_tmp ^= next_block; + // Now block_r = ref_block + prev_block and + // block_tmp = ref_block + prev_block + next_block + } + + // Apply Blake2 on columns of 64-bit words: (0,1,...,15) , then + // (16,17,..31)... finally (112,113,...127) + for i in 0..8 { + let mut v0 = block_r[16 * i]; + let mut v1 = block_r[16 * i + 1]; + let mut v2 = block_r[16 * i + 2]; + let mut v3 = block_r[16 * i + 3]; + let mut v4 = block_r[16 * i + 4]; + let mut v5 = block_r[16 * i + 5]; + let mut v6 = block_r[16 * i + 6]; + let mut v7 = block_r[16 * i + 7]; + let mut v8 = block_r[16 * i + 8]; + let mut v9 = block_r[16 * i + 9]; + let mut v10 = block_r[16 * i + 10]; + let mut v11 = block_r[16 * i + 11]; + let mut v12 = block_r[16 * i + 12]; + let mut v13 = block_r[16 * i + 13]; + let mut v14 = block_r[16 * i + 14]; + let mut v15 = block_r[16 * i + 15]; + + p( + &mut v0, &mut v1, &mut v2, &mut v3, &mut v4, &mut v5, &mut v6, &mut v7, &mut v8, + &mut v9, &mut v10, &mut v11, &mut v12, &mut v13, &mut v14, &mut v15, + ); + + block_r[16 * i] = v0; + block_r[16 * i + 1] = v1; + block_r[16 * i + 2] = v2; + block_r[16 * i + 3] = v3; + block_r[16 * i + 4] = v4; + block_r[16 * i + 5] = v5; + block_r[16 * i + 6] = v6; + block_r[16 * i + 7] = v7; + block_r[16 * i + 8] = v8; + block_r[16 * i + 9] = v9; + block_r[16 * i + 10] = v10; + block_r[16 * i + 11] = v11; + block_r[16 * i + 12] = v12; + block_r[16 * i + 13] = v13; + block_r[16 * i + 14] = v14; + block_r[16 * i + 15] = v15; + } + + // Apply Blake2 on rows of 64-bit words: (0,1,16,17,...112,113), then + // (2,3,18,19,...,114,115).. finally (14,15,30,31,...,126,127) + for i in 0..8 { + let mut v0 = block_r[2 * i]; + let mut v1 = block_r[2 * i + 1]; + let mut v2 = block_r[2 * i + 16]; + let mut v3 = block_r[2 * i + 17]; + let mut v4 = block_r[2 * i + 32]; + let mut v5 = block_r[2 * i + 33]; + let mut v6 = block_r[2 * i + 48]; + let mut v7 = block_r[2 * i + 49]; + let mut v8 = block_r[2 * i + 64]; + let mut v9 = block_r[2 * i + 65]; + let mut v10 = block_r[2 * i + 80]; + let mut v11 = block_r[2 * i + 81]; + let mut v12 = block_r[2 * i + 96]; + let mut v13 = block_r[2 * i + 97]; + let mut v14 = block_r[2 * i + 112]; + let mut v15 = block_r[2 * i + 113]; + + p( + &mut v0, &mut v1, &mut v2, &mut v3, &mut v4, &mut v5, &mut v6, &mut v7, &mut v8, + &mut v9, &mut v10, &mut v11, &mut v12, &mut v13, &mut v14, &mut v15, + ); + + block_r[2 * i] = v0; + block_r[2 * i + 1] = v1; + block_r[2 * i + 16] = v2; + block_r[2 * i + 17] = v3; + block_r[2 * i + 32] = v4; + block_r[2 * i + 33] = v5; + block_r[2 * i + 48] = v6; + block_r[2 * i + 49] = v7; + block_r[2 * i + 64] = v8; + block_r[2 * i + 65] = v9; + block_r[2 * i + 80] = v10; + block_r[2 * i + 81] = v11; + block_r[2 * i + 96] = v12; + block_r[2 * i + 97] = v13; + block_r[2 * i + 112] = v14; + block_r[2 * i + 113] = v15; + } + + block_tmp.copy_to(next_block); + *next_block ^= &block_r; +} + +fn fill_first_blocks(context: &Context, memory: &mut Memory, h0: &mut [u8]) { + for lane in 0..context.config.lanes { + let start = common::PREHASH_DIGEST_LENGTH; + // H'(H0||0||i) + h0[start..(start + 4)].clone_from_slice(&u32_as_32le(0)); + h0[(start + 4)..(start + 8)].clone_from_slice(&u32_as_32le(lane)); + hprime(memory[(lane, 0)].as_u8_mut(), &h0); + + // H'(H0||1||i) + h0[start..(start + 4)].clone_from_slice(&u32_as_32le(1)); + hprime(memory[(lane, 1)].as_u8_mut(), &h0); + } +} + +fn fill_memory_blocks_mt(context: &Context, memory: &mut Memory) { + for p in 0..context.config.time_cost { + for s in 0..common::SYNC_POINTS { + let _ = scope(|scoped| { + for (l, mem) in (0..context.config.lanes).zip(memory.as_lanes_mut()) { + let position = Position { + pass: p, + lane: l, + slice: s, + index: 0, + }; + scoped.spawn(move |_| { + fill_segment(context, &position, mem); + }); + } + }); + } + } +} + +fn fill_memory_blocks_st(context: &Context, memory: &mut Memory) { + for p in 0..context.config.time_cost { + for s in 0..common::SYNC_POINTS { + for l in 0..context.config.lanes { + let position = Position { + pass: p, + lane: l, + slice: s, + index: 0, + }; + fill_segment(context, &position, memory); + } + } + } +} + +fn fill_segment(context: &Context, position: &Position, memory: &mut Memory) { + let mut position = position.clone(); + let data_independent_addressing = (context.config.variant == Variant::Argon2i) + || (context.config.variant == Variant::Argon2id && position.pass == 0) + && (position.slice < (common::SYNC_POINTS / 2)); + let zero_block = Block::zero(); + let mut input_block = Block::zero(); + let mut address_block = Block::zero(); + + if data_independent_addressing { + input_block[0] = position.pass as u64; + input_block[1] = position.lane as u64; + input_block[2] = position.slice as u64; + input_block[3] = context.memory_blocks as u64; + input_block[4] = context.config.time_cost as u64; + input_block[5] = context.config.variant.as_u64(); + } + + let mut starting_index = 0u32; + + if position.pass == 0 && position.slice == 0 { + starting_index = 2; + + // Don't forget to generate the first block of addresses: + if data_independent_addressing { + next_addresses(&mut address_block, &mut input_block, &zero_block); + } + } + + let mut curr_offset = (position.lane * context.lane_length) + + (position.slice * context.segment_length) + + starting_index; + + let mut prev_offset = if curr_offset % context.lane_length == 0 { + // Last block in this lane + curr_offset + context.lane_length - 1 + } else { + curr_offset - 1 + }; + + let mut pseudo_rand; + for i in starting_index..context.segment_length { + // 1.1 Rotating prev_offset if needed + if curr_offset % context.lane_length == 1 { + prev_offset = curr_offset - 1; + } + + // 1.2 Computing the index of the reference block + // 1.2.1 Taking pseudo-random value from the previous block + if data_independent_addressing { + if i % common::ADDRESSES_IN_BLOCK == 0 { + next_addresses(&mut address_block, &mut input_block, &zero_block); + } + pseudo_rand = address_block[(i % common::ADDRESSES_IN_BLOCK) as usize]; + } else { + pseudo_rand = memory[(prev_offset)][0]; + } + + // 1.2.2 Computing the lane of the reference block + let mut ref_lane = (pseudo_rand >> 32) % context.config.lanes as u64; + if (position.pass == 0) && (position.slice == 0) { + // Can not reference other lanes yet + ref_lane = position.lane as u64; + } + + // 1.2.3 Computing the number of possible reference block within the lane. + position.index = i; + let pseudo_rand_u32 = (pseudo_rand & 0xFFFFFFFF) as u32; + let same_lane = ref_lane == (position.lane as u64); + let ref_index = index_alpha(context, &position, pseudo_rand_u32, same_lane); + + // 2 Creating a new block + let index = context.lane_length as u64 * ref_lane + ref_index as u64; + let mut curr_block = memory[curr_offset].clone(); + { + let ref prev_block = memory[prev_offset]; + let ref ref_block = memory[index]; + if context.config.version == Version::Version10 { + fill_block(prev_block, ref_block, &mut curr_block, false); + } else { + if position.pass == 0 { + fill_block(prev_block, ref_block, &mut curr_block, false); + } else { + fill_block(prev_block, ref_block, &mut curr_block, true); + } + } + } + + memory[curr_offset] = curr_block; + curr_offset += 1; + prev_offset += 1; + } +} + +fn g(a: &mut u64, b: &mut u64, c: &mut u64, d: &mut u64) { + *a = f_bla_mka(*a, *b); + *d = rotr64(*d ^ *a, 32); + *c = f_bla_mka(*c, *d); + *b = rotr64(*b ^ *c, 24); + *a = f_bla_mka(*a, *b); + *d = rotr64(*d ^ *a, 16); + *c = f_bla_mka(*c, *d); + *b = rotr64(*b ^ *c, 63); +} + +fn h0(context: &Context) -> [u8; common::PREHASH_SEED_LENGTH] { + let input = [ + &u32_as_32le(context.config.lanes), + &u32_as_32le(context.config.hash_length), + &u32_as_32le(context.config.mem_cost), + &u32_as_32le(context.config.time_cost), + &u32_as_32le(context.config.version.as_u32()), + &u32_as_32le(context.config.variant.as_u32()), + &len_as_32le(context.pwd), + context.pwd.as_ref(), + &len_as_32le(context.salt), + context.salt.as_ref(), + &len_as_32le(context.config.secret), + context.config.secret.as_ref(), + &len_as_32le(context.config.ad), + context.config.ad.as_ref(), + ]; + let mut out = [0u8; common::PREHASH_SEED_LENGTH]; + blake2b(&mut out[0..common::PREHASH_DIGEST_LENGTH], &input); + out +} + +fn hprime(out: &mut [u8], input: &[u8]) { + let out_len = out.len(); + if out_len <= common::BLAKE2B_OUT_LENGTH { + blake2b(out, &[&u32_as_32le(out_len as u32), input]); + } else { + let ai_len = 32; + let mut out_buffer = [0u8; common::BLAKE2B_OUT_LENGTH]; + let mut in_buffer = [0u8; common::BLAKE2B_OUT_LENGTH]; + blake2b(&mut out_buffer, &[&u32_as_32le(out_len as u32), input]); + out[0..ai_len].clone_from_slice(&out_buffer[0..ai_len]); + let mut out_pos = ai_len; + let mut to_produce = out_len - ai_len; + + while to_produce > common::BLAKE2B_OUT_LENGTH { + in_buffer.clone_from_slice(&out_buffer); + blake2b(&mut out_buffer, &[&in_buffer]); + out[out_pos..out_pos + ai_len].clone_from_slice(&out_buffer[0..ai_len]); + out_pos += ai_len; + to_produce -= ai_len; + } + blake2b(&mut out[out_pos..out_len], &[&out_buffer]); + } +} + +fn index_alpha(context: &Context, position: &Position, pseudo_rand: u32, same_lane: bool) -> u32 { + // Pass 0: + // - This lane: all already finished segments plus already constructed blocks in this segment + // - Other lanes: all already finished segments + // Pass 1+: + // - This lane: (SYNC_POINTS - 1) last segments plus already constructed blocks in this segment + // - Other lanes : (SYNC_POINTS - 1) last segments + let reference_area_size: u32 = if position.pass == 0 { + // First pass + if position.slice == 0 { + // First slice + position.index - 1 + } else { + if same_lane { + // The same lane => add current segment + position.slice * context.segment_length + position.index - 1 + } else { + if position.index == 0 { + position.slice * context.segment_length - 1 + } else { + position.slice * context.segment_length + } + } + } + } else { + // Second pass + if same_lane { + context.lane_length - context.segment_length + position.index - 1 + } else { + if position.index == 0 { + context.lane_length - context.segment_length - 1 + } else { + context.lane_length - context.segment_length + } + } + }; + let reference_area_size = reference_area_size as u64; + let mut relative_position = pseudo_rand as u64; + relative_position = relative_position * relative_position >> 32; + relative_position = reference_area_size - 1 - (reference_area_size * relative_position >> 32); + + // 1.2.5 Computing starting position + let start_position: u32 = if position.pass != 0 { + if position.slice == common::SYNC_POINTS - 1 { + 0u32 + } else { + (position.slice + 1) * context.segment_length + } + } else { + 0u32 + }; + let start_position = start_position as u64; + + // 1.2.6. Computing absolute position + ((start_position + relative_position) % context.lane_length as u64) as u32 +} + +fn len_as_32le(slice: &[u8]) -> [u8; 4] { + u32_as_32le(slice.len() as u32) +} + +fn next_addresses(address_block: &mut Block, input_block: &mut Block, zero_block: &Block) { + input_block[6] += 1; + fill_block(zero_block, input_block, address_block, false); + fill_block(zero_block, &address_block.clone(), address_block, false); +} + +fn p( + v0: &mut u64, + v1: &mut u64, + v2: &mut u64, + v3: &mut u64, + v4: &mut u64, + v5: &mut u64, + v6: &mut u64, + v7: &mut u64, + v8: &mut u64, + v9: &mut u64, + v10: &mut u64, + v11: &mut u64, + v12: &mut u64, + v13: &mut u64, + v14: &mut u64, + v15: &mut u64, +) { + g(v0, v4, v8, v12); + g(v1, v5, v9, v13); + g(v2, v6, v10, v14); + g(v3, v7, v11, v15); + g(v0, v5, v10, v15); + g(v1, v6, v11, v12); + g(v2, v7, v8, v13); + g(v3, v4, v9, v14); +} + +fn rotr64(w: u64, c: u32) -> u64 { + (w >> c) | (w << (64 - c)) +} + +fn u32_as_32le(val: u32) -> [u8; 4] { + unsafe { mem::transmute(val.to_le()) } +} diff --git a/third_party/rust/rust-argon2/src/decoded.rs b/third_party/rust/rust-argon2/src/decoded.rs new file mode 100644 index 0000000000..2a83769e14 --- /dev/null +++ b/third_party/rust/rust-argon2/src/decoded.rs @@ -0,0 +1,35 @@ +// Copyright (c) 2017 Martijn Rijkeboer <mrr@sru-systems.com> +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use version::Version; +use variant::Variant; + +/// Structure that contains the decoded data. +#[derive(Debug, Eq, PartialEq)] +pub struct Decoded { + /// The variant. + pub variant: Variant, + + /// The version. + pub version: Version, + + /// The amount of memory requested (KiB). + pub mem_cost: u32, + + /// The number of passes. + pub time_cost: u32, + + /// The parallelism. + pub parallelism: u32, + + /// The salt. + pub salt: Vec<u8>, + + /// The hash. + pub hash: Vec<u8>, +} diff --git a/third_party/rust/rust-argon2/src/encoding.rs b/third_party/rust/rust-argon2/src/encoding.rs new file mode 100644 index 0000000000..7f0d9cd705 --- /dev/null +++ b/third_party/rust/rust-argon2/src/encoding.rs @@ -0,0 +1,401 @@ +// Copyright (c) 2017 Martijn Rijkeboer <mrr@sru-systems.com> +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use base64; +use super::context::Context; +use super::decoded::Decoded; +use super::error::Error; +use super::result::Result; +use super::variant::Variant; +use super::version::Version; + +/// Structure containing the options. +struct Options { + mem_cost: u32, + time_cost: u32, + parallelism: u32, +} + +/// Gets the base64 encoded length of a byte slice with the specified length. +pub fn base64_len(length: u32) -> u32 { + let olen = (length / 3) << 2; + match length % 3 { + 2 => olen + 3, + 1 => olen + 2, + _ => olen, + } +} + +/// Attempts to decode the encoded string slice. +pub fn decode_string(encoded: &str) -> Result<Decoded> { + let items: Vec<&str> = encoded.split('$').collect(); + if items.len() == 6 { + decode_empty(items[0])?; + let variant = decode_variant(items[1])?; + let version = decode_version(items[2])?; + let options = decode_options(items[3])?; + let salt = base64::decode(items[4])?; + let hash = base64::decode(items[5])?; + + Ok(Decoded { + variant: variant, + version: version, + mem_cost: options.mem_cost, + time_cost: options.time_cost, + parallelism: options.parallelism, + salt: salt, + hash: hash, + }) + } else if items.len() == 5 { + decode_empty(items[0])?; + let variant = decode_variant(items[1])?; + let options = decode_options(items[2])?; + let salt = base64::decode(items[3])?; + let hash = base64::decode(items[4])?; + + Ok(Decoded { + variant: variant, + version: Version::Version10, + mem_cost: options.mem_cost, + time_cost: options.time_cost, + parallelism: options.parallelism, + salt: salt, + hash: hash, + }) + } else { + return Err(Error::DecodingFail); + } + +} + +fn decode_empty(str: &str) -> Result<()> { + if str == "" { + Ok(()) + } else { + Err(Error::DecodingFail) + } +} + +fn decode_options(str: &str) -> Result<Options> { + let items: Vec<&str> = str.split(',').collect(); + if items.len() == 3 { + Ok(Options { + mem_cost: decode_option(items[0], "m")?, + time_cost: decode_option(items[1], "t")?, + parallelism: decode_option(items[2], "p")?, + }) + } else { + Err(Error::DecodingFail) + } +} + +fn decode_option(str: &str, name: &str) -> Result<u32> { + let items: Vec<&str> = str.split('=').collect(); + if items.len() == 2 { + if items[0] == name { + decode_u32(items[1]) + } else { + Err(Error::DecodingFail) + } + } else { + Err(Error::DecodingFail) + } +} + +fn decode_u32(str: &str) -> Result<u32> { + match str.parse() { + Ok(i) => Ok(i), + Err(_) => Err(Error::DecodingFail), + } +} + +fn decode_variant(str: &str) -> Result<Variant> { + Variant::from_str(str) +} + +fn decode_version(str: &str) -> Result<Version> { + let items: Vec<&str> = str.split('=').collect(); + if items.len() == 2 { + if items[0] == "v" { + Version::from_str(items[1]) + } else { + Err(Error::DecodingFail) + } + } else { + Err(Error::DecodingFail) + } +} + +/// Encodes the hash and context. +pub fn encode_string(context: &Context, hash: &Vec<u8>) -> String { + format!( + "${}$v={}$m={},t={},p={}${}${}", + context.config.variant, + context.config.version, + context.config.mem_cost, + context.config.time_cost, + context.config.lanes, + base64::encode_config(context.salt, base64::STANDARD_NO_PAD), + base64::encode_config(hash, base64::STANDARD_NO_PAD), + ) +} + +/// Gets the string length of the specified number. +pub fn num_len(number: u32) -> u32 { + let mut len = 1; + let mut num = number; + while num >= 10 { + len += 1; + num /= 10; + } + len +} + + +#[cfg(test)] +mod tests { + + use config::Config; + use context::Context; + use decoded::Decoded; + use error::Error; + use thread_mode::ThreadMode; + use variant::Variant; + use version::Version; + use super::*; + + #[test] + fn base64_len_returns_correct_length() { + let tests = vec![ + (1, 2), + (2, 3), + (3, 4), + (4, 6), + (5, 7), + (6, 8), + (7, 10), + (8, 11), + (9, 12), + (10, 14), + ]; + for (len, expected) in tests { + let actual = base64_len(len); + assert_eq!(actual, expected); + } + } + + #[test] + fn decode_string_with_version10_returns_correct_result() { + let encoded = "$argon2i$v=16$m=4096,t=3,p=1\ + $c2FsdDEyMzQ=$MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI="; + let expected = Decoded { + variant: Variant::Argon2i, + version: Version::Version10, + mem_cost: 4096, + time_cost: 3, + parallelism: 1, + salt: b"salt1234".to_vec(), + hash: b"12345678901234567890123456789012".to_vec(), + }; + let actual = decode_string(encoded).unwrap(); + assert_eq!(actual, expected); + } + + #[test] + fn decode_string_with_version13_returns_correct_result() { + let encoded = "$argon2i$v=19$m=4096,t=3,p=1\ + $c2FsdDEyMzQ=$MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI="; + let expected = Decoded { + variant: Variant::Argon2i, + version: Version::Version13, + mem_cost: 4096, + time_cost: 3, + parallelism: 1, + salt: b"salt1234".to_vec(), + hash: b"12345678901234567890123456789012".to_vec(), + }; + let actual = decode_string(encoded).unwrap(); + assert_eq!(actual, expected); + } + + #[test] + fn decode_string_without_version_returns_correct_result() { + let encoded = "$argon2i$m=4096,t=3,p=1\ + $c2FsdDEyMzQ=$MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI="; + let expected = Decoded { + variant: Variant::Argon2i, + version: Version::Version10, + mem_cost: 4096, + time_cost: 3, + parallelism: 1, + salt: b"salt1234".to_vec(), + hash: b"12345678901234567890123456789012".to_vec(), + }; + let actual = decode_string(encoded).unwrap(); + assert_eq!(actual, expected); + } + + #[test] + fn decode_string_without_variant_returns_error_result() { + let encoded = "$m=4096,t=3,p=1\ + $c2FsdDEyMzQ=$MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI="; + let result = decode_string(encoded); + assert_eq!(result, Err(Error::DecodingFail)); + } + + #[test] + fn decode_string_with_empty_variant_returns_error_result() { + let encoded = "$$m=4096,t=3,p=1\ + $c2FsdDEyMzQ=$MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI="; + let result = decode_string(encoded); + assert_eq!(result, Err(Error::DecodingFail)); + } + + #[test] + fn decode_string_with_invalid_variant_returns_error_result() { + let encoded = "$argon$m=4096,t=3,p=1\ + $c2FsdDEyMzQ=$MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI="; + let result = decode_string(encoded); + assert_eq!(result, Err(Error::DecodingFail)); + } + + #[test] + fn decode_string_without_mem_cost_returns_error_result() { + let encoded = "$argon2i$t=3,p=1\ + $c2FsdDEyMzQ=$MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI="; + let result = decode_string(encoded); + assert_eq!(result, Err(Error::DecodingFail)); + } + + #[test] + fn decode_string_with_empty_mem_cost_returns_error_result() { + let encoded = "$argon2i$m=,t=3,p=1\ + $c2FsdDEyMzQ=$MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI="; + let result = decode_string(encoded); + assert_eq!(result, Err(Error::DecodingFail)); + } + + #[test] + fn decode_string_with_non_numeric_mem_cost_returns_error_result() { + let encoded = "$argon2i$m=a,t=3,p=1\ + $c2FsdDEyMzQ=$MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI="; + let result = decode_string(encoded); + assert_eq!(result, Err(Error::DecodingFail)); + } + + #[test] + fn decode_string_without_time_cost_returns_error_result() { + let encoded = "$argon2i$m=4096,p=1\ + $c2FsdDEyMzQ=$MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI="; + let result = decode_string(encoded); + assert_eq!(result, Err(Error::DecodingFail)); + } + + #[test] + fn decode_string_with_empty_time_cost_returns_error_result() { + let encoded = "$argon2i$m=4096,t=,p=1\ + $c2FsdDEyMzQ=$MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI="; + let result = decode_string(encoded); + assert_eq!(result, Err(Error::DecodingFail)); + } + + #[test] + fn decode_string_with_non_numeric_time_cost_returns_error_result() { + let encoded = "$argon2i$m=4096,t=a,p=1\ + $c2FsdDEyMzQ=$MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI="; + let result = decode_string(encoded); + assert_eq!(result, Err(Error::DecodingFail)); + } + + #[test] + fn decode_string_without_parallelism_returns_error_result() { + let encoded = "$argon2i$m=4096,t=3\ + $c2FsdDEyMzQ=$MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI="; + let result = decode_string(encoded); + assert_eq!(result, Err(Error::DecodingFail)); + } + + #[test] + fn decode_string_with_empty_parallelism_returns_error_result() { + let encoded = "$argon2i$m=4096,t=3,p=\ + $c2FsdDEyMzQ=$MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI="; + let result = decode_string(encoded); + assert_eq!(result, Err(Error::DecodingFail)); + } + + #[test] + fn decode_string_with_non_numeric_parallelism_returns_error_result() { + let encoded = "$argon2i$m=4096,t=3,p=a\ + $c2FsdDEyMzQ=$MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI="; + let result = decode_string(encoded); + assert_eq!(result, Err(Error::DecodingFail)); + } + + #[test] + fn decode_string_without_salt_returns_error_result() { + let encoded = "$argon2i$m=4096,t=3,p=1\ + $MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI="; + let result = decode_string(encoded); + assert_eq!(result, Err(Error::DecodingFail)); + } + + #[test] + fn decode_string_without_hash_returns_error_result() { + let encoded = "$argon2i$m=4096,t=3,p=a\ + $c2FsdDEyMzQ="; + let result = decode_string(encoded); + assert_eq!(result, Err(Error::DecodingFail)); + } + + #[test] + fn decode_string_with_empty_hash_returns_error_result() { + let encoded = "$argon2i$m=4096,t=3,p=a\ + $c2FsdDEyMzQ=$"; + let result = decode_string(encoded); + assert_eq!(result, Err(Error::DecodingFail)); + } + + #[test] + fn encode_string_returns_correct_string() { + let hash = b"12345678901234567890123456789012".to_vec(); + let config = Config { + ad: &[], + hash_length: hash.len() as u32, + lanes: 1, + mem_cost: 4096, + secret: &[], + thread_mode: ThreadMode::Parallel, + time_cost: 3, + variant: Variant::Argon2i, + version: Version::Version13, + }; + let pwd = b"password".to_vec(); + let salt = b"salt1234".to_vec(); + let context = Context::new(config, &pwd, &salt).unwrap(); + let expected = "$argon2i$v=19$m=4096,t=3,p=1\ + $c2FsdDEyMzQ$MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI"; + let actual = encode_string(&context, &hash); + assert_eq!(actual, expected); + } + + #[test] + fn num_len_returns_correct_length() { + let tests = vec![ + (1, 1), + (10, 2), + (110, 3), + (1230, 4), + (12340, 5), + (123457, 6), + ]; + for (num, expected) in tests { + let actual = num_len(num); + assert_eq!(actual, expected); + } + } +} diff --git a/third_party/rust/rust-argon2/src/error.rs b/third_party/rust/rust-argon2/src/error.rs new file mode 100644 index 0000000000..53d7b5a940 --- /dev/null +++ b/third_party/rust/rust-argon2/src/error.rs @@ -0,0 +1,119 @@ +// Copyright (c) 2017 Martijn Rijkeboer <mrr@sru-systems.com> +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use base64; +use std::{error, fmt}; + +/// Error type for Argon2 errors. +#[derive(Debug, PartialEq)] +pub enum Error { + /// The output (hash) is too short (minimum is 4). + OutputTooShort, + + /// The output (hash) is too long (maximum is 2^32 - 1). + OutputTooLong, + + /// The password is too short (minimum is 0). + PwdTooShort, + + /// The password is too long (maximum is 2^32 - 1). + PwdTooLong, + + /// The salt is too short (minimum is 8). + SaltTooShort, + + /// The salt is too long (maximum is 2^32 - 1). + SaltTooLong, + + /// The associated data is too short (minimum is 0). + AdTooShort, + + /// The associated data is too long (maximum is 2^32 - 1). + AdTooLong, + + /// The secret value is too short (minimum is 0). + SecretTooShort, + + /// The secret value is too long (maximum is 2^32 - 1). + SecretTooLong, + + /// The time cost (passes) is too small (minimum is 1). + TimeTooSmall, + + /// The time cost (passes) is too large (maximum is 2^32 - 1). + TimeTooLarge, + + /// The memory cost is too small (minimum is 8 x parallelism). + MemoryTooLittle, + + /// The memory cost is too large (maximum 2GiB on 32-bit or 4TiB on 64-bit). + MemoryTooMuch, + + /// The number of lanes (parallelism) is too small (minimum is 1). + LanesTooFew, + + /// The number of lanes (parallelism) is too large (maximum is 2^24 - 1). + LanesTooMany, + + /// Incorrect Argon2 variant. + IncorrectType, + + /// Incorrect Argon2 version. + IncorrectVersion, + + /// The decoding of the encoded data has failed. + DecodingFail, +} + +impl Error { + fn msg(&self) -> &str { + match *self { + Error::OutputTooShort => "Output is too short", + Error::OutputTooLong => "Output is too long", + Error::PwdTooShort => "Password is too short", + Error::PwdTooLong => "Password is too long", + Error::SaltTooShort => "Salt is too short", + Error::SaltTooLong => "Salt is too long", + Error::AdTooShort => "Associated data is too short", + Error::AdTooLong => "Associated data is too long", + Error::SecretTooShort => "Secret is too short", + Error::SecretTooLong => "Secret is too long", + Error::TimeTooSmall => "Time cost is too small", + Error::TimeTooLarge => "Time cost is too large", + Error::MemoryTooLittle => "Memory cost is too small", + Error::MemoryTooMuch => "Memory cost is too large", + Error::LanesTooFew => "Too few lanes", + Error::LanesTooMany => "Too many lanes", + Error::IncorrectType => "There is no such type of Argon2", + Error::IncorrectVersion => "There is no such version of Argon2", + Error::DecodingFail => "Decoding failed", + } + } +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.msg()) + } +} + +impl error::Error for Error { + fn description(&self) -> &str { + self.msg() + } + + fn cause(&self) -> Option<&error::Error> { + None + } +} + +impl From<base64::DecodeError> for Error { + fn from(_: base64::DecodeError) -> Self { + Error::DecodingFail + } +} diff --git a/third_party/rust/rust-argon2/src/lib.rs b/third_party/rust/rust-argon2/src/lib.rs new file mode 100644 index 0000000000..d871811ae2 --- /dev/null +++ b/third_party/rust/rust-argon2/src/lib.rs @@ -0,0 +1,103 @@ +// Copyright (c) 2017 Martijn Rijkeboer <mrr@sru-systems.com> +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Library for hashing passwords using +//! [Argon2](https://github.com/P-H-C/phc-winner-argon2), the password-hashing +//! function that won the +//! [Password Hashing Competition (PHC)](https://password-hashing.net). +//! +//! # Usage +//! +//! To use this crate, add the following to your Cargo.toml: +//! +//! ```toml +//! [dependencies] +//! rust-argon2 = "0.5" +//! ``` +//! +//! And the following to your crate root: +//! +//! ```rust +//! extern crate argon2; +//! ``` +//! +//! # Examples +//! +//! Create a password hash using the defaults and verify it: +//! +//! ```rust +//! use argon2::{self, Config}; +//! +//! let password = b"password"; +//! let salt = b"randomsalt"; +//! let config = Config::default(); +//! let hash = argon2::hash_encoded(password, salt, &config).unwrap(); +//! let matches = argon2::verify_encoded(&hash, password).unwrap(); +//! assert!(matches); +//! ``` +//! +//! Create a password hash with custom settings and verify it: +//! +//! ```rust +//! use argon2::{self, Config, ThreadMode, Variant, Version}; +//! +//! let password = b"password"; +//! let salt = b"othersalt"; +//! let config = Config { +//! variant: Variant::Argon2i, +//! version: Version::Version13, +//! mem_cost: 65536, +//! time_cost: 10, +//! lanes: 4, +//! thread_mode: ThreadMode::Parallel, +//! secret: &[], +//! ad: &[], +//! hash_length: 32 +//! }; +//! let hash = argon2::hash_encoded(password, salt, &config).unwrap(); +//! let matches = argon2::verify_encoded(&hash, password).unwrap(); +//! assert!(matches); +//! ``` +//! +//! # Limitations +//! +//! This crate has the same limitation as the `blake2-rfc` crate that it uses. +//! It does not attempt to clear potentially sensitive data from its work +//! memory. To do so correctly without a heavy performance penalty would +//! require help from the compiler. It's better to not attempt to do so than to +//! present a false assurance. +//! +//! This version uses the standard implementation and does not yet implement +//! optimizations. Therefore, it is not the fastest implementation available. + +extern crate base64; +extern crate blake2b_simd; +extern crate crossbeam_utils; + +mod argon2; +mod block; +mod common; +mod config; +mod context; +mod core; +mod decoded; +mod encoding; +mod error; +mod memory; +mod result; +mod thread_mode; +mod variant; +mod version; + +pub use argon2::*; +pub use config::Config; +pub use error::Error; +pub use result::Result; +pub use thread_mode::ThreadMode; +pub use variant::Variant; +pub use version::Version; diff --git a/third_party/rust/rust-argon2/src/memory.rs b/third_party/rust/rust-argon2/src/memory.rs new file mode 100644 index 0000000000..85f0c3313e --- /dev/null +++ b/third_party/rust/rust-argon2/src/memory.rs @@ -0,0 +1,120 @@ +// Copyright (c) 2017 Martijn Rijkeboer <mrr@sru-systems.com> +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::fmt; +use std::fmt::Debug; +use std::ops::{Index, IndexMut}; +use super::block::Block; + +/// Structure representing the memory matrix. +pub struct Memory { + /// The number of rows. + rows: usize, + + /// The number of columns. + cols: usize, + + /// The flat array of blocks representing the memory matrix. + blocks: Box<[Block]>, +} + +impl Memory { + /// Creates a new memory matrix. + pub fn new(lanes: u32, lane_length: u32) -> Memory { + let rows = lanes as usize; + let cols = lane_length as usize; + let total = rows * cols; + let blocks = vec![Block::zero(); total].into_boxed_slice(); + Memory { + rows: rows, + cols: cols, + blocks: blocks, + } + } + + /// Gets the mutable lanes representation of the memory matrix. + pub fn as_lanes_mut(&mut self) -> Vec<&mut Memory> { + let ptr: *mut Memory = self; + let mut vec = Vec::with_capacity(self.rows); + for _ in 0..self.rows { + vec.push(unsafe { &mut (*ptr) }); + } + vec + } +} + +impl Debug for Memory { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Memory {{ rows: {}, cols: {} }}", self.rows, self.cols) + } +} + +impl Index<u32> for Memory { + type Output = Block; + fn index(&self, index: u32) -> &Block { + &self.blocks[index as usize] + } +} + +impl Index<u64> for Memory { + type Output = Block; + fn index(&self, index: u64) -> &Block { + &self.blocks[index as usize] + } +} + +impl Index<(u32, u32)> for Memory { + type Output = Block; + fn index(&self, index: (u32, u32)) -> &Block { + let pos = ((index.0 as usize) * self.cols) + (index.1 as usize); + &self.blocks[pos] + } +} + +impl IndexMut<u32> for Memory { + fn index_mut(&mut self, index: u32) -> &mut Block { + &mut self.blocks[index as usize] + } +} + +impl IndexMut<u64> for Memory { + fn index_mut(&mut self, index: u64) -> &mut Block { + &mut self.blocks[index as usize] + } +} + +impl IndexMut<(u32, u32)> for Memory { + fn index_mut(&mut self, index: (u32, u32)) -> &mut Block { + let pos = ((index.0 as usize) * self.cols) + (index.1 as usize); + &mut self.blocks[pos] + } +} + + +#[cfg(test)] +mod tests { + + use super::*; + + #[test] + fn new_returns_correct_instance() { + let lanes = 4; + let lane_length = 128; + let memory = Memory::new(lanes, lane_length); + assert_eq!(memory.rows, lanes as usize); + assert_eq!(memory.cols, lane_length as usize); + assert_eq!(memory.blocks.len(), 512); + } + + #[test] + fn as_lanes_mut_returns_correct_vec() { + let mut memory = Memory::new(4, 128); + let lanes = memory.as_lanes_mut(); + assert_eq!(lanes.len(), 4); + } +} diff --git a/third_party/rust/rust-argon2/src/result.rs b/third_party/rust/rust-argon2/src/result.rs new file mode 100644 index 0000000000..f89c55815c --- /dev/null +++ b/third_party/rust/rust-argon2/src/result.rs @@ -0,0 +1,13 @@ +// Copyright (c) 2017 Martijn Rijkeboer <mrr@sru-systems.com> +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::result; +use super::error::Error; + +/// A specialized result type for Argon2 operations. +pub type Result<T> = result::Result<T, Error>; diff --git a/third_party/rust/rust-argon2/src/thread_mode.rs b/third_party/rust/rust-argon2/src/thread_mode.rs new file mode 100644 index 0000000000..0775c4d830 --- /dev/null +++ b/third_party/rust/rust-argon2/src/thread_mode.rs @@ -0,0 +1,56 @@ +// Copyright (c) 2017 Xidorn Quan <me@upsuper.org> +// Copyright (c) 2017 Martijn Rijkeboer <mrr@sru-systems.com> +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +/// The thread mode used to perform the hashing. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum ThreadMode { + /// Run in one thread. + Sequential, + + /// Run in the same number of threads as the number of lanes. + Parallel, +} + +impl ThreadMode { + /// Create a thread mode from the threads count. + pub fn from_threads(threads: u32) -> ThreadMode { + if threads > 1 { + ThreadMode::Parallel + } else { + ThreadMode::Sequential + } + } +} + +impl Default for ThreadMode { + fn default() -> ThreadMode { + ThreadMode::Sequential + } +} + + +#[cfg(test)] +mod tests { + + use super::*; + + #[test] + fn default_returns_correct_thread_mode() { + assert_eq!(ThreadMode::default(), ThreadMode::Sequential); + } + + #[test] + fn from_threads_returns_correct_thread_mode() { + assert_eq!(ThreadMode::from_threads(0), ThreadMode::Sequential); + assert_eq!(ThreadMode::from_threads(1), ThreadMode::Sequential); + assert_eq!(ThreadMode::from_threads(2), ThreadMode::Parallel); + assert_eq!(ThreadMode::from_threads(10), ThreadMode::Parallel); + assert_eq!(ThreadMode::from_threads(100), ThreadMode::Parallel); + } +} diff --git a/third_party/rust/rust-argon2/src/variant.rs b/third_party/rust/rust-argon2/src/variant.rs new file mode 100644 index 0000000000..8fb6c0b54c --- /dev/null +++ b/third_party/rust/rust-argon2/src/variant.rs @@ -0,0 +1,159 @@ +// Copyright (c) 2017 Martijn Rijkeboer <mrr@sru-systems.com> +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::fmt; +use super::error::Error; +use super::result::Result; + +/// The Argon2 variant. +#[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Ord)] +pub enum Variant { + /// Argon2 using data-dependent memory access to thwart tradeoff attacks. + /// Recommended for cryptocurrencies and backend servers. + Argon2d = 0, + + /// Argon2 using data-independent memory access to thwart side-channel + /// attacks. Recommended for password hashing and password-based key + /// derivation. + Argon2i = 1, + + /// Argon2 using hybrid construction. + Argon2id = 2, +} + +impl Variant { + /// Gets the lowercase string slice representation of the variant. + pub fn as_lowercase_str(&self) -> &'static str { + match *self { + Variant::Argon2d => "argon2d", + Variant::Argon2i => "argon2i", + Variant::Argon2id => "argon2id", + } + } + + /// Gets the u32 representation of the variant. + pub fn as_u32(&self) -> u32 { + *self as u32 + } + + /// Gets the u64 representation of the variant. + pub fn as_u64(&self) -> u64 { + *self as u64 + } + + /// Gets the uppercase string slice representation of the variant. + pub fn as_uppercase_str(&self) -> &'static str { + match *self { + Variant::Argon2d => "Argon2d", + Variant::Argon2i => "Argon2i", + Variant::Argon2id => "Argon2id", + } + } + + /// Attempts to create a variant from a string slice. + pub fn from_str(str: &str) -> Result<Variant> { + match str { + "Argon2d" => Ok(Variant::Argon2d), + "Argon2i" => Ok(Variant::Argon2i), + "Argon2id" => Ok(Variant::Argon2id), + "argon2d" => Ok(Variant::Argon2d), + "argon2i" => Ok(Variant::Argon2i), + "argon2id" => Ok(Variant::Argon2id), + _ => Err(Error::DecodingFail), + } + } + + /// Attempts to create a variant from an u32. + pub fn from_u32(val: u32) -> Result<Variant> { + match val { + 0 => Ok(Variant::Argon2d), + 1 => Ok(Variant::Argon2i), + 2 => Ok(Variant::Argon2id), + _ => Err(Error::IncorrectType), + } + } +} + +impl Default for Variant { + fn default() -> Variant { + Variant::Argon2i + } +} + +impl fmt::Display for Variant { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.as_lowercase_str()) + } +} + + +#[cfg(test)] +mod tests { + + use error::Error; + use super::*; + + #[test] + fn as_lowercase_str_returns_correct_str() { + assert_eq!(Variant::Argon2d.as_lowercase_str(), "argon2d"); + assert_eq!(Variant::Argon2i.as_lowercase_str(), "argon2i"); + assert_eq!(Variant::Argon2id.as_lowercase_str(), "argon2id"); + } + + #[test] + fn as_u32_returns_correct_u32() { + assert_eq!(Variant::Argon2d.as_u32(), 0); + assert_eq!(Variant::Argon2i.as_u32(), 1); + assert_eq!(Variant::Argon2id.as_u32(), 2); + } + + #[test] + fn as_u64_returns_correct_u64() { + assert_eq!(Variant::Argon2d.as_u64(), 0); + assert_eq!(Variant::Argon2i.as_u64(), 1); + assert_eq!(Variant::Argon2id.as_u64(), 2); + } + + #[test] + fn as_uppercase_str_returns_correct_str() { + assert_eq!(Variant::Argon2d.as_uppercase_str(), "Argon2d"); + assert_eq!(Variant::Argon2i.as_uppercase_str(), "Argon2i"); + assert_eq!(Variant::Argon2id.as_uppercase_str(), "Argon2id"); + } + + #[test] + fn default_returns_correct_variant() { + assert_eq!(Variant::default(), Variant::Argon2i); + } + + #[test] + fn display_returns_correct_string() { + assert_eq!(format!("{}", Variant::Argon2d), "argon2d"); + assert_eq!(format!("{}", Variant::Argon2i), "argon2i"); + assert_eq!(format!("{}", Variant::Argon2id), "argon2id"); + } + + #[test] + fn from_str_returns_correct_result() { + assert_eq!(Variant::from_str("Argon2d"), Ok(Variant::Argon2d)); + assert_eq!(Variant::from_str("Argon2i"), Ok(Variant::Argon2i)); + assert_eq!(Variant::from_str("Argon2id"), Ok(Variant::Argon2id)); + assert_eq!(Variant::from_str("argon2d"), Ok(Variant::Argon2d)); + assert_eq!(Variant::from_str("argon2i"), Ok(Variant::Argon2i)); + assert_eq!(Variant::from_str("argon2id"), Ok(Variant::Argon2id)); + assert_eq!(Variant::from_str("foobar"), Err(Error::DecodingFail)); + } + + #[test] + fn from_u32_returns_correct_result() { + assert_eq!(Variant::from_u32(0), Ok(Variant::Argon2d)); + assert_eq!(Variant::from_u32(1), Ok(Variant::Argon2i)); + assert_eq!(Variant::from_u32(2), Ok(Variant::Argon2id)); + assert_eq!(Variant::from_u32(3), Err(Error::IncorrectType)); + } +} diff --git a/third_party/rust/rust-argon2/src/version.rs b/third_party/rust/rust-argon2/src/version.rs new file mode 100644 index 0000000000..b8c03ba918 --- /dev/null +++ b/third_party/rust/rust-argon2/src/version.rs @@ -0,0 +1,97 @@ +// Copyright (c) 2017 Martijn Rijkeboer <mrr@sru-systems.com> +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::fmt; +use super::error::Error; +use super::result::Result; + +/// The Argon2 version. +#[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Ord)] +pub enum Version { + /// Version 0x10. + Version10 = 0x10, + + /// Version 0x13 (Recommended). + Version13 = 0x13, +} + +impl Version { + /// Gets the u32 representation of the version. + pub fn as_u32(&self) -> u32 { + *self as u32 + } + + /// Attempts to create a version from a string slice. + pub fn from_str(str: &str) -> Result<Version> { + match str { + "16" => Ok(Version::Version10), + "19" => Ok(Version::Version13), + _ => Err(Error::DecodingFail), + } + } + + /// Attempts to create a version from an u32. + pub fn from_u32(val: u32) -> Result<Version> { + match val { + 0x10 => Ok(Version::Version10), + 0x13 => Ok(Version::Version13), + _ => Err(Error::IncorrectVersion), + } + } +} + +impl Default for Version { + fn default() -> Version { + Version::Version13 + } +} + +impl fmt::Display for Version { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.as_u32()) + } +} + + +#[cfg(test)] +mod tests { + + use error::Error; + use super::*; + + #[test] + fn as_u32_returns_correct_u32() { + assert_eq!(Version::Version10.as_u32(), 0x10); + assert_eq!(Version::Version13.as_u32(), 0x13); + } + + #[test] + fn default_returns_correct_version() { + assert_eq!(Version::default(), Version::Version13); + } + + #[test] + fn display_returns_correct_string() { + assert_eq!(format!("{}", Version::Version10), "16"); + assert_eq!(format!("{}", Version::Version13), "19"); + } + + #[test] + fn from_str_returns_correct_result() { + assert_eq!(Version::from_str("16"), Ok(Version::Version10)); + assert_eq!(Version::from_str("19"), Ok(Version::Version13)); + assert_eq!(Version::from_str("11"), Err(Error::DecodingFail)); + } + + #[test] + fn from_u32_returns_correct_result() { + assert_eq!(Version::from_u32(0x10), Ok(Version::Version10)); + assert_eq!(Version::from_u32(0x13), Ok(Version::Version13)); + assert_eq!(Version::from_u32(0), Err(Error::IncorrectVersion)); + } +} |