mls_rs_crypto_rustcrypto/
mac.rs1use 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}