Expand description
This crate contains an implementation of the Hash-Based Message Authentication Code (HMAC) as specified in RFC2104, taking into account NIST Implementation Guidance in FIPS 140-2 IG A.8 and NIST SP 800-107-r1.
§Usage
The HMAC object (and the MAC trait in general) is designed in three phases:
- The initialization phase where you specify the underlying hash function and the key material.
- The update phase where you feed in the content being MAC’d, either in one-shot or in chunks.
- The finalization phase where you either obtain the MAC value or verify an existing MAC value.
The initialization phase is primarily performed via the MAC::new function which performs
checks on the provided key to ensure that it is of the correct type KeyType::MACKey and tagged
at the correct security level for the chosen hash function. In cases where you need to use HMAC
with an intentially week key (such as an all-zero salt), the alternative constructor
MAC::new_allow_weak_key can be used.
The update phase supports streaming of the content via the repeated calls to the MAC::do_update function.
One-shot APIs are provided that combine the update and finalization phases into a single function call.
§Examples
Instantiation of an HMAC object is straightforward:
use bouncycastle_hmac::HMAC_SHA256;
use bouncycastle_core::traits::MAC;
use bouncycastle_core::key_material::{KeyMaterial256};
let key: KeyMaterial256 = HMAC_SHA256::keygen().expect("Will only fail if the system RNG can't start up.");
let hmac = HMAC_SHA256::new(&key).expect(
"Should succeed because key is long enough and tagged KeyType::MACKey");Alternatively, if you have key material from somewhere else, you can create the key manually, like so:
use bouncycastle_hmac::HMAC_SHA256;
use bouncycastle_core::traits::MAC;
use bouncycastle_core::key_material::{KeyMaterial256, KeyType};
let key = KeyMaterial256::from_bytes_as_type(
b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
KeyType::MACKey).unwrap();
let hmac = HMAC_SHA256::new(&key).expect(
"Should succeed because key is long enough and tagged KeyType::MACKey");§Computing a MAC
MAC functionality is accessed via the MAC trait.
The simplest usage is via the one-shot functions.
use bouncycastle_hmac::HMAC_SHA256;
use bouncycastle_core::traits::MAC;
use bouncycastle_core::key_material::{KeyMaterial256, KeyType};
let key: KeyMaterial256 = HMAC_SHA256::keygen().expect("Will only fail if the system RNG can't start up.");
let data: &[u8] = b"Hello, world!";
let hmac = HMAC_SHA256::new(&key).expect("Should succeed because key is long enough and tagged KeyType::MACKey");
let output: Vec<u8> = hmac.mac(data);More advanced usage will require creating an HMAC object to hold state between successive calls, for example if input is received in chunks and not all available at the same time:
use bouncycastle_core::traits::MAC;
use bouncycastle_hmac::HMAC_SHA256;
use bouncycastle_core::key_material::{KeyMaterial256, KeyType};
let key: KeyMaterial256 = HMAC_SHA256::keygen().expect("Will only fail if the system RNG can't start up.");
let mut hmac = HMAC_SHA256::new(&key).expect("Should succeed because key is long enough and tagged KeyType::MACKey");
hmac.do_update(b"Hello,");
hmac.do_update(b" world!");
let output: Vec<u8> = hmac.do_final();§Verifying a MAC
MAC functionality is accessed via the MAC trait which provides functions for MAC verification.
The built-in verification functions use constant-time comparisons and so are strongly recommended
rather than re-computing the MAC value and comparing it yourself.
The simplest usage is via the one-shot functions.
use bouncycastle_core::key_material::{KeyMaterial256, KeyType};
use bouncycastle_core::traits::MAC;
// For this example to work, we are hard-coding both the key and the MAC value that it generates
// for this data.
let key = KeyMaterial256::from_bytes_as_type(
b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
KeyType::MACKey).unwrap();
let data: &[u8] = b"Hello, world!";
// .verify() returns a bool: true if the MAC is valid, false otherwise.
if bouncycastle_hmac::HMAC_SHA256::new(&key).unwrap()
.verify(data,
b"\xa2\xd1\x2e\xcf\xfc\x41\xba\xf1\x23\xd6\x3e\x44\xfc\x27\x88\x90
\x47\xcd\x08\xe7\x05\xd7\x0f\xa3\xb8\xaa\x8a\x5c\x18\x7c\x6c\xa9"
)
{
println!("MAC is valid!");
} else {
println!("MAC is invalid!");
}Similarly, a streaming version is available, which is identical to the streaming interface for
computing a mac value, but calls MAC::do_verify_final instead of MAC::do_final.
use bouncycastle_core::key_material::{KeyMaterial256, KeyType};
use bouncycastle_core::traits::MAC;
use bouncycastle_hmac::HMAC_SHA256;
// For this example to work, we are hard-coding both the key and the MAC value that it generates
// for this data.
let key = KeyMaterial256::from_bytes_as_type(
b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
KeyType::MACKey).unwrap();
let mut hmac = HMAC_SHA256::new(&key).unwrap();
hmac.do_update(b"Hello,");
hmac.do_update(b" world!");
if hmac.do_verify_final(b"\xa2\xd1\x2e\xcf\xfc\x41\xba\xf1\x23\xd6\x3e\x44\xfc\x27\x88\x90\x47\xcd\x08\xe7\x05\xd7\x0f\xa3\xb8\xaa\x8a\x5c\x18\x7c\x6c\xa9"
)
{
println!("MAC is valid!");
} else {
println!("MAC is invalid!");
}§Suspending and resuming execution
When MAC’ing a large message, it can be advantageous to be able to suspend the operation
to a cache and resume it later; for example if waiting for the message to stream over a slow network
connection. For this reason, all HMAC algorithms impl SuspendableKeyed.
Note that since HMAC is a keyed
algorithm and we do not want to serialize the private key into the state, the trait structure forces you to
re-provide the same key when you resume the operation. Securely storing this key in the interim
is the responsibility of the caller. Note also that if you resume the HMAC with the wrong key,
from_serialized_state has no way to detect this, so the end result will be a broken MAC value
computed with different keys in the inner and outer pad. So make sure you resume with the same key!
use bouncycastle_hmac::HMAC_SHA256;
use bouncycastle_core::key_material::KeyMaterial256;
use bouncycastle_core::traits::{MAC, SuspendableKeyed};
use bouncycastle_core::key_material::KeyType;
let msg_part1 = b"The quick brown fox";
let msg_part2 = b" jumped over the lazy dog";
let key = KeyMaterial256::from_bytes_as_type(
b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
KeyType::MACKey).unwrap();
let mut hmac = HMAC_SHA256::new(&key).unwrap();
hmac.do_update(msg_part1);
// suspend the in-progress mac (the key is NOT included in the serialized state)
let serialized_state = hmac.suspend();
// ...
// do other things in the meantime
// ...
// ... later, possibly on another host: resume from the serialized state by re-supplying
// the same salt (make sure you store it securely!).
let mut hmac_resumed = HMAC_SHA256::from_suspended(serialized_state, &key).unwrap();
hmac_resumed.do_update(msg_part2);
let h: Vec<u8> = hmac_resumed.do_final();Structs§
- HMAC
- Internal struct for HKDF. HMAC implements RFC 2104. Can, in theory, be instantiated with hash functions other than the ones provided by this crate (even custom ones).
Constants§
- HMAC_
SHA3_ 224_ NAME - HMAC_
SHA3_ 256_ NAME - HMAC_
SHA3_ 384_ NAME - HMAC_
SHA3_ 512_ NAME - HMAC_
SHA224_ NAME - HMAC_
SHA256_ NAME - HMAC_
SHA384_ NAME - HMAC_
SHA512_ NAME - MIN_
FIPS_ DIGEST_ LEN - Per FIPS 140-2 IG A.8 Use of a truncated HMAC (matching NIST SP 800-107-r1 Section 5.3.3. Truncation of HMAC), says that the minimum truncation of a HMAC for tagging should be 32 bits; this exceeds the lower bound set by IETF RFC 2104 Section 5 Truncated output, which sets the lower bound to be half of the hash’s length and no fewer than 80 bits.
- SUSPENDED_
HMAC_ SHA3_ 224_ STATE_ LEN - Length in bytes of the serialized state of
HMAC_SHA3_224. - SUSPENDED_
HMAC_ SHA3_ 256_ STATE_ LEN - Length in bytes of the serialized state of
HMAC_SHA3_256. - SUSPENDED_
HMAC_ SHA3_ 384_ STATE_ LEN - Length in bytes of the serialized state of
HMAC_SHA3_384. - SUSPENDED_
HMAC_ SHA3_ 512_ STATE_ LEN - Length in bytes of the serialized state of
HMAC_SHA3_512. - SUSPENDED_
HMAC_ SHA224_ STATE_ LEN - Length in bytes of the serialized state of
HMAC_SHA224. - SUSPENDED_
HMAC_ SHA256_ STATE_ LEN - Length in bytes of the serialized state of
HMAC_SHA256. - SUSPENDED_
HMAC_ SHA384_ STATE_ LEN - Length in bytes of the serialized state of
HMAC_SHA384. - SUSPENDED_
HMAC_ SHA512_ STATE_ LEN - Length in bytes of the serialized state of
HMAC_SHA512.
Type Aliases§
- HMAC_
SHA3_ 224 - Public type for HKDF using SHA3_224.
- HMAC_
SHA3_ 256 - Public type for HKDF using SHA3_256.
- HMAC_
SHA3_ 384 - Public type for HKDF using SHA3_384.
- HMAC_
SHA3_ 512 - Public type for HKDF using SHA3_512.
- HMAC_
SHA224 - Public type for HMAC using SHA224.
- HMAC_
SHA256 - Public type for HKDF using SHA256.
- HMAC_
SHA384 - Public type for HKDF using SHA384.
- HMAC_
SHA512 - Public type for HKDF using SHA512.