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 subtle::ConstantTimeEq;
8use zeroize::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 in constant time
60    fn verify_tag(key: &[u8], data: &[u8], tag: &[u8]) -> Result<bool> {
61        let computed = Self::compute_tag(key, data)?;
62
63        if computed.as_ref().len() != tag.len() {
64            return Ok(false);
65        }
66
67        Ok(computed.as_ref().ct_eq(tag).into())
68    }
69}
70
71/// Operation for MAC operations
72pub trait MacBuilder<'a, M: Mac>: Sized {
73    /// Add data to the MAC computation
74    fn update(self, data: &'a [u8]) -> Result<Self>;
75
76    /// Process multiple data chunks
77    fn update_multi(self, data: &[&'a [u8]]) -> Result<Self>;
78
79    /// Finalize and return the MAC tag
80    fn finalize(self) -> Result<M::Tag>;
81
82    /// Verify against an expected tag
83    fn verify(self, expected: &'a [u8]) -> Result<bool>;
84}
85
86/// Generic MAC builder implementation
87pub struct GenericMacBuilder<'a, M: Mac> {
88    /// Reference to the MAC instance
89    mac: &'a mut M,
90}
91
92impl<'a, M: Mac> MacBuilder<'a, M> for GenericMacBuilder<'a, M> {
93    fn update(self, data: &'a [u8]) -> Result<Self> {
94        self.mac.update(data)?;
95        Ok(self)
96    }
97
98    fn update_multi(self, data: &[&'a [u8]]) -> Result<Self> {
99        for chunk in data {
100            self.mac.update(chunk)?;
101        }
102        Ok(self)
103    }
104
105    fn finalize(self) -> Result<M::Tag> {
106        self.mac.finalize()
107    }
108
109    fn verify(self, expected: &'a [u8]) -> Result<bool> {
110        let tag = self.mac.finalize()?;
111
112        if tag.as_ref().len() != expected.len() {
113            return Ok(false);
114        }
115
116        Ok(tag.as_ref().ct_eq(expected).into())
117    }
118}
119
120/// Extension trait for MAC implementations to provide builder methods
121pub trait MacExt: Mac {
122    /// Creates a builder for this MAC instance
123    fn builder(&mut self) -> GenericMacBuilder<'_, Self>;
124}
125
126impl<T: Mac> MacExt for T {
127    fn builder(&mut self) -> GenericMacBuilder<'_, Self> {
128        GenericMacBuilder { mac: self }
129    }
130}