1use crate::error::Unspecified;
9use native_ossl::digest::DigestAlg;
10use native_ossl::mac::HmacCtx;
11use native_ossl::util::SecretBuf;
12
13#[derive(Debug, Clone, Copy)]
15pub struct Algorithm(pub(crate) &'static crate::digest::Algorithm);
16
17pub static HMAC_SHA256: Algorithm = Algorithm(&crate::digest::SHA256);
18pub static HMAC_SHA384: Algorithm = Algorithm(&crate::digest::SHA384);
19pub static HMAC_SHA512: Algorithm = Algorithm(&crate::digest::SHA512);
20
21pub struct Key {
23 alg: Algorithm,
25 key_bytes: SecretBuf,
26}
27
28impl std::fmt::Debug for Key {
29 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
30 f.debug_struct("Key")
31 .field("alg", &self.alg)
32 .finish_non_exhaustive()
33 }
34}
35
36impl Key {
37 #[must_use]
38 pub fn new(algorithm: Algorithm, key_value: &[u8]) -> Self {
39 Self {
40 alg: algorithm,
41 key_bytes: SecretBuf::from_slice(key_value),
42 }
43 }
44
45 #[must_use]
46 pub fn algorithm(&self) -> Algorithm {
47 self.alg
48 }
49}
50
51#[derive(Debug)]
53pub struct Tag {
54 bytes: [u8; 64],
55 len: usize,
56}
57
58impl AsRef<[u8]> for Tag {
59 fn as_ref(&self) -> &[u8] {
60 &self.bytes[..self.len]
61 }
62}
63
64#[must_use]
70pub fn sign(key: &Key, data: &[u8]) -> Tag {
71 let digest_alg = DigestAlg::fetch(key.alg.0.name, None)
72 .unwrap_or_else(|e| panic!("OpenSSL digest unavailable: {e}"));
73 let mut bytes = [0u8; 64];
74 let len = HmacCtx::oneshot(&digest_alg, key.key_bytes.as_ref(), data, &mut bytes)
75 .unwrap_or_else(|e| panic!("HmacCtx::oneshot failed: {e}"));
76 Tag { bytes, len }
77}
78
79pub fn verify(key: &Key, data: &[u8], tag: &[u8]) -> Result<(), Unspecified> {
85 let computed = sign(key, data);
86 if native_ossl::util::ct_eq(computed.as_ref(), tag) {
87 Ok(())
88 } else {
89 Err(Unspecified)
90 }
91}