1use std::sync::Arc;
20use tink_core::{utils::wrap_err, TinkError};
21use tink_proto::OutputPrefixType;
22
23const MAX_INT: usize = usize::MAX >> 1;
24
25pub fn new(h: &tink_core::keyset::Handle) -> Result<Box<dyn tink_core::Mac>, TinkError> {
27 new_with_key_manager(h, None)
28}
29
30fn new_with_key_manager(
32 h: &tink_core::keyset::Handle,
33 km: Option<Arc<dyn tink_core::registry::KeyManager>>,
34) -> Result<Box<dyn tink_core::Mac>, TinkError> {
35 let ps = h
36 .primitives_with_key_manager(km)
37 .map_err(|e| wrap_err("mac::factory: cannot obtain primitive set", e))?;
38
39 let ret = WrappedMac::new(ps)?;
40 Ok(Box::new(ret))
41}
42
43#[derive(Clone)]
46struct WrappedMac {
47 ps: tink_core::primitiveset::TypedPrimitiveSet<Box<dyn tink_core::Mac>>,
48}
49
50impl WrappedMac {
51 fn new(ps: tink_core::primitiveset::PrimitiveSet) -> Result<WrappedMac, TinkError> {
52 let entry = match &ps.primary {
53 None => return Err("mac::factory: no primary primitive".into()),
54 Some(p) => p,
55 };
56 match entry.primitive {
57 tink_core::Primitive::Mac(_) => {}
58 _ => return Err("mac::factory: not a Mac primitive".into()),
59 };
60 for (_, primitives) in ps.entries.iter() {
61 for p in primitives {
62 match p.primitive {
63 tink_core::Primitive::Mac(_) => {}
64 _ => return Err("mac::factory: not a Mac primitive".into()),
65 };
66 }
67 }
68 Ok(WrappedMac { ps: ps.into() })
71 }
72}
73
74impl tink_core::Mac for WrappedMac {
75 fn compute_mac(&self, data: &[u8]) -> Result<Vec<u8>, TinkError> {
76 let primary = match &self.ps.primary {
77 Some(p) => p,
78 None => return Err("mac::factory: no primary primitive".into()),
79 };
80 let mac = if primary.prefix_type == OutputPrefixType::Legacy {
81 if data.len() >= MAX_INT {
82 return Err("mac::factory: data too long".into());
83 }
84 let mut local_data = Vec::with_capacity(data.len() + 1);
85 local_data.extend_from_slice(data);
86 local_data.push(0u8);
87 primary.primitive.compute_mac(&local_data)?
88 } else {
89 primary.primitive.compute_mac(data)?
90 };
91
92 let mut ret = Vec::with_capacity(primary.prefix.len() + mac.len());
93 ret.extend_from_slice(&primary.prefix);
94 ret.extend_from_slice(&mac);
95 Ok(ret)
96 }
97
98 fn verify_mac(&self, mac: &[u8], data: &[u8]) -> Result<(), TinkError> {
99 let prefix_size = tink_core::cryptofmt::NON_RAW_PREFIX_SIZE;
102 if mac.len() <= prefix_size {
103 return Err("mac::factory: invalid mac".into());
104 }
105
106 let prefix = &mac[..prefix_size];
108 let mac_no_prefix = &mac[prefix_size..];
109 if let Some(entries) = self.ps.entries_for_prefix(prefix) {
110 for entry in entries {
111 let result = if entry.prefix_type == OutputPrefixType::Legacy {
112 if data.len() >= MAX_INT {
113 return Err("mac::factory: data too long".into());
114 }
115 let mut local_data = Vec::with_capacity(data.len() + 1);
116 local_data.extend_from_slice(data);
117 local_data.push(0u8);
118 entry.primitive.verify_mac(mac_no_prefix, &local_data)
119 } else {
120 entry.primitive.verify_mac(mac_no_prefix, data)
121 };
122 if result.is_ok() {
123 return Ok(());
124 }
125 }
126 }
127
128 if let Some(entries) = self.ps.raw_entries() {
129 for entry in entries {
130 let result = if entry.prefix_type == OutputPrefixType::Legacy {
131 let mut local_data = Vec::with_capacity(data.len() + 1);
134 local_data.extend_from_slice(data);
135 local_data.push(tink_core::cryptofmt::LEGACY_START_BYTE);
136 entry.primitive.verify_mac(mac, &local_data)
137 } else {
138 entry.primitive.verify_mac(mac, data)
139 };
140 if result.is_ok() {
141 return Ok(());
142 }
143 }
144 }
145
146 Err("mac::factory: decryption failed".into())
148 }
149}