1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
|
/*
* Copyright (c) 2024 Vaughn Nugent
*
* Package: noscrypt
* File: hkdf.c
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1
* of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with noscrypt. If not, see http://www.gnu.org/licenses/.
*/
#include "hkdf.h"
#define HKDF_MIN(a, b) (a < b ? a : b)
STATIC_ASSERT(HKDF_IN_BUF_SIZE > SHA256_DIGEST_SIZE, "HDK Buffer must be at least the size of the underlying hashing alg output")
static _nc_fn_inline void debugValidateHandler(const struct nc_hkdf_fn_cb_struct* handler)
{
DEBUG_ASSERT(handler != NULL)
DEBUG_ASSERT(handler->update != NULL)
DEBUG_ASSERT(handler->finish != NULL)
}
/*
* The following functions implements the HKDF expand function using an existing
* HMAC function.
*
* This follows the guidence from RFC 5869: https://tools.ietf.org/html/rfc5869
*/
cstatus_t hkdfExpandProcess(
const struct nc_hkdf_fn_cb_struct* handler,
void* ctx,
cspan_t info,
span_t okm
)
{
cstatus_t result;
cspan_t tSpan, counterSpan;
uint32_t tLen, okmOffset;
uint8_t counter[1];
uint8_t t[HKDF_IN_BUF_SIZE];
debugValidateHandler(handler);
ncCryptoSecureZero(t, sizeof(t));
tLen = 0; /* T(0) is an empty string(zero length) */
okmOffset = 0;
counter[0] = 1; /* counter is offset by 1 for init */
result = CSTATUS_FAIL; /* Start in fail state */
/* span over counter value that points to the counter buffer */
ncSpanInitC(&counterSpan, counter, sizeof(counter));
/* Compute T(N) = HMAC(prk, T(n-1) | info | n) */
while (okmOffset < okm.size)
{
ncSpanInitC(&tSpan, t, tLen);
if (handler->update(ctx, tSpan) != CSTATUS_OK)
{
goto Exit;
}
if (handler->update(ctx, info) != CSTATUS_OK)
{
goto Exit;
}
if (handler->update(ctx, counterSpan) != CSTATUS_OK)
{
goto Exit;
}
/*
* Write current hash state to t buffer. It is known
* that the t buffer must be at least the size of the
* underlying hash function output.
*/
if (handler->finish(ctx, t) != CSTATUS_OK)
{
goto Exit;
}
/* tlen becomes the hash size or remaining okm size */
tLen = HKDF_MIN(ncSpanGetSize(okm) - okmOffset, SHA256_DIGEST_SIZE);
DEBUG_ASSERT(tLen <= sizeof(t));
/* write the T buffer back to okm and advance okmOffset by tLen */
ncSpanAppend(okm, &okmOffset, t, tLen);
/* increment counter */
(*counter)++;
}
result = CSTATUS_OK; /* HMAC operation completed, so set success */
Exit:
return result;
}
|