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#
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#
pub struct HmacSha256A 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#
impl HmacSha256Associated function make#
pub fn make(key: &[u8]) -> HmacSha256Returns 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#
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#
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#
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#
pub struct HmacSha384A 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#
impl HmacSha384Associated function make#
pub fn make(key: &[u8]) -> HmacSha384Returns 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#
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#
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#
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.