Browse the docs

silk.crypto.hmac.

Compute HMAC tags (RFC 2104) with SHA-256 or SHA-384.

When to use#

Use HmacSha256 or HmacSha384 to prove that a message comes from someone who has a shared secret key and was not changed, for example to sign a webhook or a cookie. Use silk.crypto.hkdf to derive keys, and silk.crypto.sha2 for a hash without a key.

Details#

HmacSha256.authenticate returns the tag of one message. For a message that arrives in parts, call make with the key, then update for each part, then finish. Any key length is valid. A key longer than the block size (64 bytes for SHA-256, 128 for SHA-384) is hashed first. Nothing allocates.

Gotchas#

This module computes tags, but it does not compare them. To check a received tag, compare all bytes in constant time, as the example shows. Do not use == or a loop that stops at the first difference. The states hold key material and are not erased when they are dropped.

Examples#

Check a received tag#

silk
import silk.crypto.hmac { HmacSha256 }
import silk.num.u8

// Compares in constant time, so the time does not tell an attacker how many bytes match.
fn same(left: &[u8; 32], right: &[u8; 32]) -> bool {
  let mut difference: u8 = 0
  let mut index: usize = 0
  while index < 32 {
    difference = u8.bitOr(difference, u8.bitXor(left[index], right[index]))
    index = index + 1
  }
  return difference == 0
}

pub fn main() -> i32 {
  let key = b"key"
  let message = b"The quick brown fox jumps over the lazy dog"
  let received = HmacSha256.authenticate(key, message)
  let mut state = HmacSha256.make(key)
  state.update(b"The quick brown fox ")
  state.update(b"jumps over the lazy dog")
  let expected = state.finish()

  // HMAC-SHA-256 of this key and message is f7bc83f4...d8.
  if !same(&received, &expected) || expected[0] != 0xf7 || expected[31] != 0xd8 {
    return 1
  }
  return 0
}

Import as HmacSha256 with import silk.crypto.hmac { HmacSha256 }.

Public declarations: 2.

HmacSha256#

silk
pub struct HmacSha256

A streaming HMAC-SHA-256 state (RFC 2104) that returns a 32-byte tag.

Call HmacSha256.make with the key, HmacSha256.update for each part of the message, then HmacSha256.finish. For one message, use HmacSha256.authenticate. The state is a fixed-size value. It holds key material and is not erased when it is dropped.

When to use#

Use it to prove that a message comes from someone who has a shared secret key and was not changed, for example to sign a webhook or a cookie. Use silk.crypto.hkdf to derive keys, and silk.crypto.sha2 for a hash without a key.

Details#

Any key length is valid. A key longer than the block size (64 bytes) is hashed first. Nothing allocates.

Gotchas#

It computes tags, but it does not compare them. To check a received tag, compare all bytes in constant time. Do not use == or a loop that stops at the first difference.

Implementation HmacSha256#

silk
impl HmacSha256

Associated function make#

silk
pub fn make(key: &[u8]) -> HmacSha256

Returns an HMAC-SHA-256 state for key. Any key length is valid, also 0.

A key longer than 64 bytes is hashed first. The state copies what it needs and does not borrow key.

Method update#

silk
pub fn update(self: &mut Self, bytes: &[u8]) -> ()

Adds bytes to the end of the message.

Any split of the message into parts gives the same tag. An empty slice changes nothing.

Gotchas#

The program traps if the message is longer than 2^64 - 1 bits minus the 64-byte key block.

Method finish#

silk
pub fn finish(self: Self) -> [u8; 32]

Returns the 32-byte HMAC-SHA-256 tag of the message and consumes the state.

Associated function authenticate#

silk
pub fn authenticate(key: &[u8], message: &[u8]) -> [u8; 32]

Returns the 32-byte HMAC-SHA-256 tag of message with key.

An empty key or message is valid. To check a received tag, compare all bytes in constant time. Do not use == or a loop that stops at the first difference.

HmacSha384#

silk
pub struct HmacSha384

A streaming HMAC-SHA-384 state (RFC 2104) that returns a 48-byte tag.

Call HmacSha384.make with the key, HmacSha384.update for each part of the message, then HmacSha384.finish. For one message, use HmacSha384.authenticate. The state is a fixed-size value. It holds key material and is not erased when it is dropped.

When to use#

Use it to prove that a message comes from someone who has a shared secret key and was not changed, for example to sign a webhook or a cookie. Use silk.crypto.hkdf to derive keys, and silk.crypto.sha2 for a hash without a key.

Details#

Any key length is valid. A key longer than the block size (128 bytes) is hashed first. Nothing allocates.

Gotchas#

It computes tags, but it does not compare them. To check a received tag, compare all bytes in constant time. Do not use == or a loop that stops at the first difference.

Implementation HmacSha384#

silk
impl HmacSha384

Associated function make#

silk
pub fn make(key: &[u8]) -> HmacSha384

Returns an HMAC-SHA-384 state for key. Any key length is valid, also 0.

A key longer than 128 bytes is hashed first. The state copies what it needs and does not borrow key.

Method update#

silk
pub fn update(self: &mut Self, bytes: &[u8]) -> ()

Adds bytes to the end of the message.

Any split of the message into parts gives the same tag. An empty slice changes nothing.

Gotchas#

The program traps if the message is longer than 2^128 - 1 bits minus the 128-byte key block.

Method finish#

silk
pub fn finish(self: Self) -> [u8; 48]

Returns the 48-byte HMAC-SHA-384 tag of the message and consumes the state.

Associated function authenticate#

silk
pub fn authenticate(key: &[u8], message: &[u8]) -> [u8; 48]

Returns the 48-byte HMAC-SHA-384 tag of message with key.

An empty key or message is valid. To check a received tag, compare all bytes in constant time. Do not use == or a loop that stops at the first difference.

Category: Cryptography.

Profiles: aarch64-apple-darwin, aarch64-unknown-linux-gnu, aarch64-unknown-linux-gnu-no-libc, x86_64-unknown-linux-gnu, x86_64-unknown-linux-gnu-no-libc, wasm32-unknown-unknown, wasm32-wasip1, wasm32-wasip2.

View the source of this page