crypto_async_rs/
hmac.rs

1//! # HMAC (Hash-based Message Authentication Code)
2//!
3//! This module provides HMAC implementations using various hash functions.
4//! HMAC is a mechanism for message authentication using cryptographic hash functions.
5//!
6//! ## Features
7//!
8//! - HMAC-SHA256, HMAC-SHA384, HMAC-SHA512 implementations
9//! - RFC 2104 compliant
10//! - Constant-time operations resistant to timing attacks
11//! - Support for keys of any length
12//!
13//! ## Example
14//!
15//! ```rust
16//! use crypto_async_rs::hmac;
17//!
18//! let key = b"secret-key";
19//! let message = b"Hello, World!";
20//!
21//! // Compute HMAC-SHA256
22//! let hmac_sha256 = hmac::hmac_sha256(key, message);
23//! println!("HMAC-SHA256: {:02x?}", hmac_sha256);
24//!
25//! // Compute HMAC-SHA512
26//! let hmac_sha512 = hmac::hmac_sha512(key, message);
27//! println!("HMAC-SHA512: {:02x?}", hmac_sha512);
28//! ```
29
30use crate::{sha256, sha384, sha512};
31
32/// Compute HMAC-SHA256
33///
34/// # Arguments
35/// * `key` - The secret key (can be any length)
36/// * `text` - The message to authenticate
37///
38/// # Returns
39/// A 32-byte HMAC-SHA256 value
40///
41/// # Example
42/// ```rust
43/// use crypto_async_rs::hmac;
44///
45/// let key = b"secret-key";
46/// let message = b"Hello, World!";
47/// let hmac = hmac::hmac_sha256(key, message);
48/// ```
49pub fn hmac_sha256(key: &[u8], text: &[u8]) -> [u8; 32] {
50    hmac(key, text, 64, sha256::encode)
51}
52
53/// Compute HMAC-SHA384
54///
55/// # Arguments
56/// * `key` - The secret key (can be any length)
57/// * `text` - The message to authenticate
58///
59/// # Returns
60/// A 48-byte HMAC-SHA384 value
61pub fn hmac_sha384(key: &[u8], text: &[u8]) -> [u8; 48] {
62    hmac(key, text, 128, sha384::encode)
63}
64
65/// Compute HMAC-SHA512
66///
67/// # Arguments
68/// * `key` - The secret key (can be any length)
69/// * `text` - The message to authenticate
70///
71/// # Returns
72/// A 64-byte HMAC-SHA512 value
73pub fn hmac_sha512(key: &[u8], text: &[u8]) -> [u8; 64] {
74    hmac(key, text, 128, sha512::encode)
75}
76
77pub fn hmac<T: AsRef<[u8]>>(
78    key: &[u8],
79    text: &[u8],
80    block_length: usize,
81    sha: fn(&[u8]) -> T,
82) -> T {
83    //    const L:usize = 32;
84    const IPAD: u8 = 0x36;
85    const OPAD: u8 = 0x5c;
86    //let mut K:&[u8] = K;
87    let mut internal_key = [0u8; 128];
88
89    if key.len() > block_length {
90        let sha_result = sha(key);
91        let k = sha_result.as_ref();
92        internal_key[..k.len()].copy_from_slice(&k);
93    } else {
94        internal_key[..key.len()].copy_from_slice(key);
95    }
96
97    let mut part_1: Vec<u8> = Vec::with_capacity(block_length + text.len());
98    for i in 0..block_length {
99        part_1.push(internal_key[i] ^ IPAD);
100    }
101    part_1.extend_from_slice(text);
102    let sha_result = sha(&part_1);
103    let part_1: &[u8] = sha_result.as_ref();
104
105    let mut result: Vec<u8> = Vec::with_capacity(block_length + part_1.len());
106    for i in 0..block_length {
107        result.push(internal_key[i] ^ OPAD);
108    }
109    result.extend_from_slice(&part_1);
110    sha(result.as_slice())
111}
112
113#[cfg(test)]
114mod tests {
115    use super::*;
116    use crate::sha1;
117
118    #[test]
119    fn test_hmac_sha256() {
120        let result = hmac_sha256(b"12345", b"12345");
121        assert_eq!(
122            result,
123            [
124                0x2a, 0x1b, 0x7b, 0x2d, 0x9f, 0xf4, 0x7f, 0xb4, 0xf5, 0xa1, 0x8d, 0x28, 0x6a, 0x95,
125                0x51, 0x0b, 0xfe, 0x72, 0x9c, 0x3d, 0xfa, 0xcf, 0x84, 0x22, 0x4d, 0x35, 0xbf, 0xb1,
126                0xb5, 0xc9, 0xae, 0xc8
127            ]
128        );
129
130        let result = hmac_sha256(
131            b"1234567890123456789012345678901234567890123456789012345678901234567890",
132            b"12345",
133        );
134        assert_eq!(
135            result,
136            [
137                0x0c, 0x29, 0x12, 0x3e, 0x58, 0xae, 0xb5, 0xe8, 0x30, 0xaf, 0x48, 0xda, 0x41, 0x3c,
138                0x42, 0x74, 0xcb, 0xaf, 0x6b, 0xbd, 0x07, 0x43, 0x5b, 0x65, 0x96, 0xb3, 0xb3, 0xbd,
139                0xee, 0xd6, 0x62, 0xc9
140            ]
141        );
142    }
143
144    #[test]
145    fn test_hmac_sha256_2() {
146        let text: &[u8] = &[
147            0x00, 0x20, 0x11, 0x74, 0x6c, 0x73, 0x31, 0x33, 0x20, 0x31, 0x32, 0x33, 0x34, 0x35,
148            0x36, 0x37, 0x38, 0x39, 0x30, 0x31, 0x20, 0xda, 0x75, 0xce, 0x11, 0x39, 0xac, 0x80,
149            0xda, 0xe4, 0x04, 0x4d, 0xa9, 0x32, 0x35, 0x0c, 0xf6, 0x5c, 0x97, 0xcc, 0xc9, 0xe3,
150            0x3f, 0x1e, 0x6f, 0x7d, 0x2d, 0x4b, 0x18, 0xb7, 0x36, 0xff, 0xd5, 0x01,
151        ];
152        let key: &[u8] = &[
153            0xfb, 0x9f, 0xc8, 0x6, 0x89, 0xb3, 0xa5, 0xd0, 0x2c, 0x33, 0x24, 0x3b, 0xf6, 0x9a,
154            0x1b, 0x1b, 0x20, 0x70, 0x55, 0x88, 0xa7, 0x94, 0x30, 0x4a, 0x6e, 0x71, 0x20, 0x15,
155            0x5e, 0xdf, 0x14, 0x9a,
156        ];
157        let expected: &[u8] = &[
158            0xba, 0x98, 0x46, 0x0b, 0xbd, 0xaa, 0x64, 0xc6, 0xd6, 0x3b, 0xdc, 0xf9, 0x87, 0x3d,
159            0x8a, 0x47, 0xc0, 0x8b, 0x0e, 0xa8, 0x94, 0xb1, 0x83, 0xf6, 0xb6, 0x7c, 0xb4, 0x34,
160            0x3d, 0x9c, 0x08, 0xf8,
161        ];
162        let result = hmac_sha256(key, text);
163        assert_eq!(&result, &expected);
164    }
165
166    #[test]
167    fn test_hmac_sha256_3() {
168        let key: &[u8] = &[
169            0xfb, 0x9f, 0xc8, 0x6, 0x89, 0xb3, 0xa5, 0xd0, 0x2c, 0x33, 0x24, 0x3b, 0xf6, 0x9a,
170            0x1b, 0x1b, 0x20, 0x70, 0x55, 0x88, 0xa7, 0x94, 0x30, 0x4a, 0x6e, 0x71, 0x20, 0x15,
171            0x5e, 0xdf, 0x14, 0x9a,
172        ];
173        let text: &[u8] = &[
174            0x00, 0x20, 0x12, 0x74, 0x6c, 0x73, 0x31, 0x33, 0x20, 0x31, 0x32, 0x33, 0x34, 0x35,
175            0x36, 0x37, 0x38, 0x39, 0x30, 0x31, 0x32, 0x20, 0xda, 0x75, 0xce, 0x11, 0x39, 0xac,
176            0x80, 0xda, 0xe4, 0x04, 0x4d, 0xa9, 0x32, 0x35, 0x0c, 0xf6, 0x5c, 0x97, 0xcc, 0xc9,
177            0xe3, 0x3f, 0x1e, 0x6f, 0x7d, 0x2d, 0x4b, 0x18, 0xb7, 0x36, 0xff, 0xd5, 0x01,
178        ];
179        let expected: &[u8] = &[
180            0x5e, 0x05, 0xc8, 0x1d, 0xb1, 0x85, 0x67, 0xd7, 0x93, 0x0a, 0x1a, 0x4b, 0x04, 0x76,
181            0x44, 0xdc, 0xa3, 0xdb, 0x8c, 0x77, 0xe6, 0x25, 0x70, 0x9c, 0x6e, 0x03, 0x18, 0x68,
182            0x2e, 0x45, 0xc7, 0xcf,
183        ];
184        let result = hmac_sha256(key, text);
185        assert_eq!(&result, &expected);
186    }
187
188    #[test]
189    fn test_hmac_sha1() {
190        let key = [0x0bu8; 20];
191        let data = "Hi There";
192        let result = hmac(&key, data.as_bytes(), 64, sha1::encode);
193        assert_eq!(
194            &result,
195            &[
196                0xb6, 0x17, 0x31, 0x86, 0x55, 0x05, 0x72, 0x64, 0xe2, 0x8b, 0xc0, 0xb6, 0xfb, 0x37,
197                0x8c, 0x8e, 0xf1, 0x46, 0xbe, 0x00
198            ]
199        );
200    }
201
202    #[test]
203    fn test_hmac_sha384() {
204        let result = hmac_sha384(b"12345", b"12345");
205        assert_eq!(
206            result,
207            [
208                0x03, 0x6e, 0x51, 0x5b, 0x4f, 0xef, 0x9d, 0xee, 0x0f, 0x30, 0x09, 0xb0, 0xe2, 0xc0,
209                0xb1, 0x03, 0xe2, 0xc8, 0xe7, 0xd2, 0xda, 0xe1, 0x8c, 0x7e, 0xe4, 0xb8, 0xf9, 0xc0,
210                0x6b, 0x89, 0xc3, 0x72, 0xf0, 0x39, 0x53, 0x5b, 0xd8, 0xb5, 0x84, 0x96, 0x1b, 0x95,
211                0xd7, 0x00, 0x6d, 0x29, 0xb4, 0x03
212            ]
213        );
214
215        let result = hmac_sha384(
216            b"1234567890123456789012345678901234567890123456789012345678901234567890",
217            b"12345",
218        );
219        assert_eq!(
220            result,
221            [
222                0x2e, 0x33, 0xe2, 0xe0, 0x9c, 0x0b, 0x9c, 0x46, 0x17, 0xdf, 0xc9, 0x4f, 0x6b, 0xe0,
223                0xb5, 0x8a, 0x14, 0x4c, 0xc4, 0xa9, 0x84, 0x2b, 0xea, 0xe4, 0x6d, 0x92, 0x8e, 0x60,
224                0x7c, 0x50, 0x44, 0x7d, 0xd0, 0xf0, 0x73, 0x64, 0x1f, 0x3a, 0xe4, 0x4b, 0x43, 0x0d,
225                0xb9, 0xb4, 0xe1, 0x01, 0x89, 0x63
226            ]
227        );
228    }
229}