Skip to main content

dryoc/classic/
crypto_auth_hmacsha256.rs

1//! # HMAC-SHA-256 authentication
2//!
3//! Implements libsodium's `crypto_auth_hmacsha256_*` functions.
4//!
5//! HMAC-SHA-256 authenticates a message with a shared secret key and writes a
6//! 32-byte tag. Verification recomputes the tag and compares it in constant
7//! time. The message is not encrypted, and the same key must be available to
8//! both the sender and verifier.
9//!
10//! ```
11//! use dryoc::classic::crypto_auth_hmacsha256::*;
12//!
13//! let key = crypto_auth_hmacsha256_keygen();
14//! let message = b"What's past is prologue.";
15//!
16//! let mut mac = Mac::default();
17//! crypto_auth_hmacsha256(&mut mac, message, &key);
18//! crypto_auth_hmacsha256_verify(&mac, message, &key).expect("verify failed");
19//! crypto_auth_hmacsha256_verify(&mac, b"invalid", &key).expect_err("verify should fail");
20//! ```
21//!
22//! The incremental interface produces the same MAC as the one-shot interface:
23//!
24//! ```
25//! use dryoc::classic::crypto_auth_hmacsha256::*;
26//!
27//! let key = crypto_auth_hmacsha256_keygen();
28//! let mut one_shot = Mac::default();
29//! crypto_auth_hmacsha256(&mut one_shot, b"Parting is such sweet sorrow.", &key);
30//!
31//! let mut state = crypto_auth_hmacsha256_init(&key);
32//! crypto_auth_hmacsha256_update(&mut state, b"Parting is such ");
33//! crypto_auth_hmacsha256_update(&mut state, b"sweet sorrow.");
34//! let mut streaming = Mac::default();
35//! crypto_auth_hmacsha256_final(state, &mut streaming);
36//!
37//! assert_eq!(one_shot, streaming);
38//! ```
39
40use crate::classic::crypto_auth_hmac_impl::{
41    HmacState, hmac, hmac_final, hmac_init, hmac_keygen, hmac_update, hmac_verify,
42};
43use crate::constants::{CRYPTO_AUTH_HMACSHA256_BYTES, CRYPTO_AUTH_HMACSHA256_KEYBYTES};
44use crate::error::Error;
45use crate::sha256::Sha256;
46
47/// Key for HMAC-SHA-256 message authentication.
48pub type Key = [u8; CRYPTO_AUTH_HMACSHA256_KEYBYTES];
49/// Message authentication code type for HMAC-SHA-256.
50pub type Mac = [u8; CRYPTO_AUTH_HMACSHA256_BYTES];
51
52/// Internal state for HMAC-SHA-256.
53pub struct HmacSha256State(HmacState<Sha256, 64, CRYPTO_AUTH_HMACSHA256_BYTES>);
54
55/// Authenticates `message` using `key`, and places the result into `mac`.
56pub fn crypto_auth_hmacsha256(mac: &mut Mac, message: &[u8], key: &Key) {
57    hmac::<Sha256, CRYPTO_AUTH_HMACSHA256_KEYBYTES, 64, CRYPTO_AUTH_HMACSHA256_BYTES>(
58        mac, message, key,
59    );
60}
61
62/// Verifies that `mac` is the correct authenticator for `message` using `key`.
63///
64/// # Errors
65///
66/// Returns an error if `mac` is not valid for `input` under `key`.
67pub fn crypto_auth_hmacsha256_verify(mac: &Mac, input: &[u8], key: &Key) -> Result<(), Error> {
68    hmac_verify::<Sha256, CRYPTO_AUTH_HMACSHA256_KEYBYTES, 64, CRYPTO_AUTH_HMACSHA256_BYTES>(
69        mac, input, key,
70    )
71}
72
73/// Generates a random key for HMAC-SHA-256.
74#[must_use]
75pub fn crypto_auth_hmacsha256_keygen() -> Key {
76    hmac_keygen()
77}
78
79/// Initializes the incremental interface for HMAC-SHA-256.
80#[must_use]
81pub fn crypto_auth_hmacsha256_init(key: &[u8]) -> HmacSha256State {
82    HmacSha256State(hmac_init::<Sha256, 64, CRYPTO_AUTH_HMACSHA256_BYTES>(key))
83}
84
85/// Updates `state` for HMAC-SHA-256 with `input`.
86pub fn crypto_auth_hmacsha256_update(state: &mut HmacSha256State, input: &[u8]) {
87    hmac_update(&mut state.0, input);
88}
89
90/// Finalizes HMAC-SHA-256 and places the result into `output`.
91pub fn crypto_auth_hmacsha256_final(state: HmacSha256State, output: &mut Mac) {
92    hmac_final(state.0, output);
93}
94
95#[cfg(test)]
96mod tests {
97    use super::*;
98    use crate::classic::crypto_auth_hmac_impl::test_util::hmac_classic_tests;
99
100    hmac_classic_tests! {
101        hash: sha2::Sha256,
102        block: 64,
103        bytes: CRYPTO_AUTH_HMACSHA256_BYTES,
104        keybytes: CRYPTO_AUTH_HMACSHA256_KEYBYTES,
105        tag: sha256,
106        chunk: 17,
107        one_shot: crypto_auth_hmacsha256,
108        verify: crypto_auth_hmacsha256_verify,
109        keygen: crypto_auth_hmacsha256_keygen,
110        init: crypto_auth_hmacsha256_init,
111        update: crypto_auth_hmacsha256_update,
112        finalize: crypto_auth_hmacsha256_final,
113        sodium_one_shot: auth_hmacsha256,
114        sodium_state: AuthHmacSha256State,
115        keybytes_test: test_one_shot_matches_incremental_for_keybytes_key(b"message"),
116        rfc4231: {
117            test_rfc4231_case_1 => RFC4231_CASE_1,
118            test_rfc4231_short_key_case_2 => RFC4231_CASE_2,
119            test_rfc4231_long_message_case_3 => RFC4231_CASE_3,
120            test_rfc4231_case_4 => RFC4231_CASE_4,
121            test_rfc4231_long_key_case_6 => RFC4231_CASE_6,
122            test_rfc4231_long_key_and_message_case_7 => RFC4231_CASE_7,
123        },
124    }
125}