48 lines
1.3 KiB
Typst

#import "utils.typ": xor-bytes
#import "sha.typ": sha1
#let _compute-block-sized-key(key, hash-func: sha1, block-size: 64) = {
if key.len() > block-size {
key = hash-func(key)
}
if key.len() < block-size {
key = bytes((0,) * (block-size - key.len())) + key
}
return key
}
/// Hash-based Message Authentication Code
/// ```example
/// #bytes-to-hex(hmac("Key", "Hello World!"))
/// ```
/// -> bytes
#let hmac(
/// Hashing key
/// -> str | bytes
key,
/// Message to hash
/// -> str | bytes
message,
/// Hashing function
/// -> function
hash-func: sha1,
/// Block size
/// -> number
block-size: 64
) = {
let key = if type(key) == str {bytes(key)} else {key}
let message = if type(message) == str {bytes(message)} else {message}
assert(type(key) == bytes, message: "key must be a string or bytes, but is " + repr(type(key)))
assert(type(message) == bytes, message: "message must be a string or bytes, but is " + repr(type(message)))
let block-sized-key = _compute-block-sized-key(key, hash-func: hash-func, block-size: block-size)
let i-pad = bytes((0x36,) * block-size)
let o-pad = bytes((0x5c,) * block-size)
let i-key-pad = xor-bytes(key, i-pad)
let o-key-pad = xor-bytes(key, o-pad)
return hash-func(o-key-pad + hash-func(i-key-pad + message))
}