Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/libs/symcrypt/lib/IEEE802_11SaeCustom.c
15010 views
1
//
2
// IEEE802_11SaeCustom.c Implementation of the custom crypto of IEEE 802.11 SAE
3
//
4
// Copyright (c) Microsoft Corporation. Licensed under the MIT license.
5
//
6
//
7
8
#include "precomp.h"
9
10
// Used in SAE Hunting and Pecking methods where NIST P256 is hardcoded
11
#define PRIME_LENGTH_BITS 256
12
13
//
14
// This data structure is used to store the associated elliptic curve and the z value corresponding to
15
// each IANA group mappings for each elliptic
16
// curve defined in IEEE Std 802.11 SAE method.
17
//
18
typedef struct _SYMCRYPT_SAE_GROUP_DATA {
19
SYMCRYPT_802_11_SAE_GROUP group;
20
const PCSYMCRYPT_ECURVE_PARAMS *pCurveParams;
21
const PCSYMCRYPT_MAC *macAlgorithm;
22
INT32 z;
23
} SYMCRYPT_SAE_GROUP_DATA, *PSYMCRYPT_SAE_GROUP_DATA;
24
25
typedef const SYMCRYPT_SAE_GROUP_DATA* PCSYMCRYPT_SAE_GROUP_DATA;
26
27
//
28
// Data based on IEEE Std 802.11-2020
29
// Table 12.1 - Hash algorithm based on length of prime
30
// Table 12.2 - Unique curve parameter
31
//
32
const SYMCRYPT_SAE_GROUP_DATA g_ianaData[] = {
33
{ SYMCRYPT_SAE_GROUP_19, &SymCryptEcurveParamsNistP256, &SymCryptHmacSha256Algorithm, -10},
34
{ SYMCRYPT_SAE_GROUP_20, &SymCryptEcurveParamsNistP384, &SymCryptHmacSha384Algorithm, -12},
35
};
36
37
//
38
// Helper function that finds the associated IANA group data entry for a given group number
39
// Searches the global variable g_ianaData where the data for supported groups are stored
40
//
41
PCSYMCRYPT_SAE_GROUP_DATA SymCryptSaeFindGroupData(SYMCRYPT_802_11_SAE_GROUP ianaGroup)
42
{
43
for (UINT32 index = 0; index < SYMCRYPT_ARRAY_SIZE(g_ianaData); index++ )
44
{
45
if ( g_ianaData[index].group == ianaGroup )
46
{
47
return &g_ianaData[index];
48
}
49
}
50
51
return NULL;
52
}
53
54
//
55
// Helper function that returns the sizes of the field elements and elliptic curve points in bytes
56
// for a given IANA group number. Both output parameters are optional.
57
//
58
VOID SymCrypt802_11SaeGetGroupSizes(
59
SYMCRYPT_802_11_SAE_GROUP group,
60
_Out_opt_ SIZE_T* pcbScalar,
61
_Out_opt_ SIZE_T* pcbPoint )
62
{
63
PCSYMCRYPT_SAE_GROUP_DATA pGroupData = NULL;
64
SIZE_T cbScalar = 0;
65
SIZE_T cbPoint = 0;
66
67
pGroupData = SymCryptSaeFindGroupData( group );
68
69
if ( pGroupData != NULL )
70
{
71
cbScalar = ( *( pGroupData->pCurveParams ) )->cbFieldLength;
72
cbPoint = 2 * cbScalar;
73
}
74
75
if ( pcbScalar != NULL )
76
{
77
*pcbScalar = cbScalar;
78
}
79
80
if ( pcbPoint != NULL )
81
{
82
*pcbPoint = cbPoint;
83
}
84
}
85
86
//
87
// Calculate sqrt(peVal) if it exists. If so, *puIsQuadraticResidue is set to 0xFFFF`FFFF.
88
// Otherwise, *puIsQuadraticResidue is set to 0.
89
// WARNING: *peSqrtArg is set even if the square root doesn't exist. Use masked copy functions
90
// with *puIsQuadraticResidue so as to use the value of *peSqrtArg only if the square root exists.
91
//
92
// - pmMod: Modulus of the curve. Must equal 3 mod 4, which holds for all NIST Prime curves except P224
93
// - peVal: Value to calculate the square root of
94
// - puIsQuadraticResidue: mask value, true if sqrt(peVal) exists, false otherwise
95
// - peSqrtArg: optional out argument for square root value
96
// - pbScratch, cbScratch: scratch space >= SYMCRYPT_SCRATCH_BYTES_FOR_MODEXP( pmMod->nDigits )
97
//
98
SYMCRYPT_ERROR
99
SymCryptModSqrt(
100
_In_ PSYMCRYPT_MODULUS pmMod,
101
_In_ PSYMCRYPT_MODELEMENT peVal,
102
_Out_ PUINT32 puIsQuadraticResidue,
103
_Out_opt_ PSYMCRYPT_MODELEMENT peSqrtArg,
104
_Out_writes_bytes_( cbScratch ) PBYTE pbScratch,
105
SIZE_T cbScratch )
106
{
107
SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR;
108
109
PSYMCRYPT_INT piTmp = SymCryptIntAllocate( SymCryptDigitsFromBits( pmMod->Divisor.nBits ) );
110
PSYMCRYPT_MODELEMENT peSqrt = SymCryptModElementAllocate( pmMod );
111
PSYMCRYPT_MODELEMENT peTmp = SymCryptModElementAllocate( pmMod );
112
113
if( piTmp == NULL || peSqrt == NULL || peTmp == NULL )
114
{
115
scError = SYMCRYPT_MEMORY_ALLOCATION_FAILURE;
116
goto cleanup;
117
}
118
119
// Sqrt( v ) = v^{(P+1)/4} mod P when P = 3 mod 4 as it is here
120
SymCryptIntCopy( SymCryptIntFromModulus( pmMod ), piTmp );
121
SymCryptIntAddUint32( piTmp, 1, piTmp ); // No overflow as our prime is not 2^256 - 1
122
123
SYMCRYPT_ASSERT( (SymCryptIntGetValueLsbits32(piTmp) & 3) == 0);
124
SymCryptIntDivPow2(piTmp, 2, piTmp);
125
// iX = (P+1)/4
126
127
// Compute Sqrt( v ) if it exists
128
SymCryptModExp( pmMod, peVal, piTmp, pmMod->Divisor.nBits - 2, 0, peSqrt, pbScratch, cbScratch );
129
130
SymCryptModSquare( pmMod, peSqrt, peTmp, pbScratch, cbScratch );
131
*puIsQuadraticResidue = SymCryptModElementIsEqual( pmMod, peTmp, peVal );
132
133
if( peSqrtArg != NULL )
134
{
135
SymCryptModElementCopy( pmMod, peSqrt, peSqrtArg );
136
}
137
138
cleanup:
139
140
if( piTmp != NULL )
141
{
142
SymCryptIntFree( piTmp );
143
piTmp = NULL;
144
}
145
146
if( peSqrt != NULL )
147
{
148
SymCryptModElementFree( pmMod, peSqrt );
149
peSqrt = NULL;
150
}
151
152
if( peTmp != NULL )
153
{
154
SymCryptModElementFree( pmMod, peTmp );
155
peTmp = NULL;
156
}
157
158
return scError;
159
160
}
161
162
//
163
// Calculates SSWU( u ) as described in 12.4.4.2.3
164
//
165
// - pCurve: The curve object to use.
166
// - z: z value used in the SSWU calculation. Currently we assume this value to be negative.
167
// - peU: Value to calculate SSWU of.
168
// - popP: point on the curve found by SSWU.
169
// - pbScratch, cbScratch: scratch space >= SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_ECURVE_OPERATIONS( pCurve )
170
//
171
SYMCRYPT_ERROR
172
SymCryptSswu(
173
_In_ PSYMCRYPT_ECURVE pCurve,
174
_In_ INT32 z,
175
_In_ PSYMCRYPT_MODELEMENT peU,
176
_Out_ PSYMCRYPT_ECPOINT poP,
177
_Out_writes_bytes_( cbScratch ) PBYTE pbScratch,
178
SIZE_T cbScratch )
179
{
180
SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR;
181
182
UINT32 selectionMask = 0; // Mask variable for masked copy operations. "l" in the spec
183
184
PSYMCRYPT_INT piTmp = NULL;
185
PSYMCRYPT_MODELEMENT peTmp = NULL;
186
187
PSYMCRYPT_MODELEMENT peZ = NULL;
188
PSYMCRYPT_MODELEMENT peM = NULL;
189
PSYMCRYPT_MODELEMENT peT = NULL;
190
PSYMCRYPT_MODELEMENT peX1 = NULL;
191
PSYMCRYPT_MODELEMENT peX2 = NULL;
192
PSYMCRYPT_MODELEMENT peGX1 = NULL;
193
PSYMCRYPT_MODELEMENT peGX2 = NULL;
194
195
BYTE pointBuf[SYMCRYPT_SAE_MAX_EC_POINT_SIZE_BYTES] = { 0 };
196
197
SYMCRYPT_ASSERT( z < 0 );
198
199
piTmp = SymCryptIntAllocate( SymCryptDigitsFromBits( pCurve->FModBitsize ) );
200
201
peTmp = SymCryptModElementAllocate( pCurve->FMod );
202
peZ = SymCryptModElementAllocate( pCurve->FMod );
203
peM = SymCryptModElementAllocate( pCurve->FMod );
204
peT = SymCryptModElementAllocate( pCurve->FMod );
205
peX1 = SymCryptModElementAllocate( pCurve->FMod );
206
peX2 = SymCryptModElementAllocate( pCurve->FMod );
207
peGX1 = SymCryptModElementAllocate( pCurve->FMod );
208
peGX2 = SymCryptModElementAllocate( pCurve->FMod );
209
210
if( piTmp == NULL|| peTmp == NULL || peZ == NULL || peM == NULL || peT == NULL ||
211
peX1 == NULL || peX2 == NULL || peGX1 == NULL || peGX2 == NULL)
212
{
213
scError = SYMCRYPT_MEMORY_ALLOCATION_FAILURE;
214
goto cleanup;
215
}
216
217
// Convert z to mod element
218
// Currently we avoid a branching based on the sign of z to make the assignment and assume it will
219
// be negative which holds for the set of possible values as of now (NIST P256 and NIST P384).
220
// There is no direct function to create a SYMCRYPT_INT from a signed INT32, so when z is negative
221
// we change its sign and call SymCryptModElementSetValueNegUInt32
222
SymCryptModElementSetValueNegUint32(-z, pCurve->FMod, peZ, pbScratch, cbScratch);
223
224
// Set peTmp to 1 for convenience later
225
SymCryptModElementSetValueUint32( 1, pCurve->FMod, peTmp, pbScratch, cbScratch );
226
227
// m = ( z^2 * u^4 + z * u^2 ) = (z * u^2)(z * u^2 + 1) modulo p
228
SymCryptModSquare( pCurve->FMod, peU, peM, pbScratch, cbScratch ); // M = u^2
229
SymCryptModMul( pCurve->FMod, peM, peZ, peM, pbScratch, cbScratch ); // M = z * u^2
230
SymCryptModAdd( pCurve->FMod, peM, peTmp, peTmp, pbScratch, cbScratch ); // tmp = (z * u^2 + 1)
231
SymCryptModMul( pCurve->FMod, peM, peTmp, peM, pbScratch, cbScratch ); // M = M * tmp = (z * u^2)(z * u^2 + 1)
232
233
// l = CEQ( m, 0 )
234
selectionMask = SymCryptModElementIsZero( pCurve->FMod, peM );
235
236
// t = inverse( m ) where inverse ( m ) = m^( p-2 ) modulo p
237
SymCryptIntSubUint32( SymCryptIntFromModulus( pCurve->FMod ), 2, piTmp );
238
SymCryptModExp( pCurve->FMod, peM, piTmp, pCurve->FModBitsize, 0, peT, pbScratch, cbScratch );
239
240
//x1 = CSEL( l, ( b / ( z * a ) modulo p ), ( ( - b / a ) * ( 1 + t ) ) modulo p )
241
// where CSEL(x,y,z) operates in constant time and returns y if x is true and z otherwise.
242
SymCryptModMul( pCurve->FMod, peZ, pCurve->A, peTmp, pbScratch, cbScratch ); // tmp = z * a
243
SymCryptModInv( pCurve->FMod, peTmp, peTmp, SYMCRYPT_FLAG_DATA_PUBLIC | SYMCRYPT_FLAG_MODULUS_PRIME, pbScratch, cbScratch ); // tmp = 1/(z * a)
244
SymCryptModMul( pCurve->FMod, pCurve->B, peTmp, peX1, pbScratch, cbScratch ); // x1A = B * 1/(z * a)
245
246
SymCryptModInv( pCurve->FMod, pCurve->A, peTmp, SYMCRYPT_FLAG_DATA_PUBLIC | SYMCRYPT_FLAG_MODULUS_PRIME, pbScratch, cbScratch ); // tmp = 1/a
247
SymCryptModMul( pCurve->FMod, pCurve->B, peTmp, peTmp, pbScratch, cbScratch ); // tmp = b * 1/a
248
SymCryptModNeg( pCurve->FMod, peTmp, peTmp, pbScratch, cbScratch ); // tmp = -(b * 1/a)
249
250
// NB: in this block we're using X2 as the second candidate for CSEL. This allows us to choose the
251
// correct X1 by copying X2 to X1 if l is false
252
SymCryptIntSetValueUint32( 1, piTmp );
253
SymCryptIntToModElement( piTmp, pCurve->FMod, peX2, pbScratch, cbScratch ); // X1B = 1
254
SymCryptModAdd( pCurve->FMod, peX2, peT, peX2, pbScratch, cbScratch ); // X1B = 1 + t
255
SymCryptModMul( pCurve->FMod, peX2, peTmp, peX2, pbScratch, cbScratch ); // X1B = -(b * 1/a)(1 + t)
256
257
// Note: we need the binary complement of l since MaskedCopy copies only if the mask is 0xFFFFFFFF,
258
// and we want the second X1 candidate iff l is false
259
SymCryptModElementMaskedCopy( pCurve->FMod, peX2, peX1, ~selectionMask );
260
261
// gx1 = ( x1^3 + a * x1 + b ) = (x1^2 + a)*x1 + b modulo p
262
SymCryptModSquare( pCurve->FMod, peX1, peGX1, pbScratch, cbScratch ); // gx1 = x1^2
263
SymCryptModAdd( pCurve->FMod, peGX1, pCurve->A, peGX1, pbScratch, cbScratch ); // gx1 = x1^2 + a
264
SymCryptModMul( pCurve->FMod, peGX1, peX1, peGX1, pbScratch, cbScratch ); // gx1 = (x1^2 + a)*x1
265
SymCryptModAdd( pCurve->FMod, peGX1, pCurve->B, peGX1, pbScratch, cbScratch ); // gx1 = (x1^2 + a)*x1 + b
266
267
//x2 = ( z * u^2 * x1 ) modulo p
268
SymCryptModSquare( pCurve->FMod, peU, peX2, pbScratch, cbScratch ); // x2 = u^2
269
SymCryptModMul( pCurve->FMod, peX2, peZ, peX2, pbScratch, cbScratch ); // x2 = u^2 * z
270
SymCryptModMul( pCurve->FMod, peX2, peX1, peX2, pbScratch, cbScratch ); // x2 = u^2 * z * x1
271
272
//gx2 = ( x2^3 + a * x2 + b ) = (x2^2 + a)*x2 + b modulo p
273
SymCryptModSquare( pCurve->FMod, peX2, peGX2, pbScratch, cbScratch ); // gx2 = x2^2
274
SymCryptModAdd( pCurve->FMod, peGX2, pCurve->A, peGX2, pbScratch, cbScratch ); // gx2 = x2^2 + a
275
SymCryptModMul( pCurve->FMod, peGX2, peX2, peGX2, pbScratch, cbScratch ); // gx2 = (x2^2 + a)*x2
276
SymCryptModAdd( pCurve->FMod, peGX2, pCurve->B, peGX2, pbScratch, cbScratch ); // gx2 = (x2^2 + a)*x2 + b
277
278
//l = gx1 is a quadratic residue modulo p
279
scError = SymCryptModSqrt( pCurve->FMod, peGX1, &selectionMask, NULL, pbScratch, cbScratch );
280
if( scError != SYMCRYPT_NO_ERROR )
281
{
282
goto cleanup;
283
}
284
285
// v = CSEL( l, gx1, gx2 )
286
// (Using gx1 as a temporary for v)
287
SymCryptModElementMaskedCopy( pCurve->FMod, peGX2, peGX1, ~selectionMask );
288
289
// x = CSEL( l, x1, x2 )
290
// (Using x1 as a temporary for x)
291
SymCryptModElementMaskedCopy( pCurve->FMod, peX2, peX1, ~selectionMask );
292
293
// y = sqrt( v ) = v^{(P+1)/4}
294
// (Using gx1 as a temporary for y)
295
scError = SymCryptModSqrt( pCurve->FMod, peGX1, &selectionMask, peGX1, pbScratch, cbScratch );
296
297
// l = CEQ( LSB( u ), LSB( y ) )
298
// LSB returns the least significant *BIT* of its argument
299
SymCryptModElementToInt( pCurve->FMod, peU, piTmp, pbScratch, cbScratch );
300
UINT32 u = SymCryptIntGetValueLsbits32( piTmp );
301
302
SymCryptModElementToInt( pCurve->FMod, peGX1, piTmp, pbScratch, cbScratch );
303
UINT32 y = SymCryptIntGetValueLsbits32( piTmp );
304
305
selectionMask = SYMCRYPT_MASK32_EQ( u & 1, y & 1 );
306
307
// P = CSEL( l, ( x, y ), ( x, p - y ) )
308
// equivalently, y = CSEL( l, y, p - y )
309
// (p - y) mod p is equivalent to -y mod p, so we end up with
310
// y = CSEL(l, y, -y)
311
// We use gx1 for y
312
SymCryptModNeg( pCurve->FMod, peGX1, peTmp, pbScratch, cbScratch );
313
SymCryptModElementMaskedCopy( pCurve->FMod, peTmp, peGX1, ~selectionMask );
314
315
SymCryptModElementGetValue( pCurve->FMod, peX1, &pointBuf[0], pCurve->FModBytesize, SYMCRYPT_NUMBER_FORMAT_MSB_FIRST, pbScratch, cbScratch );
316
SymCryptModElementGetValue( pCurve->FMod, peGX1, &pointBuf[pCurve->FModBytesize], pCurve->FModBytesize, SYMCRYPT_NUMBER_FORMAT_MSB_FIRST, pbScratch, cbScratch );
317
318
scError = SymCryptEcpointSetValue( pCurve,
319
pointBuf,
320
2 * pCurve->FModBytesize,
321
SYMCRYPT_NUMBER_FORMAT_MSB_FIRST,
322
SYMCRYPT_ECPOINT_FORMAT_XY,
323
poP,
324
0,
325
pbScratch,
326
cbScratch );
327
if( scError != SYMCRYPT_NO_ERROR )
328
{
329
goto cleanup;
330
}
331
332
cleanup:
333
334
if( peGX2 != NULL )
335
{
336
SymCryptModElementFree( pCurve->FMod, peGX2 );
337
peGX2 = NULL;
338
}
339
340
if( peGX1 != NULL )
341
{
342
SymCryptModElementFree( pCurve->FMod, peGX1 );
343
peGX1 = NULL;
344
}
345
346
if( peX2 != NULL )
347
{
348
SymCryptModElementFree( pCurve->FMod, peX2 );
349
peX2 = NULL;
350
}
351
352
if( peX1 != NULL )
353
{
354
SymCryptModElementFree( pCurve->FMod, peX1 );
355
peX1 = NULL;
356
}
357
358
if( peT != NULL )
359
{
360
SymCryptModElementFree( pCurve->FMod, peT );
361
peT = NULL;
362
}
363
364
if( peM != NULL )
365
{
366
SymCryptModElementFree( pCurve->FMod, peM );
367
peM = NULL;
368
}
369
370
if( peZ != NULL )
371
{
372
SymCryptModElementFree( pCurve->FMod, peZ );
373
peZ = NULL;
374
}
375
376
if( peTmp != NULL )
377
{
378
SymCryptModElementFree( pCurve->FMod, peTmp );
379
peTmp = NULL;
380
}
381
382
if( piTmp != NULL )
383
{
384
SymCryptIntFree( piTmp );
385
piTmp = NULL;
386
}
387
388
return scError;
389
}
390
391
SYMCRYPT_ERROR
392
SymCrypt802_11SaeCustomSetRandMask(
393
_Inout_ PSYMCRYPT_802_11_SAE_CUSTOM_STATE pState,
394
_Inout_updates_opt_( cbRand ) PBYTE pbRand,
395
SIZE_T cbRand,
396
_Inout_updates_opt_( cbMask) PBYTE pbMask,
397
SIZE_T cbMask,
398
_Out_writes_bytes_( cbScratch ) PBYTE pbScratch,
399
SIZE_T cbScratch )
400
{
401
SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR;
402
403
PCSYMCRYPT_ECURVE pcCurve = pState->pCurve;
404
405
SymCryptModElementSetValueUint32( 0, pcCurve->GOrd, pState->peRand, pbScratch, cbScratch );
406
if( pbRand != NULL )
407
{
408
scError = SymCryptModElementSetValue( pbRand, cbRand, SYMCRYPT_NUMBER_FORMAT_MSB_FIRST, pcCurve->GOrd, pState->peRand, pbScratch, cbScratch );
409
if( scError != SYMCRYPT_NO_ERROR )
410
{
411
goto cleanup;
412
}
413
}
414
415
if( SymCryptModElementIsZero( pcCurve->GOrd, pState->peRand ) )
416
{
417
SymCryptModSetRandom( pcCurve->GOrd, pState->peRand, SYMCRYPT_FLAG_MODRANDOM_ALLOW_MINUSONE, pbScratch, cbScratch );
418
}
419
420
if( pbRand != NULL )
421
{
422
scError = SymCryptModElementGetValue( pcCurve->GOrd, pState->peRand, pbRand, cbRand, SYMCRYPT_NUMBER_FORMAT_MSB_FIRST, pbScratch, cbScratch );
423
if( scError != SYMCRYPT_NO_ERROR )
424
{
425
goto cleanup;
426
}
427
}
428
429
SymCryptModElementSetValueUint32( 0, pcCurve->GOrd, pState->peMask, pbScratch, cbScratch );
430
if( pbMask != NULL )
431
{
432
scError = SymCryptModElementSetValue( pbMask, cbMask, SYMCRYPT_NUMBER_FORMAT_MSB_FIRST, pcCurve->GOrd, pState->peMask, pbScratch, cbScratch );
433
if( scError != SYMCRYPT_NO_ERROR )
434
{
435
goto cleanup;
436
}
437
}
438
439
if( SymCryptModElementIsZero( pcCurve->GOrd, pState->peMask ) )
440
{
441
SymCryptModSetRandom( pcCurve->GOrd, pState->peMask, SYMCRYPT_FLAG_MODRANDOM_ALLOW_MINUSONE, pbScratch, cbScratch );
442
}
443
444
if( pbMask != NULL )
445
{
446
scError = SymCryptModElementGetValue( pcCurve->GOrd, pState->peMask, pbMask, cbMask, SYMCRYPT_NUMBER_FORMAT_MSB_FIRST, pbScratch, cbScratch );
447
if( scError != SYMCRYPT_NO_ERROR )
448
{
449
goto cleanup;
450
}
451
}
452
453
//
454
// The standard calls for checking that peRand and peMask are not 0 or 1, and peRand + peMask is not 0 or 1.
455
// When the caller specifies the values we don't want to do any checking as they might be helpful in test vectors.
456
// When this code generates the random values, we avoid 0 or 1 (by not passing the flags allowing 0 and 1).
457
// We don't check that peRand + peMask > 1 because the probability of that occurring randomly is about 2^{-254} so the
458
// risk of this happening on any machine ever in the world is much smaller than the risk associated with adding several lines of code.
459
//
460
461
cleanup:
462
463
return scError;
464
}
465
466
SYMCRYPT_ERROR
467
SymCrypt802_11SaeCustomInit(
468
_Out_ PSYMCRYPT_802_11_SAE_CUSTOM_STATE pState,
469
_In_reads_( 6 ) PCBYTE pbMac1,
470
_In_reads_( 6 ) PCBYTE pbMac2,
471
_In_reads_( cbPassword ) PCBYTE pbPassword,
472
SIZE_T cbPassword,
473
_Out_opt_ PBYTE pbCounter,
474
_Inout_updates_opt_( 32 ) PBYTE pbRand,
475
_Inout_updates_opt_( 32 ) PBYTE pbMask )
476
{
477
SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR;
478
479
BYTE counter;
480
UINT32 notFoundMask;
481
UINT32 solutionMask;
482
UINT32 negMask;
483
BYTE abSeed[SYMCRYPT_HMAC_SHA256_RESULT_SIZE];
484
BYTE abValue[SYMCRYPT_HMAC_SHA256_RESULT_SIZE];
485
BYTE abSeedKey[16]; // Need only 12, but the extra bytes make the code easier.
486
SYMCRYPT_HMAC_SHA256_EXPANDED_KEY hmacSeedKey;
487
SYMCRYPT_HMAC_SHA256_EXPANDED_KEY hmacValueKey;
488
SYMCRYPT_HMAC_SHA256_STATE hmacState;
489
BYTE abTmp[2];
490
BYTE pointBuf[ 64 ];
491
PBYTE pbScratch = NULL;
492
SIZE_T cbScratch = 0;
493
UINT64 minMac;
494
UINT64 maxMac;
495
496
UINT32 nDigits;
497
PSYMCRYPT_ECURVE pCurve; // Only a cache, pState->pCurve owns the allocation
498
PSYMCRYPT_INT piTmp = NULL;
499
PSYMCRYPT_MODELEMENT peX = NULL;
500
PSYMCRYPT_MODELEMENT peY = NULL;
501
PSYMCRYPT_MODELEMENT peCubic = NULL;
502
PSYMCRYPT_MODELEMENT peTmp = NULL;
503
PSYMCRYPT_ECPOINT poPWECandidate = NULL;
504
505
// Set state to 0 so that our pointers have valid values.
506
SymCryptWipe( pState, sizeof( *pState ) );
507
508
// Per IEEE 802.11-2016 section 12.4.4.1 the mandatory-to-implement curve is
509
// number 19 from the IANA Group description for RFC 2409 (IKE)
510
// The IANA website maps this to a 256-bit Random ECP group in RFC 5903.
511
// RFC 5903 specifies this group to be identical to the NIST P256 curve.
512
pCurve = SymCryptEcurveAllocate( SymCryptEcurveParamsNistP256, 0 );
513
pState->pCurve = pCurve;
514
if( pCurve == NULL )
515
{
516
scError = SYMCRYPT_MEMORY_ALLOCATION_FAILURE;
517
goto cleanup;
518
}
519
520
pState->macAlgorithm = SymCryptHmacSha256Algorithm;
521
522
pState->peRand = SymCryptModElementAllocate( pCurve->GOrd );
523
if( pState->peRand == NULL )
524
{
525
scError = SYMCRYPT_MEMORY_ALLOCATION_FAILURE;
526
goto cleanup;
527
}
528
529
pState->peMask = SymCryptModElementAllocate( pCurve->GOrd );
530
if( pState->peMask == NULL )
531
{
532
scError = SYMCRYPT_MEMORY_ALLOCATION_FAILURE;
533
goto cleanup;
534
}
535
536
pState->poPWE = SymCryptEcpointAllocate( pCurve );
537
if( pState->poPWE == NULL )
538
{
539
scError = SYMCRYPT_MEMORY_ALLOCATION_FAILURE;
540
goto cleanup;
541
}
542
543
nDigits = SymCryptDigitsFromBits( PRIME_LENGTH_BITS );
544
545
cbScratch = SYMCRYPT_MAX( SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_MOD_OPERATIONS( nDigits ),
546
SYMCRYPT_MAX( SYMCRYPT_SCRATCH_BYTES_FOR_MODEXP( nDigits ),
547
SYMCRYPT_SCRATCH_BYTES_FOR_GETSET_VALUE_ECURVE_OPERATIONS( pCurve ) ) );
548
pbScratch = SymCryptCallbackAlloc( cbScratch );
549
550
piTmp = SymCryptIntAllocate( nDigits );
551
peX = SymCryptModElementAllocate( pCurve->FMod );
552
peY = SymCryptModElementAllocate( pCurve->FMod );
553
peCubic = SymCryptModElementAllocate( pCurve->FMod );
554
peTmp = SymCryptModElementAllocate( pCurve->FMod );
555
poPWECandidate = SymCryptEcpointAllocate( pCurve );
556
557
if( pbScratch == NULL || piTmp == NULL || peX == NULL || peY == NULL || peCubic == NULL || peTmp == NULL || poPWECandidate == NULL )
558
{
559
scError = SYMCRYPT_MEMORY_ALLOCATION_FAILURE;
560
goto cleanup;
561
}
562
563
SymCryptWipeKnownSize( abSeedKey, sizeof( abSeedKey ) );
564
memcpy( &abSeedKey[0], pbMac1, 6 );
565
minMac = SYMCRYPT_LOAD_MSBFIRST64( abSeedKey );
566
memcpy( &abSeedKey[0], pbMac2, 6 );
567
maxMac = SYMCRYPT_LOAD_MSBFIRST64( abSeedKey );
568
569
if( minMac > maxMac )
570
{
571
// MAC values are public, no side-channel issues with this if()
572
// Swap the two values
573
minMac ^= maxMac;
574
maxMac ^= minMac;
575
minMac ^= maxMac;
576
}
577
578
// Now we write the two MACs into the buffer.
579
// Note the slight overlap, and the use of 14 bytes rather than 12
580
SYMCRYPT_STORE_MSBFIRST64( &abSeedKey[0], maxMac );
581
SYMCRYPT_STORE_MSBFIRST64( &abSeedKey[6], minMac ); // This writes up to abSeedKey[14]
582
583
SymCryptHmacSha256ExpandKey( &hmacSeedKey, abSeedKey, 12 );
584
SymCryptWipeKnownSize( abSeedKey, sizeof( abSeedKey ) ); // Not strictly speaking a secret, but good general hygiene
585
586
notFoundMask = (UINT32)-1;
587
counter = 0;
588
589
// We exit the loop only after 40 or more iterations
590
// This greatly reduces the side-channel of how often we run this loop.
591
while( notFoundMask != 0 || counter < 40 )
592
{
593
counter += 1;
594
if( counter == 0 )
595
{
596
scError = SYMCRYPT_INVALID_ARGUMENT;
597
goto cleanup;
598
}
599
600
// pwd-seed = Hmac-sha256( MacA || MacB , Password || counter )
601
SymCryptHmacSha256Init( &hmacState, &hmacSeedKey );
602
SymCryptHmacSha256Append( &hmacState, pbPassword, cbPassword );
603
SymCryptHmacSha256Append( &hmacState, &counter, 1 );
604
SymCryptHmacSha256Result( &hmacState, abSeed );
605
606
// pwd-value
607
SymCryptHmacSha256ExpandKey( &hmacValueKey, abSeed, sizeof( abSeed ) );
608
SymCryptHmacSha256Init( &hmacState, &hmacValueKey );
609
610
SYMCRYPT_STORE_LSBFIRST16( abTmp, 1 );
611
SymCryptHmacSha256Append( &hmacState, abTmp, 2 ); // i value = 1
612
// Spec is unclear on whether there should be a terminating 0 on the context
613
// There are 23 characters in the string, so using len=24 gives us a zero
614
SymCryptHmacSha256Append( &hmacState, (PCBYTE) "SAE Hunting and Pecking", 23 );
615
616
// Pick up the byte representation of p from the parameters
617
SymCryptHmacSha256Append( &hmacState, (BYTE *)(SymCryptEcurveParamsNistP256 + 1), 32 );
618
619
SYMCRYPT_STORE_LSBFIRST16( abTmp, 256 );
620
SymCryptHmacSha256Append( &hmacState, abTmp, 2 ); // Length value = 256
621
SymCryptHmacSha256Result( &hmacState, abValue );
622
623
// Get the pwd-value into an integer
624
scError = SymCryptIntSetValue( abValue, sizeof( abValue ), SYMCRYPT_NUMBER_FORMAT_MSB_FIRST, piTmp );
625
if( scError != SYMCRYPT_NO_ERROR )
626
{
627
goto cleanup;
628
}
629
630
// Check that it is less than P
631
if( !SymCryptIntIsLessThan( piTmp, SymCryptIntFromModulus( pCurve->FMod ) ) )
632
{
633
// This is a slight side-channel, but our prime P starts with FFFFFFFF so the probability of
634
// hitting this case is < 2^-32.
635
continue;
636
}
637
638
// Compute x^3 + A*x + B
639
SymCryptIntToModElement( piTmp, pCurve->FMod, peX, pbScratch, cbScratch );
640
SymCryptModSquare( pCurve->FMod, peX, peCubic, pbScratch, cbScratch );
641
SymCryptModAdd( pCurve->FMod, peCubic, pCurve->A, peCubic, pbScratch, cbScratch );
642
SymCryptModMul( pCurve->FMod, peCubic, peX, peCubic, pbScratch, cbScratch );
643
SymCryptModAdd( pCurve->FMod, peCubic, pCurve->B, peCubic, pbScratch, cbScratch );
644
645
// Get the quadratic residue of (x^3 + A*x + B) modulo P if it exists
646
scError = SymCryptModSqrt( pCurve->FMod, peCubic, &solutionMask, peY, pbScratch, cbScratch );
647
if( scError != SYMCRYPT_NO_ERROR )
648
{
649
goto cleanup;
650
}
651
652
solutionMask &= notFoundMask;
653
654
// Pick Y or -Y according to the LSbits
655
SymCryptModElementToInt( pCurve->FMod, peY, piTmp, pbScratch, cbScratch );
656
SymCryptModNeg( pCurve->FMod, peY, peTmp, pbScratch, cbScratch );
657
658
negMask = 0 - ((abSeed[ sizeof( abSeed ) - 1 ] ^ SymCryptIntGetValueLsbits32( piTmp ) ) & 1);
659
SymCryptModElementMaskedCopy( pCurve->FMod, peTmp, peY, negMask );
660
661
SymCryptModElementGetValue( pCurve->FMod, peX, &pointBuf[ 0], 32, SYMCRYPT_NUMBER_FORMAT_MSB_FIRST, pbScratch, cbScratch );
662
SymCryptModElementGetValue( pCurve->FMod, peY, &pointBuf[32], 32, SYMCRYPT_NUMBER_FORMAT_MSB_FIRST, pbScratch, cbScratch );
663
scError = SymCryptEcpointSetValue( pCurve,
664
pointBuf,
665
sizeof( pointBuf ),
666
SYMCRYPT_NUMBER_FORMAT_MSB_FIRST,
667
SYMCRYPT_ECPOINT_FORMAT_XY,
668
poPWECandidate,
669
0,
670
pbScratch,
671
cbScratch );
672
if( scError != SYMCRYPT_NO_ERROR )
673
{
674
goto cleanup;
675
}
676
677
SymCryptEcpointMaskedCopy( pCurve, poPWECandidate, pState->poPWE, solutionMask );
678
pState->counter |= (BYTE)(counter & solutionMask);
679
680
notFoundMask &= ~solutionMask;
681
}
682
683
scError = SymCrypt802_11SaeCustomSetRandMask( pState, pbRand, 32, pbMask, 32, pbScratch, cbScratch );
684
if( scError != SYMCRYPT_NO_ERROR)
685
{
686
goto cleanup;
687
}
688
689
if( pbCounter != NULL )
690
{
691
*pbCounter = pState->counter;
692
}
693
694
cleanup:
695
696
SymCryptWipe( &hmacSeedKey, sizeof( hmacSeedKey ) );
697
SymCryptWipe( &hmacValueKey, sizeof( hmacValueKey ) );
698
SymCryptWipe( abSeed, sizeof( abSeed ) );
699
SymCryptWipe( abValue, sizeof( abValue ) );
700
SymCryptWipe( pointBuf, sizeof( pointBuf ) );
701
702
if( piTmp != NULL )
703
{
704
SymCryptIntFree( piTmp );
705
piTmp = NULL;
706
}
707
708
if( peX != NULL )
709
{
710
SymCryptModElementFree( pCurve->FMod, peX );
711
peX = NULL;
712
}
713
714
if( peY != NULL )
715
{
716
SymCryptModElementFree( pCurve->FMod, peY );
717
peY = NULL;
718
}
719
720
if( peCubic != NULL )
721
{
722
SymCryptModElementFree( pCurve->FMod, peCubic );
723
peCubic = NULL;
724
}
725
726
if( peTmp != NULL )
727
{
728
SymCryptModElementFree( pCurve->FMod, peTmp );
729
peTmp = NULL;
730
}
731
732
if( poPWECandidate != NULL )
733
{
734
SymCryptEcpointFree( pCurve, poPWECandidate );
735
poPWECandidate = NULL;
736
}
737
738
if( scError != SYMCRYPT_NO_ERROR )
739
{
740
SymCrypt802_11SaeCustomDestroy( pState );
741
}
742
743
if( pbScratch != NULL )
744
{
745
SymCryptWipe( pbScratch, cbScratch );
746
SymCryptCallbackFree( pbScratch );
747
pbScratch = NULL;
748
}
749
750
return scError;
751
}
752
753
754
SYMCRYPT_ERROR
755
SymCrypt802_11SaeCustomCreatePTGeneric(
756
SYMCRYPT_802_11_SAE_GROUP group,
757
_In_reads_( cbSsid ) PCBYTE pbSsid,
758
SIZE_T cbSsid,
759
_In_reads_( cbPassword ) PCBYTE pbPassword,
760
SIZE_T cbPassword,
761
_In_reads_opt_( cbPasswordIdentifier ) PCBYTE pbPasswordIdentifier,
762
SIZE_T cbPasswordIdentifier,
763
_Out_writes_( cbPT ) PBYTE pbPT,
764
SIZE_T cbPT)
765
{
766
SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR;
767
768
SIZE_T cbIkm = 0;
769
SIZE_T cbScratch = 0;
770
771
PBYTE pbPwdValue = NULL;
772
UINT32 cbPwdValue = 0;
773
PBYTE pbScratch = NULL;
774
SYMCRYPT_HKDF_EXPANDED_KEY hkdfKey;
775
776
PSYMCRYPT_ECURVE pCurve = NULL;
777
PCSYMCRYPT_MAC pMacAlgorithm = NULL;
778
PSYMCRYPT_INT piU1 = NULL;
779
PSYMCRYPT_INT piU2 = NULL;
780
PSYMCRYPT_MODELEMENT peU1 = NULL;
781
PSYMCRYPT_MODELEMENT peU2 = NULL;
782
783
PSYMCRYPT_ECPOINT poP1 = NULL;
784
PSYMCRYPT_ECPOINT poP2 = NULL;
785
PSYMCRYPT_ECPOINT poPT = NULL;
786
787
PCSYMCRYPT_SAE_GROUP_DATA pGroupData = NULL;
788
789
790
pGroupData = SymCryptSaeFindGroupData( group );
791
792
// Provided IANA group number must match one of the supported groups
793
if ( pGroupData == NULL)
794
{
795
scError = SYMCRYPT_INVALID_ARGUMENT;
796
goto cleanup;
797
}
798
799
// Construct the objects associated with the IANA group number
800
pCurve = SymCryptEcurveAllocate( *( pGroupData->pCurveParams), 0 );
801
if( pCurve == NULL )
802
{
803
scError = SYMCRYPT_MEMORY_ALLOCATION_FAILURE;
804
goto cleanup;
805
}
806
807
pMacAlgorithm = *( pGroupData->macAlgorithm );
808
809
const UINT32 nDigits = SymCryptEcurveDigitsofFieldElement( pCurve );
810
811
cbIkm = cbPassword + cbPasswordIdentifier;
812
cbScratch = SYMCRYPT_MAX( cbIkm,
813
SYMCRYPT_MAX( SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_MOD_OPERATIONS( nDigits ),
814
SYMCRYPT_MAX( SYMCRYPT_SCRATCH_BYTES_FOR_MODEXP( nDigits ),
815
SYMCRYPT_MAX( SYMCRYPT_SCRATCH_BYTES_FOR_GETSET_VALUE_ECURVE_OPERATIONS( pCurve ),
816
SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_ECURVE_OPERATIONS( pCurve ) ) ) ) );
817
pbScratch = SymCryptCallbackAlloc( cbScratch );
818
819
// len = olen( p ) + floor( olen( p ) / 2 )
820
cbPwdValue = SYMCRYPT_BYTES_FROM_BITS(pCurve->FModBitsize) + SYMCRYPT_BYTES_FROM_BITS(pCurve->FModBitsize) / 2;
821
822
pbPwdValue = SymCryptCallbackAlloc( cbPwdValue );
823
824
piU1 = SymCryptIntAllocate( SymCryptDigitsFromBits( cbPwdValue * 8 ) );
825
piU2 = SymCryptIntAllocate( SymCryptDigitsFromBits( cbPwdValue * 8 ) );
826
peU1 = SymCryptModElementAllocate( pCurve->FMod );
827
peU2 = SymCryptModElementAllocate( pCurve->FMod );
828
829
poP1 = SymCryptEcpointAllocate( pCurve );
830
poP2 = SymCryptEcpointAllocate( pCurve );
831
poPT = SymCryptEcpointAllocate( pCurve );
832
833
if( pbScratch == NULL || pbPwdValue == NULL || piU1 == NULL || piU2 == NULL ||
834
peU1 == NULL || peU2 == NULL || poP1 == NULL || poP2 == NULL || poPT == NULL)
835
{
836
scError = SYMCRYPT_MEMORY_ALLOCATION_FAILURE;
837
goto cleanup;
838
}
839
840
// pwd-seed = HKDF-Extract( ssid, password [|| identifier] )
841
// Note that SymCryptHkdfExpandKey corresponds to HKDF-Extract
842
memcpy( pbScratch, pbPassword, cbPassword );
843
if( pbPasswordIdentifier )
844
{
845
memcpy( pbScratch + cbPassword, pbPasswordIdentifier, cbPasswordIdentifier );
846
}
847
848
scError = SymCryptHkdfExpandKey( &hkdfKey, pMacAlgorithm, pbScratch, cbIkm, pbSsid, cbSsid );
849
if( scError != SYMCRYPT_NO_ERROR )
850
{
851
goto cleanup;
852
}
853
854
// pwd-value = HKDF-Expand( pwd-seed, "SAE Hash to Element u1 P1", len )
855
// Note that SymCryptHkdf derive corresponds to HKDF-Expand
856
// Salt does not include a null terminator, so the length is 25 chars
857
scError = SymCryptHkdfDerive( &hkdfKey, (PCBYTE) "SAE Hash to Element u1 P1", 25, pbPwdValue, cbPwdValue );
858
if( scError != SYMCRYPT_NO_ERROR )
859
{
860
goto cleanup;
861
}
862
863
// u1 = pwd-value modulo p
864
scError = SymCryptIntSetValue( pbPwdValue, cbPwdValue, SYMCRYPT_NUMBER_FORMAT_MSB_FIRST, piU1 );
865
if( scError != SYMCRYPT_NO_ERROR )
866
{
867
goto cleanup;
868
}
869
870
SymCryptIntToModElement( piU1, pCurve->FMod, peU1, pbScratch, cbScratch );
871
872
// P1 = SSWU( u1 )
873
SymCryptSswu( pCurve, pGroupData->z, peU1, poP1, pbScratch, cbScratch );
874
875
// pwd-value = HKDF-Expand( pwd-seed, "SAE Hash to Element u2 P2", len )
876
scError = SymCryptHkdfDerive( &hkdfKey, (PCBYTE) "SAE Hash to Element u2 P2", 25, pbPwdValue, cbPwdValue );
877
if( scError != SYMCRYPT_NO_ERROR )
878
{
879
goto cleanup;
880
}
881
882
// u2 = pwd-value modulo p
883
scError = SymCryptIntSetValue( pbPwdValue, cbPwdValue, SYMCRYPT_NUMBER_FORMAT_MSB_FIRST, piU2 );
884
if( scError != SYMCRYPT_NO_ERROR )
885
{
886
goto cleanup;
887
}
888
889
SymCryptIntToModElement( piU2, pCurve->FMod, peU2, pbScratch, cbScratch );
890
891
// P2 = SSWU( u2 )
892
scError = SymCryptSswu( pCurve, pGroupData->z, peU2, poP2, pbScratch, cbScratch );
893
if( scError != SYMCRYPT_NO_ERROR )
894
{
895
goto cleanup;
896
}
897
898
// PT = P1 + P2
899
SymCryptEcpointAdd( pCurve, poP1, poP2, poPT, 0, pbScratch, cbScratch );
900
901
scError = SymCryptEcpointGetValue( pCurve,
902
poPT,
903
SYMCRYPT_NUMBER_FORMAT_MSB_FIRST,
904
SYMCRYPT_ECPOINT_FORMAT_XY,
905
pbPT,
906
cbPT,
907
0,
908
pbScratch,
909
cbScratch );
910
SYMCRYPT_ASSERT( scError == SYMCRYPT_NO_ERROR );
911
912
cleanup:
913
914
if( poP2 != NULL )
915
{
916
SymCryptEcpointFree( pCurve, poP2 );
917
poP2 = NULL;
918
}
919
920
if( poP1 != NULL )
921
{
922
SymCryptEcpointFree( pCurve, poP1 );
923
poP1 = NULL;
924
}
925
926
if( poPT != NULL )
927
{
928
SymCryptEcpointFree( pCurve, poPT );
929
poPT = NULL;
930
}
931
932
if( peU2 != NULL )
933
{
934
SymCryptModElementFree( pCurve->FMod, peU2 );
935
peU2 = NULL;
936
}
937
938
if( peU1 != NULL )
939
{
940
SymCryptModElementFree( pCurve->FMod, peU1 );
941
peU1 = NULL;
942
}
943
944
if( piU2 != NULL )
945
{
946
SymCryptIntFree( piU2 );
947
piU2 = NULL;
948
}
949
950
if( piU1 != NULL )
951
{
952
SymCryptIntFree( piU1 );
953
piU1 = NULL;
954
}
955
956
if( pbPwdValue != NULL )
957
{
958
SymCryptWipe( pbPwdValue, cbPwdValue );
959
SymCryptCallbackFree( pbPwdValue );
960
pbPwdValue = NULL;
961
}
962
963
if( pbScratch != NULL )
964
{
965
SymCryptWipe( pbScratch, cbScratch );
966
SymCryptCallbackFree( pbScratch );
967
pbScratch = NULL;
968
}
969
970
if ( pCurve != NULL )
971
{
972
SymCryptEcurveFree( pCurve );
973
pCurve = NULL;
974
}
975
976
return scError;
977
}
978
979
980
SYMCRYPT_ERROR
981
SymCrypt802_11SaeCustomCreatePT(
982
_In_reads_( cbSsid ) PCBYTE pbSsid,
983
SIZE_T cbSsid,
984
_In_reads_( cbPassword ) PCBYTE pbPassword,
985
SIZE_T cbPassword,
986
_In_reads_opt_( cbPasswordIdentifier ) PCBYTE pbPasswordIdentifier,
987
SIZE_T cbPasswordIdentifier,
988
_Out_writes_( 64 ) PBYTE pbPT )
989
{
990
return SymCrypt802_11SaeCustomCreatePTGeneric( SYMCRYPT_SAE_GROUP_19,
991
pbSsid,
992
cbSsid,
993
pbPassword,
994
cbPassword,
995
pbPasswordIdentifier,
996
cbPasswordIdentifier,
997
pbPT,
998
64 );
999
}
1000
1001
1002
SYMCRYPT_ERROR
1003
SymCrypt802_11SaeCustomInitH2EGeneric(
1004
_Out_ PSYMCRYPT_802_11_SAE_CUSTOM_STATE pState,
1005
SYMCRYPT_802_11_SAE_GROUP group,
1006
_In_reads_( cbPT ) PCBYTE pbPT,
1007
SIZE_T cbPT,
1008
_In_reads_( 6 ) PCBYTE pbMacA,
1009
_In_reads_( 6 ) PCBYTE pbMacB,
1010
_Inout_updates_opt_( cbRand ) PBYTE pbRand,
1011
SIZE_T cbRand,
1012
_Inout_updates_opt_( cbMask ) PBYTE pbMask,
1013
SIZE_T cbMask)
1014
{
1015
SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR;
1016
1017
BYTE hmacKeyBytes[SYMCRYPT_SAE_MAX_HMAC_OUTPUT_SIZE_BYTES] = { 0 };
1018
BYTE valBytes[SYMCRYPT_SAE_MAX_HMAC_OUTPUT_SIZE_BYTES] = { 0 };
1019
BYTE macBuffer[16] = { 0 }; // Need only 12, but the extra bytes make the code easier.
1020
SYMCRYPT_MAC_EXPANDED_KEY hmacKey = { 0 };
1021
SYMCRYPT_MAC_STATE hmacState = { 0 };
1022
1023
SIZE_T cbScratch = 0;
1024
PBYTE pbScratch = NULL;
1025
1026
UINT64 minMac = 0;
1027
UINT64 maxMac = 0;
1028
1029
UINT32 nDigits = 0;
1030
1031
PSYMCRYPT_INT piTmp = NULL;
1032
PSYMCRYPT_MODULUS pmMod = NULL;
1033
PSYMCRYPT_MODELEMENT peVal = NULL;
1034
PSYMCRYPT_MODELEMENT peTmp = NULL;
1035
PSYMCRYPT_ECPOINT poPT = NULL;
1036
PCSYMCRYPT_SAE_GROUP_DATA pGroupData = NULL;
1037
PCSYMCRYPT_MAC pMacAlgorithm = NULL;
1038
1039
// Set state to 0 so that our pointers have valid values.
1040
SymCryptWipeKnownSize( pState, sizeof( *pState ) );
1041
1042
PSYMCRYPT_ECURVE pCurve = NULL; // Weak reference; curve is owned by pState
1043
1044
pGroupData = SymCryptSaeFindGroupData( group );
1045
1046
// Provided IANA group number must match one of the supported groups
1047
if ( pGroupData == NULL )
1048
{
1049
scError = SYMCRYPT_INVALID_ARGUMENT;
1050
goto cleanup;
1051
}
1052
1053
// Construct the objects associated with the IANA group number
1054
pCurve = SymCryptEcurveAllocate( *( pGroupData->pCurveParams ), 0 );
1055
if ( pCurve == NULL )
1056
{
1057
scError = SYMCRYPT_MEMORY_ALLOCATION_FAILURE;
1058
goto cleanup;
1059
}
1060
1061
pState->pCurve = pCurve;
1062
1063
pMacAlgorithm = *( pGroupData->macAlgorithm );
1064
1065
SIZE_T cbHMACOutputSize = pMacAlgorithm->resultSize;
1066
1067
pState->peRand = SymCryptModElementAllocate( pCurve->GOrd );
1068
if( pState->peRand == NULL )
1069
{
1070
scError = SYMCRYPT_MEMORY_ALLOCATION_FAILURE;
1071
goto cleanup;
1072
}
1073
1074
pState->peMask = SymCryptModElementAllocate( pCurve->GOrd );
1075
if( pState->peMask == NULL )
1076
{
1077
scError = SYMCRYPT_MEMORY_ALLOCATION_FAILURE;
1078
goto cleanup;
1079
}
1080
1081
pState->poPWE = SymCryptEcpointAllocate( pCurve );
1082
if( pState->poPWE == NULL )
1083
{
1084
scError = SYMCRYPT_MEMORY_ALLOCATION_FAILURE;
1085
goto cleanup;
1086
}
1087
1088
nDigits = SymCryptDigitsFromBits( pCurve->GOrdBitsize );
1089
1090
piTmp = SymCryptIntAllocate( nDigits );
1091
pmMod = SymCryptModulusAllocate( nDigits );
1092
poPT = SymCryptEcpointAllocate( pCurve );
1093
1094
cbScratch = SYMCRYPT_MAX( SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_MOD_OPERATIONS( nDigits ),
1095
SYMCRYPT_MAX( SYMCRYPT_SCRATCH_BYTES_FOR_GETSET_VALUE_ECURVE_OPERATIONS( pCurve ),
1096
SYMCRYPT_MAX( SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_ECURVE_OPERATIONS( pCurve ),
1097
SYMCRYPT_INTERNAL_SCRATCH_BYTES_FOR_SCALAR_ECURVE_OPERATIONS ( pCurve, 1 ) ) ) );
1098
pbScratch = SymCryptCallbackAlloc( cbScratch );
1099
1100
if( piTmp == NULL || pmMod == NULL || poPT == NULL || pbScratch == NULL )
1101
{
1102
scError = SYMCRYPT_MEMORY_ALLOCATION_FAILURE;
1103
goto cleanup;
1104
}
1105
1106
memcpy( &macBuffer[0], pbMacA, 6 );
1107
minMac = SYMCRYPT_LOAD_MSBFIRST64( macBuffer );
1108
memcpy( &macBuffer[0], pbMacB, 6 );
1109
maxMac = SYMCRYPT_LOAD_MSBFIRST64( macBuffer );
1110
1111
if( minMac > maxMac )
1112
{
1113
// MAC values are public, no side-channel issues with this if()
1114
// Swap the two values
1115
minMac ^= maxMac;
1116
maxMac ^= minMac;
1117
minMac ^= maxMac;
1118
}
1119
1120
// Now we write the two MACs into the buffer.
1121
// Note the slight overlap, and the use of 14 bytes rather than 12
1122
SYMCRYPT_STORE_MSBFIRST64( &macBuffer[0], maxMac );
1123
SYMCRYPT_STORE_MSBFIRST64( &macBuffer[6], minMac ); // This writes up to macBuffer[14]
1124
1125
// val = hmac-sha256( 0^n, maxMac || minMac )
1126
// The HMAC key is is a buffer of all zeros whose length equals the length of the digest from the hash function
1127
pMacAlgorithm->expandKeyFunc(&hmacKey, hmacKeyBytes, cbHMACOutputSize);
1128
1129
pMacAlgorithm->initFunc( &hmacState, &hmacKey );
1130
pMacAlgorithm->appendFunc( &hmacState, macBuffer, 12 );
1131
pMacAlgorithm->resultFunc( &hmacState, valBytes );
1132
1133
// val = val (#4666)modulo (q - 1) + 1
1134
SymCryptIntSubUint32( SymCryptIntFromModulus(pCurve->GOrd), 1, piTmp );
1135
SymCryptIntToModulus( piTmp, pmMod, 1, SYMCRYPT_FLAG_DATA_PUBLIC, pbScratch, cbScratch );
1136
1137
peVal = SymCryptModElementAllocate( pmMod );
1138
peTmp = SymCryptModElementAllocate( pmMod );
1139
1140
if( peVal == NULL || peTmp == NULL )
1141
{
1142
scError = SYMCRYPT_MEMORY_ALLOCATION_FAILURE;
1143
goto cleanup;
1144
}
1145
1146
scError = SymCryptModElementSetValue( valBytes, cbHMACOutputSize, SYMCRYPT_NUMBER_FORMAT_MSB_FIRST, pmMod, peVal, pbScratch, cbScratch );
1147
if( scError != SYMCRYPT_NO_ERROR )
1148
{
1149
goto cleanup;
1150
}
1151
1152
SymCryptModElementSetValueUint32( 1, pmMod, peTmp, pbScratch, cbScratch );
1153
SymCryptModAdd( pmMod, peVal, peTmp, peVal, pbScratch, cbScratch );
1154
1155
SymCryptModElementToInt( pmMod, peVal, piTmp, pbScratch, cbScratch );
1156
1157
scError = SymCryptEcpointSetValue( pCurve,
1158
pbPT,
1159
cbPT,
1160
SYMCRYPT_NUMBER_FORMAT_MSB_FIRST,
1161
SYMCRYPT_ECPOINT_FORMAT_XY,
1162
poPT,
1163
0,
1164
pbScratch,
1165
cbScratch );
1166
if( scError != SYMCRYPT_NO_ERROR )
1167
{
1168
goto cleanup;
1169
}
1170
1171
scError = SymCryptEcpointScalarMul( pCurve, piTmp, poPT, 0, pState->poPWE, pbScratch, cbScratch );
1172
if( scError != SYMCRYPT_NO_ERROR )
1173
{
1174
goto cleanup;
1175
}
1176
1177
scError = SymCrypt802_11SaeCustomSetRandMask( pState, pbRand, cbRand, pbMask, cbMask, pbScratch, cbScratch );
1178
if( scError != SYMCRYPT_NO_ERROR )
1179
{
1180
goto cleanup;
1181
}
1182
1183
cleanup:
1184
1185
if( peTmp != NULL )
1186
{
1187
SymCryptModElementFree( pmMod, peTmp );
1188
peTmp = NULL;
1189
}
1190
1191
if( peVal != NULL )
1192
{
1193
SymCryptModElementFree( pmMod, peVal );
1194
peVal = NULL;
1195
}
1196
1197
if( poPT != NULL )
1198
{
1199
SymCryptEcpointFree( pCurve, poPT );
1200
poPT = NULL;
1201
}
1202
1203
if( pmMod != NULL )
1204
{
1205
SymCryptModulusFree( pmMod );
1206
pmMod = NULL;
1207
}
1208
1209
if( piTmp != NULL )
1210
{
1211
SymCryptIntFree( piTmp );
1212
piTmp = NULL;
1213
}
1214
1215
if( pbScratch != NULL )
1216
{
1217
SymCryptWipe( pbScratch, cbScratch );
1218
SymCryptCallbackFree( pbScratch );
1219
pbScratch = NULL;
1220
}
1221
1222
if( scError != SYMCRYPT_NO_ERROR )
1223
{
1224
SymCrypt802_11SaeCustomDestroy( pState );
1225
}
1226
1227
return scError;
1228
}
1229
1230
SYMCRYPT_ERROR
1231
SymCrypt802_11SaeCustomInitH2E(
1232
_Out_ PSYMCRYPT_802_11_SAE_CUSTOM_STATE pState,
1233
_In_reads_( 64 ) PCBYTE pbPT,
1234
_In_reads_( 6 ) PCBYTE pbMacA,
1235
_In_reads_( 6 ) PCBYTE pbMacB,
1236
_Inout_updates_opt_( 32 ) PBYTE pbRand,
1237
_Inout_updates_opt_( 32 ) PBYTE pbMask )
1238
{
1239
return SymCrypt802_11SaeCustomInitH2EGeneric( pState,
1240
SYMCRYPT_SAE_GROUP_19,
1241
pbPT,
1242
64,
1243
pbMacA,
1244
pbMacB,
1245
pbRand,
1246
32,
1247
pbMask,
1248
32 );
1249
}
1250
1251
1252
VOID
1253
SymCrypt802_11SaeCustomDestroy(
1254
_Inout_ PSYMCRYPT_802_11_SAE_CUSTOM_STATE pState )
1255
{
1256
PSYMCRYPT_ECURVE pCurve = pState->pCurve;
1257
1258
if( pState->poPWE != NULL )
1259
{
1260
SymCryptEcpointFree( pCurve, pState->poPWE );
1261
}
1262
1263
if( pState->peMask != NULL )
1264
{
1265
SymCryptModElementFree( pCurve->GOrd, pState->peMask );
1266
}
1267
1268
if( pState->peRand != NULL )
1269
{
1270
SymCryptModElementFree( pCurve->GOrd, pState->peRand );
1271
}
1272
1273
if( pCurve != NULL )
1274
{
1275
SymCryptEcurveFree( pCurve );
1276
}
1277
1278
SymCryptWipeKnownSize( pState, sizeof( *pState ) );
1279
}
1280
1281
SYMCRYPT_ERROR
1282
SymCrypt802_11SaeCustomCommitCreateGeneric(
1283
_In_ PCSYMCRYPT_802_11_SAE_CUSTOM_STATE pState,
1284
_Out_writes_( cbCommitScalar ) PBYTE pbCommitScalar,
1285
SIZE_T cbCommitScalar,
1286
_Out_writes_( cbCommitElement ) PBYTE pbCommitElement,
1287
SIZE_T cbCommitElement)
1288
{
1289
SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR;
1290
PSYMCRYPT_MODELEMENT peTmp = NULL;
1291
PSYMCRYPT_INT piTmp = NULL;
1292
PSYMCRYPT_ECPOINT poPoint = NULL;
1293
PBYTE pbScratch = NULL;
1294
SIZE_T cbScratch;
1295
SIZE_T nDigits;
1296
1297
PCSYMCRYPT_ECURVE pCurve = pState->pCurve;
1298
1299
nDigits = SymCryptDigitsFromBits( pCurve->FModBitsize );
1300
cbScratch = SYMCRYPT_MAX( SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_MOD_OPERATIONS( nDigits ),
1301
SYMCRYPT_MAX( SYMCRYPT_SCRATCH_BYTES_FOR_SCALAR_ECURVE_OPERATIONS( pCurve ),
1302
SYMCRYPT_SCRATCH_BYTES_FOR_GETSET_VALUE_ECURVE_OPERATIONS( pCurve ) ) );
1303
1304
pbScratch = SymCryptCallbackAlloc( cbScratch );
1305
1306
peTmp = SymCryptModElementAllocate( pCurve->GOrd );
1307
piTmp = SymCryptIntAllocate( SymCryptEcurveDigitsofScalarMultiplier( pCurve ) );
1308
poPoint = SymCryptEcpointAllocate( pCurve );
1309
1310
if( peTmp == NULL || piTmp == NULL || poPoint == NULL || pbScratch == NULL )
1311
{
1312
scError = SYMCRYPT_MEMORY_ALLOCATION_FAILURE;
1313
goto cleanup;
1314
}
1315
1316
SymCryptModAdd( pCurve->GOrd, pState->peRand, pState->peMask, peTmp, pbScratch, cbScratch );
1317
scError = SymCryptModElementGetValue( pCurve->GOrd, peTmp, pbCommitScalar, cbCommitScalar, SYMCRYPT_NUMBER_FORMAT_MSB_FIRST, pbScratch, cbScratch );
1318
if( scError != SYMCRYPT_NO_ERROR )
1319
{
1320
goto cleanup;
1321
}
1322
1323
SymCryptModElementToInt( pCurve->GOrd, pState->peMask, piTmp, pbScratch, cbScratch );
1324
scError = SymCryptEcpointScalarMul( pCurve,
1325
piTmp,
1326
pState->poPWE,
1327
0,
1328
poPoint,
1329
pbScratch,
1330
cbScratch );
1331
if( scError != SYMCRYPT_NO_ERROR )
1332
{
1333
goto cleanup;
1334
}
1335
1336
// Now we have mask * PWE, but we need the negative...
1337
SymCryptEcpointNegate( pCurve, poPoint, (UINT32)-1, pbScratch, cbScratch );
1338
1339
scError = SymCryptEcpointGetValue( pCurve,
1340
poPoint,
1341
SYMCRYPT_NUMBER_FORMAT_MSB_FIRST,
1342
SYMCRYPT_ECPOINT_FORMAT_XY,
1343
pbCommitElement,
1344
cbCommitElement,
1345
0,
1346
pbScratch,
1347
cbScratch );
1348
if( scError != SYMCRYPT_NO_ERROR )
1349
{
1350
goto cleanup;
1351
}
1352
1353
cleanup:
1354
1355
if( piTmp != NULL )
1356
{
1357
SymCryptIntFree( piTmp );
1358
piTmp = NULL;
1359
}
1360
1361
if( peTmp != NULL )
1362
{
1363
SymCryptModElementFree( pCurve->GOrd, peTmp );
1364
peTmp = NULL;
1365
}
1366
1367
if( poPoint != NULL )
1368
{
1369
SymCryptEcpointFree( pCurve, poPoint );
1370
poPoint = NULL;
1371
}
1372
1373
if( pbScratch != NULL )
1374
{
1375
SymCryptWipe( pbScratch, cbScratch );
1376
SymCryptCallbackFree( pbScratch );
1377
pbScratch = NULL;
1378
}
1379
1380
return scError;
1381
}
1382
1383
SYMCRYPT_ERROR
1384
SymCrypt802_11SaeCustomCommitCreate(
1385
_In_ PCSYMCRYPT_802_11_SAE_CUSTOM_STATE pState,
1386
_Out_writes_( 32 ) PBYTE pbCommitScalar,
1387
_Out_writes_( 64 ) PBYTE pbCommitElement )
1388
{
1389
return SymCrypt802_11SaeCustomCommitCreateGeneric( pState,
1390
pbCommitScalar,
1391
32,
1392
pbCommitElement,
1393
64 );
1394
}
1395
1396
SYMCRYPT_ERROR
1397
SymCrypt802_11SaeCustomCommitProcessGeneric(
1398
_In_ PCSYMCRYPT_802_11_SAE_CUSTOM_STATE pState,
1399
_In_reads_( cbPeerCommitScalar ) PCBYTE pbPeerCommitScalar,
1400
SIZE_T cbPeerCommitScalar,
1401
_In_reads_( cbPeerCommitElement ) PCBYTE pbPeerCommitElement,
1402
SIZE_T cbPeerCommitElement,
1403
_Out_writes_( cbSharedSecret ) PBYTE pbSharedSecret,
1404
SIZE_T cbSharedSecret,
1405
_Out_writes_( cbScalarSum ) PBYTE pbScalarSum,
1406
SIZE_T cbScalarSum )
1407
{
1408
SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR;
1409
1410
PSYMCRYPT_ECURVE pCurve = pState->pCurve;
1411
PSYMCRYPT_MODELEMENT peCommitScalarSum = NULL;
1412
PSYMCRYPT_ECPOINT poPeerCommitElement = NULL;
1413
PSYMCRYPT_ECPOINT poTmp = NULL;
1414
PSYMCRYPT_INT piTmp = NULL;
1415
UINT32 nDigits;
1416
1417
PBYTE pbScratch = NULL;
1418
SIZE_T cbScratch;
1419
1420
nDigits = SymCryptDigitsFromBits( pCurve->FModBitsize );
1421
cbScratch = SYMCRYPT_MAX( SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_MOD_OPERATIONS( nDigits ),
1422
SYMCRYPT_MAX( SYMCRYPT_SCRATCH_BYTES_FOR_SCALAR_ECURVE_OPERATIONS( pCurve ),
1423
SYMCRYPT_MAX( SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_ECURVE_OPERATIONS( pCurve ),
1424
SYMCRYPT_SCRATCH_BYTES_FOR_GETSET_VALUE_ECURVE_OPERATIONS( pCurve ) ) ) );
1425
pbScratch = SymCryptCallbackAlloc( cbScratch );
1426
1427
peCommitScalarSum = SymCryptModElementAllocate( pCurve->GOrd );
1428
poPeerCommitElement = SymCryptEcpointAllocate( pCurve );
1429
poTmp = SymCryptEcpointAllocate( pCurve );
1430
piTmp = SymCryptIntAllocate( SymCryptEcurveDigitsofScalarMultiplier( pCurve ) );
1431
1432
if( pbScratch == NULL || peCommitScalarSum == NULL || poPeerCommitElement == NULL || poTmp == NULL || piTmp == NULL )
1433
{
1434
scError = SYMCRYPT_MEMORY_ALLOCATION_FAILURE;
1435
goto cleanup;
1436
}
1437
1438
// piTmp = peer commit value
1439
scError = SymCryptIntSetValue( pbPeerCommitScalar, cbPeerCommitScalar, SYMCRYPT_NUMBER_FORMAT_MSB_FIRST, piTmp );
1440
if( scError != SYMCRYPT_NO_ERROR )
1441
{
1442
goto cleanup;
1443
}
1444
1445
// The Standard requires a check that the Peer commit value must be 1 < peer-commit < r where r is the group order.
1446
if( !SymCryptIntIsLessThan( piTmp, SymCryptIntFromModulus( pCurve->GOrd ) ) ||
1447
SymCryptIntIsEqualUint32( piTmp, 0 ) ||
1448
SymCryptIntIsEqualUint32( piTmp, 1 ) )
1449
{
1450
scError = SYMCRYPT_INVALID_ARGUMENT;
1451
goto cleanup;
1452
}
1453
1454
SymCryptIntToModElement( piTmp, pCurve->GOrd, peCommitScalarSum, pbScratch, cbScratch );
1455
1456
// Now compute the sum of the scalar commit values
1457
SymCryptModAdd( pCurve->GOrd, peCommitScalarSum, pState->peRand, peCommitScalarSum, pbScratch, cbScratch );
1458
SymCryptModAdd( pCurve->GOrd, peCommitScalarSum, pState->peMask, peCommitScalarSum, pbScratch, cbScratch );
1459
1460
scError = SymCryptEcpointSetValue( pCurve,
1461
pbPeerCommitElement,
1462
cbPeerCommitElement,
1463
SYMCRYPT_NUMBER_FORMAT_MSB_FIRST,
1464
SYMCRYPT_ECPOINT_FORMAT_XY,
1465
poPeerCommitElement,
1466
0,
1467
pbScratch,
1468
cbScratch );
1469
if( scError != SYMCRYPT_NO_ERROR )
1470
{
1471
goto cleanup;
1472
}
1473
1474
// The EcPointSetValue routine returns an error if either coordinate is >= P.
1475
// We need to check that the point is on the curve and not the zero point of the curve
1476
// (The zero point is sometimes called the 'point at infinity'.)
1477
if( !SymCryptEcpointOnCurve( pCurve, poPeerCommitElement, pbScratch, cbScratch ) ||
1478
SymCryptEcpointIsZero( pCurve, poPeerCommitElement, pbScratch, cbScratch ) )
1479
{
1480
scError = SYMCRYPT_INVALID_ARGUMENT;
1481
goto cleanup;
1482
}
1483
1484
1485
scError = SymCryptEcpointScalarMul( pCurve,
1486
piTmp,
1487
pState->poPWE,
1488
0,
1489
poTmp,
1490
pbScratch,
1491
cbScratch );
1492
if( scError != SYMCRYPT_NO_ERROR )
1493
{
1494
goto cleanup;
1495
}
1496
1497
SymCryptEcpointAdd( pCurve, poTmp, poPeerCommitElement, poTmp, 0, pbScratch, cbScratch );
1498
1499
SymCryptModElementToInt( pCurve->GOrd, pState->peRand, piTmp, pbScratch, cbScratch );
1500
scError = SymCryptEcpointScalarMul( pCurve,
1501
piTmp,
1502
poTmp,
1503
0,
1504
poTmp,
1505
pbScratch,
1506
cbScratch );
1507
if( scError != SYMCRYPT_NO_ERROR )
1508
{
1509
goto cleanup;
1510
}
1511
1512
scError = SymCryptEcpointGetValue( pCurve,
1513
poTmp,
1514
SYMCRYPT_NUMBER_FORMAT_MSB_FIRST,
1515
SYMCRYPT_ECPOINT_FORMAT_X,
1516
pbSharedSecret,
1517
cbSharedSecret,
1518
0,
1519
pbScratch,
1520
cbScratch );
1521
if( scError != SYMCRYPT_NO_ERROR )
1522
{
1523
goto cleanup;
1524
}
1525
1526
scError = SymCryptModElementGetValue( pCurve->GOrd, peCommitScalarSum, pbScalarSum, cbScalarSum, SYMCRYPT_NUMBER_FORMAT_MSB_FIRST, pbScratch, cbScratch );
1527
if( scError != SYMCRYPT_NO_ERROR )
1528
{
1529
goto cleanup;
1530
}
1531
1532
cleanup:
1533
1534
if( peCommitScalarSum != NULL )
1535
{
1536
SymCryptModElementFree( pCurve->GOrd, peCommitScalarSum );
1537
peCommitScalarSum = NULL;
1538
}
1539
1540
if( poPeerCommitElement != NULL )
1541
{
1542
SymCryptEcpointFree( pCurve, poPeerCommitElement );
1543
poPeerCommitElement = NULL;
1544
}
1545
1546
if( poTmp != NULL )
1547
{
1548
SymCryptEcpointFree( pCurve, poTmp );
1549
poTmp = NULL;
1550
}
1551
1552
if( piTmp != NULL )
1553
{
1554
SymCryptIntFree( piTmp );
1555
piTmp = NULL;
1556
}
1557
1558
if( pbScratch != NULL )
1559
{
1560
SymCryptWipe( pbScratch, cbScratch );
1561
SymCryptCallbackFree( pbScratch );
1562
pbScratch = NULL;
1563
}
1564
1565
return scError;
1566
}
1567
1568
SYMCRYPT_ERROR
1569
SymCrypt802_11SaeCustomCommitProcess(
1570
_In_ PCSYMCRYPT_802_11_SAE_CUSTOM_STATE pState,
1571
_In_reads_( 32 ) PCBYTE pbPeerCommitScalar,
1572
_In_reads_( 64 ) PCBYTE pbPeerCommitElement,
1573
_Out_writes_( 32 ) PBYTE pbSharedSecret,
1574
_Out_writes_( 32 ) PBYTE pbScalarSum )
1575
{
1576
return SymCrypt802_11SaeCustomCommitProcessGeneric( pState,
1577
pbPeerCommitScalar,
1578
32,
1579
pbPeerCommitElement,
1580
64,
1581
pbSharedSecret,
1582
32,
1583
pbScalarSum,
1584
32 );
1585
}
1586
1587