summaryrefslogtreecommitdiffstats
path: root/third_party/rust/rust-argon2/src
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--third_party/rust/rust-argon2/src/argon2.rs717
-rw-r--r--third_party/rust/rust-argon2/src/block.rs142
-rw-r--r--third_party/rust/rust-argon2/src/common.rs92
-rw-r--r--third_party/rust/rust-argon2/src/config.rs105
-rw-r--r--third_party/rust/rust-argon2/src/context.rs213
-rw-r--r--third_party/rust/rust-argon2/src/core.rs474
-rw-r--r--third_party/rust/rust-argon2/src/decoded.rs35
-rw-r--r--third_party/rust/rust-argon2/src/encoding.rs401
-rw-r--r--third_party/rust/rust-argon2/src/error.rs119
-rw-r--r--third_party/rust/rust-argon2/src/lib.rs103
-rw-r--r--third_party/rust/rust-argon2/src/memory.rs120
-rw-r--r--third_party/rust/rust-argon2/src/result.rs13
-rw-r--r--third_party/rust/rust-argon2/src/thread_mode.rs56
-rw-r--r--third_party/rust/rust-argon2/src/variant.rs159
-rw-r--r--third_party/rust/rust-argon2/src/version.rs97
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));
+ }
+}