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::RngCore;
117 let mut rng = rand::thread_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::{Hmac, Mac};
198 type HmacSha256 = Hmac<Sha256>;
199
200 let mut mac =
201 HmacSha256::new_from_slice(key.as_bytes()).expect("HMAC can take key of any size");
202 mac.update(message);
203 let result = mac.finalize();
204 HmacTag::from_bytes(&result.into_bytes())
205}
206
207pub fn compute_hmac_blake3(key: &HmacKey, message: &[u8]) -> HmacTag {
209 let key_array: [u8; 32] = key.as_bytes().try_into().expect("key is 32 bytes");
211 let hash = blake3::keyed_hash(&key_array, message);
212 HmacTag::from_bytes(hash.as_bytes())
213}
214
215pub fn compute_hmac(key: &HmacKey, message: &[u8]) -> HmacTag {
217 compute_hmac_blake3(key, message)
218}
219
220pub fn verify_hmac(key: &HmacKey, message: &[u8], tag: &HmacTag) -> bool {
222 let computed = compute_hmac(key, message);
223 computed.verify(tag)
224}
225
226pub fn verify_hmac_sha256(key: &HmacKey, message: &[u8], tag: &HmacTag) -> bool {
228 let computed = compute_hmac_sha256(key, message);
229 computed.verify(tag)
230}
231
232pub fn verify_hmac_blake3(key: &HmacKey, message: &[u8], tag: &HmacTag) -> bool {
234 let computed = compute_hmac_blake3(key, message);
235 computed.verify(tag)
236}
237
238pub fn compute_tagged_hmac(key: &HmacKey, context: &[u8], message: &[u8]) -> HmacTag {
243 let key_array: [u8; 32] = key.as_bytes().try_into().expect("key is 32 bytes");
244 let mut hasher = blake3::Hasher::new_keyed(&key_array);
245 hasher.update(context);
246 hasher.update(message);
247 HmacTag::from_bytes(hasher.finalize().as_bytes())
248}
249
250pub fn verify_tagged_hmac(key: &HmacKey, context: &[u8], message: &[u8], tag: &HmacTag) -> bool {
252 let computed = compute_tagged_hmac(key, context, message);
253 computed.verify(tag)
254}
255
256#[derive(Clone, Debug, Serialize, Deserialize)]
258pub struct AuthenticatedMessage {
259 #[serde(with = "serde_bytes")]
260 data: Vec<u8>,
261 tag: HmacTag,
262}
263
264impl AuthenticatedMessage {
265 pub fn new(key: &HmacKey, data: Vec<u8>) -> Self {
267 let tag = compute_hmac(key, &data);
268 Self { data, tag }
269 }
270
271 pub fn new_tagged(key: &HmacKey, context: &[u8], data: Vec<u8>) -> Self {
273 let tag = compute_tagged_hmac(key, context, &data);
274 Self { data, tag }
275 }
276
277 pub fn verify(self, key: &HmacKey) -> HmacResult<Vec<u8>> {
283 if verify_hmac(key, &self.data, &self.tag) {
284 Ok(self.data)
285 } else {
286 Err(HmacError::VerificationFailed)
287 }
288 }
289
290 pub fn verify_tagged(self, key: &HmacKey, context: &[u8]) -> HmacResult<Vec<u8>> {
296 if verify_tagged_hmac(key, context, &self.data, &self.tag) {
297 Ok(self.data)
298 } else {
299 Err(HmacError::VerificationFailed)
300 }
301 }
302
303 pub fn data(&self) -> &[u8] {
305 &self.data
306 }
307
308 pub fn tag(&self) -> &HmacTag {
310 &self.tag
311 }
312
313 pub fn to_bytes(&self) -> HmacResult<Vec<u8>> {
315 crate::codec::encode(self).map_err(|e| HmacError::SerializationError(e.to_string()))
316 }
317
318 pub fn from_bytes(bytes: &[u8]) -> HmacResult<Self> {
320 crate::codec::decode(bytes).map_err(|e| HmacError::SerializationError(e.to_string()))
321 }
322}
323
324#[cfg(test)]
325mod tests {
326 use super::*;
327
328 #[test]
329 fn test_hmac_basic() {
330 let key = HmacKey::generate();
331 let message = b"Hello, CHIE!";
332
333 let tag = compute_hmac(&key, message);
334 assert!(verify_hmac(&key, message, &tag));
335
336 assert!(!verify_hmac(&key, b"Wrong message", &tag));
338 }
339
340 #[test]
341 fn test_hmac_sha256() {
342 let key = HmacKey::generate();
343 let message = b"Test message";
344
345 let tag = compute_hmac_sha256(&key, message);
346 assert!(verify_hmac_sha256(&key, message, &tag));
347 assert_eq!(tag.as_bytes().len(), HMAC_SHA256_TAG_SIZE);
348 }
349
350 #[test]
351 fn test_hmac_blake3() {
352 let key = HmacKey::generate();
353 let message = b"Test message";
354
355 let tag = compute_hmac_blake3(&key, message);
356 assert!(verify_hmac_blake3(&key, message, &tag));
357 assert_eq!(tag.as_bytes().len(), HMAC_BLAKE3_TAG_SIZE);
358 }
359
360 #[test]
361 fn test_tagged_hmac() {
362 let key = HmacKey::generate();
363 let context = b"CHIE:BandwidthProof";
364 let message = b"1234567890";
365
366 let tag = compute_tagged_hmac(&key, context, message);
367 assert!(verify_tagged_hmac(&key, context, message, &tag));
368
369 assert!(!verify_tagged_hmac(&key, b"wrong", message, &tag));
371 }
372
373 #[test]
374 fn test_authenticated_message() {
375 let key = HmacKey::generate();
376 let data = b"Secret data".to_vec();
377
378 let msg = AuthenticatedMessage::new(&key, data.clone());
379 let verified = msg.verify(&key).unwrap();
380 assert_eq!(verified, data);
381 }
382
383 #[test]
384 fn test_authenticated_message_fails() {
385 let key1 = HmacKey::generate();
386 let key2 = HmacKey::generate();
387 let data = b"Secret data".to_vec();
388
389 let msg = AuthenticatedMessage::new(&key1, data);
390 assert!(msg.verify(&key2).is_err());
391 }
392
393 #[test]
394 fn test_tagged_authenticated_message() {
395 let key = HmacKey::generate();
396 let context = b"CHIE:Chunk";
397 let data = b"Chunk data".to_vec();
398
399 let msg = AuthenticatedMessage::new_tagged(&key, context, data.clone());
400 let verified = msg.verify_tagged(&key, context).unwrap();
401 assert_eq!(verified, data);
402 }
403
404 #[test]
405 fn test_hmac_key_from_bytes() {
406 let bytes = [42u8; HMAC_KEY_SIZE];
407 let key = HmacKey::from_bytes(&bytes).unwrap();
408 assert_eq!(key.as_bytes(), &bytes);
409 }
410
411 #[test]
412 fn test_hmac_key_invalid_size() {
413 let bytes = [42u8; 16]; assert!(HmacKey::from_bytes(&bytes).is_err());
415 }
416
417 #[test]
418 fn test_hmac_key_derive_from_password() {
419 let password = b"my secret password";
420 let salt = b"unique salt";
421 let key1 = HmacKey::derive_from_password(password, salt, 10000);
422 let key2 = HmacKey::derive_from_password(password, salt, 10000);
423
424 assert_eq!(key1.as_bytes(), key2.as_bytes());
426
427 let key3 = HmacKey::derive_from_password(password, b"different salt", 10000);
429 assert_ne!(key1.as_bytes(), key3.as_bytes());
430 }
431
432 #[test]
433 fn test_serialization() {
434 let key = HmacKey::generate();
435 let data = b"Test data".to_vec();
436 let msg = AuthenticatedMessage::new(&key, data);
437
438 let bytes = msg.to_bytes().unwrap();
439 let deserialized = AuthenticatedMessage::from_bytes(&bytes).unwrap();
440
441 assert_eq!(msg.data, deserialized.data);
442 assert_eq!(msg.tag, deserialized.tag);
443 }
444
445 #[test]
446 fn test_constant_time_verification() {
447 let key = HmacKey::generate();
448 let message = b"Test message";
449 let tag1 = compute_hmac(&key, message);
450 let tag2 = compute_hmac(&key, message);
451
452 assert!(tag1.verify(&tag2));
453
454 let mut wrong_tag = tag1.clone();
456 wrong_tag.tag[0] ^= 1;
457
458 assert!(!tag1.verify(&wrong_tag));
459 }
460}