|
| 1 | +# RustCrypto: KMAC |
| 2 | + |
| 3 | +A rust implementation of [KMAC](https://en.wikipedia.org/wiki/SHA-3#Additional_instances), following the [NIST SP 800-185] specification. |
| 4 | + |
| 5 | +This crate provides implementations for KMAC128, KMAC256, KMACXOF128, and KMACXOF256. KMAC is a PRF and keyed hash function based on the Keccak (SHA-3) sponge construction, designed for message authentication (MAC) and key derivation (KDF). |
| 6 | + |
| 7 | +## NIST security guidance |
| 8 | + |
| 9 | +Security guidance for KMAC is discussed in Section 8.4 of [NIST SP 800-185]. |
| 10 | + |
| 11 | +KMAC128 is built from cSHAKE128, giving it a security strength <= 128 bits. The `Kmac128` default MAC tag length is the NIST recommended 32 bytes (256 bits). The input key length must also be at least 16 bytes (128 bits) to achieve the full security strength. |
| 12 | + |
| 13 | +KMAC256 is built from cSHAKE256, giving it a security strength <= 256 bits. The `Kmac256` default MAC tag length is the NIST recommended 64 bytes (512 bits). The input key length must also be at least 32 bytes (256 bits) to achieve the full security strength. |
| 14 | + |
| 15 | +The below table summarises the equivalence with other MAC algorithms, where `K` is the input key, `text` is the input message, `L` is the output tag length, and `S` is an optional customization string. |
| 16 | + |
| 17 | +| Existing MAC Algorithm | KMAC Equivalent | |
| 18 | +|------------------------|------------------------------| |
| 19 | +| `AES-KMAC(K, text)` | `KMAC128(K, text, L=128, S)` | |
| 20 | +| `HMAC-SHA256(K, text)` | `KMAC256(K, text, L=256, S)` | |
| 21 | +| `HMAC-SHA512(K, text)` | `KMAC256(K, text, L=512, S)` | |
| 22 | + |
| 23 | +## Examples |
| 24 | + |
| 25 | +### Generating a MAC |
| 26 | +```rust |
| 27 | +use kmac::{Kmac128, Mac, KeyInit}; |
| 28 | +use hex_literal::hex; |
| 29 | + |
| 30 | +// Use KMAC128 to produce a MAC |
| 31 | +let mut kmac = Kmac128::new_from_slice(b"key material").unwrap(); |
| 32 | +kmac.update(b"input message"); |
| 33 | + |
| 34 | +// `result` has type `CtOutput` which is a thin wrapper around array of |
| 35 | +// bytes for providing constant time equality check |
| 36 | +let result = kmac.finalize(); |
| 37 | + |
| 38 | +// To get underlying array use `into_bytes`, but be careful, since |
| 39 | +// incorrect use of the code value may permit timing attacks which defeats |
| 40 | +// the security provided by the `CtOutput` |
| 41 | +let mac_bytes = result.into_bytes(); |
| 42 | +let expected = hex!(" |
| 43 | + c39a8f614f8821443599440df5402787 |
| 44 | + 0f67e4c47919061584f14a616f3efcf5 |
| 45 | +"); |
| 46 | +assert_eq!(mac_bytes[..], expected[..]); |
| 47 | +``` |
| 48 | + |
| 49 | +### Verifying a MAC |
| 50 | +```rust |
| 51 | +use kmac::{Kmac128, Mac, KeyInit}; |
| 52 | +use hex_literal::hex; |
| 53 | + |
| 54 | +let mut kmac = Kmac128::new_from_slice(b"key material").unwrap(); |
| 55 | +kmac.update(b"input message"); |
| 56 | + |
| 57 | +let mac_bytes = hex!(" |
| 58 | + c39a8f614f8821443599440df5402787 |
| 59 | + 0f67e4c47919061584f14a616f3efcf5 |
| 60 | +"); |
| 61 | + |
| 62 | +// `verify_slice` will return `Ok(())` if code is correct, `Err(MacError)` otherwise |
| 63 | +kmac.verify_slice(&mac_bytes).unwrap(); |
| 64 | +``` |
| 65 | + |
| 66 | +### Producing a fixed-length output |
| 67 | + |
| 68 | +KMAC can also be used to produce an output of any length, which is particularly useful when KMAC is being used as a [key-derivation function (KDF)](https://en.wikipedia.org/wiki/Key_derivation_function). |
| 69 | + |
| 70 | +This method finalizes the KMAC and mixes the requested output length into the KMAC domain separation. The resulting bytes are dependent on the exact length of `out`. Use this when the output length is part of the MAC/derivation semantics (for example when the length itself must influence the MAC result). |
| 71 | + |
| 72 | +A customisation string can also be provided to further domain-separate different uses of KMAC with the same key when initialising the KMAC instance with `new_customization`. |
| 73 | + |
| 74 | +```rust |
| 75 | +use kmac::{Kmac256, Mac}; |
| 76 | +use hex_literal::hex; |
| 77 | + |
| 78 | +let mut mac = Kmac256::new_customization(b"key material", b"customization").unwrap(); |
| 79 | +mac.update(b"input message"); |
| 80 | +let mut output = [0u8; 32]; |
| 81 | +mac.finalize_into(&mut output); |
| 82 | + |
| 83 | +let expected = hex!(" |
| 84 | + 85fb77da3a35e4c4b0057c3151e6cc54 |
| 85 | + ee401ffe65ec2f0239f439be8896f7b6 |
| 86 | +"); |
| 87 | +assert_eq!(output[..], expected[..]); |
| 88 | +``` |
| 89 | + |
| 90 | +### Producing a variable-length output |
| 91 | + |
| 92 | +Variable length KMAC output uses the `ExtendableOutput` trait. This is useful when the desired output length is not immediately known, and will append data to a buffer until the desired length is reached. |
| 93 | + |
| 94 | +The XOF variant finalizes the sponge state without binding the requested output length into the KMAC domain separation. The returned reader yields an effectively infinite stream of bytes; reading the first `N` bytes from the reader (and truncating) produces the same `N`-byte prefix regardless of whether more bytes will be read later. |
| 95 | + |
| 96 | +```rust |
| 97 | +use kmac::{Kmac256, Mac, ExtendableOutput, XofReader}; |
| 98 | +use hex_literal::hex; |
| 99 | + |
| 100 | +let mut kmac = Kmac256::new_customization(b"key material", b"customization").unwrap(); |
| 101 | +kmac.update(b"input message"); |
| 102 | +let mut reader = kmac.finalize_xof(); |
| 103 | + |
| 104 | +let mut output = [0u8; 32]; |
| 105 | +reader.read(&mut output); |
| 106 | + |
| 107 | +let expected = hex!(" |
| 108 | + b675b75668eab0706ab05650f34fa1b6 |
| 109 | + 24051a9a42b5e42cfe9970e8f903d45b |
| 110 | +"); |
| 111 | +assert_eq!(output[..], expected[..]); |
| 112 | +``` |
| 113 | + |
| 114 | +## License |
| 115 | + |
| 116 | +Licensed under either of: |
| 117 | +- [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0) |
| 118 | +- [MIT license](http://opensource.org/licenses/MIT) |
| 119 | +at your option. |
| 120 | + |
| 121 | +### Contribution |
| 122 | +Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions. |
| 123 | + |
| 124 | +[NIST SP 800-185]: https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-185.pdf |
0 commit comments