mas_jose/jwa/
hmac.rs

1// Copyright 2024 New Vector Ltd.
2// Copyright 2022-2024 The Matrix.org Foundation C.I.C.
3//
4// SPDX-License-Identifier: AGPL-3.0-only
5// Please see LICENSE in the repository root for full details.
6
7use std::marker::PhantomData;
8
9use digest::{
10    Digest, Mac, OutputSizeUser,
11    crypto_common::BlockSizeUser,
12    generic_array::{ArrayLength, GenericArray},
13};
14use signature::{Signer, Verifier};
15use thiserror::Error;
16
17pub struct Signature<S: ArrayLength<u8>> {
18    signature: GenericArray<u8, S>,
19}
20
21impl<S: ArrayLength<u8>> PartialEq for Signature<S> {
22    fn eq(&self, other: &Self) -> bool {
23        self.signature == other.signature
24    }
25}
26
27impl<S: ArrayLength<u8>> Eq for Signature<S> {}
28
29impl<S: ArrayLength<u8>> std::fmt::Debug for Signature<S> {
30    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
31        write!(f, "{:?}", self.signature)
32    }
33}
34
35impl<S: ArrayLength<u8>> Clone for Signature<S> {
36    fn clone(&self) -> Self {
37        Self {
38            signature: self.signature.clone(),
39        }
40    }
41}
42
43impl<S: ArrayLength<u8>> From<Signature<S>> for GenericArray<u8, S> {
44    fn from(val: Signature<S>) -> Self {
45        val.signature
46    }
47}
48
49impl<'a, S: ArrayLength<u8>> TryFrom<&'a [u8]> for Signature<S> {
50    type Error = InvalidLength;
51
52    fn try_from(value: &'a [u8]) -> Result<Self, Self::Error> {
53        if value.len() != S::to_usize() {
54            return Err(InvalidLength);
55        }
56        let mut signature = GenericArray::default();
57        signature.copy_from_slice(value);
58        Ok(Self { signature })
59    }
60}
61
62impl<S: ArrayLength<u8>> signature::SignatureEncoding for Signature<S> {
63    type Repr = GenericArray<u8, S>;
64}
65
66impl<S: ArrayLength<u8>> AsRef<[u8]> for Signature<S> {
67    fn as_ref(&self) -> &[u8] {
68        self.signature.as_ref()
69    }
70}
71
72pub struct Hmac<D> {
73    key: Vec<u8>,
74    digest: PhantomData<D>,
75}
76
77impl<D> Hmac<D> {
78    pub const fn new(key: Vec<u8>) -> Self {
79        Self {
80            key,
81            digest: PhantomData,
82        }
83    }
84}
85
86#[derive(Error, Debug)]
87#[error("invalid length")]
88pub struct InvalidLength;
89
90impl<D> From<Vec<u8>> for Hmac<D> {
91    fn from(key: Vec<u8>) -> Self {
92        Self {
93            key,
94            digest: PhantomData,
95        }
96    }
97}
98
99impl<D: Digest + BlockSizeUser>
100    Signer<Signature<<hmac::SimpleHmac<D> as OutputSizeUser>::OutputSize>> for Hmac<D>
101{
102    fn try_sign(
103        &self,
104        msg: &[u8],
105    ) -> Result<Signature<<hmac::SimpleHmac<D> as OutputSizeUser>::OutputSize>, signature::Error>
106    {
107        let mut mac = <hmac::SimpleHmac<D> as Mac>::new_from_slice(&self.key)
108            .map_err(signature::Error::from_source)?;
109        mac.update(msg);
110        let signature = mac.finalize().into_bytes();
111        Ok(Signature { signature })
112    }
113}
114
115impl<D: Digest + BlockSizeUser>
116    Verifier<Signature<<hmac::SimpleHmac<D> as OutputSizeUser>::OutputSize>> for Hmac<D>
117{
118    fn verify(
119        &self,
120        msg: &[u8],
121        signature: &Signature<<hmac::SimpleHmac<D> as OutputSizeUser>::OutputSize>,
122    ) -> Result<(), signature::Error> {
123        let new_signature = self.try_sign(msg)?;
124        if &new_signature != signature {
125            return Err(signature::Error::new());
126        }
127        Ok(())
128    }
129}