HMAC(3)

πŸ“¦ version 4.4.0, in alpine 3.24, arch rolling

πŸ’– HMAC(3) β€” library functions manual, but make it make sense πŸ’–

okay bestie so this is the HMAC(3) page from the library functions manual and it's genuinely one of those pages that looks scary and then turns out to be a whole vibe once you actually read it. we're doing message authentication codes today. hydrate first. πŸ₯€


✨ NAME ✨

HMAC, HMAC_CTX_new, HMAC_CTX_reset, HMAC_CTX_free, HMAC_Init_ex, HMAC_Update, HMAC_Final, HMAC_CTX_copy, HMAC_CTX_set_flags, HMAC_CTX_get_md, HMAC_size β€” HMAC message authentication code. that's the whole roster, no one's getting left out πŸ’…


🌸 SYNOPSIS 🌸

so first of all, this whole thing lives in library β€œlibcrypto”, and you get to it like this:

#include <openssl/hmac.h>

then the functions, in all their glory:

unsigned char *
HMAC(const EVP_MD *evp_md, const void *key, int key_len,
    const unsigned char *d, size_t n, unsigned char *md,
    unsigned int *md_len);

HMAC_CTX *
HMAC_CTX_new(void);

int
HMAC_CTX_reset(HMAC_CTX *ctx);

void
HMAC_CTX_free(HMAC_CTX *ctx);

int
HMAC_Init_ex(HMAC_CTX *ctx, const void *key, int key_len,
    const EVP_MD *md, ENGINE *engine);

int
HMAC_Update(HMAC_CTX *ctx, const unsigned char *data, size_t len);

int
HMAC_Final(HMAC_CTX *ctx, unsigned char *md, unsigned int *len);

int
HMAC_CTX_copy(HMAC_CTX *dctx, HMAC_CTX *sctx);

void
HMAC_CTX_set_flags(HMAC_CTX *ctx, unsigned long flags);

const EVP_MD *
HMAC_CTX_get_md(const HMAC_CTX *ctx);

size_t
HMAC_size(const HMAC_CTX *e);

copy those exactly babe, don't freestyle the signatures, that's not the assignment πŸ™ˆ


πŸ¦‹ DESCRIPTION πŸ¦‹

so HMAC is a MAC β€” that's a message authentication code β€” which is literally just a keyed hash function used for message authentication, built on top of a hash function. it's giving "hash but with a secret" and honestly? iconic. πŸ‘‘

πŸŽ€ the one-shot girlies πŸŽ€

HMAC() computes the message authentication code of the n bytes at d, using the hash function evp_md and the key key which is key_len bytes long.

it drops the result into md, which must have space for the output of the hash function β€” and that output is no more than EVP_MAX_MD_SIZE bytes, so plan accordingly bestie. the size of the output goes into md_len, unless that's NULL, in which case, fine, keep your secrets.

evp_md can be EVP_sha1(3), EVP_ripemd160(3), etc. mix and match, live your truth ✨

πŸ’œ the context girlies πŸ’œ

HMAC_CTX_new() allocates and initializes a brand new HMAC_CTX object. new context, new me.

HMAC_CTX_reset() zeroes and re-initializes ctx and its associated resources, making it suitable for new computations β€” like it was deleted with HMAC_CTX_free() and freshly created with HMAC_CTX_new() all over again. glow-up via reset, we love a reinvention arc πŸ’«

HMAC_CTX_free() erases the key and other data from ctx, releases any associated resources, and finally frees ctx itself. it's the goodbye tour, and it's thorough πŸ’€

🌈 when your message doesn't fit in memory 🌈

the following functions may be used if the message is not completely stored in memory. streaming era fr fr:

HMAC_Init_ex() sets up or reuses ctx to use the hash function evp_md and the key key. either one can be NULL, in which case the existing one is reused. honestly so chill of it.

ok important detail: the ctx must have been created with HMAC_CTX_new() before the first use in this function. don't skip steps babe.

and also β€” if HMAC_Init_ex() is called with a NULL key but evp_md is neither NULL nor the same as the previous digest used by ctx, then an error is returned, because reuse of an existing key with a different digest is not supported. it's a compatibility thing, not a you thing.

the ENGINE *engine argument is always ignored and passing NULL is recommended. it's giving decorative. it's giving background character energy. πŸ«₯

HMAC_Update() can be called repeatedly with chunks of the message to be authenticated (len bytes at data). feed it piece by piece, it eats πŸ“

HMAC_Final() places the message authentication code in md, which must have space for the hash function output. final answer, no takesies backsies.

HMAC_CTX_copy() copies all of the internal state from sctx into dctx. clone behavior, and we're obsessed.

HMAC_CTX_set_flags() applies the specified flags to the internal EVP_MD_CTX objects. the possible flag values EVP_MD_CTX_FLAG_* are defined in <openssl/evp.h>. go read the header, it's free ✨

HMAC_size() returns the length in bytes of the underlying hash function output. and heads up β€” it's implemented as a macro, so it's not a real function call, keep that in mind iykyk.


⭐ RETURN VALUES ⭐

vibe check on what comes back to you:

  • HMAC() returns a pointer to the message authentication code, or NULL if an error occurred.
  • HMAC_CTX_new() returns a pointer to the new HMAC_CTX object, or NULL if an error occurred.
  • HMAC_CTX_reset(), HMAC_Init_ex(), HMAC_Update(), HMAC_Final(), and HMAC_CTX_copy() return 1 for success or 0 if an error occurred. classic binary yes/no, very demure.
  • HMAC_CTX_get_md() returns the message digest that was previously set for ctx with HMAC_Init_ex(), or NULL if none was set.
  • HMAC_size() returns the length in bytes of the underlying hash function output, or 0 on error.

πŸ”₯ SEE ALSO πŸ”₯

go read these next, bestie, they're the supporting cast:


πŸ‘‘ STANDARDS πŸ‘‘

RFC 2104. that's it, that's the standard. periodt. πŸ’…


🌸 HISTORY 🌸

the lore drop, chronological order, and yes it goes all the way back:

  • HMAC(), HMAC_Update(), HMAC_Final(), and HMAC_size() first appeared in SSLeay 0.9.0 and have been available since OpenBSD 2.4.
  • HMAC_Init_ex() first appeared in OpenSSL 0.9.7 and have been available since OpenBSD 3.2.
  • HMAC_CTX_set_flags() first appeared in OpenSSL 0.9.7f and have been available since OpenBSD 3.8.
  • HMAC_CTX_copy() first appeared in OpenSSL 1.0.0 and has been available since OpenBSD 4.9.
  • HMAC_CTX_new(), HMAC_CTX_reset(), HMAC_CTX_free(), and HMAC_CTX_get_md() first appeared in OpenSSL 1.1.0 and have been available since OpenBSD 6.3.

generational icons, all of them 🧚


πŸ’€ CAVEATS πŸ’€

not me having to tell you this but: other implementations allow md in HMAC() to be NULL and return a static array, which is not thread safe. so like, that's a them thing, not a here thing. do not assume. do not copy that behavior. πŸ™ˆ

that's the whole page bestie, you ate it up, no crumbs left πŸ“πŸ’–

Debian Β· June 8, 2025 Β· HMAC(3) β€” mwah, go authenticate something responsibly. πŸŽ€πŸ«Ά

πŸ“¦ where this page comes from