summaryrefslogtreecommitdiffstats
path: root/third_party/rust/digest/src/mac.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/digest/src/mac.rs')
-rw-r--r--third_party/rust/digest/src/mac.rs305
1 files changed, 305 insertions, 0 deletions
diff --git a/third_party/rust/digest/src/mac.rs b/third_party/rust/digest/src/mac.rs
new file mode 100644
index 0000000000..1c31359ea3
--- /dev/null
+++ b/third_party/rust/digest/src/mac.rs
@@ -0,0 +1,305 @@
+use crate::{FixedOutput, FixedOutputReset, Update};
+use crypto_common::{InvalidLength, Key, KeyInit, Output, OutputSizeUser, Reset};
+
+#[cfg(feature = "rand_core")]
+use crate::rand_core::{CryptoRng, RngCore};
+use core::fmt;
+use crypto_common::typenum::Unsigned;
+use subtle::{Choice, ConstantTimeEq};
+
+/// Marker trait for Message Authentication algorithms.
+#[cfg_attr(docsrs, doc(cfg(feature = "mac")))]
+pub trait MacMarker {}
+
+/// Convenience wrapper trait covering functionality of Message Authentication algorithms.
+///
+/// This trait wraps [`KeyInit`], [`Update`], [`FixedOutput`], and [`MacMarker`]
+/// traits and provides additional convenience methods.
+#[cfg_attr(docsrs, doc(cfg(feature = "mac")))]
+pub trait Mac: OutputSizeUser + Sized {
+ /// Create new value from fixed size key.
+ fn new(key: &Key<Self>) -> Self
+ where
+ Self: KeyInit;
+
+ /// Generate random key using the provided [`CryptoRng`].
+ #[cfg(feature = "rand_core")]
+ #[cfg_attr(docsrs, doc(cfg(feature = "rand_core")))]
+ fn generate_key(rng: impl CryptoRng + RngCore) -> Key<Self>
+ where
+ Self: KeyInit;
+
+ /// Create new value from variable size key.
+ fn new_from_slice(key: &[u8]) -> Result<Self, InvalidLength>
+ where
+ Self: KeyInit;
+
+ /// Update state using the provided data.
+ fn update(&mut self, data: &[u8]);
+
+ /// Process input data in a chained manner.
+ #[must_use]
+ fn chain_update(self, data: impl AsRef<[u8]>) -> Self;
+
+ /// Obtain the result of a [`Mac`] computation as a [`CtOutput`] and consume
+ /// [`Mac`] instance.
+ fn finalize(self) -> CtOutput<Self>;
+
+ /// Obtain the result of a [`Mac`] computation as a [`CtOutput`] and reset
+ /// [`Mac`] instance.
+ fn finalize_reset(&mut self) -> CtOutput<Self>
+ where
+ Self: FixedOutputReset;
+
+ /// Reset MAC instance to its initial state.
+ fn reset(&mut self)
+ where
+ Self: Reset;
+
+ /// Check if tag/code value is correct for the processed input.
+ fn verify(self, tag: &Output<Self>) -> Result<(), MacError>;
+
+ /// Check if tag/code value is correct for the processed input and reset
+ /// [`Mac`] instance.
+ fn verify_reset(&mut self, tag: &Output<Self>) -> Result<(), MacError>
+ where
+ Self: FixedOutputReset;
+
+ /// Check truncated tag correctness using all bytes
+ /// of calculated tag.
+ ///
+ /// Returns `Error` if `tag` is not valid or not equal in length
+ /// to MAC's output.
+ fn verify_slice(self, tag: &[u8]) -> Result<(), MacError>;
+
+ /// Check truncated tag correctness using all bytes
+ /// of calculated tag and reset [`Mac`] instance.
+ ///
+ /// Returns `Error` if `tag` is not valid or not equal in length
+ /// to MAC's output.
+ fn verify_slice_reset(&mut self, tag: &[u8]) -> Result<(), MacError>
+ where
+ Self: FixedOutputReset;
+
+ /// Check truncated tag correctness using left side bytes
+ /// (i.e. `tag[..n]`) of calculated tag.
+ ///
+ /// Returns `Error` if `tag` is not valid or empty.
+ fn verify_truncated_left(self, tag: &[u8]) -> Result<(), MacError>;
+
+ /// Check truncated tag correctness using right side bytes
+ /// (i.e. `tag[n..]`) of calculated tag.
+ ///
+ /// Returns `Error` if `tag` is not valid or empty.
+ fn verify_truncated_right(self, tag: &[u8]) -> Result<(), MacError>;
+}
+
+impl<T: Update + FixedOutput + MacMarker> Mac for T {
+ #[inline(always)]
+ fn new(key: &Key<Self>) -> Self
+ where
+ Self: KeyInit,
+ {
+ KeyInit::new(key)
+ }
+
+ #[inline(always)]
+ fn new_from_slice(key: &[u8]) -> Result<Self, InvalidLength>
+ where
+ Self: KeyInit,
+ {
+ KeyInit::new_from_slice(key)
+ }
+
+ #[inline]
+ fn update(&mut self, data: &[u8]) {
+ Update::update(self, data);
+ }
+
+ #[inline]
+ fn chain_update(mut self, data: impl AsRef<[u8]>) -> Self {
+ Update::update(&mut self, data.as_ref());
+ self
+ }
+
+ #[inline]
+ fn finalize(self) -> CtOutput<Self> {
+ CtOutput::new(self.finalize_fixed())
+ }
+
+ #[inline(always)]
+ fn finalize_reset(&mut self) -> CtOutput<Self>
+ where
+ Self: FixedOutputReset,
+ {
+ CtOutput::new(self.finalize_fixed_reset())
+ }
+
+ #[inline]
+ fn reset(&mut self)
+ where
+ Self: Reset,
+ {
+ Reset::reset(self)
+ }
+
+ #[inline]
+ fn verify(self, tag: &Output<Self>) -> Result<(), MacError> {
+ if self.finalize() == tag.into() {
+ Ok(())
+ } else {
+ Err(MacError)
+ }
+ }
+
+ #[inline]
+ fn verify_reset(&mut self, tag: &Output<Self>) -> Result<(), MacError>
+ where
+ Self: FixedOutputReset,
+ {
+ if self.finalize_reset() == tag.into() {
+ Ok(())
+ } else {
+ Err(MacError)
+ }
+ }
+
+ #[inline]
+ fn verify_slice(self, tag: &[u8]) -> Result<(), MacError> {
+ let n = tag.len();
+ if n != Self::OutputSize::USIZE {
+ return Err(MacError);
+ }
+ let choice = self.finalize_fixed().ct_eq(tag);
+ if choice.into() {
+ Ok(())
+ } else {
+ Err(MacError)
+ }
+ }
+
+ #[inline]
+ fn verify_slice_reset(&mut self, tag: &[u8]) -> Result<(), MacError>
+ where
+ Self: FixedOutputReset,
+ {
+ let n = tag.len();
+ if n != Self::OutputSize::USIZE {
+ return Err(MacError);
+ }
+ let choice = self.finalize_fixed_reset().ct_eq(tag);
+ if choice.into() {
+ Ok(())
+ } else {
+ Err(MacError)
+ }
+ }
+
+ fn verify_truncated_left(self, tag: &[u8]) -> Result<(), MacError> {
+ let n = tag.len();
+ if n == 0 || n > Self::OutputSize::USIZE {
+ return Err(MacError);
+ }
+ let choice = self.finalize_fixed()[..n].ct_eq(tag);
+
+ if choice.into() {
+ Ok(())
+ } else {
+ Err(MacError)
+ }
+ }
+
+ fn verify_truncated_right(self, tag: &[u8]) -> Result<(), MacError> {
+ let n = tag.len();
+ if n == 0 || n > Self::OutputSize::USIZE {
+ return Err(MacError);
+ }
+ let m = Self::OutputSize::USIZE - n;
+ let choice = self.finalize_fixed()[m..].ct_eq(tag);
+
+ if choice.into() {
+ Ok(())
+ } else {
+ Err(MacError)
+ }
+ }
+
+ #[cfg(feature = "rand_core")]
+ #[cfg_attr(docsrs, doc(cfg(feature = "rand_core")))]
+ #[inline]
+ fn generate_key(rng: impl CryptoRng + RngCore) -> Key<Self>
+ where
+ Self: KeyInit,
+ {
+ <T as KeyInit>::generate_key(rng)
+ }
+}
+
+/// Fixed size output value which provides a safe [`Eq`] implementation that
+/// runs in constant time.
+///
+/// It is useful for implementing Message Authentication Codes (MACs).
+#[derive(Clone)]
+#[cfg_attr(docsrs, doc(cfg(feature = "mac")))]
+pub struct CtOutput<T: OutputSizeUser> {
+ bytes: Output<T>,
+}
+
+impl<T: OutputSizeUser> CtOutput<T> {
+ /// Create a new [`CtOutput`] value.
+ #[inline(always)]
+ pub fn new(bytes: Output<T>) -> Self {
+ Self { bytes }
+ }
+
+ /// Get the inner [`Output`] array this type wraps.
+ #[inline(always)]
+ pub fn into_bytes(self) -> Output<T> {
+ self.bytes
+ }
+}
+
+impl<T: OutputSizeUser> From<Output<T>> for CtOutput<T> {
+ #[inline(always)]
+ fn from(bytes: Output<T>) -> Self {
+ Self { bytes }
+ }
+}
+
+impl<'a, T: OutputSizeUser> From<&'a Output<T>> for CtOutput<T> {
+ #[inline(always)]
+ fn from(bytes: &'a Output<T>) -> Self {
+ bytes.clone().into()
+ }
+}
+
+impl<T: OutputSizeUser> ConstantTimeEq for CtOutput<T> {
+ #[inline(always)]
+ fn ct_eq(&self, other: &Self) -> Choice {
+ self.bytes.ct_eq(&other.bytes)
+ }
+}
+
+impl<T: OutputSizeUser> PartialEq for CtOutput<T> {
+ #[inline(always)]
+ fn eq(&self, x: &CtOutput<T>) -> bool {
+ self.ct_eq(x).into()
+ }
+}
+
+impl<T: OutputSizeUser> Eq for CtOutput<T> {}
+
+/// Error type for when the [`Output`] of a [`Mac`]
+/// is not equal to the expected value.
+#[derive(Default, Debug, Copy, Clone, Eq, PartialEq)]
+#[cfg_attr(docsrs, doc(cfg(feature = "mac")))]
+pub struct MacError;
+
+impl fmt::Display for MacError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.write_str("MAC tag mismatch")
+ }
+}
+
+#[cfg(feature = "std")]
+impl std::error::Error for MacError {}