Coverage Report

Created: 2024-11-21 07:03

/src/SymCrypt/lib/hkdf.c
Line
Count
Source (jump to first uncovered line)
1
//
2
// hkdf.c
3
//
4
// Copyright (c) Microsoft Corporation. Licensed under the MIT license.
5
//
6
7
//
8
// This module contains the routines to implement the HKDF
9
// function for the TLS protocol 1.3. It is used in
10
// the protocol's key derivation function.
11
//
12
//
13
14
#include "precomp.h"
15
16
SYMCRYPT_ERROR
17
SYMCRYPT_CALL
18
SymCryptHkdfExpandKey(
19
    _Out_                   PSYMCRYPT_HKDF_EXPANDED_KEY     pExpandedKey,
20
    _In_                    PCSYMCRYPT_MAC                  macAlgorithm,
21
    _In_reads_(cbIkm)       PCBYTE                          pbIkm,
22
                            SIZE_T                          cbIkm,
23
    _In_reads_opt_(cbSalt)  PCBYTE                          pbSalt,
24
                            SIZE_T                          cbSalt )
25
199
{
26
199
    SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR;
27
28
199
    SYMCRYPT_ALIGN BYTE rbPrk[SYMCRYPT_MAC_MAX_RESULT_SIZE] = { 0 };
29
30
199
    SYMCRYPT_ASSERT( macAlgorithm->expandedKeySize <= sizeof( pExpandedKey->macKey ) );
31
32
199
    scError = SymCryptHkdfExtractPrk( macAlgorithm, pbIkm, cbIkm, pbSalt, cbSalt, rbPrk, macAlgorithm->resultSize );
33
199
    if (scError != SYMCRYPT_NO_ERROR)
34
0
    {
35
0
        goto cleanup;
36
0
    }
37
38
199
    scError = SymCryptHkdfPrkExpandKey( pExpandedKey, macAlgorithm, rbPrk, macAlgorithm->resultSize );
39
199
    if (scError != SYMCRYPT_NO_ERROR)
40
0
    {
41
0
        goto cleanup;
42
0
    }
43
44
199
cleanup:
45
199
    SymCryptWipeKnownSize(&rbPrk[0], sizeof(rbPrk));
46
47
199
    return scError;
48
199
}
49
50
SYMCRYPT_ERROR
51
SYMCRYPT_CALL
52
SymCryptHkdfExtractPrk(
53
    _In_                    PCSYMCRYPT_MAC                  macAlgorithm,
54
    _In_reads_(cbIkm)       PCBYTE                          pbIkm,
55
                            SIZE_T                          cbIkm,
56
    _In_reads_opt_(cbSalt)  PCBYTE                          pbSalt,
57
                            SIZE_T                          cbSalt,
58
    _Out_writes_(cbPrk)     PBYTE                           pbPrk,
59
                            SIZE_T                          cbPrk )
60
199
{
61
199
    SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR;
62
63
199
    SYMCRYPT_MAC_STATE state;
64
199
    SYMCRYPT_MAC_EXPANDED_KEY key;
65
66
    // Ensure that pbPrk is the correct size
67
199
    if (cbPrk != macAlgorithm->resultSize)
68
0
    {
69
0
        scError = SYMCRYPT_INVALID_ARGUMENT;
70
0
        goto cleanup;
71
0
    }
72
    
73
    // Calculation of PRK = HMAC-Hash(salt, IKM)
74
199
    scError = macAlgorithm->expandKeyFunc( &key, pbSalt, cbSalt );
75
199
    if (scError != SYMCRYPT_NO_ERROR)
76
0
    {
77
0
        goto cleanup;
78
0
    }
79
80
199
    macAlgorithm->initFunc( &state, &key );
81
199
    macAlgorithm->appendFunc( &state, pbIkm, cbIkm );
82
199
    macAlgorithm->resultFunc( &state, pbPrk );
83
84
199
cleanup:
85
199
    SymCryptWipeKnownSize(&key, sizeof(key));
86
87
199
    return scError;
88
199
}
89
90
SYMCRYPT_ERROR
91
SYMCRYPT_CALL
92
SymCryptHkdfPrkExpandKey(
93
    _Out_                   PSYMCRYPT_HKDF_EXPANDED_KEY     pExpandedKey,
94
    _In_                    PCSYMCRYPT_MAC                  macAlgorithm,
95
    _In_reads_(cbPrk)       PCBYTE                          pbPrk,
96
                            SIZE_T                          cbPrk )
97
199
{
98
199
    SYMCRYPT_ASSERT( macAlgorithm->expandedKeySize <= sizeof( pExpandedKey->macKey ) );
99
100
199
    pExpandedKey->macAlg = macAlgorithm;
101
199
    return macAlgorithm->expandKeyFunc( &pExpandedKey->macKey, pbPrk, cbPrk );
102
199
}
103
104
SYMCRYPT_ERROR
105
SYMCRYPT_CALL
106
SymCryptHkdfDerive(
107
    _In_                    PCSYMCRYPT_HKDF_EXPANDED_KEY    pExpandedKey,
108
    _In_reads_opt_(cbInfo)  PCBYTE                          pbInfo,
109
                            SIZE_T                          cbInfo,
110
    _Out_writes_(cbResult)  PBYTE                           pbResult,
111
                            SIZE_T                          cbResult)
