sphinx_packet/header/
mac.rs1use crate::constants::{
16 HeaderIntegrityHmacAlgorithm, HeaderIntegrityMacSize, HEADER_INTEGRITY_MAC_SIZE,
17};
18use crate::crypto;
19use crate::header::keys::HeaderIntegrityMacKey;
20use digest::generic_array::GenericArray;
21use subtle::{Choice, ConstantTimeEq};
22
23#[derive(Clone, Debug)]
25pub struct HeaderIntegrityMac(GenericArray<u8, HeaderIntegrityMacSize>);
26
27impl HeaderIntegrityMac {
28 pub(crate) fn compute(key: &HeaderIntegrityMacKey, header_data: &[u8]) -> Self {
29 let routing_info_mac =
30 crypto::compute_keyed_hmac::<HeaderIntegrityHmacAlgorithm>(key, header_data);
31
32 let mac_bytes = routing_info_mac.into_bytes();
35 if mac_bytes.len() < HEADER_INTEGRITY_MAC_SIZE {
36 panic!("Algorithm used for computing header integrity mac produced output smaller than minimum length of {}", HEADER_INTEGRITY_MAC_SIZE)
37 }
38
39 Self(
41 mac_bytes
42 .into_iter()
43 .take(HEADER_INTEGRITY_MAC_SIZE)
44 .collect(),
45 )
46 }
47
48 pub fn verify(
49 &self,
50 integrity_mac_key: &HeaderIntegrityMacKey,
51 enc_routing_info: &[u8],
52 ) -> bool {
53 let recomputed_integrity_mac = Self::compute(integrity_mac_key, enc_routing_info);
54 self.ct_eq(&recomputed_integrity_mac).into()
55 }
56
57 pub fn into_inner(self) -> GenericArray<u8, HeaderIntegrityMacSize> {
58 self.0
59 }
60
61 pub fn as_bytes(&self) -> &[u8] {
62 &self.0
63 }
64
65 pub fn from_bytes(bytes: [u8; HEADER_INTEGRITY_MAC_SIZE]) -> Self {
66 Self(bytes.into())
67 }
68}
69
70impl ConstantTimeEq for HeaderIntegrityMac {
71 fn ct_eq(&self, other: &Self) -> Choice {
72 self.0.ct_eq(&other.0)
73 }
74}
75
76#[cfg(test)]
77mod computing_integrity_mac {
78 use super::*;
79 use crate::constants::INTEGRITY_MAC_KEY_SIZE;
80 use crate::header::routing::ENCRYPTED_ROUTING_INFO_SIZE;
81
82 #[test]
83 fn it_is_possible_to_verify_correct_mac() {
84 let key = [2u8; INTEGRITY_MAC_KEY_SIZE];
85 let data = vec![3u8; ENCRYPTED_ROUTING_INFO_SIZE];
86 let integrity_mac = HeaderIntegrityMac::compute(&key, &data);
87
88 assert!(integrity_mac.verify(&key, &data));
89 }
90
91 #[test]
92 fn it_lets_detecting_flipped_data_bits() {
93 let key = [2u8; INTEGRITY_MAC_KEY_SIZE];
94 let mut data = vec![3u8; ENCRYPTED_ROUTING_INFO_SIZE];
95 let integrity_mac = HeaderIntegrityMac::compute(&key, &data);
96 data[10] = !data[10];
97 assert!(!integrity_mac.verify(&key, &data));
98 }
99}