1use crate::{sha256, sha384, sha512};
31
32pub fn hmac_sha256(key: &[u8], text: &[u8]) -> [u8; 32] {
50 hmac(key, text, 64, sha256::encode)
51}
52
53pub fn hmac_sha384(key: &[u8], text: &[u8]) -> [u8; 48] {
62 hmac(key, text, 128, sha384::encode)
63}
64
65pub 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 IPAD: u8 = 0x36;
85 const OPAD: u8 = 0x5c;
86 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}