48 lines
		
	
	
		
			1.3 KiB
		
	
	
	
		
			Typst
		
	
	
	
	
	
			
		
		
	
	
			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))
 | |
| } |