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