diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
commit | 2aa4a82499d4becd2284cdb482213d541b8804dd (patch) | |
tree | b80bf8bf13c3766139fbacc530efd0dd9d54394c /third_party/rust/rust-argon2 | |
parent | Initial commit. (diff) | |
download | firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.tar.xz firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.zip |
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/rust-argon2')
22 files changed, 4311 insertions, 0 deletions
diff --git a/third_party/rust/rust-argon2/.cargo-checksum.json b/third_party/rust/rust-argon2/.cargo-checksum.json new file mode 100644 index 0000000000..cb81f8f153 --- /dev/null +++ b/third_party/rust/rust-argon2/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"01442e11a70787ec85073f75c29ac23e84821a3e6aabca9423f68e507096463f","Cargo.toml":"d08e0d7065ae57f095e31d01210c0a39c6fc43c7bf19af79fbd2352d9fff3838","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"26b997d1a1496df49cb1ad2cbe024714cd9126543c18e1bc6c7bbca1b3dc42b6","README.md":"af8291721405e2ed769b5b0bdc90eb1f78a9a01c665a7747c1ca7ad76f66ac2d","src/argon2.rs":"df5dfa100a25abf57be38ba22dc201a0b9f75dd9d6b3a098151382b0cda5d874","src/block.rs":"20c0198d37eab2a096c78e0c38b4b8bcc2eeba3256e6a57dce8f732be0bc1920","src/common.rs":"a24dbea8091d8439279713c27b434c732f5c4c06482b51876fd5d8e0631c18a0","src/config.rs":"c3dbd2d15e55cb47dc16cbb17ba2bfba4eff33de7d7f8bb50511184edc255754","src/context.rs":"d652c26c90a4499ddc4460861486e14b95a90eefc0124ee0c9f1e3440c37ad8a","src/core.rs":"962d64f6d1b1c8f4217af5cd516874260aa080645dd951628a9c0979722347aa","src/decoded.rs":"3ccdac14ceff9c7c3596cac8a0725588bf6dfb728b64c9b9cda5b88aa18d2238","src/encoding.rs":"5579d6bc5c81e7baacfa510bed01938b4d4c2d13cfa697cb1b38baffd4c82704","src/error.rs":"72c862923c8e6f2bd54c02834dbdcc3b17337b8d0b5e8ff22b15e7c4c3c337a5","src/lib.rs":"11b123afab0e3ecdc6bd4c74dd2b6fccdd331ece49b5b94aee3fe81841b650a9","src/memory.rs":"25e7f5e6d349d14a76d7a457d9d4a28e6d583499e9612928843b3ebc3d257d35","src/result.rs":"92cb6463af8230655bf946ff5e52d92c26674fbf47e0640bdbc631a4400cd644","src/thread_mode.rs":"afeb39243e1bb253b124732b36c46ffd8249a4996d5d043106b34679144a1523","src/variant.rs":"e1d88e1dfb1a2ab01bf59b8699ef7548b1d7c40426baaef46ae955e9ff696cb8","src/version.rs":"91d493f1331dd2cba71b4e6a426ecb5de42a52a26c6e3659083a322b3c14c293","tests/integration_test.rs":"97bc547a9b0d38623a593928f5785166e87d9bdf1c8105a00b006644e06b9faa"},"package":"4ca4eaef519b494d1f2848fc602d18816fed808a981aedf4f1f00ceb7c9d32cf"}
\ No newline at end of file diff --git a/third_party/rust/rust-argon2/CHANGELOG.md b/third_party/rust/rust-argon2/CHANGELOG.md new file mode 100644 index 0000000000..3619b27eaf --- /dev/null +++ b/third_party/rust/rust-argon2/CHANGELOG.md @@ -0,0 +1,44 @@ +ChangeLog for rust-argon2 +========================= + +This documents all notable changes to +[rust-argon2](https://github.com/sru-systems/rust-argon2). + +## 0.5.1 + +- Use crossbeam utils 0.6 instead of crossbeam 0.5 + + +## 0.5.0 + +- Replace blake2-rfc with blake2b_simd. + + +## 0.4.0 + +- Replace rustc-serialize dependency with base64 and hex. +- Update base64 dependency. +- Update crossbeam dependency. +- Update hex dependency. +- Allow updating to minor versions of blake2-rfc. + + +## 0.3.0 + +- Embed Config struct in Context struct. + + +## 0.2.0 + +- Use ThreadMode enum instead of explicit thread number. +- Use a Config struct instead of explicit configuration arguments. +- Use references instead of vectors for byte data in the Context struct. +- Deprecate the following functions: + - hash_encoded_defaults + - hash_encoded_old + - hash_encoded_std + - hash_raw_defaults + - hash_raw_old + - hash_raw_std + - verify_raw_old + - verify_raw_std diff --git a/third_party/rust/rust-argon2/Cargo.toml b/third_party/rust/rust-argon2/Cargo.toml new file mode 100644 index 0000000000..65e3547997 --- /dev/null +++ b/third_party/rust/rust-argon2/Cargo.toml @@ -0,0 +1,36 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "rust-argon2" +version = "0.5.1" +authors = ["Martijn Rijkeboer <mrr@sru-systems.com>"] +description = "Rust implementation of the Argon2 password hashing function." +homepage = "https://github.com/sru-systems/rust-argon2" +documentation = "https://docs.sru-systems.com/rust-argon2/0.5.0/argon2/" +readme = "README.md" +keywords = ["argon2", "argon2d", "argon2i", "hash", "password"] +license = "MIT/Apache-2.0" +repository = "https://github.com/sru-systems/rust-argon2" + +[lib] +name = "argon2" +[dependencies.base64] +version = "0.10" + +[dependencies.blake2b_simd] +version = "0.5" + +[dependencies.crossbeam-utils] +version = "0.6" +[dev-dependencies.hex] +version = "0.3" diff --git a/third_party/rust/rust-argon2/LICENSE-APACHE b/third_party/rust/rust-argon2/LICENSE-APACHE new file mode 100644 index 0000000000..16fe87b06e --- /dev/null +++ b/third_party/rust/rust-argon2/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/third_party/rust/rust-argon2/LICENSE-MIT b/third_party/rust/rust-argon2/LICENSE-MIT new file mode 100644 index 0000000000..96cd88f451 --- /dev/null +++ b/third_party/rust/rust-argon2/LICENSE-MIT @@ -0,0 +1,22 @@ +The MIT license. + +Copyright (c) 2017 Martijn Rijkeboer <mrr@sru-systems.com> + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/third_party/rust/rust-argon2/README.md b/third_party/rust/rust-argon2/README.md new file mode 100644 index 0000000000..b1280af6c2 --- /dev/null +++ b/third_party/rust/rust-argon2/README.md @@ -0,0 +1,85 @@ +# Rust-argon2 + +Rust 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 `rust-argon2`, 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. + + +## License + +Rust-argon2 is dual licensed under the [MIT](LICENSE-MIT) and +[Apache 2.0](LICENSE-APACHE) licenses, the same licenses as the Rust compiler. + + +## Contributions + +Contributions are welcome. By submitting a pull request you are agreeing to +make you work available under the license terms of the Rust-argon2 project. + 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)); + } +} diff --git a/third_party/rust/rust-argon2/tests/integration_test.rs b/third_party/rust/rust-argon2/tests/integration_test.rs new file mode 100644 index 0000000000..c2e07c78f4 --- /dev/null +++ b/third_party/rust/rust-argon2/tests/integration_test.rs @@ -0,0 +1,1076 @@ +// 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. + +// These tests are based on Argon's test.c test suite. + +extern crate argon2; +extern crate hex; + +use argon2::{Error, Config, ThreadMode, Variant, Version}; +use hex::ToHex; + +#[cfg(not(debug_assertions))] +#[test] +fn test_argon2d_version10_1() { + hash_test( + Variant::Argon2d, + Version::Version10, + 2, + 65536, + 1, + b"password", + b"somesalt", + "2ec0d925358f5830caf0c1cc8a3ee58b34505759428b859c79b72415f51f9221", + "$argon2d$m=65536,t=2,p=1$c29tZXNhbHQ\ + $LsDZJTWPWDDK8MHMij7lizRQV1lCi4WcebckFfUfkiE", + ); +} + +#[cfg(not(debug_assertions))] +#[test] +fn test_argon2d_version10_2() { + hash_test( + Variant::Argon2d, + Version::Version10, + 2, + 1048576, + 1, + b"password", + b"somesalt", + "28ae0d1037991b55faec18425274d5f9169b2f44bee19b45b7a561d489d6019a", + "$argon2d$m=1048576,t=2,p=1$c29tZXNhbHQ\ + $KK4NEDeZG1X67BhCUnTV+RabL0S+4ZtFt6Vh1InWAZo", + ); +} + +#[cfg(not(debug_assertions))] +#[test] +fn test_argon2d_version10_3() { + hash_test( + Variant::Argon2d, + Version::Version10, + 2, + 262144, + 1, + b"password", + b"somesalt", + "41c89760d85b80ba1be7e959ebd16390bfb4176db9466d70f670457ccade4ec8", + "$argon2d$m=262144,t=2,p=1$c29tZXNhbHQ\ + $QciXYNhbgLob5+lZ69FjkL+0F225Rm1w9nBFfMreTsg", + ); +} + +#[test] +fn test_argon2d_version10_4() { + hash_test( + Variant::Argon2d, + Version::Version10, + 2, + 256, + 1, + b"password", + b"somesalt", + "bd404868ff00c52e7543c8332e6a772a5724892d7e328d5cf253bbc8e726b371", + "$argon2d$m=256,t=2,p=1$c29tZXNhbHQ\ + $vUBIaP8AxS51Q8gzLmp3KlckiS1+Mo1c8lO7yOcms3E", + ); +} + +#[test] +fn test_argon2d_version10_5() { + hash_test( + Variant::Argon2d, + Version::Version10, + 2, + 256, + 2, + b"password", + b"somesalt", + "6a91d02b9f8854ba0841f04aa6e53c1d3374c0a0c646b8e431b03de805b91ec3", + "$argon2d$m=256,t=2,p=2$c29tZXNhbHQ\ + $apHQK5+IVLoIQfBKpuU8HTN0wKDGRrjkMbA96AW5HsM", + ); +} + +#[cfg(not(debug_assertions))] +#[test] +fn test_argon2d_version10_6() { + hash_test( + Variant::Argon2d, + Version::Version10, + 1, + 65536, + 1, + b"password", + b"somesalt", + "05d1d0a85f499e9397b9c1c936b20f366a7273ccf259e2edfdb44ca8f86dd11f", + "$argon2d$m=65536,t=1,p=1$c29tZXNhbHQ\ + $BdHQqF9JnpOXucHJNrIPNmpyc8zyWeLt/bRMqPht0R8", + ); +} + +#[cfg(not(debug_assertions))] +#[test] +fn test_argon2d_version10_7() { + hash_test( + Variant::Argon2d, + Version::Version10, + 4, + 65536, + 1, + b"password", + b"somesalt", + "99e787faced20949df5a3b9c8620712b45cfea061716adf8b13efb7feee44084", + "$argon2d$m=65536,t=4,p=1$c29tZXNhbHQ\ + $meeH+s7SCUnfWjuchiBxK0XP6gYXFq34sT77f+7kQIQ", + ); +} + +#[cfg(not(debug_assertions))] +#[test] +fn test_argon2d_version10_8() { + hash_test( + Variant::Argon2d, + Version::Version10, + 2, + 65536, + 1, + b"differentpassword", + b"somesalt", + "b9c2e4a4ec9a6db99ca4e2b549dd64256305b95754b0a70ad757cd1ff7eed4a4", + "$argon2d$m=65536,t=2,p=1$c29tZXNhbHQ\ + $ucLkpOyabbmcpOK1Sd1kJWMFuVdUsKcK11fNH/fu1KQ", + ); +} + +#[cfg(not(debug_assertions))] +#[test] +fn test_argon2d_version10_9() { + hash_test( + Variant::Argon2d, + Version::Version10, + 2, + 65536, + 1, + b"password", + b"diffsalt", + "d1da14196c233e0a3cb687aa6e6c465cb50669ffdb891158c2b75722395f14d5", + "$argon2d$m=65536,t=2,p=1$ZGlmZnNhbHQ\ + $0doUGWwjPgo8toeqbmxGXLUGaf/biRFYwrdXIjlfFNU", + ); +} + +#[cfg(not(debug_assertions))] +#[test] +fn test_argon2d_version13_1() { + hash_test( + Variant::Argon2d, + Version::Version13, + 2, + 65536, + 1, + b"password", + b"somesalt", + "955e5d5b163a1b60bba35fc36d0496474fba4f6b59ad53628666f07fb2f93eaf", + "$argon2d$v=19$m=65536,t=2,p=1$c29tZXNhbHQ\ + $lV5dWxY6G2C7o1/DbQSWR0+6T2tZrVNihmbwf7L5Pq8", + ); +} + +#[cfg(not(debug_assertions))] +#[test] +fn test_argon2d_version13_2() { + hash_test( + Variant::Argon2d, + Version::Version13, + 2, + 1048576, + 1, + b"password", + b"somesalt", + "c2d680a6e7ac1b75e2c2b1e5e71b1701584869492efea4a76ccc91fec622d1ae", + "$argon2d$v=19$m=1048576,t=2,p=1$c29tZXNhbHQ\ + $wtaApuesG3XiwrHl5xsXAVhIaUku/qSnbMyR/sYi0a4", + ); +} + +#[cfg(not(debug_assertions))] +#[test] +fn test_argon2d_version13_3() { + hash_test( + Variant::Argon2d, + Version::Version13, + 2, + 262144, + 1, + b"password", + b"somesalt", + "9678b3379ce20ddc96fa38f045c8cdc96282287ff2848efd867582b9528a2155", + "$argon2d$v=19$m=262144,t=2,p=1$c29tZXNhbHQ\ + $lnizN5ziDdyW+jjwRcjNyWKCKH/yhI79hnWCuVKKIVU", + ); +} + +#[test] +fn test_argon2d_version13_4() { + hash_test( + Variant::Argon2d, + Version::Version13, + 2, + 256, + 1, + b"password", + b"somesalt", + "25c4ee8ba448054b49efc804e478b9d823be1f9bd2e99f51d6ec4007a3a1501f", + "$argon2d$v=19$m=256,t=2,p=1$c29tZXNhbHQ\ + $JcTui6RIBUtJ78gE5Hi52CO+H5vS6Z9R1uxAB6OhUB8", + ); +} + +#[test] +fn test_argon2d_version13_5() { + hash_test( + Variant::Argon2d, + Version::Version13, + 2, + 256, + 2, + b"password", + b"somesalt", + "7b69c92d7c3889aad1281dbc8baefc12cc37c80f1c75e33ef2c2d40c28ebc573", + "$argon2d$v=19$m=256,t=2,p=2$c29tZXNhbHQ\ + $e2nJLXw4iarRKB28i678Esw3yA8cdeM+8sLUDCjrxXM", + ); +} + +#[cfg(not(debug_assertions))] +#[test] +fn test_argon2d_version13_6() { + hash_test( + Variant::Argon2d, + Version::Version13, + 1, + 65536, + 1, + b"password", + b"somesalt", + "8193708c030f09b121526b0efdffce738fef0ddb13937a65d43f3f1eab9aa802", + "$argon2d$v=19$m=65536,t=1,p=1$c29tZXNhbHQ\ + $gZNwjAMPCbEhUmsO/f/Oc4/vDdsTk3pl1D8/HquaqAI", + ); +} + +#[cfg(not(debug_assertions))] +#[test] +fn test_argon2d_version13_7() { + hash_test( + Variant::Argon2d, + Version::Version13, + 4, + 65536, + 1, + b"password", + b"somesalt", + "cd1e2816cf8895fffe535b87b7a0aa3612f73c6ce063de83b1e7b4621ca0afe6", + "$argon2d$v=19$m=65536,t=4,p=1$c29tZXNhbHQ\ + $zR4oFs+Ilf/+U1uHt6CqNhL3PGzgY96Dsee0Yhygr+Y", + ); +} + +#[cfg(not(debug_assertions))] +#[test] +fn test_argon2d_version13_8() { + hash_test( + Variant::Argon2d, + Version::Version13, + 2, + 65536, + 1, + b"differentpassword", + b"somesalt", + "a34dafc893182d521ae467bbfdce60f973a1223c4615654efeb0bfef8a930e25", + "$argon2d$v=19$m=65536,t=2,p=1$c29tZXNhbHQ\ + $o02vyJMYLVIa5Ge7/c5g+XOhIjxGFWVO/rC/74qTDiU", + ); +} + +#[cfg(not(debug_assertions))] +#[test] +fn test_argon2d_version13_9() { + hash_test( + Variant::Argon2d, + Version::Version13, + 2, + 65536, + 1, + b"password", + b"diffsalt", + "f00eb8a999a1c6949c61fbbee3c3cece5066e3ff5c79aed421266055e2bf4dd7", + "$argon2d$v=19$m=65536,t=2,p=1$ZGlmZnNhbHQ\ + $8A64qZmhxpScYfu+48POzlBm4/9cea7UISZgVeK/Tdc", + ); +} + +#[cfg(not(debug_assertions))] +#[test] +fn test_argon2i_version10_1() { + hash_test( + Variant::Argon2i, + Version::Version10, + 2, + 65536, + 1, + b"password", + b"somesalt", + "f6c4db4a54e2a370627aff3db6176b94a2a209a62c8e36152711802f7b30c694", + "$argon2i$m=65536,t=2,p=1$c29tZXNhbHQ\ + $9sTbSlTio3Biev89thdrlKKiCaYsjjYVJxGAL3swxpQ", + ); +} + +#[cfg(not(debug_assertions))] +#[test] +fn test_argon2i_version10_2() { + hash_test( + Variant::Argon2i, + Version::Version10, + 2, + 1048576, + 1, + b"password", + b"somesalt", + "9690ec55d28d3ed32562f2e73ea62b02b018757643a2ae6e79528459de8106e9", + "$argon2i$m=1048576,t=2,p=1$c29tZXNhbHQ\ + $lpDsVdKNPtMlYvLnPqYrArAYdXZDoq5ueVKEWd6BBuk", + ); +} + +#[cfg(not(debug_assertions))] +#[test] +fn test_argon2i_version10_3() { + hash_test( + Variant::Argon2i, + Version::Version10, + 2, + 262144, + 1, + b"password", + b"somesalt", + "3e689aaa3d28a77cf2bc72a51ac53166761751182f1ee292e3f677a7da4c2467", + "$argon2i$m=262144,t=2,p=1$c29tZXNhbHQ\ + $Pmiaqj0op3zyvHKlGsUxZnYXURgvHuKS4/Z3p9pMJGc", + ); +} + +#[test] +fn test_argon2i_version10_4() { + hash_test( + Variant::Argon2i, + Version::Version10, + 2, + 256, + 1, + b"password", + b"somesalt", + "fd4dd83d762c49bdeaf57c47bdcd0c2f1babf863fdeb490df63ede9975fccf06", + "$argon2i$m=256,t=2,p=1$c29tZXNhbHQ\ + $/U3YPXYsSb3q9XxHvc0MLxur+GP960kN9j7emXX8zwY", + ); +} + +#[test] +fn test_argon2i_version10_5() { + hash_test( + Variant::Argon2i, + Version::Version10, + 2, + 256, + 2, + b"password", + b"somesalt", + "b6c11560a6a9d61eac706b79a2f97d68b4463aa3ad87e00c07e2b01e90c564fb", + "$argon2i$m=256,t=2,p=2$c29tZXNhbHQ\ + $tsEVYKap1h6scGt5ovl9aLRGOqOth+AMB+KwHpDFZPs", + ); +} + +#[cfg(not(debug_assertions))] +#[test] +fn test_argon2i_version10_6() { + hash_test( + Variant::Argon2i, + Version::Version10, + 1, + 65536, + 1, + b"password", + b"somesalt", + "81630552b8f3b1f48cdb1992c4c678643d490b2b5eb4ff6c4b3438b5621724b2", + "$argon2i$m=65536,t=1,p=1$c29tZXNhbHQ\ + $gWMFUrjzsfSM2xmSxMZ4ZD1JCytetP9sSzQ4tWIXJLI", + ); +} + +#[cfg(not(debug_assertions))] +#[test] +fn test_argon2i_version10_7() { + hash_test( + Variant::Argon2i, + Version::Version10, + 4, + 65536, + 1, + b"password", + b"somesalt", + "f212f01615e6eb5d74734dc3ef40ade2d51d052468d8c69440a3a1f2c1c2847b", + "$argon2i$m=65536,t=4,p=1$c29tZXNhbHQ\ + $8hLwFhXm6110c03D70Ct4tUdBSRo2MaUQKOh8sHChHs", + ); +} + +#[cfg(not(debug_assertions))] +#[test] +fn test_argon2i_version10_8() { + hash_test( + Variant::Argon2i, + Version::Version10, + 2, + 65536, + 1, + b"differentpassword", + b"somesalt", + "e9c902074b6754531a3a0be519e5baf404b30ce69b3f01ac3bf21229960109a3", + "$argon2i$m=65536,t=2,p=1$c29tZXNhbHQ\ + $6ckCB0tnVFMaOgvlGeW69ASzDOabPwGsO/ISKZYBCaM", + ); +} + +#[cfg(not(debug_assertions))] +#[test] +fn test_argon2i_version10_9() { + hash_test( + Variant::Argon2i, + Version::Version10, + 2, + 65536, + 1, + b"password", + b"diffsalt", + "79a103b90fe8aef8570cb31fc8b22259778916f8336b7bdac3892569d4f1c497", + "$argon2i$m=65536,t=2,p=1$ZGlmZnNhbHQ\ + $eaEDuQ/orvhXDLMfyLIiWXeJFvgza3vaw4kladTxxJc", + ); +} + +#[cfg(not(debug_assertions))] +#[test] +fn test_argon2i_version13_1() { + hash_test( + Variant::Argon2i, + Version::Version13, + 2, + 65536, + 1, + b"password", + b"somesalt", + "c1628832147d9720c5bd1cfd61367078729f6dfb6f8fea9ff98158e0d7816ed0", + "$argon2i$v=19$m=65536,t=2,p=1$c29tZXNhbHQ\ + $wWKIMhR9lyDFvRz9YTZweHKfbftvj+qf+YFY4NeBbtA", + ); +} + +#[cfg(not(debug_assertions))] +#[test] +fn test_argon2i_version13_2() { + hash_test( + Variant::Argon2i, + Version::Version13, + 2, + 1048576, + 1, + b"password", + b"somesalt", + "d1587aca0922c3b5d6a83edab31bee3c4ebaef342ed6127a55d19b2351ad1f41", + "$argon2i$v=19$m=1048576,t=2,p=1$c29tZXNhbHQ\ + $0Vh6ygkiw7XWqD7asxvuPE667zQu1hJ6VdGbI1GtH0E", + ); +} + +#[cfg(not(debug_assertions))] +#[test] +fn test_argon2i_version13_3() { + hash_test( + Variant::Argon2i, + Version::Version13, + 2, + 262144, + 1, + b"password", + b"somesalt", + "296dbae80b807cdceaad44ae741b506f14db0959267b183b118f9b24229bc7cb", + "$argon2i$v=19$m=262144,t=2,p=1$c29tZXNhbHQ\ + $KW266AuAfNzqrUSudBtQbxTbCVkmexg7EY+bJCKbx8s", + ); +} + +#[test] +fn test_argon2i_version13_4() { + hash_test( + Variant::Argon2i, + Version::Version13, + 2, + 256, + 1, + b"password", + b"somesalt", + "89e9029f4637b295beb027056a7336c414fadd43f6b208645281cb214a56452f", + "$argon2i$v=19$m=256,t=2,p=1$c29tZXNhbHQ\ + $iekCn0Y3spW+sCcFanM2xBT63UP2sghkUoHLIUpWRS8", + ); +} + +#[test] +fn test_argon2i_version13_5() { + hash_test( + Variant::Argon2i, + Version::Version13, + 2, + 256, + 2, + b"password", + b"somesalt", + "4ff5ce2769a1d7f4c8a491df09d41a9fbe90e5eb02155a13e4c01e20cd4eab61", + "$argon2i$v=19$m=256,t=2,p=2$c29tZXNhbHQ\ + $T/XOJ2mh1/TIpJHfCdQan76Q5esCFVoT5MAeIM1Oq2E", + ); +} + +#[cfg(not(debug_assertions))] +#[test] +fn test_argon2i_version13_6() { + hash_test( + Variant::Argon2i, + Version::Version13, + 1, + 65536, + 1, + b"password", + b"somesalt", + "d168075c4d985e13ebeae560cf8b94c3b5d8a16c51916b6f4ac2da3ac11bbecf", + "$argon2i$v=19$m=65536,t=1,p=1$c29tZXNhbHQ\ + $0WgHXE2YXhPr6uVgz4uUw7XYoWxRkWtvSsLaOsEbvs8", + ); +} + +#[cfg(not(debug_assertions))] +#[test] +fn test_argon2i_version13_7() { + hash_test( + Variant::Argon2i, + Version::Version13, + 4, + 65536, + 1, + b"password", + b"somesalt", + "aaa953d58af3706ce3df1aefd4a64a84e31d7f54175231f1285259f88174ce5b", + "$argon2i$v=19$m=65536,t=4,p=1$c29tZXNhbHQ\ + $qqlT1YrzcGzj3xrv1KZKhOMdf1QXUjHxKFJZ+IF0zls", + ); +} + +#[cfg(not(debug_assertions))] +#[test] +fn test_argon2i_version13_8() { + hash_test( + Variant::Argon2i, + Version::Version13, + 2, + 65536, + 1, + b"differentpassword", + b"somesalt", + "14ae8da01afea8700c2358dcef7c5358d9021282bd88663a4562f59fb74d22ee", + "$argon2i$v=19$m=65536,t=2,p=1$c29tZXNhbHQ\ + $FK6NoBr+qHAMI1jc73xTWNkCEoK9iGY6RWL1n7dNIu4", + ); +} + +#[cfg(not(debug_assertions))] +#[test] +fn test_argon2i_version13_9() { + hash_test( + Variant::Argon2i, + Version::Version13, + 2, + 65536, + 1, + b"password", + b"diffsalt", + "b0357cccfbef91f3860b0dba447b2348cbefecadaf990abfe9cc40726c521271", + "$argon2i$v=19$m=65536,t=2,p=1$ZGlmZnNhbHQ\ + $sDV8zPvvkfOGCw26RHsjSMvv7K2vmQq/6cxAcmxSEnE", + ); +} + +#[cfg(not(debug_assertions))] +#[test] +fn test_argon2id_version10_1() { + hash_test( + Variant::Argon2id, + Version::Version10, + 2, + 65536, + 1, + b"password", + b"somesalt", + "980ebd24a4e667f16346f9d4a78b175728783613e0cc6fb17c2ec884b16435df", + "$argon2id$v=16$m=65536,t=2,p=1$c29tZXNhbHQ\ + $mA69JKTmZ/FjRvnUp4sXVyh4NhPgzG+xfC7IhLFkNd8", + ); +} + +#[cfg(not(debug_assertions))] +#[test] +fn test_argon2id_version10_2() { + hash_test( + Variant::Argon2id, + Version::Version10, + 2, + 1048576, + 1, + b"password", + b"somesalt", + "ce622fc2053acd224c06e7be122f9e9554b62b8a414b032056b46123422e32ab", + "$argon2id$v=16$m=1048576,t=2,p=1$c29tZXNhbHQ\ + $zmIvwgU6zSJMBue+Ei+elVS2K4pBSwMgVrRhI0IuMqs", + ); +} + +#[cfg(not(debug_assertions))] +#[test] +fn test_argon2id_version10_3() { + hash_test( + Variant::Argon2id, + Version::Version10, + 2, + 262144, + 1, + b"password", + b"somesalt", + "01cbafb58f2dc764adced1ab9a90fcb62f6ed8a066023b6ba0c204db6c9b90cd", + "$argon2id$v=16$m=262144,t=2,p=1$c29tZXNhbHQ\ + $AcuvtY8tx2StztGrmpD8ti9u2KBmAjtroMIE22ybkM0", + ); +} + +#[test] +fn test_argon2id_version10_4() { + hash_test( + Variant::Argon2id, + Version::Version10, + 2, + 256, + 1, + b"password", + b"somesalt", + "da070e576e50f2f38a3c897cbddc6c7fb4028e870971ff9eae7b4e1879295e6e", + "$argon2id$v=16$m=256,t=2,p=1$c29tZXNhbHQ\ + $2gcOV25Q8vOKPIl8vdxsf7QCjocJcf+erntOGHkpXm4", + ); +} + +#[test] +fn test_argon2id_version10_5() { + hash_test( + Variant::Argon2id, + Version::Version10, + 2, + 256, + 2, + b"password", + b"somesalt", + "f8aabb5315c63cddcdb3b4a021550928e525699da8fcbd1c2b0b1ccd35cc87a7", + "$argon2id$v=16$m=256,t=2,p=2$c29tZXNhbHQ\ + $+Kq7UxXGPN3Ns7SgIVUJKOUlaZ2o/L0cKwsczTXMh6c", + ); +} + +#[cfg(not(debug_assertions))] +#[test] +fn test_argon2id_version10_6() { + hash_test( + Variant::Argon2id, + Version::Version10, + 1, + 65536, + 1, + b"password", + b"somesalt", + "8e0f310407a989013a823defbd6cbae54d86b35d1ac16e4f88eb4645e1357956", + "$argon2id$v=16$m=65536,t=1,p=1$c29tZXNhbHQ\ + $jg8xBAepiQE6gj3vvWy65U2Gs10awW5PiOtGReE1eVY", + ); +} + +#[cfg(not(debug_assertions))] +#[test] +fn test_argon2id_version10_7() { + hash_test( + Variant::Argon2id, + Version::Version10, + 4, + 65536, + 1, + b"password", + b"somesalt", + "16653426e582143da6a0ff75daac9fa94c21ac2c221c96bd3645a5c15c2d962a", + "$argon2id$v=16$m=65536,t=4,p=1$c29tZXNhbHQ\ + $FmU0JuWCFD2moP912qyfqUwhrCwiHJa9NkWlwVwtlio", + ); +} + +#[cfg(not(debug_assertions))] +#[test] +fn test_argon2id_version10_8() { + hash_test( + Variant::Argon2id, + Version::Version10, + 2, + 65536, + 1, + b"differentpassword", + b"somesalt", + "75709d4c96a2c235696a77eefeecf33e64221f470b26177c19e5e27642612dbb", + "$argon2id$v=16$m=65536,t=2,p=1$c29tZXNhbHQ\ + $dXCdTJaiwjVpanfu/uzzPmQiH0cLJhd8GeXidkJhLbs", + ); +} + +#[cfg(not(debug_assertions))] +#[test] +fn test_argon2id_version10_9() { + hash_test( + Variant::Argon2id, + Version::Version10, + 2, + 65536, + 1, + b"password", + b"diffsalt", + "f0b57cfe03a9d78c4700e2fe802002343660a56b1b5d21ead788e6bb44ef48d3", + "$argon2id$v=16$m=65536,t=2,p=1$ZGlmZnNhbHQ\ + $8LV8/gOp14xHAOL+gCACNDZgpWsbXSHq14jmu0TvSNM", + ); +} + +#[cfg(not(debug_assertions))] +#[test] +fn test_argon2id_version13_1() { + hash_test( + Variant::Argon2id, + Version::Version13, + 2, + 65536, + 1, + b"password", + b"somesalt", + "09316115d5cf24ed5a15a31a3ba326e5cf32edc24702987c02b6566f61913cf7", + "$argon2id$v=19$m=65536,t=2,p=1$c29tZXNhbHQ\ + $CTFhFdXPJO1aFaMaO6Mm5c8y7cJHAph8ArZWb2GRPPc", + ); +} + +#[cfg(not(debug_assertions))] +#[test] +fn test_argon2id_version13_2() { + hash_test( + Variant::Argon2id, + Version::Version13, + 2, + 1048576, + 1, + b"password", + b"somesalt", + "16a1cb8a061cf1f8b16fb195fe559fa6d1435e43dded2f4fb07293176be892fa", + "$argon2id$v=19$m=1048576,t=2,p=1$c29tZXNhbHQ\ + $FqHLigYc8fixb7GV/lWfptFDXkPd7S9PsHKTF2vokvo", + ); +} + +#[cfg(not(debug_assertions))] +#[test] +fn test_argon2id_version13_3() { + hash_test( + Variant::Argon2id, + Version::Version13, + 2, + 262144, + 1, + b"password", + b"somesalt", + "78fe1ec91fb3aa5657d72e710854e4c3d9b9198c742f9616c2f085bed95b2e8c", + "$argon2id$v=19$m=262144,t=2,p=1$c29tZXNhbHQ\ + $eP4eyR+zqlZX1y5xCFTkw9m5GYx0L5YWwvCFvtlbLow", + ); +} + +#[test] +fn test_argon2id_version13_4() { + hash_test( + Variant::Argon2id, + Version::Version13, + 2, + 256, + 1, + b"password", + b"somesalt", + "9dfeb910e80bad0311fee20f9c0e2b12c17987b4cac90c2ef54d5b3021c68bfe", + "$argon2id$v=19$m=256,t=2,p=1$c29tZXNhbHQ\ + $nf65EOgLrQMR/uIPnA4rEsF5h7TKyQwu9U1bMCHGi/4", + ); +} + +#[test] +fn test_argon2id_version13_5() { + hash_test( + Variant::Argon2id, + Version::Version13, + 2, + 256, + 2, + b"password", + b"somesalt", + "6d093c501fd5999645e0ea3bf620d7b8be7fd2db59c20d9fff9539da2bf57037", + "$argon2id$v=19$m=256,t=2,p=2$c29tZXNhbHQ\ + $bQk8UB/VmZZF4Oo79iDXuL5/0ttZwg2f/5U52iv1cDc", + ); +} + +#[cfg(not(debug_assertions))] +#[test] +fn test_argon2id_version13_6() { + hash_test( + Variant::Argon2id, + Version::Version13, + 1, + 65536, + 1, + b"password", + b"somesalt", + "f6a5adc1ba723dddef9b5ac1d464e180fcd9dffc9d1cbf76cca2fed795d9ca98", + "$argon2id$v=19$m=65536,t=1,p=1$c29tZXNhbHQ\ + $9qWtwbpyPd3vm1rB1GThgPzZ3/ydHL92zKL+15XZypg", + ); +} + +#[cfg(not(debug_assertions))] +#[test] +fn test_argon2id_version13_7() { + hash_test( + Variant::Argon2id, + Version::Version13, + 4, + 65536, + 1, + b"password", + b"somesalt", + "9025d48e68ef7395cca9079da4c4ec3affb3c8911fe4f86d1a2520856f63172c", + "$argon2id$v=19$m=65536,t=4,p=1$c29tZXNhbHQ\ + $kCXUjmjvc5XMqQedpMTsOv+zyJEf5PhtGiUghW9jFyw", + ); +} + +#[cfg(not(debug_assertions))] +#[test] +fn test_argon2id_version13_8() { + hash_test( + Variant::Argon2id, + Version::Version13, + 2, + 65536, + 1, + b"differentpassword", + b"somesalt", + "0b84d652cf6b0c4beaef0dfe278ba6a80df6696281d7e0d2891b817d8c458fde", + "$argon2id$v=19$m=65536,t=2,p=1$c29tZXNhbHQ\ + $C4TWUs9rDEvq7w3+J4umqA32aWKB1+DSiRuBfYxFj94", + ); +} + +#[cfg(not(debug_assertions))] +#[test] +fn test_argon2id_version13_9() { + hash_test( + Variant::Argon2id, + Version::Version13, + 2, + 65536, + 1, + b"password", + b"diffsalt", + "bdf32b05ccc42eb15d58fd19b1f856b113da1e9a5874fdcc544308565aa8141c", + "$argon2id$v=19$m=65536,t=2,p=1$ZGlmZnNhbHQ\ + $vfMrBczELrFdWP0ZsfhWsRPaHppYdP3MVEMIVlqoFBw", + ); +} + +#[test] +fn test_verify_encoded_with_missing_dollar_before_salt_version10() { + let encoded = "$argon2i$m=65536,t=2,p=1c29tZXNhbHQ\ + $9sTbSlTio3Biev89thdrlKKiCaYsjjYVJxGAL3swxpQ"; + let password = b"password"; + let res = argon2::verify_encoded(encoded, password); + assert_eq!(res, Err(Error::DecodingFail)); +} + +#[test] +fn test_verify_encoded_with_missing_dollar_before_salt_version13() { + let encoded = "$argon2i$v=19$m=65536,t=2,p=1c29tZXNhbHQ\ + $wWKIMhR9lyDFvRz9YTZweHKfbftvj+qf+YFY4NeBbtA"; + let password = b"password"; + let res = argon2::verify_encoded(encoded, password); + assert_eq!(res, Err(Error::DecodingFail)); +} + +#[test] +fn test_verify_encoded_with_missing_dollar_before_hash_version10() { + let encoded = "$argon2i$m=65536,t=2,p=1$c29tZXNhbHQ\ + 9sTbSlTio3Biev89thdrlKKiCaYsjjYVJxGAL3swxpQ"; + let password = b"password"; + let res = argon2::verify_encoded(encoded, password); + assert_eq!(res, Err(Error::DecodingFail)); +} + +#[test] +fn test_verify_encoded_with_missing_dollar_before_hash_version13() { + let encoded = "$argon2i$v=19$m=65536,t=2,p=1$c29tZXNhbHQ\ + wWKIMhR9lyDFvRz9YTZweHKfbftvj+qf+YFY4NeBbtA"; + let password = b"password"; + let res = argon2::verify_encoded(encoded, password); + assert_eq!(res, Err(Error::DecodingFail)); +} + +#[test] +fn test_verify_encoded_with_too_short_salt_version10() { + let encoded = "$argon2i$m=65536,t=2,p=1$\ + $9sTbSlTio3Biev89thdrlKKiCaYsjjYVJxGAL3swxpQ"; + let password = b"password"; + let res = argon2::verify_encoded(encoded, password); + assert_eq!(res, Err(Error::SaltTooShort)); +} + +#[test] +fn test_verify_encoded_with_too_short_salt_version13() { + let encoded = "$argon2i$v=19$m=65536,t=2,p=1$\ + $9sTbSlTio3Biev89thdrlKKiCaYsjjYVJxGAL3swxpQ"; + let password = b"password"; + let res = argon2::verify_encoded(encoded, password); + assert_eq!(res, Err(Error::SaltTooShort)); +} + +#[cfg(not(debug_assertions))] +#[test] +fn test_verify_encoded_with_wrong_password_version10() { + let encoded = "$argon2i$m=65536,t=2,p=1$c29tZXNhbHQ\ + $b2G3seW+uPzerwQQC+/E1K50CLLO7YXy0JRcaTuswRo"; + let password = b"password"; // should be passwore + let res = argon2::verify_encoded(encoded, password); + assert_eq!(res, Ok(false)); +} + +#[cfg(not(debug_assertions))] +#[test] +fn test_verify_encoded_with_wrong_password_version13() { + let encoded = "$argon2i$v=19$m=65536,t=2,p=1$c29tZXNhbHQ\ + $8iIuixkI73Js3G1uMbezQXD0b8LG4SXGsOwoQkdAQIM"; + let password = b"password"; // should be passwore + let res = argon2::verify_encoded(encoded, password); + assert_eq!(res, Ok(false)); +} + +#[test] +fn test_encoded_len_returns_correct_length() { + assert_eq!(argon2::encoded_len(Variant::Argon2d, 256, 1, 1, 8, 32), 83); + assert_eq!(argon2::encoded_len(Variant::Argon2i, 4096, 10, 10, 8, 32), 86); + assert_eq!(argon2::encoded_len(Variant::Argon2id, 65536, 100, 10, 8, 32), 89); +} + +#[test] +fn test_hash_raw_with_not_enough_memory() { + let pwd = b"password"; + let salt = b"diffsalt"; + let config = Config { + variant: Variant::Argon2i, + version: Version::Version13, + mem_cost: 2, + time_cost: 2, + lanes: 1, + thread_mode: ThreadMode::Sequential, + secret: &[], + ad: &[], + hash_length: 32, + }; + let res = argon2::hash_raw(pwd, salt, &config); + assert_eq!(res, Err(Error::MemoryTooLittle)); +} + +#[test] +fn test_hash_raw_with_too_short_salt() { + let pwd = b"password"; + let salt = b"s"; + let config = Config { + variant: Variant::Argon2i, + version: Version::Version13, + mem_cost: 2048, + time_cost: 2, + lanes: 1, + thread_mode: ThreadMode::Sequential, + secret: &[], + ad: &[], + hash_length: 32, + }; + let res = argon2::hash_raw(pwd, salt, &config); + assert_eq!(res, Err(Error::SaltTooShort)); +} + +fn hash_test( + var: Variant, + ver: Version, + t: u32, + m: u32, + p: u32, + pwd: &[u8], + salt: &[u8], + hex: &str, + enc: &str, +) { + let config = Config { + variant: var, + version: ver, + mem_cost: m, + time_cost: t, + lanes: p, + thread_mode: ThreadMode::from_threads(p), + secret: &[], + ad: &[], + hash_length: 32, + }; + let hash = argon2::hash_raw(pwd, salt, &config).unwrap(); + let mut hex_str = String::new(); + let res = hash.write_hex(&mut hex_str); + assert_eq!(res, Ok(())); + assert_eq!(hex_str.as_str(), hex); + + let encoded = argon2::hash_encoded(pwd, salt, &config).unwrap(); + let result = argon2::verify_encoded(encoded.as_str(), pwd).unwrap(); + assert!(result); + + let result = argon2::verify_encoded(enc, pwd).unwrap(); + assert!(result); +} |