| 1 | use alloc::boxed::Box; |
| 2 | |
| 3 | use zeroize::Zeroize; |
| 4 | |
| 5 | /// A concrete HMAC implementation, for a single cryptographic hash function. |
| 6 | /// |
| 7 | /// You should have one object that implements this trait for HMAC-SHA256, another |
| 8 | /// for HMAC-SHA384, etc. |
| 9 | pub trait Hmac: Send + Sync { |
| 10 | /// Prepare to use `key` as a HMAC key. |
| 11 | fn with_key(&self, key: &[u8]) -> Box<dyn Key>; |
| 12 | |
| 13 | /// Give the length of the underlying hash function. In RFC2104 terminology this is `L`. |
| 14 | fn hash_output_len(&self) -> usize; |
| 15 | |
| 16 | /// Return `true` if this is backed by a FIPS-approved implementation. |
| 17 | fn fips(&self) -> bool { |
| 18 | false |
| 19 | } |
| 20 | } |
| 21 | |
| 22 | /// A HMAC tag, stored as a value. |
| 23 | #[derive (Clone)] |
| 24 | pub struct Tag { |
| 25 | buf: [u8; Self::MAX_LEN], |
| 26 | used: usize, |
| 27 | } |
| 28 | |
| 29 | impl Tag { |
| 30 | /// Build a tag by copying a byte slice. |
| 31 | /// |
| 32 | /// The slice can be up to [`Tag::MAX_LEN`] bytes in length. |
| 33 | pub fn new(bytes: &[u8]) -> Self { |
| 34 | let mut tag: Tag = Self { |
| 35 | buf: [0u8; Self::MAX_LEN], |
| 36 | used: bytes.len(), |
| 37 | }; |
| 38 | tag.buf[..bytes.len()].copy_from_slice(src:bytes); |
| 39 | tag |
| 40 | } |
| 41 | |
| 42 | /// Maximum supported HMAC tag size: supports up to SHA512. |
| 43 | pub const MAX_LEN: usize = 64; |
| 44 | } |
| 45 | |
| 46 | impl Drop for Tag { |
| 47 | fn drop(&mut self) { |
| 48 | self.buf.zeroize(); |
| 49 | } |
| 50 | } |
| 51 | |
| 52 | impl AsRef<[u8]> for Tag { |
| 53 | fn as_ref(&self) -> &[u8] { |
| 54 | &self.buf[..self.used] |
| 55 | } |
| 56 | } |
| 57 | |
| 58 | /// A HMAC key that is ready for use. |
| 59 | /// |
| 60 | /// The algorithm used is implicit in the `Hmac` object that produced the key. |
| 61 | pub trait Key: Send + Sync { |
| 62 | /// Calculates a tag over `data` -- a slice of byte slices. |
| 63 | fn sign(&self, data: &[&[u8]]) -> Tag { |
| 64 | self.sign_concat(&[], middle:data, &[]) |
| 65 | } |
| 66 | |
| 67 | /// Calculates a tag over the concatenation of `first`, the items in `middle`, and `last`. |
| 68 | fn sign_concat(&self, first: &[u8], middle: &[&[u8]], last: &[u8]) -> Tag; |
| 69 | |
| 70 | /// Returns the length of the tag returned by a computation using |
| 71 | /// this key. |
| 72 | fn tag_len(&self) -> usize; |
| 73 | } |
| 74 | |