143 lines
5.1 KiB
Markdown
143 lines
5.1 KiB
Markdown
# [RustCrypto]: HMAC
|
|
|
|
[![crate][crate-image]][crate-link]
|
|
[![Docs][docs-image]][docs-link]
|
|
[![Build Status][build-image]][build-link]
|
|
![Apache2/MIT licensed][license-image]
|
|
![Rust Version][rustc-image]
|
|
[![Project Chat][chat-image]][chat-link]
|
|
|
|
Generic implementation of [Hash-based Message Authentication Code (HMAC)][HMAC].
|
|
|
|
To use it you will need a cryptographic hash function implementation which
|
|
implements the [`digest`] crate traits. You can find compatible crates
|
|
(e.g. [`sha2`]) in the [`RustCrypto/hashes`] repository.
|
|
|
|
This crate provides four HMAC implementations: [`Hmac`], [`HmacReset`],
|
|
[`SimpleHmac`], and [`SimpleHmacReset`].
|
|
|
|
The first two types are buffered wrappers around block-level
|
|
[`block_api::HmacCore`] and [`block_api::HmacResetCore`] types respectively.
|
|
Internally they uses efficient state representation, but work only with
|
|
hash functions which expose block-level API and consume blocks eagerly
|
|
(e.g. they will not work with the BLAKE2 family of hash functions).
|
|
|
|
On the other hand, [`SimpleHmac`] and [`SimpleHmacReset`] are a bit less
|
|
efficient, but work with all hash functions which implement
|
|
the [`Digest`] trait.
|
|
|
|
[`Hmac`] and [`SimpleHmac`] do not support resetting MAC state (i.e. they
|
|
do not implement the [`Reset`] and [`FixedOutputReset`] traits). Use
|
|
[`HmacReset`] or [`SimpleHmacReset`] if you want to reuse MAC state.
|
|
|
|
## Examples
|
|
|
|
Let us demonstrate how to use HMAC using the SHA-256 hash function
|
|
implemented in the [`sha2`] crate.
|
|
|
|
In the following examples [`Hmac`] is interchangeable with [`SimpleHmac`].
|
|
|
|
To get authentication code:
|
|
|
|
```rust
|
|
use sha2::Sha256;
|
|
use hmac::{Hmac, KeyInit, Mac};
|
|
use hex_literal::hex;
|
|
|
|
// Create alias for HMAC-SHA256
|
|
type HmacSha256 = Hmac<Sha256>;
|
|
|
|
let mut mac = HmacSha256::new_from_slice(b"my secret and secure key")
|
|
.expect("HMAC can take key of any size");
|
|
mac.update(b"input message");
|
|
|
|
// `result` has type `CtOutput` which is a thin wrapper around array of
|
|
// bytes for providing constant time equality check
|
|
let result = mac.finalize();
|
|
// To get underlying array use `into_bytes`, but be careful, since
|
|
// incorrect use of the code value may permit timing attacks which defeats
|
|
// the security provided by the `CtOutput`
|
|
let code_bytes = result.into_bytes();
|
|
let expected = hex!("
|
|
97d2a569059bbcd8ead4444ff99071f4
|
|
c01d005bcefe0d3567e1be628e5fdcd9
|
|
");
|
|
assert_eq!(code_bytes[..], expected[..]);
|
|
```
|
|
|
|
To verify the message:
|
|
|
|
```rust
|
|
use sha2::Sha256;
|
|
use hmac::{Hmac, KeyInit, Mac};
|
|
use hex_literal::hex;
|
|
|
|
type HmacSha256 = Hmac<Sha256>;
|
|
|
|
let mut mac = HmacSha256::new_from_slice(b"my secret and secure key")
|
|
.expect("HMAC can take key of any size");
|
|
|
|
mac.update(b"input message");
|
|
|
|
let code_bytes = hex!("
|
|
97d2a569059bbcd8ead4444ff99071f4
|
|
c01d005bcefe0d3567e1be628e5fdcd9
|
|
");
|
|
// `verify_slice` will return `Ok(())` if code is correct, `Err(MacError)` otherwise
|
|
mac.verify_slice(&code_bytes[..]).unwrap();
|
|
```
|
|
|
|
## Block and input sizes
|
|
|
|
Usually it is assumed that block size is larger than output size. Due to the
|
|
generic nature of the implementation, we must handle cases when this assumption
|
|
does not hold. This is done by truncating hash output to the hash
|
|
block size if needed.
|
|
|
|
## License
|
|
|
|
Licensed under either of:
|
|
|
|
* [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0)
|
|
* [MIT license](http://opensource.org/licenses/MIT)
|
|
|
|
at your option.
|
|
|
|
### Contribution
|
|
|
|
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.
|
|
|
|
[//]: # (badges)
|
|
|
|
[crate-image]: https://img.shields.io/crates/v/hmac.svg?logo=rust
|
|
[crate-link]: https://crates.io/crates/hmac
|
|
[docs-image]: https://docs.rs/hmac/badge.svg
|
|
[docs-link]: https://docs.rs/hmac/
|
|
[build-image]: https://github.com/RustCrypto/MACs/actions/workflows/hmac.yml/badge.svg
|
|
[build-link]: https://github.com/RustCrypto/MACs/actions/workflows/hmac.yml
|
|
[license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg
|
|
[rustc-image]: https://img.shields.io/badge/rustc-1.85+-blue.svg
|
|
[chat-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg
|
|
[chat-link]: https://rustcrypto.zulipchat.com/#narrow/stream/260044-MACs
|
|
|
|
[//]: # (general links)
|
|
|
|
[RustCrypto]: https://github.com/RustCrypto
|
|
[HMAC]: https://en.wikipedia.org/wiki/HMAC
|
|
[`digest`]: https://docs.rs/digest
|
|
[`sha2`]: https://docs.rs/sha2
|
|
[`RustCrypto/hashes`]: https://github.com/RustCrypto/hashes
|
|
|
|
[//]: # (intra-crate links)
|
|
[`Reset`]: https://docs.rs/digest/latest/digest/trait.Reset.html
|
|
[`Digest`]: https://docs.rs/digest/latest/digest/trait.Digest.html
|
|
[`FixedOutputReset`]: https://docs.rs/digest/latest/digest/trait.FixedOutputReset.html
|
|
[`Hmac`]: https://docs.rs/hmac/latest/hmac/struct.Hmac.html
|
|
[`HmacReset`]: https://docs.rs/hmac/latest/hmac/struct.HmacReset.html
|
|
[`SimpleHmac`]: https://docs.rs/hmac/latest/hmac/struct.SimpleHmac.html
|
|
[`SimpleHmacReset`]: https://docs.rs/hmac/latest/hmac/struct.SimpleHmacReset.html
|
|
[`block_api::HmacCore`]: https://docs.rs/hmac/latest/hmac/block_api/struct.HmacCore.html
|
|
[`block_api::HmacResetCore`]: https://docs.rs/hmac/latest/hmac/block_api/struct.HmacResetCore.html
|