Tiny HMAC is a lightweight, configurable C library for computing HMACs using all SHA and SHA3 variants.
It builds on Tiny SHA — also available as a standalone project at https://github.com/0xNullll/tiny-sha — and allows optional direct use of Tiny SHA functions.
- Configurable HMAC support for multiple hash algorithms:
- SHA-1 / SHA-2: SHA1, SHA224, SHA256, SHA384, SHA512, SHA512/224, SHA512/256
- SHA-3: SHA3-224, SHA3-256, SHA3-384, SHA3-512
- Separate implementation file (tiny_hmac.c) and header (tiny_hmac.h)
- One-shot HMAC computation or incremental update/finalize interface.
- Context cloning and heap allocation support.
- Function name prefixing for integration into larger projects.
- Key size up to 512 bytes.
- Safe Constant-time HMAC equality comparison using
HMAC_ConstTimeCompare, returning 1 if equal or 0 if different, without leaking timing. - Handles endianness automatically.
- Lightweight — the compiled library stays under 30 KB.
SHA variants in Tiny SHA can also be used directly, but SHAKE and raw Keccak are disabled by default.
Before including the header, users can configure feature flags:
#define ENABLE_SHA1 1 // enable SHA1 HMAC
#define ENABLE_SHA256 1 // enable SHA256 HMAC
#define ENABLE_SHA3_512 0 // disable SHA3-512 HMAC
#define TSHASH_PREFIX mylib_ // optional prefix for exported functionsYou can also define it via compiler flags or CMake for build integration:
target_compile_definitions(tiny_hmac_test PRIVATE
ENABLE_SHA1=1
ENABLE_SHA224=1
ENABLE_SHA256=1
ENABLE_SHA384=1
ENABLE_SHA512=1
ENABLE_SHA512_224=1
ENABLE_SHA512_256=1
ENABLE_SHA3_224=1
ENABLE_SHA3_256=1
ENABLE_SHA3_384=1
ENABLE_SHA3_512=1
TSHASH_PREFIX=MyLib # optional function prefix
)
⚠️ Note:TSHASH_PREFIXmust be defined before including the header. If not defined, functions will have no prefix (default behavior).
- Open a terminal and navigate to your project folder:
$ cd /path/to/repo/tiny-hmac- Create and enter the
builddirectory:
$ mkdir build
$ cd build- Configure the project:
$ cmake ..- Build the project (Release mode recommended):
$ cmake --build . --config Release- The final binary will be located in:
$ build/bin/Release/hmac_test.exe
The library uses an internal table to map HMAC algorithms to their properties and Tiny SHA function pointers:
static const struct _HMAC_TABLE {
hmac_alg_t alg; // Algorithm identifier
size_t digest_size; // Digest length in bytes
size_t block_size; // Internal block size
size_t ctx_size; // Size of hash context
bool (*hash_init)(void*); // Hash init function pointer
bool (*hash_update)(void*, const uint8_t*, size_t); // Hash update pointer
bool (*hash_final)(void*, uint8_t*, size_t); // Hash final pointer
bool (*hash_squeeze)(void*, uint8_t*, size_t); // Hash squeeze pointer
} HMAC_TABLE[];This table is used internally by HMAC_Init to configure the context according to the selected algorithm.
#include "tiny_hmac.h"uint8_t digest[64]; // max digest size
HMAC_Compute(HMAC_SHA256, key, key_len, data, data_len, digest, sizeof(digest));HMAC_CTX ctx;
HMAC_Init(&ctx, HMAC_SHA256, key, key_len);
HMAC_Update(&ctx, data_part1, len1);
HMAC_Update(&ctx, data_part2, len2);
HMAC_Final(&ctx, digest, sizeof(digest));
HMAC_Free(&ctx);HMAC_CTX *ctx = HMAC_InitAlloc(HMAC_SHA256, key, key_len);
HMAC_Update(ctx, data, data_len);
HMAC_Final(ctx, digest, sizeof(digest));
HMAC_FreeAlloc(&ctx);typedef enum {
HMAC_SHA1, HMAC_SHA224, HMAC_SHA256,
HMAC_SHA384, HMAC_SHA512, HMAC_SHA512_224, HMAC_SHA512_256,
HMAC_SHA3_224, HMAC_SHA3_256, HMAC_SHA3_384, HMAC_SHA3_512
} hmac_alg_t;| Algorithm | Digest Size |
|---|---|
| HMAC-SHA-1 | 20 bytes |
| HMAC-SHA-224 | 28 bytes |
| HMAC-SHA-256 | 32 bytes |
| HMAC-SHA-384 | 48 bytes |
| HMAC-SHA-512 | 64 bytes |
| HMAC-SHA-512/224 | 28 bytes |
| HMAC-SHA-512/256 | 32 bytes |
| HMAC-SHA3-224 | 28 bytes |
| HMAC-SHA3-256 | 32 bytes |
| HMAC-SHA3-384 | 48 bytes |
| HMAC-SHA3-512 | 64 bytes |
typedef struct _HMAC_CTX {
hmac_alg_t alg;
void *ipad_ctx;
void *opad_ctx;
size_t ctx_buf_size;
size_t ctx_block_size;
size_t out_len;
bool (*hash_init)(void*);
bool (*hash_update)(void*, const uint8_t*, size_t);
bool (*hash_final)(void*, uint8_t*, size_t);
bool (*hash_squeeze)(void*, uint8_t*, size_t);
uint8_t key[512];
size_t key_len;
int isFinalized;
int isHeapAlloc;
} HMAC_CTX;| Function | Description |
|---|---|
HMAC_Init |
Initialize a pre-allocated HMAC context |
HMAC_InitAlloc |
Initialize and allocate a heap HMAC context |
HMAC_Update |
Feed data into the HMAC |
HMAC_Final |
Finalize HMAC and write digest |
HMAC_Free |
Free internal buffers for pre-allocated context |
HMAC_FreeAlloc |
Free heap-allocated context |
HMAC_Compute |
One-shot HMAC computation |
HMAC_CloneCtx |
Clone an existing HMAC context into a destination context |
HMAC_CloneCtxAlloc |
Clone an HMAC context into a new heap-allocated context |
HMAC_ConstTimeCompareOrder |
Constant-time digest comparison returning ordering (-1,0,+1) |
HMAC_DigestSize |
Get the digest size of a hash algorithm |
HMAC_Name |
Get the human-readable name of the algorithm |
#include "tiny_hmac.h"
#include <stdio.h>
int main() {
uint8_t key[] = "secret";
uint8_t data[] = "hello world";
uint8_t digest[SHA256_DIGEST_SIZE];
if(HMAC_Compute(HMAC_SHA256, key, sizeof(key)-1, data, sizeof(data)-1, digest, sizeof(digest))) {
printf("HMAC-SHA256 computed successfully!\n");
} else {
printf("HMAC computation failed\n");
}
return 0;
}- RFC 6234 – US Secure Hash Algorithms (SHA and SHA‑based HMAC and HKDF), May 2011
- FIPS PUB 202 – SHA‑3 Standard: Permutation-Based Hash and Extendable-Output Functions, August 2015
- RFC 5869 – HMAC-based Extract-and-Expand Key Derivation Function (HKDF), May 2010
This project is released under the MIT License. See LICENSE for full text.