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 ic_core::module::operational()?;
109 ensure!(
110 !tag.is_empty() && tag.len() <= MAX_TAG,
111 InvalidLength,
112 "kmac tag length"
113 );
114 let mut expected = [0u8; MAX_TAG];
115 Self::mac(key, custom, data, &mut expected[..tag.len()]);
116 ensure!(
117 ic_core::ct::verify(&expected[..tag.len()], tag),
118 AuthenticationFailed,
119 $id
120 );
121 Ok(())
122 }
123 }
124
125 impl SelfTest for $name {
126 fn self_test() -> Result<()> {
136 let key = [0x40u8; 32];
137 let mut short = [0u8; 32];
138 let mut long = [0u8; 64];
139 Self::mac(&key, b"self-test", b"message", &mut short);
140 Self::mac(&key, b"self-test", b"message", &mut long);
141
142 ensure!(short[..] != long[..32], SelfTestFailed, $id);
145
146 let mut again = [0u8; 32];
147 Self::mac(&key, b"self-test", b"message", &mut again);
148 ensure!(ic_core::ct::verify(&short, &again), SelfTestFailed, $id);
149 Self::verify(&key, b"self-test", b"message", &short)?;
150
151 let mut tampered = short;
152 tampered[0] ^= 1;
153 ensure!(
154 Self::verify(&key, b"self-test", b"message", &tampered).is_err(),
155 SelfTestFailed,
156 $id
157 );
158 ensure!(
160 Self::verify(&key, b"other", b"message", &short).is_err(),
161 SelfTestFailed,
162 $id
163 );
164 Ok(())
165 }
166 }
167 };
168}
169
170kmac!(Kmac128, ic_hash::CShake128, "kmac128", "KMAC128", "128");
171kmac!(Kmac256, ic_hash::CShake256, "kmac256", "KMAC256", "256");
172
173#[cfg(test)]
174mod tests {
175 use super::*;
176 use ic_hash::sp800_185::{left_encode, CShake128, CShake256};
177
178 fn reference_kmac(
188 rate: usize,
189 key: &[u8],
190 custom: &[u8],
191 data: &[u8],
192 out: &mut [u8],
193 xof: bool,
194 ) {
195 fn enc(x: u64) -> Vec<u8> {
196 let mut bytes = x.to_be_bytes().to_vec();
197 while bytes.len() > 1 && bytes[0] == 0 {
198 bytes.remove(0);
199 }
200 let mut v = vec![bytes.len() as u8];
201 v.extend_from_slice(&bytes);
202 v
203 }
204 fn renc(x: u64) -> Vec<u8> {
205 let mut bytes = x.to_be_bytes().to_vec();
206 while bytes.len() > 1 && bytes[0] == 0 {
207 bytes.remove(0);
208 }
209 let n = bytes.len() as u8;
210 bytes.push(n);
211 bytes
212 }
213
214 let mut message = enc(rate as u64);
216 message.extend_from_slice(&enc((key.len() as u64) * 8));
217 message.extend_from_slice(key);
218 while !message.len().is_multiple_of(rate) {
219 message.push(0);
220 }
221 message.extend_from_slice(data);
222 message.extend_from_slice(&renc(if xof { 0 } else { (out.len() as u64) * 8 }));
223
224 if rate == 168 {
225 CShake128::xof(b"KMAC", custom, &message, out);
226 } else {
227 CShake256::xof(b"KMAC", custom, &message, out);
228 }
229 }
230
231 #[test]
232 fn kmac_matches_an_independent_construction() {
233 let cases: &[(&[u8], &[u8], &[u8])] = &[
234 (&[0x40u8; 32], b"", b""),
235 (&[0x40u8; 32], b"My Tagged Application", b"\x00\x01\x02\x03"),
236 (b"short key", b"S", &[0xa5u8; 500]),
237 (&[0x11u8; 200], b"", b"key longer than the rate"),
238 ];
239
240 for (key, custom, data) in cases {
241 for len in [16usize, 32, 64] {
242 let mut want = vec![0u8; len];
243 let mut got = vec![0u8; len];
244
245 reference_kmac(168, key, custom, data, &mut want, false);
246 Kmac128::mac(key, custom, data, &mut got);
247 assert_eq!(got, want, "KMAC128 fixed, {len} bytes");
248
249 reference_kmac(136, key, custom, data, &mut want, false);
250 Kmac256::mac(key, custom, data, &mut got);
251 assert_eq!(got, want, "KMAC256 fixed, {len} bytes");
252
253 reference_kmac(168, key, custom, data, &mut want, true);
254 Kmac128::mac_xof(key, custom, data, &mut got);
255 assert_eq!(got, want, "KMAC128 xof, {len} bytes");
256
257 reference_kmac(136, key, custom, data, &mut want, true);
258 Kmac256::mac_xof(key, custom, data, &mut got);
259 assert_eq!(got, want, "KMAC256 xof, {len} bytes");
260 }
261 }
262 }
263
264 #[test]
267 fn tag_length_is_bound_into_the_tag() {
268 let key = [0x7fu8; 32];
269 let mut short = [0u8; 32];
270 let mut long = [0u8; 64];
271 Kmac128::mac(&key, b"", b"message", &mut short);
272 Kmac128::mac(&key, b"", b"message", &mut long);
273 assert_ne!(short[..], long[..32], "truncation must not forge");
274 }
275
276 #[test]
279 fn the_xof_variant_extends_rather_than_changes() {
280 let key = [0x7fu8; 32];
281 let mut short = [0u8; 32];
282 let mut long = [0u8; 64];
283 Kmac128::mac_xof(&key, b"", b"message", &mut short);
284 Kmac128::mac_xof(&key, b"", b"message", &mut long);
285 assert_eq!(short[..], long[..32], "the xof output is a prefix");
286 }
287
288 #[test]
289 fn streaming_matches_the_one_shot() {
290 let key = [0x31u8; 32];
291 let data = [0x62u8; 777];
292 let mut one = [0u8; 32];
293 Kmac256::mac(&key, b"S", &data, &mut one);
294
295 let mut k = Kmac256::new(&key, b"S");
296 for chunk in data.chunks(13) {
297 k.update(chunk);
298 }
299 let mut streamed = [0u8; 32];
300 k.finalize(&mut streamed);
301 assert_eq!(one, streamed);
302 }
303
304 #[test]
305 fn keys_and_customization_both_change_the_tag() {
306 let mut a = [0u8; 32];
307 let mut b = [0u8; 32];
308 Kmac128::mac(&[1u8; 32], b"S", b"m", &mut a);
309 Kmac128::mac(&[2u8; 32], b"S", b"m", &mut b);
310 assert_ne!(a, b, "the key matters");
311 Kmac128::mac(&[1u8; 32], b"T", b"m", &mut b);
312 assert_ne!(a, b, "the customization matters");
313 }
314
315 #[test]
316 fn verification_rejects_tampering_and_bad_lengths() {
317 let key = [0x55u8; 32];
318 let mut tag = [0u8; 32];
319 Kmac128::mac(&key, b"S", b"message", &mut tag);
320 Kmac128::verify(&key, b"S", b"message", &tag).unwrap();
321
322 for bit in [0usize, 7, 128, 255] {
323 let mut bad = tag;
324 bad[bit / 8] ^= 1 << (bit % 8);
325 assert!(Kmac128::verify(&key, b"S", b"message", &bad).is_err());
326 }
327 assert!(Kmac128::verify(&key, b"S", b"messagf", &tag).is_err());
328 assert!(Kmac128::verify(&[0u8; 32], b"S", b"message", &tag).is_err());
329 assert!(
330 Kmac128::verify(&key, b"S", b"message", &[]).is_err(),
331 "empty tag"
332 );
333 assert!(
334 Kmac128::verify(&key, b"S", b"message", &[0u8; 65]).is_err(),
335 "over-long tag"
336 );
337 }
338
339 #[test]
340 fn both_self_tests_pass() {
341 Kmac128::self_test().unwrap();
342 Kmac256::self_test().unwrap();
343 }
344
345 #[test]
348 fn the_encoding_helpers_are_reachable() {
349 let mut buf = [0u8; MAX_ENCODE];
350 assert_eq!(left_encode(168, &mut buf), 2);
351 assert_eq!(&buf[..2], &[0x01, 0xa8]);
352 }
353}