Why does the RFC version of HKDF-Expand start the counter at 1?

In RFC 5869, the definition of HKDF-Expand is given as follows, with the terminating counter value ranging from 1 to (presumably) 255:

The output OKM is calculated as follows:

N = ceil(L/HashLen)
T = T(1) | T(2) | T(3) | ... | T(N)
OKM = first L octets of T

where:
T(0) = empty string (zero length)
T(1) = HMAC-Hash(PRK, T(0) | info | 0x01)
T(2) = HMAC-Hash(PRK, T(1) | info | 0x02)
T(3) = HMAC-Hash(PRK, T(2) | info | 0x03)
...


However, in section 4.2 of the HKDF paper the same function is instead defined with the counter value starting at 0. Is there some subtle reason to avoid a 0 value in this terminal counter byte?

• It is a matter of taste... May 30, 2022 at 21:02
• It's not the only modification the IETF people ever made to an algorithm. The academic version of ChaCha20 cipher had 64-bit IV and 64-big counter, they changed it to 96-bit IV and 32-bit counter so as to make it fit better for Internet protocols. May 31, 2022 at 8:16
• My final comment here is that, these kind of questions are better asked to the people made the decision. The drafters of the RFC can probably still be reached from the contacts listed in the last page of that RFC. One of them is a member of this community (albeit inactive). May 31, 2022 at 8:19
• Seconded, but I will add that it would be helpful if they could answer here, or - if you receive an answer - to post it as a self answer. May 31, 2022 at 8:44
• Wouldn't that be $255 \cdot 32$ bytes, which is $(2^8 - 1) \cdot (2^5) = 2^{13} - 32 = 8 Ki - 32$ bytes of data? May 31, 2022 at 22:02

2 Answers

Hugo Krawczyk answered on the CFRG mailing list that the RFC version was adjusted to be compatible with IKE, which starts the counter at 1:

Good question. I believe (I checked some old email of mine with Pasi) this was done for compatibility with the definition of HKDF in IKE (which is when I originally designed HKDF, though without a name and published analysis). I wasn't too happy about being limited by backwards compatibility but it was judged at the time as one less hurdle for adoption.

This HKDF RFC change to start HKDF-Extract counter at 1 also made it (likely unintentionally) output-incompatible with SP800-108 KDFs, which end their data buffers with a big-endian 4-byte length-of-derived-keying-material-in-bits. Starting HKDF-Extract counter at 1 corresponds to an odd number of requested SP800-108 bits (indivisible into bytes), which kills the idea of making HKDF-Extract and SP800-108 outputs match for some combination of HKDF's "info" and SP800-108's "label"/"context".