Skip to main content

dcrypt_algorithms/mac/
mod.rs

1//! Message Authentication Code (MAC) implementations with type-safe interfaces
2//!
3//! This module contains implementations of various Message Authentication Codes (MACs)
4//! used throughout the dcrypt library, with improved type safety and ergonomic APIs.
5
6use crate::error::Result;
7use dcrypt_internal::constant_time::ConstantTimeEq;
8use dcrypt_internal::zeroing::Zeroize;
9
10pub mod hmac;
11pub mod poly1305;
12
13// Re-exports
14pub use hmac::Hmac;
15pub use poly1305::{Poly1305, POLY1305_KEY_SIZE, POLY1305_TAG_SIZE};
16
17/// Marker trait for MAC algorithms with algorithm-specific constants
18pub trait MacAlgorithm {
19    /// Key size in bytes
20    const KEY_SIZE: usize;
21
22    /// Tag size in bytes
23    const TAG_SIZE: usize;
24
25    /// Block size in bytes (if applicable)
26    const BLOCK_SIZE: usize;
27
28    /// Algorithm name
29    fn name() -> &'static str;
30}
31
32/// Trait for Message Authentication Code (MAC) algorithms
33pub trait Mac: Sized {
34    /// Key type with appropriate algorithm binding
35    type Key: AsRef<[u8]> + AsMut<[u8]> + Clone + Zeroize;
36
37    /// Tag output type with appropriate size constraint
38    type Tag: AsRef<[u8]> + AsMut<[u8]> + Clone;
39
40    /// Creates a new MAC instance with the given key
41    fn new(key: &[u8]) -> Result<Self>;
42
43    /// Updates the MAC state with data, returning self for method chaining
44    fn update(&mut self, data: &[u8]) -> Result<&mut Self>;
45
46    /// Finalizes and returns the MAC tag
47    fn finalize(&mut self) -> Result<Self::Tag>;
48
49    /// Reset the MAC state for reuse
50    fn reset(&mut self) -> Result<()>;
51
52    /// One-shot MAC computation
53    fn compute_tag(key: &[u8], data: &[u8]) -> Result<Self::Tag> {
54        let mut mac = Self::new(key)?;
55        mac.update(data)?;
56        mac.finalize()
57    }
58
59    /// Verify a MAC tag with equal-length byte comparison that avoids early exit.
60    ///
61    /// Public lengths and errors use ordinary control flow; this is not a
62    /// whole-operation constant-time guarantee. This reusable-key trait must
63    /// not be implemented by one-time authenticators such as Poly1305.
64    fn verify_tag(key: &[u8], data: &[u8], tag: &[u8]) -> Result<bool> {
65        let computed = Self::compute_tag(key, data)?;
66
67        if computed.as_ref().len() != tag.len() {
68            return Ok(false);
69        }
70
71        Ok(computed.as_ref().ct_eq(tag).into())
72    }
73}
74
75/// Operation for MAC operations
76pub trait MacBuilder<'a, M: Mac>: Sized {
77    /// Add data to the MAC computation
78    fn update(self, data: &'a [u8]) -> Result<Self>;
79
80    /// Process multiple data chunks
81    fn update_multi(self, data: &[&'a [u8]]) -> Result<Self>;
82
83    /// Finalize and return the MAC tag
84    fn finalize(self) -> Result<M::Tag>;
85
86    /// Verify against an expected tag
87    fn verify(self, expected: &'a [u8]) -> Result<bool>;
88}
89
90/// Generic MAC builder implementation
91pub struct GenericMacBuilder<'a, M: Mac> {
92    /// Reference to the MAC instance
93    mac: &'a mut M,
94}
95
96impl<'a, M: Mac> MacBuilder<'a, M> for GenericMacBuilder<'a, M> {
97    fn update(self, data: &'a [u8]) -> Result<Self> {
98        self.mac.update(data)?;
99        Ok(self)
100    }
101
102    fn update_multi(self, data: &[&'a [u8]]) -> Result<Self> {
103        for chunk in data {
104            self.mac.update(chunk)?;
105        }
106        Ok(self)
107    }
108
109    fn finalize(self) -> Result<M::Tag> {
110        self.mac.finalize()
111    }
112
113    fn verify(self, expected: &'a [u8]) -> Result<bool> {
114        let tag = self.mac.finalize()?;
115
116        if tag.as_ref().len() != expected.len() {
117            return Ok(false);
118        }
119
120        Ok(tag.as_ref().ct_eq(expected).into())
121    }
122}
123
124/// Extension trait for reusable-key MAC implementations to provide builders.
125pub trait MacExt: Mac {
126    /// Creates a builder for this MAC instance
127    fn builder(&mut self) -> GenericMacBuilder<'_, Self>;
128}
129
130impl<T: Mac> MacExt for T {
131    fn builder(&mut self) -> GenericMacBuilder<'_, Self> {
132        GenericMacBuilder { mac: self }
133    }
134}