112
199
{
113
114
199
    SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR;
115
116
199
    SYMCRYPT_MAC_STATE state;
117
118
199
    PCSYMCRYPT_MAC pMacAlgorithm = pExpandedKey->macAlg;
119
120
199
    SYMCRYPT_ALIGN BYTE    rbPartialResult[SYMCRYPT_MAC_MAX_RESULT_SIZE];
121
199
                   BYTE *  pbCurr = pbResult;
122
123
199
    SIZE_T  cbMacResultSize = pMacAlgorithm->resultSize;
124
125
199
    BYTE cntr = 0x01;
126
127
    // Check that cbResult <= 255*HashLen
128
199
    if (cbResult > 0xff * cbMacResultSize)
129
44
    {
130
44
        scError = SYMCRYPT_WRONG_DATA_SIZE;
131
44
        goto cleanup;
132
44
    }
133
134
    // In the first iteration T(0) is the empty string
135
    // Calculate T(1) = HMAC-Hash(PRK, T(0) | info | 0x01)
136
155
    pMacAlgorithm->initFunc( &state, pExpandedKey );
137
155
    pMacAlgorithm->appendFunc( &state, pbInfo, cbInfo );
138
155
    pMacAlgorithm->appendFunc( &state, &cntr, sizeof(cntr) );
139
155
    pMacAlgorithm->resultFunc( &state, rbPartialResult );
140
141
    // Store the result in the output buffer
142
155
    memcpy(pbCurr, rbPartialResult, SYMCRYPT_MIN(cbResult, cbMacResultSize));
143
155
    if (cbResult <= cbMacResultSize)
144
2
    {
145
2
        goto cleanup;
146
2
    }
147
148
    // Update counters
149
153
    cntr++;
150
153
    pbCurr += cbMacResultSize;
151
153
    cbResult -= cbMacResultSize;
152
153
17.3k
    while( cbResult > 0 )
154
17.3k
    {
155
        // Calculate T(i) = HMAC-Hash(PRK, T(i-1) | info | 0xi)
156
17.3k
        pMacAlgorithm->initFunc( &state, pExpandedKey );
157
17.3k
        pMacAlgorithm->appendFunc( &state, rbPartialResult, cbMacResultSize );
158
17.3k
        pMacAlgorithm->appendFunc( &state, pbInfo, cbInfo );
159
17.3k
        pMacAlgorithm->appendFunc( &state, &cntr, sizeof(cntr) );
160
17.3k
        pMacAlgorithm->resultFunc( &state, rbPartialResult );
161
162
        // Store the result in the output buffer
163
17.3k
        memcpy(pbCurr, rbPartialResult, SYMCRYPT_MIN(cbResult, cbMacResultSize));
164
17.3k
        if (cbResult <= cbMacResultSize)
165
153
        {
166
153
            goto cleanup;
167
153
        }
168
169
        // Update counters
170
17.1k
        cntr++;
171
17.1k
        pbCurr += cbMacResultSize;
172
17.1k
        cbResult -= cbMacResultSize;
173
17.1k
    }
174
175
199
cleanup:
176
199
    SymCryptWipeKnownSize(&rbPartialResult[0], sizeof(rbPartialResult));
177
178
199
    return scError;
179
153
}
180
181
//
182
// The full HKDF
183
//
184
SYMCRYPT_ERROR
185
SYMCRYPT_CALL
186
SymCryptHkdf(
187
                            PCSYMCRYPT_MAC  macAlgorithm,
188
    _In_reads_(cbIkm)       PCBYTE          pbIkm,
189
                            SIZE_T          cbIkm,
190
    _In_reads_opt_(cbSalt)  PCBYTE          pbSalt,
191
                            SIZE_T          cbSalt,
192
    _In_reads_opt_(cbInfo)  PCBYTE          pbInfo,
193
                            SIZE_T          cbInfo,
194
    _Out_writes_(cbResult)  PBYTE           pbResult,
195
                            SIZE_T          cbResult)
196
199
{
197
199
    SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR;
198
199
    SYMCRYPT_HKDF_EXPANDED_KEY key;
199
200
    // Create the expanded key
201
199
    scError = SymCryptHkdfExpandKey(
202
199
        &key,
203
199
        macAlgorithm,
204
199
        pbIkm,
205
199
        cbIkm,
206
199
        pbSalt,
207
199
        cbSalt );
208
199
    if (scError != SYMCRYPT_NO_ERROR)
209
0
    {
210
0
        goto cleanup;
211
0
    }
212
213
    // Derive the key
214
199
    scError = SymCryptHkdfDerive(
215
199
        &key,
216
199
        pbInfo,
217
199
        cbInfo,
218
199
        pbResult,
219
199
        cbResult );
220
199
    if (scError != SYMCRYPT_NO_ERROR)
221
44
    {
222
44
        goto cleanup;
223
44
    }
224
225
199
cleanup:
226
199
    SymCryptWipeKnownSize(&key, sizeof(key));
227
228
199
    return scError;
229
199
}
230
231