Skip to main content

Crate bouncycastle_hmac

Crate bouncycastle_hmac 

Source
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.