Last edited 3 years ago

# How to implement HKDF with the Cryptographic library

The CMOX does not provide HMAC-based key derivation function (HKDF) utilities. However HKDF can be constructed based on the available CMOX HMAC services.

## 1. HKDF theory

Extract from rfc5869

```2.  HMAC-based Key Derivation Function (HKDF)

2.1.  Notation

HMAC-Hash denotes the HMAC function [HMAC] instantiated with hash
function 'Hash'.  HMAC always has two arguments: the first is a key
and the second an input (or message).  (Note that in the extract
step, 'IKM' is used as the HMAC input, not as the HMAC key.)

When the message is composed of several elements we use concatenation
(denoted |) in the second argument; for example, HMAC(K, elem1 |
elem2 | elem3).

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
"SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
document are to be interpreted as described in [KEYWORDS].

2.2.  Step 1: Extract

HKDF-Extract(salt, IKM) -> PRK

Options:
Hash     a hash function; HashLen denotes the length of the
hash function output in octets

Inputs:
salt     optional salt value (a non-secret random value);
if not provided, it is set to a string of HashLen zeros.
IKM      input keying material

Output:
PRK      a pseudorandom key (of HashLen octets)

The output PRK is calculated as follows:

PRK = HMAC-Hash(salt, IKM)

2.3.  Step 2: Expand

HKDF-Expand(PRK, info, L) -> OKM

Options:
Hash     a hash function; HashLen denotes the length of the
hash function output in octets

Inputs:
PRK      a pseudorandom key of at least HashLen octets
(usually, the output from the extract step)
info     optional context and application specific information
(can be a zero-length string)
L        length of output keying material in octets
(<= 255*HashLen)

Output:
OKM      output keying material (of L octets)

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)
...```

## 2. HKDF implementation example using HMAC-SHA256 Cryptographic library services

```  /* Computed data buffer */
uint8_t computed_hash[CMOX_SHA256_SIZE];
uint8_t computed_PRK[CMOX_SHA256_SIZE];
uint8_t computed_OKM[82];  /* L    = 82 */

/* HMAC context handle */
cmox_hmac_handle_t Hmac_Ctx;
size_t computed_size;
/* General mac context */
cmox_mac_handle_t *mac_ctx;
uint8_t t;
uint32_t index;

/* Initialize cryptographic library */
if (cmox_initialize(NULL) != CMOX_INIT_SUCCESS) Error_Handler();

/*
* Compute PRK = HMAC-Hash(salt, IKM)
*/
retval = cmox_mac_compute(CMOX_HMAC_SHA256_ALGO,
IKM, sizeof(IKM),
salt, sizeof(salt),
NULL, 0,
computed_PRK,
CMOX_SHA256_SIZE,
&computed_size);

/* Verify API returned value */
if (retval != CMOX_MAC_SUCCESS) Error_Handler();

/*
* Compute N = ceil(L/HashLen)
*/
N = (uint32_t)(L / CMOX_SHA256_SIZE);
if ((N * CMOX_SHA256_SIZE) < L) N++;

/*
* Compute 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)
...
*/

mac_ctx = cmox_hmac_construct(&Hmac_Ctx, CMOX_HMAC_SHA256);
if (mac_ctx == NULL) Error_Handler();

index = 0;
for (uint8_t i = 1; i <= N; i++)
{
retval = cmox_mac_init(mac_ctx);
if (retval != CMOX_MAC_SUCCESS) Error_Handler();
/* For the last iteration, tag length may be reduced to fit requested length L */
if (i == N)
{
retval = cmox_mac_setTagLen(mac_ctx, L - index);
}
if (retval != CMOX_MAC_SUCCESS) Error_Handler();
retval = cmox_mac_setKey(mac_ctx, computed_PRK, sizeof(computed_PRK));
if (retval != CMOX_MAC_SUCCESS) Error_Handler();
if (i > 1)
{
retval = cmox_mac_append(mac_ctx, computed_hash, CMOX_SHA256_SIZE);
if (retval != CMOX_MAC_SUCCESS) Error_Handler();
}
retval = cmox_mac_append(mac_ctx, info, sizeof(info));
if (retval != CMOX_MAC_SUCCESS) Error_Handler();
retval = cmox_mac_append(mac_ctx, &i, 1);
if (retval != CMOX_MAC_SUCCESS) Error_Handler();
retval = cmox_mac_generateTag(mac_ctx, computed_hash, NULL);
if (retval != CMOX_MAC_SUCCESS) Error_Handler();
if (i == N)
{
memcpy(&computed_OKM[index], computed_hash, L - index);
index = L;
}
else
{
memcpy(&computed_OKM[index], computed_hash, CMOX_SHA256_SIZE);
index += CMOX_SHA256_SIZE;
}
}
retval = cmox_mac_cleanup(mac_ctx);
if (retval != CMOX_MAC_SUCCESS) Error_Handler();
```