mls_rs_crypto_rustcrypto/
mac.rs

1// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2// Copyright by contributors to this project.
3// SPDX-License-Identifier: (Apache-2.0 OR MIT)
4
5use hmac::{
6    digest::{crypto_common::BlockSizeUser, FixedOutputReset},
7    Mac, SimpleHmac,
8};
9use mls_rs_core::crypto::CipherSuite;
10use sha2::{Digest, Sha256, Sha384, Sha512};
11
12use alloc::vec::Vec;
13
14#[derive(Debug)]
15#[cfg_attr(feature = "std", derive(thiserror::Error))]
16pub enum HashError {
17    #[cfg_attr(feature = "std", error("invalid hmac length"))]
18    InvalidHmacLength,
19    #[cfg_attr(feature = "std", error("unsupported cipher suite"))]
20    UnsupportedCipherSuite,
21}
22
23#[derive(Clone, Copy, Debug, Eq, PartialEq)]
24#[repr(u16)]
25pub enum Hash {
26    Sha256,
27    Sha384,
28    Sha512,
29}
30
31impl Hash {
32    pub fn new(cipher_suite: CipherSuite) -> Result<Self, HashError> {
33        match cipher_suite {
34            CipherSuite::CURVE25519_AES128
35            | CipherSuite::P256_AES128
36            | CipherSuite::CURVE25519_CHACHA => Ok(Hash::Sha256),
37            CipherSuite::P384_AES256 => Ok(Hash::Sha384),
38            CipherSuite::CURVE448_AES256
39            | CipherSuite::CURVE448_CHACHA
40            | CipherSuite::P521_AES256 => Ok(Hash::Sha512),
41            _ => Err(HashError::UnsupportedCipherSuite),
42        }
43    }
44
45    pub fn hash(&self, data: &[u8]) -> Vec<u8> {
46        match self {
47            Hash::Sha256 => Sha256::digest(data).to_vec(),
48            Hash::Sha384 => Sha384::digest(data).to_vec(),
49            Hash::Sha512 => Sha512::digest(data).to_vec(),
50        }
51    }
52
53    pub fn mac(&self, key: &[u8], data: &[u8]) -> Result<Vec<u8>, HashError> {
54        match self {
55            Hash::Sha256 => generic_generate_tag(
56                SimpleHmac::<Sha256>::new_from_slice(key)
57                    .map_err(|_| HashError::InvalidHmacLength)?,
58                data,
59            ),
60            Hash::Sha384 => generic_generate_tag(
61                SimpleHmac::<Sha384>::new_from_slice(key)
62                    .map_err(|_| HashError::InvalidHmacLength)?,
63                data,
64            ),
65            Hash::Sha512 => generic_generate_tag(
66                SimpleHmac::<Sha512>::new_from_slice(key)
67                    .map_err(|_| HashError::InvalidHmacLength)?,
68                data,
69            ),
70        }
71    }
72}
73
74fn generic_generate_tag<D: Digest + BlockSizeUser + FixedOutputReset>(
75    mut hmac: SimpleHmac<D>,
76    data: &[u8],
77) -> Result<Vec<u8>, HashError> {
78    hmac.update(data);
79    let res = hmac.finalize().into_bytes().to_vec();
80    Ok(res)
81}