RFC 2104
HMAC: Keyed-Hashing for Message Authentication
RFC 2104: HMAC: Keyed-Hashing for Message Authentication π
okay bestie, so this is the RFC that gave us HMAC πβ¨ It's from February 1997 and it's part of the Network Working Group. The authors are H. Krawczyk (IBM), M. Bellare (UCSD), and R. Canetti (IBM). It's Informational π§, and the title block doesn't list anything it obsoletes or updates.
Status of This Memo π
this one is giving "just for info, not a rule" π It provides information for the Internet community, and it does not specify an Internet standard of any kind. Distribution is unlimited π
Abstract π¦
HMAC is a way to do message authentication using cryptographic hash functions. You can plug in any iterative hash function (MD5 and SHA-1 are the examples) and combine it with a secret shared key. The strength of HMAC depends on how good the underlying hash function is, so it's only as strong as its hash π
1. Introduction β¨
okay so keeping information safe while it's zooming around an unreliable network, or sitting in storage, is a huge deal in open computing π Checks that prove a message hasn't been messed with using a secret key are usually called "message authentication codes" (MAC). Two parties that share a secret key usually use one to check the stuff they send each other π«Ά
This document introduces a MAC built on cryptographic hash functions, called HMAC. It comes from the authors' earlier work [BCK1], where the construction is presented and analyzed. If you want the rationale, the security analysis, and how it compares to other keyed-hash methods, go read that work π
HMAC works with any iterated cryptographic hash function. MD5 and SHA-1 are examples. It also uses a secret key to calculate and verify the authentication values. These are the main goals:
- To use available hash functions without modifications, especially ones that run well in software and whose code is free and widely available π
- To keep the original performance of the hash function without a big slowdown π
- To handle keys in a simple way π
- To have a well understood cryptographic analysis of the strength of the authentication mechanism, based on reasonable assumptions about the hash function π§
- To make it easy to swap the underlying hash function if faster or more secure ones show up or get required π
This document describes HMAC with a generic cryptographic hash function, written as H. Real versions of HMAC have to pick a specific hash function. Current candidates include SHA-1 [SHA], MD5 [MD5], and RIPEMD-128/160 [RIPEMD]. These versions are written as HMAC-SHA1, HMAC-MD5, HMAC-RIPEMD, and so on π
Note: As of when this was written, MD5 and SHA-1 were the most widely used cryptographic hash functions. MD5 was recently shown to be vulnerable to collision search attacks [Dobb]. That attack and the other known MD5 weaknesses do not compromise using MD5 inside HMAC as this document specifies (see [Dobb]). SHA-1 does look cryptographically stronger, though. For now, MD5 can be considered inside HMAC where MD5's better performance really matters. Either way, implementers and users need to keep an eye out for cryptanalytic developments on any of these hash functions, and be ready to replace the underlying hash function if they need to. (See section 6 for more on HMAC security.) π
2. Definition of HMAC π₯
HMAC needs a cryptographic hash function (we call it H) and a secret key K. H is assumed to hash data by repeatedly running a basic compression function over blocks of data. B is the byte length of those blocks (B=64 for all the hash functions mentioned above), and L is the byte length of the hash output (L=16 for MD5, L=20 for SHA-1). The authentication key K can be any length up to B, the block length of the hash function. If you use a key longer than B bytes, you first hash it with H, and then use that L byte result as the actual HMAC key. Either way, the minimum recommended length for K is L bytes (the hash output length). See section 3 for more on keys ποΈ
Two fixed, different strings called ipad and opad are defined as follows. The "i" and "o" are short for inner and outer π
ipad = the byte 0x36 repeated B times
opad = the byte 0x5C repeated B times.
To compute HMAC over the data text, you do:
H(K XOR opad, H(K XOR ipad, text))
Here is how it breaks down, step by step π
- Append zeros to the end of K to make a B byte string. (For example, if K is 20 bytes long and B=64, then K gets 44 zero bytes
0x00appended to it.) - XOR (bitwise exclusive-OR) the B byte string from step (1) with ipad.
- Append the stream of data
textto the B byte string from step (2). - Apply H to the stream from step (3).
- XOR (bitwise exclusive-OR) the B byte string from step (1) with opad.
- Append the H result from step (4) to the B byte string from step (5).
- Apply H to the stream from step (6), and output the result.
For illustration, sample code based on MD5 is given in an appendix β¨
3. Keys ποΈ
The HMAC key can be any length. Keys longer than B bytes get hashed with H first. Using less than L bytes is strongly discouraged, though, because it lowers the security strength of the function π¬ Keys longer than L bytes are fine, but the extra length won't meaningfully boost the strength. (A longer key might be a good idea if you think the key's randomness is weak πΈ)
Keys need to be picked at random (or made with a cryptographically strong pseudo-random generator seeded with a random seed), and they should be refreshed periodically π Current attacks don't point to one specific recommended frequency for changing keys, since these attacks are practically infeasible. Still, periodic key refreshing is a fundamental security practice. It helps guard against possible weaknesses in the function and keys, and it limits the damage if a key ever gets exposed π‘οΈ
4. Implementation Note π»
HMAC is designed so the underlying hash function H can be used with no modification to its code. It runs H with the predefined initial value IV, which is a fixed value each iterative hash function specifies to start its compression function. If you want, you can get a performance boost by changing H's code to support variable IVs, though that's optional and might mean modifying H π§
The idea is this: the intermediate results of the compression function on the B-byte blocks (K XOR ipad) and (K XOR opad) can be precomputed just once, either when K is generated or before its first use. These intermediate results get stored, and then used to initialize H's IV every time a message needs to be authenticated. This saves, for each authenticated message, running H's compression function on two B-byte blocks (that is, on (K XOR ipad) and (K XOR opad)). That can add up to a real saving when you're authenticating short streams of data β‘ Important: the stored intermediate values have to be treated and protected the same way as secret keys π
Doing HMAC this way is up to the local implementation, and it has no effect on interoperability π«Ά
5. Truncated output βοΈ
Truncating a MAC's output, so only some of the bits come out, is a well-known practice. For example, see [MM, ANSI]. Preneel and van Oorschot [PV] show some analytical advantages to truncating hash-based MAC output. The results here aren't absolute when it comes to the overall security benefits of truncation. Truncation has advantages (the attacker has less information about the hash result) and disadvantages (the attacker has fewer bits to predict) π€
Applications can truncate HMAC's output by keeping the t leftmost bits of the HMAC computation, for some parameter t. The computation runs normally as defined in section 2, and only the final result gets cut down to t bits. The recommendation is that the output length t be not less than half the length of the hash output (to match the birthday attack bound), and not less than 80 bits (a suitable lower bound on the number of bits an attacker needs to predict) π
This document proposes naming a version of HMAC that uses a hash function H with t bits of output HMAC-H-t. For example, HMAC-SHA1-80 means HMAC computed with the SHA-1 function and output truncated to 80 bits. If t isn't specified (like HMAC-MD5), then all the bits of the hash are output π¦
6. Security π‘οΈ
okay bestie, this is the part where we talk about why HMAC is actually safe π The security of this message authentication mechanism depends on some cryptographic properties of the hash function H. First, it needs resistance to collision finding, which only counts when the initial value is secret and random and the output isn't explicitly available to the attacker. Second, it needs the message authentication property of the compression function of H when it's applied to single blocks. In HMAC those blocks are partially unknown to an attacker, since they contain the result of the inner H computation, so the attacker can't fully choose them. Lowkey iconic π
These properties, and honestly stronger ones too, are commonly assumed for hash functions of the kind used with HMAC πΈ A hash function where these properties don't hold would become unsuitable for most (probably all) cryptographic applications, and that includes alternative message authentication schemes built on top of those functions. (If you want a full analysis and rationale of the HMAC function, go read [BCK1]. It's a whole vibe π€)
Okay, so, the confidence we have in candidate hash functions is kind of limited so far, which means it's really important to notice these two properties of the HMAC construction and how it's used securely for message authentication π¦
- The construction doesn't depend on the details of the particular hash function H in use. That means H can be replaced by any other secure (iterative) cryptographic hash function. Main character flexibility β¨
- Message authentication, unlike encryption, has a "transient" effect π§ If someone publishes a break of a message authentication scheme, the scheme gets replaced, but it has no adversarial effect on information that was authenticated in the past. This is in sharp contrast with encryption, where information encrypted today might get exposed in the future if and when the encryption algorithm gets broken. Encryption really said "later problem" π
The strongest attack known against HMAC is based on the frequency of collisions for the hash function H, which is called the "birthday attack" [PV,BCK2]. It's totally impractical for minimally reasonable hash functions π
Here's an example. Say we look at a hash function like MD5, where the output length equals L=16 bytes (128 bits). The attacker would need to acquire the correct message authentication tags, computed with the same secret key K!, on about 264 known plaintexts. That would require processing at least 264 blocks under H, which is an impossible task in any realistic scenario. For a block length of 64 bytes, this would take 250,000 years on a continuous 1Gbps link, and that's without changing the secret key K during all that time π This attack could only become realistic if serious flaws in the collision behavior of the function H were discovered (for example, collisions found after 2**30 messages). Such a discovery would immediately determine the replacement of the function H. And the effects of that failure would be way more severe for the traditional uses of H in digital signatures, public key certificates, and so on π¨
Note: this attack needs to be strongly contrasted with regular collision attacks on cryptographic hash functions. Those don't involve any secret key, and 264 off-line parallelizable (!) operations are enough to find collisions. That latter attack is approaching feasibility [VW], while the birthday attack on HMAC is totally impractical. (In the examples above, if you use a hash function with, say, 160 bit of output, then 264 should be replaced by 2**80.)
Finally, the whole integrity thing needs a few ingredients to be essential: a correct implementation of the construction above, the choice of random (or cryptographically pseudorandom) keys, a secure key exchange mechanism, frequent key refreshments, and good secrecy protection of keys ππ«Ά Treat your keys like your diary, bestie π
Appendix -- Sample Code π§ͺ
For the sake of illustration, here's sample code for implementing HMAC-MD5, along with some matching test vectors. The code is based on the MD5 code described in [MD5] π
/*
** Function: hmac_md5
*/
void
hmac_md5(text, text_len, key, key_len, digest)
unsigned char* text; /* pointer to data stream */
int text_len; /* length of data stream */
unsigned char* key; /* pointer to authentication key */
int key_len; /* length of authentication key */
caddr_t digest; /* caller digest to be filled in */
{
MD5_CTX context;
unsigned char k_ipad[65]; /* inner padding -
* key XORd with ipad
*/
unsigned char k_opad[65]; /* outer padding -
* key XORd with opad
*/
unsigned char tk[16];
int i;
/* if key is longer than 64 bytes reset it to key=MD5(key) */
if (key_len > 64) {
MD5_CTX tctx;
MD5Init(&tctx);
MD5Update(&tctx, key, key_len);
MD5Final(tk, &tctx);
key = tk;
key_len = 16;
}
/*
* the HMAC_MD5 transform looks like:
*
* MD5(K XOR opad, MD5(K XOR ipad, text))
*
* where K is an n byte key
* ipad is the byte 0x36 repeated 64 times
* opad is the byte 0x5c repeated 64 times
* and text is the data being protected
*/
/* start out by storing key in pads */
bzero( k_ipad, sizeof k_ipad);
bzero( k_opad, sizeof k_opad);
bcopy( key, k_ipad, key_len);
bcopy( key, k_opad, key_len);
/* XOR key with ipad and opad values */
for (i=0; i<64; i++) {
k_ipad[i] ^= 0x36;
k_opad[i] ^= 0x5c;
}
/*
* perform inner MD5
*/
MD5Init(&context); /* init context for 1st
* pass */
MD5Update(&context, k_ipad, 64) /* start with inner pad */
MD5Update(&context, text, text_len); /* then text of datagram */
MD5Final(digest, &context); /* finish up 1st pass */
/*
* perform outer MD5
*/
MD5Init(&context); /* init context for 2nd
* pass */
MD5Update(&context, k_opad, 64); /* start with outer pad */
MD5Update(&context, digest, 16); /* then results of 1st
* hash */
MD5Final(digest, &context); /* finish up 2nd pass */
}
Now for the test vectors π§ (the trailing '\0' of a character string isn't included in the test):
Test Vectors (Trailing '\0' of a character string not included in test):
key = 0x0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b
key_len = 16 bytes
data = "Hi There"
data_len = 8 bytes
digest = 0x9294727a3638bb1c13f48ef8158bfc9d
key = "Jefe"
data = "what do ya want for nothing?"
data_len = 28 bytes
digest = 0x750c783e6ab0b503eaa86e310a5db738
key = 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
key_len 16 bytes
data = 0xDDDDDDDDDDDDDDDDDDDD...
..DDDDDDDDDDDDDDDDDDDD...
..DDDDDDDDDDDDDDDDDDDD...
..DDDDDDDDDDDDDDDDDDDD...
..DDDDDDDDDDDDDDDDDDDD
data_len = 50 bytes
digest = 0x56be34521d144c88dbb8c733f0e8b3f6
Acknowledgments π«Ά
Pau-Chen Cheng, Jeff Kraemer, and Michael Oehler gave useful comments on early drafts, and they ran the first interoperability tests of this specification π Jeff and Pau-Chen also kindly provided the sample code and test vectors in the appendix. Burt Kaliski, Bart Preneel, Matt Robshaw, Adi Shamir, and Paul van Oorschot gave useful comments and suggestions while the HMAC construction was being investigated π
References π
[ANSI] ANSI X9.9, "American National Standard for Financial
Institution Message Authentication (Wholesale)," American
Bankers Association, 1981. Revised 1986.
[Atk] Atkinson, R., "IP Authentication Header", RFC 1826, August
1995.
[BCK1] M. Bellare, R. Canetti, and H. Krawczyk,
"Keyed Hash Functions and Message Authentication",
Proceedings of Crypto'96, LNCS 1109, pp. 1-15.
(http://www.research.ibm.com/security/keyed-md5.html)
[BCK2] M. Bellare, R. Canetti, and H. Krawczyk,
"Pseudorandom Functions Revisited: The Cascade Construction",
Proceedings of FOCS'96.
[Dobb] H. Dobbertin, "The Status of MD5 After a Recent Attack",
RSA Labs' CryptoBytes, Vol. 2 No. 2, Summer 1996.
http://www.rsa.com/rsalabs/pubs/cryptobytes.html
[PV] B. Preneel and P. van Oorschot, "Building fast MACs from hash
functions", Advances in Cryptology -- CRYPTO'95 Proceedings,
Lecture Notes in Computer Science, Springer-Verlag Vol.963,
1995, pp. 1-14.
[MD5] Rivest, R., "The MD5 Message-Digest Algorithm",
RFC 1321, April 1992.
[MM] Meyer, S. and Matyas, S.M., Cryptography, New York Wiley,
1982.
[RIPEMD] H. Dobbertin, A. Bosselaers, and B. Preneel, "RIPEMD-160: A
strengthened version of RIPEMD", Fast Software Encryption,
LNCS Vol 1039, pp. 71-82.
ftp://ftp.esat.kuleuven.ac.be/pub/COSIC/bosselae/ripemd/.
[SHA] NIST, FIPS PUB 180-1: Secure Hash Standard, April 1995.
[Tsu] G. Tsudik, "Message authentication with one-way hash
functions", In Proceedings of Infocom'92, May 1992.
(Also in "Access Control and Policy Enforcement in
Internetworks", Ph.D. Dissertation, Computer Science
Department, University of Southern California, April 1991.)
[VW] P. van Oorschot and M. Wiener, "Parallel Collision
Search with Applications to Hash Functions and Discrete
Logarithms", Proceedings of the 2nd ACM Conf. Computer and
Communications Security, Fairfax, VA, November 1994.
Authors' Addresses π
Hugo Krawczyk
IBM T.J. Watson Research Center
P.O.Box 704
Yorktown Heights, NY 10598
EMail: hugo@watson.ibm.com
Mihir Bellare
Dept of Computer Science and Engineering
Mail Code 0114
University of California at San Diego
9500 Gilman Drive
La Jolla, CA 92093
EMail: mihir@cs.ucsd.edu
Ran Canetti
IBM T.J. Watson Research Center
P.O.Box 704
Yorktown Heights, NY 10598
EMail: canetti@watson.ibm.com
π¦ where this page comes from
- ietf: rfc2104 1997-02
- π girlified by claude-haiku-5-5 on : a language model's rewrite of the original, under its terms