diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 12:41:41 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 12:41:41 +0000 |
commit | 10ee2acdd26a7f1298c6f6d6b7af9b469fe29b87 (patch) | |
tree | bdffd5d80c26cf4a7a518281a204be1ace85b4c1 /vendor/hkdf/src | |
parent | Releasing progress-linux version 1.70.0+dfsg1-9~progress7.99u1. (diff) | |
download | rustc-10ee2acdd26a7f1298c6f6d6b7af9b469fe29b87.tar.xz rustc-10ee2acdd26a7f1298c6f6d6b7af9b469fe29b87.zip |
Merging upstream version 1.70.0+dfsg2.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/hkdf/src')
-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 |
3 files changed, 406 insertions, 0 deletions
diff --git a/vendor/hkdf/src/errors.rs b/vendor/hkdf/src/errors.rs new file mode 100644 index 000000000..e2109b473 --- /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 000000000..ca05bf7a3 --- /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 000000000..5a2ec6214 --- /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()) + } +} |