1use blake3;
43use serde::{Deserialize, Serialize};
44use sha2::Sha256;
45use zeroize::{Zeroize, ZeroizeOnDrop};
46
47use crate::ct::ct_eq;
48
49mod serde_bytes {
51 use serde::{Deserialize, Deserializer, Serializer};
52
53 pub fn serialize<S>(bytes: &[u8], serializer: S) -> Result<S::Ok, S::Error>
54 where
55 S: Serializer,
56 {
57 serializer.serialize_bytes(bytes)
58 }
59
60 pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
61 where
62 D: Deserializer<'de>,
63 {
64 <Vec<u8>>::deserialize(deserializer)
65 }
66}
67
68#[derive(Debug, Clone, PartialEq, Eq)]
70pub enum HmacError {
71 InvalidKeySize,
73 InvalidTagSize,
75 VerificationFailed,
77 SerializationError(String),
79}
80
81impl std::fmt::Display for HmacError {
82 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
83 match self {
84 Self::InvalidKeySize => write!(f, "Invalid HMAC key size"),
85 Self::InvalidTagSize => write!(f, "Invalid HMAC tag size"),
86 Self::VerificationFailed => write!(f, "HMAC verification failed"),
87 Self::SerializationError(e) => write!(f, "Serialization error: {}", e),
88 }
89 }
90}
91
92impl std::error::Error for HmacError {}
93
94pub type HmacResult<T> = Result<T, HmacError>;
96
97pub const HMAC_KEY_SIZE: usize = 32;
99
100pub const HMAC_SHA256_TAG_SIZE: usize = 32;
102
103pub const HMAC_BLAKE3_TAG_SIZE: usize = 32;
105
106#[derive(Clone, Zeroize, ZeroizeOnDrop, Serialize, Deserialize)]
108pub struct HmacKey {
109 #[serde(with = "serde_bytes")]
110 key: Vec<u8>,
111}
112
113impl HmacKey {
114 pub fn generate() -> Self {
116 use rand::Rng as _;
117 let mut rng = rand::rng();
118 let mut key = vec![0u8; HMAC_KEY_SIZE];
119 rng.fill_bytes(&mut key[..]);
120 Self { key }
121 }
122
123 pub fn from_bytes(bytes: &[u8]) -> HmacResult<Self> {
129 if bytes.len() != HMAC_KEY_SIZE {
130 return Err(HmacError::InvalidKeySize);
131 }
132 Ok(Self {
133 key: bytes.to_vec(),
134 })
135 }
136
137 pub fn as_bytes(&self) -> &[u8] {
139 &self.key
140 }
141
142 pub fn to_bytes(&self) -> Vec<u8> {
144 self.key.clone()
145 }
146
147 pub fn derive_from_password(password: &[u8], salt: &[u8], iterations: u32) -> Self {
149 use pbkdf2::pbkdf2_hmac;
150 let mut key = vec![0u8; HMAC_KEY_SIZE];
151 pbkdf2_hmac::<Sha256>(password, salt, iterations, &mut key);
152 Self { key }
153 }
154}
155
156impl std::fmt::Debug for HmacKey {
157 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
158 f.debug_struct("HmacKey")
159 .field("key", &"[REDACTED]")
160 .finish()
161 }
162}
163
164#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
166pub struct HmacTag {
167 #[serde(with = "serde_bytes")]
168 tag: Vec<u8>,
169}
170
171impl HmacTag {
172 pub fn from_bytes(bytes: &[u8]) -> Self {
174 Self {
175 tag: bytes.to_vec(),
176 }
177 }
178
179 pub fn as_bytes(&self) -> &[u8] {
181 &self.tag
182 }
183
184 pub fn to_bytes(&self) -> Vec<u8> {
186 self.tag.clone()
187 }
188
189 pub fn verify(&self, other: &Self) -> bool {
191 ct_eq(&self.tag, &other.tag)
192 }
193}
194
195pub fn compute_hmac_sha256(key: &HmacKey, message: &[u8]) -> HmacTag {
197 use hmac::digest::KeyInit;
198 use hmac::{Hmac, Mac};
199 type HmacSha256 = Hmac<Sha256>;
200
201 let mut mac = <HmacSha256 as KeyInit>::new_from_slice(key.as_bytes())
202 .expect("HMAC can take key of any size");
203 mac.update(message);
204 let result = mac.finalize();
205 HmacTag::from_bytes(&result.into_bytes())
206}
207
208pub fn compute_hmac_blake3(key: &HmacKey, message: &[u8]) -> HmacTag {
210 let key_array: [u8; 32] = key.as_bytes().try_into().expect("key is 32 bytes");
212 let hash = blake3::keyed_hash(&key_array, message);
213 HmacTag::from_bytes(hash.as_bytes())
214}
215
216pub fn compute_hmac(key: &HmacKey, message: &[u8]) -> HmacTag {
218 compute_hmac_blake3(key, message)
219}
220
221pub fn verify_hmac(key: &HmacKey, message: &[u8], tag: &HmacTag) -> bool {
223 let computed = compute_hmac(key, message);
224 computed.verify(tag)
225}
226
227pub fn verify_hmac_sha256(key: &HmacKey, message: &[u8], tag: &HmacTag) -> bool {
229 let computed = compute_hmac_sha256(key, message);
230 computed.verify(tag)
231}
232
233pub fn verify_hmac_blake3(key: &HmacKey, message: &[u8], tag: &HmacTag) -> bool {
235 let computed = compute_hmac_blake3(key, message);
236 computed.verify(tag)
237}
238
239pub fn compute_tagged_hmac(key: &HmacKey, context: &[u8], message: &[u8]) -> HmacTag {
244 let key_array: [u8; 32] = key.as_bytes().try_into().expect("key is 32 bytes");
245 let mut hasher = blake3::Hasher::new_keyed(&key_array);
246 hasher.update(context);
247 hasher.update(message);
248 HmacTag::from_bytes(hasher.finalize().as_bytes())
249}
250
251pub fn verify_tagged_hmac(key: &HmacKey, context: &[u8], message: &[u8], tag: &HmacTag) -> bool {
253 let computed = compute_tagged_hmac(key, context, message);
254 computed.verify(tag)
255}
256
257#[derive(Clone, Debug, Serialize, Deserialize)]
259pub struct AuthenticatedMessage {
260 #[serde(with = "serde_bytes")]
261 data: Vec<u8>,
262 tag: HmacTag,
263}
264
265impl AuthenticatedMessage {
266 pub fn new(key: &HmacKey, data: Vec<u8>) -> Self {
268 let tag = compute_hmac(key, &data);
269 Self { data, tag }
270 }
271
272 pub fn new_tagged(key: &HmacKey, context: &[u8], data: Vec<u8>) -> Self {
274 let tag = compute_tagged_hmac(key, context, &data);
275 Self { data, tag }
276 }
277
278 pub fn verify(self, key: &HmacKey) -> HmacResult<Vec<u8>> {
284 if verify_hmac(key, &self.data, &self.tag) {
285 Ok(self.data)
286 } else {
287 Err(HmacError::VerificationFailed)
288 }
289 }
290
291 pub fn verify_tagged(self, key: &HmacKey, context: &[u8]) -> HmacResult<Vec<u8>> {
297 if verify_tagged_hmac(key, context, &self.data, &self.tag) {
298 Ok(self.data)
299 } else {
300 Err(HmacError::VerificationFailed)
301 }
302 }
303
304 pub fn data(&self) -> &[u8] {
306 &self.data
307 }
308
309 pub fn tag(&self) -> &HmacTag {
311 &self.tag
312 }
313
314 pub fn to_bytes(&self) -> HmacResult<Vec<u8>> {
316 crate::codec::encode(self).map_err(|e| HmacError::SerializationError(e.to_string()))
317 }
318
319 pub fn from_bytes(bytes: &[u8]) -> HmacResult<Self> {
321 crate::codec::decode(bytes).map_err(|e| HmacError::SerializationError(e.to_string()))
322 }
323}
324
325#[cfg(test)]
326mod tests {
327 use super::*;
328
329 #[test]
330 fn test_hmac_basic() {
331 let key = HmacKey::generate();
332 let message = b"Hello, CHIE!";
333
334 let tag = compute_hmac(&key, message);
335 assert!(verify_hmac(&key, message, &tag));
336
337 assert!(!verify_hmac(&key, b"Wrong message", &tag));
339 }
340
341 #[test]
342 fn test_hmac_sha256() {
343 let key = HmacKey::generate();
344 let message = b"Test message";
345
346 let tag = compute_hmac_sha256(&key, message);
347 assert!(verify_hmac_sha256(&key, message, &tag));
348 assert_eq!(tag.as_bytes().len(), HMAC_SHA256_TAG_SIZE);
349 }
350
351 #[test]
352 fn test_hmac_blake3() {
353 let key = HmacKey::generate();
354 let message = b"Test message";
355
356 let tag = compute_hmac_blake3(&key, message);
357 assert!(verify_hmac_blake3(&key, message, &tag));
358 assert_eq!(tag.as_bytes().len(), HMAC_BLAKE3_TAG_SIZE);
359 }
360
361 #[test]
362 fn test_tagged_hmac() {
363 let key = HmacKey::generate();
364 let context = b"CHIE:BandwidthProof";
365 let message = b"1234567890";
366
367 let tag = compute_tagged_hmac(&key, context, message);
368 assert!(verify_tagged_hmac(&key, context, message, &tag));
369
370 assert!(!verify_tagged_hmac(&key, b"wrong", message, &tag));
372 }
373
374 #[test]
375 fn test_authenticated_message() {
376 let key = HmacKey::generate();
377 let data = b"Secret data".to_vec();
378
379 let msg = AuthenticatedMessage::new(&key, data.clone());
380 let verified = msg.verify(&key).unwrap();
381 assert_eq!(verified, data);
382 }
383
384 #[test]
385 fn test_authenticated_message_fails() {
386 let key1 = HmacKey::generate();
387 let key2 = HmacKey::generate();
388 let data = b"Secret data".to_vec();
389
390 let msg = AuthenticatedMessage::new(&key1, data);
391 assert!(msg.verify(&key2).is_err());
392 }
393
394 #[test]
395 fn test_tagged_authenticated_message() {
396 let key = HmacKey::generate();
397 let context = b"CHIE:Chunk";
398 let data = b"Chunk data".to_vec();
399
400 let msg = AuthenticatedMessage::new_tagged(&key, context, data.clone());
401 let verified = msg.verify_tagged(&key, context).unwrap();
402 assert_eq!(verified, data);
403 }
404
405 #[test]
406 fn test_hmac_key_from_bytes() {
407 let bytes = [42u8; HMAC_KEY_SIZE];
408 let key = HmacKey::from_bytes(&bytes).unwrap();
409 assert_eq!(key.as_bytes(), &bytes);
410 }
411
412 #[test]
413 fn test_hmac_key_invalid_size() {
414 let bytes = [42u8; 16]; assert!(HmacKey::from_bytes(&bytes).is_err());
416 }
417
418 #[test]
419 fn test_hmac_key_derive_from_password() {
420 let password = b"my secret password";
421 let salt = b"unique salt";
422 let key1 = HmacKey::derive_from_password(password, salt, 10000);
423 let key2 = HmacKey::derive_from_password(password, salt, 10000);
424
425 assert_eq!(key1.as_bytes(), key2.as_bytes());
427
428 let key3 = HmacKey::derive_from_password(password, b"different salt", 10000);
430 assert_ne!(key1.as_bytes(), key3.as_bytes());
431 }
432
433 #[test]
434 fn test_serialization() {
435 let key = HmacKey::generate();
436 let data = b"Test data".to_vec();
437 let msg = AuthenticatedMessage::new(&key, data);
438
439 let bytes = msg.to_bytes().unwrap();
440 let deserialized = AuthenticatedMessage::from_bytes(&bytes).unwrap();
441
442 assert_eq!(msg.data, deserialized.data);
443 assert_eq!(msg.tag, deserialized.tag);
444 }
445
446 #[test]
447 fn test_constant_time_verification() {
448 let key = HmacKey::generate();
449 let message = b"Test message";
450 let tag1 = compute_hmac(&key, message);
451 let tag2 = compute_hmac(&key, message);
452
453 assert!(tag1.verify(&tag2));
454
455 let mut wrong_tag = tag1.clone();
457 wrong_tag.tag[0] ^= 1;
458
459 assert!(!tag1.verify(&wrong_tag));
460 }
461}