Skip to content

Commit 86f8839

Browse files
committed
kmac: Initial crate submission
1 parent 711f5c6 commit 86f8839

File tree

11 files changed

+1228
-2
lines changed

11 files changed

+1228
-2
lines changed

.github/workflows/kmac.yml

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
name: kmac
2+
3+
on:
4+
pull_request:
5+
paths:
6+
- ".github/workflows/kmac.yml"
7+
- "kmac/**"
8+
- "Cargo.*"
9+
push:
10+
branches: master
11+
12+
defaults:
13+
run:
14+
working-directory: kmac
15+
16+
env:
17+
CARGO_INCREMENTAL: 0
18+
RUSTFLAGS: "-Dwarnings"
19+
20+
jobs:
21+
build:
22+
runs-on: ubuntu-latest
23+
strategy:
24+
matrix:
25+
rust:
26+
- 1.85.0 # MSRV
27+
- stable
28+
target:
29+
- thumbv7em-none-eabi
30+
- wasm32-unknown-unknown
31+
steps:
32+
- uses: actions/checkout@v5
33+
- uses: RustCrypto/actions/cargo-cache@master
34+
- uses: dtolnay/rust-toolchain@master
35+
with:
36+
toolchain: ${{ matrix.rust }}
37+
targets: ${{ matrix.target }}
38+
- run: cargo build --no-default-features --target ${{ matrix.target }}
39+
40+
minimal-versions:
41+
# disabled until belt-block gets published
42+
if: false
43+
uses: RustCrypto/actions/.github/workflows/minimal-versions.yml@master
44+
with:
45+
working-directory: ${{ github.workflow }}
46+
47+
test:
48+
runs-on: ubuntu-latest
49+
strategy:
50+
matrix:
51+
rust:
52+
- 1.85.0 # MSRV
53+
- stable
54+
steps:
55+
- uses: actions/checkout@v5
56+
- uses: RustCrypto/actions/cargo-cache@master
57+
- uses: dtolnay/rust-toolchain@master
58+
with:
59+
toolchain: ${{ matrix.rust }}
60+
- uses: RustCrypto/actions/cargo-hack-install@master
61+
- run: cargo hack test --feature-powerset
62+
- run: cargo test --release --all-features

Cargo.lock

Lines changed: 44 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ members = [
55
"cbc-mac",
66
"cmac",
77
"hmac",
8+
"kmac",
89
"pmac",
910
"retail-mac",
1011
]

kmac/Cargo.toml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
[package]
2+
name = "kmac"
3+
version = "0.1.0"
4+
description = "Keccak Message Authentication Code (KMAC)"
5+
authors = ["RustCrypto Developers"]
6+
license = "MIT OR Apache-2.0"
7+
edition = "2024"
8+
readme = "README.md"
9+
documentation = "https://docs.rs/kmac"
10+
repository = "https://github.com/RustCrypto/MACs"
11+
keywords = ["crypto", "mac", "kmac", "digest"]
12+
categories = ["cryptography", "no-std"]
13+
rust-version = "1.85"
14+
15+
[dependencies]
16+
digest = { version = "0.11.0-rc.3", features = ["mac"] }
17+
sha3 = "0.11.0-rc.3"
18+
19+
[dev-dependencies]
20+
digest = { version = "0.11.0-rc.3", features = ["dev"] }
21+
hex-literal = "1.1.0"
22+
hex = "0.4.3"

kmac/README.md

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
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

kmac/benches/mod.rs

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
#![feature(test)]
2+
extern crate test;
3+
4+
use core::hint::black_box;
5+
use kmac::{KeyInit, Kmac128, Kmac256, Mac};
6+
use test::Bencher;
7+
8+
#[macro_export]
9+
macro_rules! bench_full {
10+
(
11+
$init:expr;
12+
$($name:ident $bs:expr;)*
13+
) => {
14+
$(
15+
#[bench]
16+
fn $name(b: &mut Bencher) {
17+
let data = [0; $bs];
18+
19+
b.iter(|| {
20+
let mut d = $init;
21+
digest::Update::update(&mut d, black_box(&data[..]));
22+
black_box(d.finalize());
23+
});
24+
25+
b.bytes = $bs;
26+
}
27+
)*
28+
};
29+
}
30+
31+
bench_full!(
32+
Kmac128::new(black_box(&Default::default()));
33+
kmac128_10 10;
34+
kmac128_100 100;
35+
kmac128_1000 1000;
36+
kmac128_10000 10000;
37+
);
38+
39+
bench_full!(
40+
Kmac256::new(black_box(&Default::default()));
41+
kmac256_10 10;
42+
kmac256_100 100;
43+
kmac256_1000 1000;
44+
kmac256_10000 10000;
45+
);
46+
47+
digest::bench_update!(
48+
Kmac128::new(black_box(&Default::default()));
49+
kmac128_update_10 10;
50+
kmac128_update_100 100;
51+
kmac128_update_1000 1000;
52+
kmac128_update_10000 10000;
53+
);
54+
55+
digest::bench_update!(
56+
Kmac256::new(black_box(&Default::default()));
57+
kmac256_update_10 10;
58+
kmac256_update_100 100;
59+
kmac256_update_1000 1000;
60+
kmac256_update_10000 10000;
61+
);

0 commit comments

Comments
 (0)