diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 12:47:55 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 12:47:55 +0000 |
commit | 2aadc03ef15cb5ca5cc2af8a7c08e070742f0ac4 (patch) | |
tree | 033cc839730fda84ff08db877037977be94e5e3a /vendor/hkdf | |
parent | Initial commit. (diff) | |
download | cargo-2aadc03ef15cb5ca5cc2af8a7c08e070742f0ac4.tar.xz cargo-2aadc03ef15cb5ca5cc2af8a7c08e070742f0ac4.zip |
Adding upstream version 0.70.1+ds1.upstream/0.70.1+ds1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/hkdf')
-rw-r--r-- | vendor/hkdf/.cargo-checksum.json | 1 | ||||
-rw-r--r-- | vendor/hkdf/CHANGELOG.md | 115 | ||||
-rw-r--r-- | vendor/hkdf/Cargo.toml | 44 | ||||
-rw-r--r-- | vendor/hkdf/LICENSE-APACHE | 201 | ||||
-rw-r--r-- | vendor/hkdf/LICENSE-MIT | 26 | ||||
-rw-r--r-- | vendor/hkdf/README.md | 85 | ||||
-rw-r--r-- | vendor/hkdf/benches/mod.rs | 27 | ||||
-rw-r--r-- | vendor/hkdf/debian/patches/relax-dep.diff | 12 | ||||
-rw-r--r-- | vendor/hkdf/debian/patches/series | 1 | ||||
-rw-r--r-- | vendor/hkdf/src/errors.rs | 29 | ||||
-rw-r--r-- | vendor/hkdf/src/lib.rs | 280 | ||||
-rw-r--r-- | vendor/hkdf/src/sealed.rs | 97 | ||||
-rw-r--r-- | vendor/hkdf/tests/data/wycheproof-sha1.blb | bin | 0 -> 23773 bytes | |||
-rw-r--r-- | vendor/hkdf/tests/data/wycheproof-sha256.blb | bin | 0 -> 33115 bytes | |||
-rw-r--r-- | vendor/hkdf/tests/data/wycheproof-sha384.blb | bin | 0 -> 45304 bytes | |||
-rw-r--r-- | vendor/hkdf/tests/data/wycheproof-sha512.blb | bin | 0 -> 57877 bytes | |||
-rw-r--r-- | vendor/hkdf/tests/tests.rs | 448 |
17 files changed, 1366 insertions, 0 deletions
diff --git a/vendor/hkdf/.cargo-checksum.json b/vendor/hkdf/.cargo-checksum.json new file mode 100644 index 0000000..904e86c --- /dev/null +++ b/vendor/hkdf/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"791a029f6b9fc27657f6f188ec6e5e43f6911f6f878e0dc5501396e09809d437"}
\ No newline at end of file diff --git a/vendor/hkdf/CHANGELOG.md b/vendor/hkdf/CHANGELOG.md new file mode 100644 index 0000000..4e8c321 --- /dev/null +++ b/vendor/hkdf/CHANGELOG.md @@ -0,0 +1,115 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## 0.12.3 (2022-02-17) +### Fixed +- Minimal versions build ([#63]) + +[#63]: https://github.com/RustCrypto/KDFs/pull/63 + +## 0.12.2 (2022-01-27) +### Fixed +- Re-export `InvalidLength` and `InvalidPrkLength` ([#59]) + +[#59]: https://github.com/RustCrypto/KDFs/pull/59 + +## 0.12.1 (2022-01-27) [YANKED] +### Added +- Ability to switch HMAC implementation to `SimpleHmac` with respective `SimpleHkdfExtract` and `SimpleHkdf` aliases ([#57]) + +[#57]: https://github.com/RustCrypto/KDFs/pull/55 + +## 0.12.0 (2021-12-07) +### Changed +- Bump `hmac` crate dependency to v0.12 and `digest` to v0.10 ([#52]) + +[#52]: https://github.com/RustCrypto/KDFs/pull/52 + +## 0.11.0 (2021-04-29) +### Added +- Wycheproof HKDF test vectors ([#49]) + +### Changed +- Bump `hmac` crate dependency to v0.11 ([#50]) + +### Fixed +- HKDF-Extract with empty salt ([#46]) + +[#46]: https://github.com/RustCrypto/KDFs/pull/46 +[#49]: https://github.com/RustCrypto/KDFs/pull/49 +[#50]: https://github.com/RustCrypto/KDFs/pull/50 + +## 0.10.0 (2020-10-26) +### Changed +- Bump `hmac` dependency to v0.10 ([#40]) + +[#40]: https://github.com/RustCrypto/KDFs/pull/40 + +## 0.9.0 (2020-06-22) +### Added +- Multipart features for HKDF-Extract and HKDF-Expand ([#34]) + +### Changed +- Bump `digest` v0.9; `hmac` v0.9 ([#35]) + +[#34]: https://github.com/RustCrypto/KDFs/pull/34 +[#35]: https://github.com/RustCrypto/KDFs/pull/35 + +## 0.8.0 (2019-07-26) +### Added +- `Hkdf::from_prk()`, `Hkdf::extract()` + +## 0.7.1 (2019-07-15) + +## 0.7.0 (2018-10-16) +### Changed +- Update digest to 0.8 +- Refactor for API changes + +### Removed +- Redundant `generic-array` crate. + +## 0.6.0 (2018-08-20) +### Changed +- The `expand` signature has changed. + +### Removed +- `std` requirement + +## 0.5.0 (2018-05-20) +### Fixed +- Omitting HKDF salt. + +### Removed +- Deprecated interface + +## 0.4.0 (2018-03-20 +### Added +- Benchmarks +- derive `Clone` + +### Changed +- RFC-inspired interface +- Reduce heap allocation +- Bump deps: hex-0.3 + +### Removed +- Unnecessary mut + +## 0.3.0 (2017-11-29) +### Changed +- update dependencies: digest-0.7, hmac-0.5 + +## 0.2.0 (2017-09-21) +### Fixed +- Support for rustc 1.20.0 + +## 0.1.2 (2017-09-21) +### Fixed +- Support for rustc 1.5.0 + +## 0.1.0 (2017-09-21) +- Initial release diff --git a/vendor/hkdf/Cargo.toml b/vendor/hkdf/Cargo.toml new file mode 100644 index 0000000..acefe87 --- /dev/null +++ b/vendor/hkdf/Cargo.toml @@ -0,0 +1,44 @@ +# 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 are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2018" +name = "hkdf" +version = "0.12.3" +authors = ["RustCrypto Developers"] +description = "HMAC-based Extract-and-Expand Key Derivation Function (HKDF)" +homepage = "https://github.com/RustCrypto/KDFs/" +readme = "README.md" +keywords = ["crypto", "HKDF", "KDF"] +categories = ["cryptography", "no-std"] +license = "MIT OR Apache-2.0" +repository = "https://github.com/RustCrypto/KDFs/" +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] +[dependencies.hmac] +version = "0.12.1" +[dev-dependencies.blobby] +version = "0.3" + +[dev-dependencies.hex-literal] +version = "0.3" + +[dev-dependencies.sha1] +version = "0.10" +default-features = false + +[dev-dependencies.sha2] +version = "0.10" +default-features = false + +[features] +std = ["hmac/std"] diff --git a/vendor/hkdf/LICENSE-APACHE b/vendor/hkdf/LICENSE-APACHE new file mode 100644 index 0000000..53b7ccd --- /dev/null +++ b/vendor/hkdf/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.
\ No newline at end of file diff --git a/vendor/hkdf/LICENSE-MIT b/vendor/hkdf/LICENSE-MIT new file mode 100644 index 0000000..c0d0781 --- /dev/null +++ b/vendor/hkdf/LICENSE-MIT @@ -0,0 +1,26 @@ +Copyright (c) 2015-2018 Vlad Filippov +Copyright (c) 2018-2021 RustCrypto Developers + +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/vendor/hkdf/README.md b/vendor/hkdf/README.md new file mode 100644 index 0000000..76efd86 --- /dev/null +++ b/vendor/hkdf/README.md @@ -0,0 +1,85 @@ +# RustCrypto: HKDF + +[![crate][crate-image]][crate-link] +[![Docs][docs-image]][docs-link] +![Apache2/MIT licensed][license-image] +![Rust Version][rustc-image] +[![Project Chat][chat-image]][chat-link] +[![Build Status][build-image]][build-link] + +Pure Rust implementation of the [HMAC-based Extract-and-Expand Key Derivation Function (HKDF)](https://tools.ietf.org/html/rfc5869) generic over hash function. + +# Usage + +The most common way to use HKDF is as follows: you provide the Initial Key Material (IKM) and an optional salt, then you expand it (perhaps multiple times) into some Output Key Material (OKM) bound to an "info" context string. + +```rust +use sha2::Sha256; +use hkdf::Hkdf; +use hex_literal::hex; + +let ikm = hex!("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"); +let salt = hex!("000102030405060708090a0b0c"); +let info = hex!("f0f1f2f3f4f5f6f7f8f9"); + +let hk = Hkdf::<Sha256>::new(Some(&salt[..]), &ikm); +let mut okm = [0u8; 42]; +hk.expand(&info, &mut okm) + .expect("42 is a valid length for Sha256 to output"); + +let expected = hex!(" + 3cb25f25faacd57a90434f64d0362f2a + 2d2d0a90cf1a5a4c5db02d56ecc4c5bf + 34007208d5b887185865 +"); +assert_eq!(okm, expected); +``` + +Normally the PRK (Pseudo-Random Key) remains hidden within the HKDF object, but if you need to access it, use `Hkdf::extract` instead of `Hkdf::new`. + +```rust +let (prk, hk) = Hkdf::<Sha256>::extract(Some(&salt[..]), &ikm); +let expected = hex!(" + 077709362c2e32df0ddc3f0dc47bba63 + 90b6c73bb50f9c3122ec844ad7c2b3e5 +"); +assert_eq!(prk[..], expected[..]); +``` + +If you already have a strong key to work from (uniformly-distributed and +long enough), you can save a tiny amount of time by skipping the extract +step. In this case, you pass a Pseudo-Random Key (PRK) into the +`Hkdf::from_prk` constructor, then use the resulting `Hkdf` object +as usual. + +```rust +let prk = hex!(" + 077709362c2e32df0ddc3f0dc47bba63 + 90b6c73bb50f9c3122ec844ad7c2b3e5 +"); + +let hk = Hkdf::<Sha256>::from_prk(&prk).expect("PRK should be large enough"); +let mut okm = [0u8; 42]; +hk.expand(&info, &mut okm) + .expect("42 is a valid length for Sha256 to output"); + +let expected = hex!(" + 3cb25f25faacd57a90434f64d0362f2a + 2d2d0a90cf1a5a4c5db02d56ecc4c5bf + 34007208d5b887185865 +"); +assert_eq!(okm, expected); +``` + +[//]: # (badges) + +[crate-image]: https://img.shields.io/crates/v/hkdf.svg +[crate-link]: https://crates.io/crates/hkdf +[docs-image]: https://docs.rs/hkdf/badge.svg +[docs-link]: https://docs.rs/hkdf/ +[license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg +[rustc-image]: https://img.shields.io/badge/rustc-1.41+-blue.svg +[chat-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg +[chat-link]: https://rustcrypto.zulipchat.com/#narrow/stream/260043-KDFs +[build-image]: https://github.com/RustCrypto/KDFs/workflows/hkdf/badge.svg?branch=master&event=push +[build-link]: https://github.com/RustCrypto/KDFs/actions?query=workflow:hkdf diff --git a/vendor/hkdf/benches/mod.rs b/vendor/hkdf/benches/mod.rs new file mode 100644 index 0000000..4679b59 --- /dev/null +++ b/vendor/hkdf/benches/mod.rs @@ -0,0 +1,27 @@ +#![feature(test)] +extern crate test; + +use test::Bencher; + +type HkdfSha256 = hkdf::Hkdf<sha2::Sha256>; + +#[bench] +fn hkdf_sha256_10(b: &mut Bencher) { + let mut okm = vec![0u8; 10]; + b.iter(|| HkdfSha256::new(Some(&[]), &[]).expand(&[], &mut okm)); + b.bytes = okm.len() as u64; +} + +#[bench] +fn hkdf_sha256_1024(b: &mut Bencher) { + let mut okm = vec![0u8; 1024]; + b.iter(|| HkdfSha256::new(Some(&[]), &[]).expand(&[], &mut okm)); + b.bytes = okm.len() as u64; +} + +#[bench] +fn hkdf_sha256_8000(b: &mut Bencher) { + let mut okm = vec![0u8; 8000]; + b.iter(|| HkdfSha256::new(Some(&[]), &[]).expand(&[], &mut okm)); + b.bytes = okm.len() as u64; +} diff --git a/vendor/hkdf/debian/patches/relax-dep.diff b/vendor/hkdf/debian/patches/relax-dep.diff new file mode 100644 index 0000000..5f39ca0 --- /dev/null +++ b/vendor/hkdf/debian/patches/relax-dep.diff @@ -0,0 +1,12 @@ +--- hmac.orig/Cargo.toml ++++ hmac/Cargo.toml +@@ -34,3 +34,3 @@ + [dev-dependencies.hex-literal] +-version = "0.2.2" ++version = "0.3" + +@@ -40,3 +40,3 @@ + +-[dev-dependencies.sha-1] ++[dev-dependencies.sha1] + version = "0.10" diff --git a/vendor/hkdf/debian/patches/series b/vendor/hkdf/debian/patches/series new file mode 100644 index 0000000..75abb7f --- /dev/null +++ b/vendor/hkdf/debian/patches/series @@ -0,0 +1 @@ +relax-dep.diff diff --git a/vendor/hkdf/src/errors.rs b/vendor/hkdf/src/errors.rs new file mode 100644 index 0000000..e2109b4 --- /dev/null +++ b/vendor/hkdf/src/errors.rs @@ -0,0 +1,29 @@ +use core::fmt; + +/// Error that is returned when supplied pseudorandom key (PRK) is not long enough. +#[derive(Copy, Clone, Debug)] +pub struct InvalidPrkLength; + +impl fmt::Display for InvalidPrkLength { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + f.write_str("invalid pseudorandom key length, too short") + } +} + +#[cfg(feature = "std")] +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] +impl ::std::error::Error for InvalidPrkLength {} + +/// Structure for InvalidLength, used for output error handling. +#[derive(Copy, Clone, Debug)] +pub struct InvalidLength; + +impl fmt::Display for InvalidLength { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + f.write_str("invalid number of blocks, too large output") + } +} + +#[cfg(feature = "std")] +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] +impl ::std::error::Error for InvalidLength {} diff --git a/vendor/hkdf/src/lib.rs b/vendor/hkdf/src/lib.rs new file mode 100644 index 0000000..ca05bf7 --- /dev/null +++ b/vendor/hkdf/src/lib.rs @@ -0,0 +1,280 @@ +//! An implementation of HKDF, the [HMAC-based Extract-and-Expand Key Derivation Function][1]. +//! +//! # Usage +//! +//! The most common way to use HKDF is as follows: you provide the Initial Key +//! Material (IKM) and an optional salt, then you expand it (perhaps multiple times) +//! into some Output Key Material (OKM) bound to an "info" context string. +//! +//! ```rust +//! use sha2::Sha256; +//! use hkdf::Hkdf; +//! use hex_literal::hex; +//! +//! let ikm = hex!("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"); +//! let salt = hex!("000102030405060708090a0b0c"); +//! let info = hex!("f0f1f2f3f4f5f6f7f8f9"); +//! +//! let hk = Hkdf::<Sha256>::new(Some(&salt[..]), &ikm); +//! let mut okm = [0u8; 42]; +//! hk.expand(&info, &mut okm) +//! .expect("42 is a valid length for Sha256 to output"); +//! +//! let expected = hex!(" +//! 3cb25f25faacd57a90434f64d0362f2a +//! 2d2d0a90cf1a5a4c5db02d56ecc4c5bf +//! 34007208d5b887185865 +//! "); +//! assert_eq!(okm[..], expected[..]); +//! ``` +//! +//! Normally the PRK (Pseudo-Random Key) remains hidden within the HKDF +//! object, but if you need to access it, use [`Hkdf::extract`] instead of +//! [`Hkdf::new`]. +//! +//! ```rust +//! # use sha2::Sha256; +//! # use hkdf::Hkdf; +//! # use hex_literal::hex; +//! # let ikm = hex!("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"); +//! # let salt = hex!("000102030405060708090a0b0c"); +//! +//! let (prk, hk) = Hkdf::<Sha256>::extract(Some(&salt[..]), &ikm); +//! let expected = hex!(" +//! 077709362c2e32df0ddc3f0dc47bba63 +//! 90b6c73bb50f9c3122ec844ad7c2b3e5 +//! "); +//! assert_eq!(prk[..], expected[..]); +//! ``` +//! +//! If you already have a strong key to work from (uniformly-distributed and +//! long enough), you can save a tiny amount of time by skipping the extract +//! step. In this case, you pass a Pseudo-Random Key (PRK) into the +//! [`Hkdf::from_prk`] constructor, then use the resulting [`Hkdf`] object +//! as usual. +//! +//! ```rust +//! # use sha2::Sha256; +//! # use hkdf::Hkdf; +//! # use hex_literal::hex; +//! # let salt = hex!("000102030405060708090a0b0c"); +//! # let info = hex!("f0f1f2f3f4f5f6f7f8f9"); +//! let prk = hex!(" +//! 077709362c2e32df0ddc3f0dc47bba63 +//! 90b6c73bb50f9c3122ec844ad7c2b3e5 +//! "); +//! +//! let hk = Hkdf::<Sha256>::from_prk(&prk).expect("PRK should be large enough"); +//! let mut okm = [0u8; 42]; +//! hk.expand(&info, &mut okm) +//! .expect("42 is a valid length for Sha256 to output"); +//! +//! let expected = hex!(" +//! 3cb25f25faacd57a90434f64d0362f2a +//! 2d2d0a90cf1a5a4c5db02d56ecc4c5bf +//! 34007208d5b887185865 +//! "); +//! assert_eq!(okm[..], expected[..]); +//! ``` +//! +//! [1]: https://tools.ietf.org/html/rfc5869 + +#![no_std] +#![doc( + html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg", + html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg", + html_root_url = "https://docs.rs/hkdf/0.12.3" +)] +#![cfg_attr(docsrs, feature(doc_cfg))] +#![forbid(unsafe_code)] +#![warn(missing_docs, rust_2018_idioms)] + +#[cfg(feature = "std")] +extern crate std; + +pub use hmac; + +use core::fmt; +use core::marker::PhantomData; +use hmac::digest::{ + crypto_common::AlgorithmName, generic_array::typenum::Unsigned, Output, OutputSizeUser, +}; +use hmac::{Hmac, SimpleHmac}; + +mod errors; +mod sealed; + +pub use errors::{InvalidLength, InvalidPrkLength}; + +/// [`HkdfExtract`] variant which uses [`SimpleHmac`] for underlying HMAC +/// implementation. +pub type SimpleHkdfExtract<H> = HkdfExtract<H, SimpleHmac<H>>; +/// [`Hkdf`] variant which uses [`SimpleHmac`] for underlying HMAC +/// implementation. +pub type SimpleHkdf<H> = Hkdf<H, SimpleHmac<H>>; + +/// Structure representing the streaming context of an HKDF-Extract operation +/// ```rust +/// # use hkdf::{Hkdf, HkdfExtract}; +/// # use sha2::Sha256; +/// let mut extract_ctx = HkdfExtract::<Sha256>::new(Some(b"mysalt")); +/// extract_ctx.input_ikm(b"hello"); +/// extract_ctx.input_ikm(b" world"); +/// let (streamed_res, _) = extract_ctx.finalize(); +/// +/// let (oneshot_res, _) = Hkdf::<Sha256>::extract(Some(b"mysalt"), b"hello world"); +/// assert_eq!(streamed_res, oneshot_res); +/// ``` +#[derive(Clone)] +pub struct HkdfExtract<H, I = Hmac<H>> +where + H: OutputSizeUser, + I: HmacImpl<H>, +{ + hmac: I, + _pd: PhantomData<H>, +} + +impl<H, I> HkdfExtract<H, I> +where + H: OutputSizeUser, + I: HmacImpl<H>, +{ + /// Initiates the HKDF-Extract context with the given optional salt + pub fn new(salt: Option<&[u8]>) -> Self { + let default_salt = Output::<H>::default(); + let salt = salt.unwrap_or(&default_salt); + Self { + hmac: I::new_from_slice(salt), + _pd: PhantomData, + } + } + + /// Feeds in additional input key material to the HKDF-Extract context + pub fn input_ikm(&mut self, ikm: &[u8]) { + self.hmac.update(ikm); + } + + /// Completes the HKDF-Extract operation, returning both the generated pseudorandom key and + /// `Hkdf` struct for expanding. + pub fn finalize(self) -> (Output<H>, Hkdf<H, I>) { + let prk = self.hmac.finalize(); + let hkdf = Hkdf::from_prk(&prk).expect("PRK size is correct"); + (prk, hkdf) + } +} + +impl<H, I> fmt::Debug for HkdfExtract<H, I> +where + H: OutputSizeUser + AlgorithmName, + I: HmacImpl<H>, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("HkdfExtract<")?; + <H as AlgorithmName>::write_alg_name(f)?; + f.write_str("> { ... }") + } +} + +/// Structure representing the HKDF, capable of HKDF-Expand and HKDF-Extract operations. +#[derive(Clone)] +pub struct Hkdf<H: OutputSizeUser, I: HmacImpl<H> = Hmac<H>> { + hmac: I::Core, + _pd: PhantomData<H>, +} + +impl<H: OutputSizeUser, I: HmacImpl<H>> Hkdf<H, I> { + /// Convenience method for [`extract`][Hkdf::extract] when the generated + /// pseudorandom key can be ignored and only HKDF-Expand operation is needed. This is the most + /// common constructor. + pub fn new(salt: Option<&[u8]>, ikm: &[u8]) -> Self { + let (_, hkdf) = Self::extract(salt, ikm); + hkdf + } + + /// Create `Hkdf` from an already cryptographically strong pseudorandom key + /// as per section 3.3 from RFC5869. + pub fn from_prk(prk: &[u8]) -> Result<Self, InvalidPrkLength> { + // section 2.3 specifies that prk must be "at least HashLen octets" + if prk.len() < <H as OutputSizeUser>::OutputSize::to_usize() { + return Err(InvalidPrkLength); + } + Ok(Self { + hmac: I::new_core(prk), + _pd: PhantomData, + }) + } + + /// The RFC5869 HKDF-Extract operation returning both the generated + /// pseudorandom key and `Hkdf` struct for expanding. + pub fn extract(salt: Option<&[u8]>, ikm: &[u8]) -> (Output<H>, Self) { + let mut extract_ctx = HkdfExtract::new(salt); + extract_ctx.input_ikm(ikm); + extract_ctx.finalize() + } + + /// The RFC5869 HKDF-Expand operation. This is equivalent to calling + /// [`expand`][Hkdf::extract] with the `info` argument set equal to the + /// concatenation of all the elements of `info_components`. + pub fn expand_multi_info( + &self, + info_components: &[&[u8]], + okm: &mut [u8], + ) -> Result<(), InvalidLength> { + let mut prev: Option<Output<H>> = None; + + let chunk_len = <H as OutputSizeUser>::OutputSize::USIZE; + if okm.len() > chunk_len * 255 { + return Err(InvalidLength); + } + + for (block_n, block) in okm.chunks_mut(chunk_len).enumerate() { + let mut hmac = I::from_core(&self.hmac); + + if let Some(ref prev) = prev { + hmac.update(prev) + }; + + // Feed in the info components in sequence. This is equivalent to feeding in the + // concatenation of all the info components + for info in info_components { + hmac.update(info); + } + + hmac.update(&[block_n as u8 + 1]); + + let output = hmac.finalize(); + + let block_len = block.len(); + block.copy_from_slice(&output[..block_len]); + + prev = Some(output); + } + + Ok(()) + } + + /// The RFC5869 HKDF-Expand operation + /// + /// If you don't have any `info` to pass, use an empty slice. + pub fn expand(&self, info: &[u8], okm: &mut [u8]) -> Result<(), InvalidLength> { + self.expand_multi_info(&[info], okm) + } +} + +impl<H, I> fmt::Debug for Hkdf<H, I> +where + H: OutputSizeUser + AlgorithmName, + I: HmacImpl<H>, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("Hkdf<")?; + <H as AlgorithmName>::write_alg_name(f)?; + f.write_str("> { ... }") + } +} + +/// Sealed trait implemented for [`Hmac`] and [`SimpleHmac`]. +pub trait HmacImpl<H: OutputSizeUser>: sealed::Sealed<H> {} + +impl<H: OutputSizeUser, T: sealed::Sealed<H>> HmacImpl<H> for T {} diff --git a/vendor/hkdf/src/sealed.rs b/vendor/hkdf/src/sealed.rs new file mode 100644 index 0000000..5a2ec62 --- /dev/null +++ b/vendor/hkdf/src/sealed.rs @@ -0,0 +1,97 @@ +use hmac::digest::{ + block_buffer::Eager, + core_api::{ + BlockSizeUser, BufferKindUser, CoreProxy, CoreWrapper, FixedOutputCore, OutputSizeUser, + UpdateCore, + }, + generic_array::typenum::{IsLess, Le, NonZero, U256}, + Digest, FixedOutput, HashMarker, KeyInit, Output, Update, +}; +use hmac::{Hmac, HmacCore, SimpleHmac}; + +pub trait Sealed<H: OutputSizeUser> { + type Core: Clone; + + fn new_from_slice(key: &[u8]) -> Self; + + fn new_core(key: &[u8]) -> Self::Core; + + fn from_core(core: &Self::Core) -> Self; + + fn update(&mut self, data: &[u8]); + + fn finalize(self) -> Output<H>; +} + +impl<H> Sealed<H> for Hmac<H> +where + H: CoreProxy + OutputSizeUser, + H::Core: HashMarker + + UpdateCore + + FixedOutputCore + + BufferKindUser<BufferKind = Eager> + + Default + + Clone, + <H::Core as BlockSizeUser>::BlockSize: IsLess<U256>, + Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero, +{ + type Core = HmacCore<H>; + + #[inline(always)] + fn new_from_slice(key: &[u8]) -> Self { + KeyInit::new_from_slice(key).expect("HMAC can take a key of any size") + } + + #[inline(always)] + fn new_core(key: &[u8]) -> Self::Core { + HmacCore::new_from_slice(key).expect("HMAC can take a key of any size") + } + + #[inline(always)] + fn from_core(core: &Self::Core) -> Self { + CoreWrapper::from_core(core.clone()) + } + + #[inline(always)] + fn update(&mut self, data: &[u8]) { + Update::update(self, data); + } + + #[inline(always)] + fn finalize(self) -> Output<H> { + // Output<H> and Output<H::Core> are always equal to each other, + // but we can not prove it at type level + Output::<H>::clone_from_slice(&self.finalize_fixed()) + } +} + +impl<H: Digest + BlockSizeUser + Clone> Sealed<H> for SimpleHmac<H> { + type Core = Self; + + #[inline(always)] + fn new_from_slice(key: &[u8]) -> Self { + KeyInit::new_from_slice(key).expect("HMAC can take a key of any size") + } + + #[inline(always)] + fn new_core(key: &[u8]) -> Self::Core { + KeyInit::new_from_slice(key).expect("HMAC can take a key of any size") + } + + #[inline(always)] + fn from_core(core: &Self::Core) -> Self { + core.clone() + } + + #[inline(always)] + fn update(&mut self, data: &[u8]) { + Update::update(self, data); + } + + #[inline(always)] + fn finalize(self) -> Output<H> { + // Output<H> and Output<H::Core> are always equal to each other, + // but we can not prove it at type level + Output::<H>::clone_from_slice(&self.finalize_fixed()) + } +} diff --git a/vendor/hkdf/tests/data/wycheproof-sha1.blb b/vendor/hkdf/tests/data/wycheproof-sha1.blb Binary files differnew file mode 100644 index 0000000..cb7dd3c --- /dev/null +++ b/vendor/hkdf/tests/data/wycheproof-sha1.blb diff --git a/vendor/hkdf/tests/data/wycheproof-sha256.blb b/vendor/hkdf/tests/data/wycheproof-sha256.blb Binary files differnew file mode 100644 index 0000000..6213609 --- /dev/null +++ b/vendor/hkdf/tests/data/wycheproof-sha256.blb diff --git a/vendor/hkdf/tests/data/wycheproof-sha384.blb b/vendor/hkdf/tests/data/wycheproof-sha384.blb Binary files differnew file mode 100644 index 0000000..2323055 --- /dev/null +++ b/vendor/hkdf/tests/data/wycheproof-sha384.blb diff --git a/vendor/hkdf/tests/data/wycheproof-sha512.blb b/vendor/hkdf/tests/data/wycheproof-sha512.blb Binary files differnew file mode 100644 index 0000000..7a75318 --- /dev/null +++ b/vendor/hkdf/tests/data/wycheproof-sha512.blb diff --git a/vendor/hkdf/tests/tests.rs b/vendor/hkdf/tests/tests.rs new file mode 100644 index 0000000..6893889 --- /dev/null +++ b/vendor/hkdf/tests/tests.rs @@ -0,0 +1,448 @@ +use core::iter; + +use hex_literal::hex; +use hkdf::{Hkdf, HkdfExtract, SimpleHkdf, SimpleHkdfExtract}; +use sha1::Sha1; +use sha2::{Sha256, Sha384, Sha512}; + +struct Test<'a> { + ikm: &'a [u8], + salt: &'a [u8], + info: &'a [u8], + prk: &'a [u8], + okm: &'a [u8], +} + +// Test Vectors from https://tools.ietf.org/html/rfc5869. +#[test] +#[rustfmt::skip] +fn test_rfc5869_sha256() { + let tests = [ + Test { + // Test Case 1 + ikm: &hex!("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"), + salt: &hex!("000102030405060708090a0b0c"), + info: &hex!("f0f1f2f3f4f5f6f7f8f9"), + prk: &hex!(" + 077709362c2e32df0ddc3f0dc47bba63 + 90b6c73bb50f9c3122ec844ad7c2b3e5 + "), + okm: &hex!(" + 3cb25f25faacd57a90434f64d0362f2a + 2d2d0a90cf1a5a4c5db02d56ecc4c5bf + 34007208d5b887185865 + "), + }, + Test { + // Test Case 2 + ikm: &hex!(" + 000102030405060708090a0b0c0d0e0f + 101112131415161718191a1b1c1d1e1f + 202122232425262728292a2b2c2d2e2f + 303132333435363738393a3b3c3d3e3f + 404142434445464748494a4b4c4d4e4f + "), + salt: &hex!(" + 606162636465666768696a6b6c6d6e6f + 707172737475767778797a7b7c7d7e7f + 808182838485868788898a8b8c8d8e8f + 909192939495969798999a9b9c9d9e9f + a0a1a2a3a4a5a6a7a8a9aaabacadaeaf + "), + info: &hex!(" + b0b1b2b3b4b5b6b7b8b9babbbcbdbebf + c0c1c2c3c4c5c6c7c8c9cacbcccdcecf + d0d1d2d3d4d5d6d7d8d9dadbdcdddedf + e0e1e2e3e4e5e6e7e8e9eaebecedeeef + f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff + "), + prk: &hex!(" + 06a6b88c5853361a06104c9ceb35b45c + ef760014904671014a193f40c15fc244 + "), + okm: &hex!(" + b11e398dc80327a1c8e7f78c596a4934 + 4f012eda2d4efad8a050cc4c19afa97c + 59045a99cac7827271cb41c65e590e09 + da3275600c2f09b8367793a9aca3db71 + cc30c58179ec3e87c14c01d5c1f3434f + 1d87 + "), + }, + Test { + // Test Case 3 + ikm: &hex!("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"), + salt: &hex!(""), + info: &hex!(""), + prk: &hex!(" + 19ef24a32c717b167f33a91d6f648bdf + 96596776afdb6377ac434c1c293ccb04 + "), + okm: &hex!(" + 8da4e775a563c18f715f802a063c5a31 + b8a11f5c5ee1879ec3454e5f3c738d2d + 9d201395faa4b61a96c8 + "), + }, + ]; + for Test { ikm, salt, info, prk, okm } in tests.iter() { + let salt = if salt.is_empty() { + None + } else { + Some(&salt[..]) + }; + let (prk2, hkdf) = Hkdf::<Sha256>::extract(salt, ikm); + let mut okm2 = vec![0u8; okm.len()]; + assert!(hkdf.expand(&info[..], &mut okm2).is_ok()); + + assert_eq!(prk2[..], prk[..]); + assert_eq!(okm2[..], okm[..]); + + okm2.iter_mut().for_each(|b| *b = 0); + let hkdf = Hkdf::<Sha256>::from_prk(prk).unwrap(); + assert!(hkdf.expand(&info[..], &mut okm2).is_ok()); + assert_eq!(okm2[..], okm[..]); + } +} + +#[test] +#[rustfmt::skip] +fn test_rfc5869_sha1() { + let tests = [ + Test { + // Test Case 4 + ikm: &hex!("0b0b0b0b0b0b0b0b0b0b0b"), + salt: &hex!("000102030405060708090a0b0c"), + info: &hex!("f0f1f2f3f4f5f6f7f8f9"), + prk: &hex!("9b6c18c432a7bf8f0e71c8eb88f4b30baa2ba243"), + okm: &hex!(" + 085a01ea1b10f36933068b56efa5ad81 + a4f14b822f5b091568a9cdd4f155fda2 + c22e422478d305f3f896 + "), + }, + Test { + // Test Case 5 + ikm: &hex!(" + 000102030405060708090a0b0c0d0e0f + 101112131415161718191a1b1c1d1e1f + 202122232425262728292a2b2c2d2e2f + 303132333435363738393a3b3c3d3e3f + 404142434445464748494a4b4c4d4e4f + "), + salt: &hex!(" + 606162636465666768696a6b6c6d6e6f + 707172737475767778797a7b7c7d7e7f + 808182838485868788898a8b8c8d8e8f + 909192939495969798999a9b9c9d9e9f + a0a1a2a3a4a5a6a7a8a9aaabacadaeaf + "), + info: &hex!(" + b0b1b2b3b4b5b6b7b8b9babbbcbdbebf + c0c1c2c3c4c5c6c7c8c9cacbcccdcecf + d0d1d2d3d4d5d6d7d8d9dadbdcdddedf + e0e1e2e3e4e5e6e7e8e9eaebecedeeef + f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff + "), + prk: &hex!("8adae09a2a307059478d309b26c4115a224cfaf6"), + okm: &hex!(" + 0bd770a74d1160f7c9f12cd5912a06eb + ff6adcae899d92191fe4305673ba2ffe + 8fa3f1a4e5ad79f3f334b3b202b2173c + 486ea37ce3d397ed034c7f9dfeb15c5e + 927336d0441f4c4300e2cff0d0900b52 + d3b4 + "), + }, + Test { + // Test Case 6 + ikm: &hex!("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"), + salt: &hex!(""), + info: &hex!(""), + prk: &hex!("da8c8a73c7fa77288ec6f5e7c297786aa0d32d01"), + okm: &hex!(" + 0ac1af7002b3d761d1e55298da9d0506 + b9ae52057220a306e07b6b87e8df21d0 + ea00033de03984d34918 + "), + }, + Test { + // Test Case 7 + ikm: &hex!("0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c"), + salt: &hex!(""), // "Not Provided" + info: &hex!(""), + prk: &hex!("2adccada18779e7c2077ad2eb19d3f3e731385dd"), + okm: &hex!(" + 2c91117204d745f3500d636a62f64f0a + b3bae548aa53d423b0d1f27ebba6f5e5 + 673a081d70cce7acfc48 + "), + }, + ]; + for Test { ikm, salt, info, prk, okm } in tests.iter() { + let salt = if salt.is_empty() { + None + } else { + Some(&salt[..]) + }; + let (prk2, hkdf) = Hkdf::<Sha1>::extract(salt, ikm); + let mut okm2 = vec![0u8; okm.len()]; + assert!(hkdf.expand(&info[..], &mut okm2).is_ok()); + + assert_eq!(prk2[..], prk[..]); + assert_eq!(okm2[..], okm[..]); + + okm2.iter_mut().for_each(|b| *b = 0); + let hkdf = Hkdf::<Sha1>::from_prk(prk).unwrap(); + assert!(hkdf.expand(&info[..], &mut okm2).is_ok()); + assert_eq!(okm2[..], okm[..]); + } +} + +const MAX_SHA256_LENGTH: usize = 255 * (256 / 8); // =8160 + +#[test] +fn test_lengths() { + let hkdf = Hkdf::<Sha256>::new(None, &[]); + let mut longest = vec![0u8; MAX_SHA256_LENGTH]; + assert!(hkdf.expand(&[], &mut longest).is_ok()); + // Runtime is O(length), so exhaustively testing all legal lengths + // would take too long (at least without --release). Only test a + // subset: the first 500, the last 10, and every 100th in between. + let lengths = (0..MAX_SHA256_LENGTH + 1) + .filter(|&len| len < 500 || len > MAX_SHA256_LENGTH - 10 || len % 100 == 0); + + for length in lengths { + let mut okm = vec![0u8; length]; + assert!(hkdf.expand(&[], &mut okm).is_ok()); + assert_eq!(okm.len(), length); + assert_eq!(okm[..], longest[..length]); + } +} + +#[test] +fn test_max_length() { + let hkdf = Hkdf::<Sha256>::new(Some(&[]), &[]); + let mut okm = vec![0u8; MAX_SHA256_LENGTH]; + assert!(hkdf.expand(&[], &mut okm).is_ok()); +} + +#[test] +fn test_max_length_exceeded() { + let hkdf = Hkdf::<Sha256>::new(Some(&[]), &[]); + let mut okm = vec![0u8; MAX_SHA256_LENGTH + 1]; + assert!(hkdf.expand(&[], &mut okm).is_err()); +} + +#[test] +fn test_unsupported_length() { + let hkdf = Hkdf::<Sha256>::new(Some(&[]), &[]); + let mut okm = vec![0u8; 90000]; + assert!(hkdf.expand(&[], &mut okm).is_err()); +} + +#[test] +fn test_prk_too_short() { + use sha2::digest::Digest; + + let output_len = Sha256::output_size(); + let prk = vec![0; output_len - 1]; + assert!(Hkdf::<Sha256>::from_prk(&prk).is_err()); +} + +#[test] +#[rustfmt::skip] +fn test_derive_sha1_with_none() { + let ikm = hex!("0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c"); + let salt = None; + let info = hex!(""); + let (prk, hkdf) = Hkdf::<Sha1>::extract(salt, &ikm[..]); + let mut okm = [0u8; 42]; + assert!(hkdf.expand(&info[..], &mut okm).is_ok()); + + assert_eq!( + prk[..], + hex!("2adccada18779e7c2077ad2eb19d3f3e731385dd")[..] + ); + assert_eq!( + okm[..], + hex!(" + 2c91117204d745f3500d636a62f64f0a + b3bae548aa53d423b0d1f27ebba6f5e5 + 673a081d70cce7acfc48 + ")[..], + ); +} + +#[test] +fn test_expand_multi_info() { + let info_components = &[ + &b"09090909090909090909090909090909090909090909"[..], + &b"8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a"[..], + &b"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0"[..], + &b"4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4"[..], + &b"1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d"[..], + ]; + + let (_, hkdf_ctx) = Hkdf::<Sha256>::extract(None, b"some ikm here"); + + // Compute HKDF-Expand on the concatenation of all the info components + let mut oneshot_res = [0u8; 16]; + hkdf_ctx + .expand(&info_components.concat(), &mut oneshot_res) + .unwrap(); + + // Now iteratively join the components of info_components until it's all 1 component. The value + // of HKDF-Expand should be the same throughout + let mut num_concatted = 0; + let mut info_head = Vec::new(); + + while num_concatted < info_components.len() { + info_head.extend(info_components[num_concatted]); + + // Build the new input to be the info head followed by the remaining components + let input: Vec<&[u8]> = iter::once(info_head.as_slice()) + .chain(info_components.iter().cloned().skip(num_concatted + 1)) + .collect(); + + // Compute and compare to the one-shot answer + let mut multipart_res = [0u8; 16]; + hkdf_ctx + .expand_multi_info(&input, &mut multipart_res) + .unwrap(); + assert_eq!(multipart_res, oneshot_res); + + num_concatted += 1; + } +} + +#[test] +fn test_extract_streaming() { + let ikm_components = &[ + &b"09090909090909090909090909090909090909090909"[..], + &b"8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a"[..], + &b"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0"[..], + &b"4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4"[..], + &b"1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d"[..], + ]; + let salt = b"mysalt"; + + // Compute HKDF-Extract on the concatenation of all the IKM components + let (oneshot_res, _) = Hkdf::<Sha256>::extract(Some(&salt[..]), &ikm_components.concat()); + + // Now iteratively join the components of ikm_components until it's all 1 component. The value + // of HKDF-Extract should be the same throughout + let mut num_concatted = 0; + let mut ikm_head = Vec::new(); + + while num_concatted < ikm_components.len() { + ikm_head.extend(ikm_components[num_concatted]); + + // Make a new extraction context and build the new input to be the IKM head followed by the + // remaining components + let mut extract_ctx = HkdfExtract::<Sha256>::new(Some(&salt[..])); + let input = iter::once(ikm_head.as_slice()) + .chain(ikm_components.iter().cloned().skip(num_concatted + 1)); + + // Stream in the IKM input in the chunks specified + for ikm in input { + extract_ctx.input_ikm(ikm); + } + + // Finalize and compare to the one-shot answer + let (multipart_res, _) = extract_ctx.finalize(); + assert_eq!(multipart_res, oneshot_res); + + num_concatted += 1; + } + + let mut num_concatted = 0; + let mut ikm_head = Vec::new(); + + while num_concatted < ikm_components.len() { + ikm_head.extend(ikm_components[num_concatted]); + + // Make a new extraction context and build the new input to be the IKM head followed by the + // remaining components + let mut extract_ctx = SimpleHkdfExtract::<Sha256>::new(Some(&salt[..])); + let input = iter::once(ikm_head.as_slice()) + .chain(ikm_components.iter().cloned().skip(num_concatted + 1)); + + // Stream in the IKM input in the chunks specified + for ikm in input { + extract_ctx.input_ikm(ikm); + } + + // Finalize and compare to the one-shot answer + let (multipart_res, _) = extract_ctx.finalize(); + assert_eq!(multipart_res, oneshot_res); + + num_concatted += 1; + } +} + +/// Define test +macro_rules! new_test { + ($name:ident, $test_name:expr, $hkdf:ty) => { + #[test] + fn $name() { + use blobby::Blob4Iterator; + + fn run_test(ikm: &[u8], salt: &[u8], info: &[u8], okm: &[u8]) -> Option<&'static str> { + let prk = <$hkdf>::new(Some(salt), ikm); + let mut got_okm = vec![0; okm.len()]; + + if prk.expand(info, &mut got_okm).is_err() { + return Some("prk expand"); + } + if got_okm != okm { + return Some("mismatch in okm"); + } + None + } + + let data = include_bytes!(concat!("data/", $test_name, ".blb")); + + for (i, row) in Blob4Iterator::new(data).unwrap().enumerate() { + let [ikm, salt, info, okm] = row.unwrap(); + if let Some(desc) = run_test(ikm, salt, info, okm) { + panic!( + "\n\ + Failed test №{}: {}\n\ + ikm:\t{:?}\n\ + salt:\t{:?}\n\ + info:\t{:?}\n\ + okm:\t{:?}\n", + i, desc, ikm, salt, info, okm + ); + } + } + } + }; +} + +new_test!(wycheproof_sha1, "wycheproof-sha1", Hkdf::<Sha1>); +new_test!(wycheproof_sha256, "wycheproof-sha256", Hkdf::<Sha256>); +new_test!(wycheproof_sha384, "wycheproof-sha384", Hkdf::<Sha384>); +new_test!(wycheproof_sha512, "wycheproof-sha512", Hkdf::<Sha512>); + +new_test!( + wycheproof_sha1_simple, + "wycheproof-sha1", + SimpleHkdf::<Sha1> +); +new_test!( + wycheproof_sha256_simple, + "wycheproof-sha256", + SimpleHkdf::<Sha256> +); +new_test!( + wycheproof_sha384_simple, + "wycheproof-sha384", + SimpleHkdf::<Sha384> +); +new_test!( + wycheproof_sha512_simple, + "wycheproof-sha512", + SimpleHkdf::<Sha512> +); |