1use ic_core::traits::{Algorithm, SelfTest};
32use ic_core::{ensure, Result};
33use ic_hash::sp800_185::{right_encode, MAX_ENCODE};
34
35const MAX_TAG: usize = 64;
37
38macro_rules! kmac {
40 ($name:ident, $cshake:ty, $id:literal, $disp:literal, $bits:literal) => {
41 #[doc = concat!("SP 800-185 ", $disp, ", offering ", $bits, "-bit security.")]
42 #[derive(Clone)]
43 pub struct $name {
44 inner: $cshake,
45 }
46
47 impl Algorithm for $name {
48 const ID: &'static str = $id;
49 const NAME: &'static str = $disp;
50 }
51
52 impl $name {
53 pub fn new(key: &[u8], custom: &[u8]) -> Self {
57 let mut inner = <$cshake>::new(b"KMAC", custom);
58 inner.absorb_bytepadded_string(key);
59 Self { inner }
60 }
61
62 pub fn update(&mut self, data: &[u8]) {
64 self.inner.update(data);
65 }
66
67 pub fn finalize(mut self, out: &mut [u8]) {
72 let mut buf = [0u8; MAX_ENCODE];
73 let used = right_encode((out.len() as u64) * 8, &mut buf);
74 self.inner.update(&buf[..used]);
75 self.inner.finalize_xof(out);
76 }
77
78 pub fn finalize_xof(mut self, out: &mut [u8]) {
82 let mut buf = [0u8; MAX_ENCODE];
83 let used = right_encode(0, &mut buf);
84 self.inner.update(&buf[..used]);
85 self.inner.finalize_xof(out);
86 }
87
88 pub fn mac(key: &[u8], custom: &[u8], data: &[u8], out: &mut [u8]) {
90 let mut k = Self::new(key, custom);
91 k.update(data);
92 k.finalize(out);
93 }
94
95 pub fn mac_xof(key: &[u8], custom: &[u8], data: &[u8], out: &mut [u8]) {
97 let mut k = Self::new(key, custom);
98 k.update(data);
99 k.finalize_xof(out);
100 }
101
102 pub fn verify(key: &[u8], custom: &[u8], data: &[u8], tag: &[u8]) -> Result<()> {
108 ensure!(
109 !tag.is_empty() && tag.len() <= MAX_TAG,
110 InvalidLength,
111 "kmac tag length"
112 );
113 let mut expected = [0u8; MAX_TAG];
114 Self::mac(key, custom, data, &mut expected[..tag.len()]);
115 ensure!(
116 ic_core::ct::verify(&expected[..tag.len()], tag),
117 AuthenticationFailed,
118 $id
119 );
120 Ok(())
121 }
122 }
123
124 impl SelfTest for $name {
125 fn self_test() -> Result<()> {
135 let key = [0x40u8; 32];
136 let mut short = [0u8; 32];
137 let mut long = [0u8; 64];
138 Self::mac(&key, b"self-test", b"message", &mut short);
139 Self::mac(&key, b"self-test", b"message", &mut long);
140
141 ensure!(short[..] != long[..32], SelfTestFailed, $id);
144
145 let mut again = [0u8; 32];
146 Self::mac(&key, b"self-test", b"message", &mut again);
147 ensure!(ic_core::ct::verify(&short, &again), SelfTestFailed, $id);
148 Self::verify(&key, b"self-test", b"message", &short)?;
149
150 let mut tampered = short;
151 tampered[0] ^= 1;
152 ensure!(
153 Self::verify(&key, b"self-test", b"message", &tampered).is_err(),
154 SelfTestFailed,
155 $id
156 );
157 ensure!(
159 Self::verify(&key, b"other", b"message", &short).is_err(),
160 SelfTestFailed,
161 $id
162 );
163 Ok(())
164 }
165 }
166 };
167}
168
169kmac!(Kmac128, ic_hash::CShake128, "kmac128", "KMAC128", "128");
170kmac!(Kmac256, ic_hash::CShake256, "kmac256", "KMAC256", "256");
171
172#[cfg(test)]
173mod tests {
174 use super::*;
175 use ic_hash::sp800_185::{left_encode, CShake128, CShake256};
176
177 fn reference_kmac(
187 rate: usize,
188 key: &[u8],
189 custom: &[u8],
190 data: &[u8],
191 out: &mut [u8],
192 xof: bool,
193 ) {
194 fn enc(x: u64) -> Vec<u8> {
195 let mut bytes = x.to_be_bytes().to_vec();
196 while bytes.len() > 1 && bytes[0] == 0 {
197 bytes.remove(0);
198 }
199 let mut v = vec![bytes.len() as u8];
200 v.extend_from_slice(&bytes);
201 v
202 }
203 fn renc(x: u64) -> Vec<u8> {
204 let mut bytes = x.to_be_bytes().to_vec();
205 while bytes.len() > 1 && bytes[0] == 0 {
206 bytes.remove(0);
207 }
208 let n = bytes.len() as u8;
209 bytes.push(n);
210 bytes
211 }
212
213 let mut message = enc(rate as u64);
215 message.extend_from_slice(&enc((key.len() as u64) * 8));
216 message.extend_from_slice(key);
217 while message.len() % rate != 0 {
218 message.push(0);
219 }
220 message.extend_from_slice(data);
221 message.extend_from_slice(&renc(if xof { 0 } else { (out.len() as u64) * 8 }));
222
223 if rate == 168 {
224 CShake128::xof(b"KMAC", custom, &message, out);
225 } else {
226 CShake256::xof(b"KMAC", custom, &message, out);
227 }
228 }
229
230 #[test]
231 fn kmac_matches_an_independent_construction() {
232 let cases: &[(&[u8], &[u8], &[u8])] = &[
233 (&[0x40u8; 32], b"", b""),
234 (&[0x40u8; 32], b"My Tagged Application", b"\x00\x01\x02\x03"),
235 (b"short key", b"S", &[0xa5u8; 500]),
236 (&[0x11u8; 200], b"", b"key longer than the rate"),
237 ];
238
239 for (key, custom, data) in cases {
240 for len in [16usize, 32, 64] {
241 let mut want = vec![0u8; len];
242 let mut got = vec![0u8; len];
243
244 reference_kmac(168, key, custom, data, &mut want, false);
245 Kmac128::mac(key, custom, data, &mut got);
246 assert_eq!(got, want, "KMAC128 fixed, {len} bytes");
247
248 reference_kmac(136, key, custom, data, &mut want, false);
249 Kmac256::mac(key, custom, data, &mut got);
250 assert_eq!(got, want, "KMAC256 fixed, {len} bytes");
251
252 reference_kmac(168, key, custom, data, &mut want, true);
253 Kmac128::mac_xof(key, custom, data, &mut got);
254 assert_eq!(got, want, "KMAC128 xof, {len} bytes");
255
256 reference_kmac(136, key, custom, data, &mut want, true);
257 Kmac256::mac_xof(key, custom, data, &mut got);
258 assert_eq!(got, want, "KMAC256 xof, {len} bytes");
259 }
260 }
261 }
262
263 #[test]
266 fn tag_length_is_bound_into_the_tag() {
267 let key = [0x7fu8; 32];
268 let mut short = [0u8; 32];
269 let mut long = [0u8; 64];
270 Kmac128::mac(&key, b"", b"message", &mut short);
271 Kmac128::mac(&key, b"", b"message", &mut long);
272 assert_ne!(short[..], long[..32], "truncation must not forge");
273 }
274
275 #[test]
278 fn the_xof_variant_extends_rather_than_changes() {
279 let key = [0x7fu8; 32];
280 let mut short = [0u8; 32];
281 let mut long = [0u8; 64];
282 Kmac128::mac_xof(&key, b"", b"message", &mut short);
283 Kmac128::mac_xof(&key, b"", b"message", &mut long);
284 assert_eq!(short[..], long[..32], "the xof output is a prefix");
285 }
286
287 #[test]
288 fn streaming_matches_the_one_shot() {
289 let key = [0x31u8; 32];
290 let data = [0x62u8; 777];
291 let mut one = [0u8; 32];
292 Kmac256::mac(&key, b"S", &data, &mut one);
293
294 let mut k = Kmac256::new(&key, b"S");
295 for chunk in data.chunks(13) {
296 k.update(chunk);
297 }
298 let mut streamed = [0u8; 32];
299 k.finalize(&mut streamed);
300 assert_eq!(one, streamed);
301 }
302
303 #[test]
304 fn keys_and_customization_both_change_the_tag() {
305 let mut a = [0u8; 32];
306 let mut b = [0u8; 32];
307 Kmac128::mac(&[1u8; 32], b"S", b"m", &mut a);
308 Kmac128::mac(&[2u8; 32], b"S", b"m", &mut b);
309 assert_ne!(a, b, "the key matters");
310 Kmac128::mac(&[1u8; 32], b"T", b"m", &mut b);
311 assert_ne!(a, b, "the customization matters");
312 }
313
314 #[test]
315 fn verification_rejects_tampering_and_bad_lengths() {
316 let key = [0x55u8; 32];
317 let mut tag = [0u8; 32];
318 Kmac128::mac(&key, b"S", b"message", &mut tag);
319 Kmac128::verify(&key, b"S", b"message", &tag).unwrap();
320
321 for bit in [0usize, 7, 128, 255] {
322 let mut bad = tag;
323 bad[bit / 8] ^= 1 << (bit % 8);
324 assert!(Kmac128::verify(&key, b"S", b"message", &bad).is_err());
325 }
326 assert!(Kmac128::verify(&key, b"S", b"messagf", &tag).is_err());
327 assert!(Kmac128::verify(&[0u8; 32], b"S", b"message", &tag).is_err());
328 assert!(
329 Kmac128::verify(&key, b"S", b"message", &[]).is_err(),
330 "empty tag"
331 );
332 assert!(
333 Kmac128::verify(&key, b"S", b"message", &[0u8; 65]).is_err(),
334 "over-long tag"
335 );
336 }
337
338 #[test]
339 fn both_self_tests_pass() {
340 Kmac128::self_test().unwrap();
341 Kmac256::self_test().unwrap();
342 }
343
344 #[test]
347 fn the_encoding_helpers_are_reachable() {
348 let mut buf = [0u8; MAX_ENCODE];
349 assert_eq!(left_encode(168, &mut buf), 2);
350 assert_eq!(&buf[..2], &[0x01, 0xa8]);
351 }
352}