Path: blob/master/libs/symcrypt/lib/IEEE802_11SaeCustom.c
15010 views
//1// IEEE802_11SaeCustom.c Implementation of the custom crypto of IEEE 802.11 SAE2//3// Copyright (c) Microsoft Corporation. Licensed under the MIT license.4//5//67#include "precomp.h"89// Used in SAE Hunting and Pecking methods where NIST P256 is hardcoded10#define PRIME_LENGTH_BITS 2561112//13// This data structure is used to store the associated elliptic curve and the z value corresponding to14// each IANA group mappings for each elliptic15// curve defined in IEEE Std 802.11 SAE method.16//17typedef struct _SYMCRYPT_SAE_GROUP_DATA {18SYMCRYPT_802_11_SAE_GROUP group;19const PCSYMCRYPT_ECURVE_PARAMS *pCurveParams;20const PCSYMCRYPT_MAC *macAlgorithm;21INT32 z;22} SYMCRYPT_SAE_GROUP_DATA, *PSYMCRYPT_SAE_GROUP_DATA;2324typedef const SYMCRYPT_SAE_GROUP_DATA* PCSYMCRYPT_SAE_GROUP_DATA;2526//27// Data based on IEEE Std 802.11-202028// Table 12.1 - Hash algorithm based on length of prime29// Table 12.2 - Unique curve parameter30//31const SYMCRYPT_SAE_GROUP_DATA g_ianaData[] = {32{ SYMCRYPT_SAE_GROUP_19, &SymCryptEcurveParamsNistP256, &SymCryptHmacSha256Algorithm, -10},33{ SYMCRYPT_SAE_GROUP_20, &SymCryptEcurveParamsNistP384, &SymCryptHmacSha384Algorithm, -12},34};3536//37// Helper function that finds the associated IANA group data entry for a given group number38// Searches the global variable g_ianaData where the data for supported groups are stored39//40PCSYMCRYPT_SAE_GROUP_DATA SymCryptSaeFindGroupData(SYMCRYPT_802_11_SAE_GROUP ianaGroup)41{42for (UINT32 index = 0; index < SYMCRYPT_ARRAY_SIZE(g_ianaData); index++ )43{44if ( g_ianaData[index].group == ianaGroup )45{46return &g_ianaData[index];47}48}4950return NULL;51}5253//54// Helper function that returns the sizes of the field elements and elliptic curve points in bytes55// for a given IANA group number. Both output parameters are optional.56//57VOID SymCrypt802_11SaeGetGroupSizes(58SYMCRYPT_802_11_SAE_GROUP group,59_Out_opt_ SIZE_T* pcbScalar,60_Out_opt_ SIZE_T* pcbPoint )61{62PCSYMCRYPT_SAE_GROUP_DATA pGroupData = NULL;63SIZE_T cbScalar = 0;64SIZE_T cbPoint = 0;6566pGroupData = SymCryptSaeFindGroupData( group );6768if ( pGroupData != NULL )69{70cbScalar = ( *( pGroupData->pCurveParams ) )->cbFieldLength;71cbPoint = 2 * cbScalar;72}7374if ( pcbScalar != NULL )75{76*pcbScalar = cbScalar;77}7879if ( pcbPoint != NULL )80{81*pcbPoint = cbPoint;82}83}8485//86// Calculate sqrt(peVal) if it exists. If so, *puIsQuadraticResidue is set to 0xFFFF`FFFF.87// Otherwise, *puIsQuadraticResidue is set to 0.88// WARNING: *peSqrtArg is set even if the square root doesn't exist. Use masked copy functions89// with *puIsQuadraticResidue so as to use the value of *peSqrtArg only if the square root exists.90//91// - pmMod: Modulus of the curve. Must equal 3 mod 4, which holds for all NIST Prime curves except P22492// - peVal: Value to calculate the square root of93// - puIsQuadraticResidue: mask value, true if sqrt(peVal) exists, false otherwise94// - peSqrtArg: optional out argument for square root value95// - pbScratch, cbScratch: scratch space >= SYMCRYPT_SCRATCH_BYTES_FOR_MODEXP( pmMod->nDigits )96//97SYMCRYPT_ERROR98SymCryptModSqrt(99_In_ PSYMCRYPT_MODULUS pmMod,100_In_ PSYMCRYPT_MODELEMENT peVal,101_Out_ PUINT32 puIsQuadraticResidue,102_Out_opt_ PSYMCRYPT_MODELEMENT peSqrtArg,103_Out_writes_bytes_( cbScratch ) PBYTE pbScratch,104SIZE_T cbScratch )105{106SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR;107108PSYMCRYPT_INT piTmp = SymCryptIntAllocate( SymCryptDigitsFromBits( pmMod->Divisor.nBits ) );109PSYMCRYPT_MODELEMENT peSqrt = SymCryptModElementAllocate( pmMod );110PSYMCRYPT_MODELEMENT peTmp = SymCryptModElementAllocate( pmMod );111112if( piTmp == NULL || peSqrt == NULL || peTmp == NULL )113{114scError = SYMCRYPT_MEMORY_ALLOCATION_FAILURE;115goto cleanup;116}117118// Sqrt( v ) = v^{(P+1)/4} mod P when P = 3 mod 4 as it is here119SymCryptIntCopy( SymCryptIntFromModulus( pmMod ), piTmp );120SymCryptIntAddUint32( piTmp, 1, piTmp ); // No overflow as our prime is not 2^256 - 1121122SYMCRYPT_ASSERT( (SymCryptIntGetValueLsbits32(piTmp) & 3) == 0);123SymCryptIntDivPow2(piTmp, 2, piTmp);124// iX = (P+1)/4125126// Compute Sqrt( v ) if it exists127SymCryptModExp( pmMod, peVal, piTmp, pmMod->Divisor.nBits - 2, 0, peSqrt, pbScratch, cbScratch );128129SymCryptModSquare( pmMod, peSqrt, peTmp, pbScratch, cbScratch );130*puIsQuadraticResidue = SymCryptModElementIsEqual( pmMod, peTmp, peVal );131132if( peSqrtArg != NULL )133{134SymCryptModElementCopy( pmMod, peSqrt, peSqrtArg );135}136137cleanup:138139if( piTmp != NULL )140{141SymCryptIntFree( piTmp );142piTmp = NULL;143}144145if( peSqrt != NULL )146{147SymCryptModElementFree( pmMod, peSqrt );148peSqrt = NULL;149}150151if( peTmp != NULL )152{153SymCryptModElementFree( pmMod, peTmp );154peTmp = NULL;155}156157return scError;158159}160161//162// Calculates SSWU( u ) as described in 12.4.4.2.3163//164// - pCurve: The curve object to use.165// - z: z value used in the SSWU calculation. Currently we assume this value to be negative.166// - peU: Value to calculate SSWU of.167// - popP: point on the curve found by SSWU.168// - pbScratch, cbScratch: scratch space >= SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_ECURVE_OPERATIONS( pCurve )169//170SYMCRYPT_ERROR171SymCryptSswu(172_In_ PSYMCRYPT_ECURVE pCurve,173_In_ INT32 z,174_In_ PSYMCRYPT_MODELEMENT peU,175_Out_ PSYMCRYPT_ECPOINT poP,176_Out_writes_bytes_( cbScratch ) PBYTE pbScratch,177SIZE_T cbScratch )178{179SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR;180181UINT32 selectionMask = 0; // Mask variable for masked copy operations. "l" in the spec182183PSYMCRYPT_INT piTmp = NULL;184PSYMCRYPT_MODELEMENT peTmp = NULL;185186PSYMCRYPT_MODELEMENT peZ = NULL;187PSYMCRYPT_MODELEMENT peM = NULL;188PSYMCRYPT_MODELEMENT peT = NULL;189PSYMCRYPT_MODELEMENT peX1 = NULL;190PSYMCRYPT_MODELEMENT peX2 = NULL;191PSYMCRYPT_MODELEMENT peGX1 = NULL;192PSYMCRYPT_MODELEMENT peGX2 = NULL;193194BYTE pointBuf[SYMCRYPT_SAE_MAX_EC_POINT_SIZE_BYTES] = { 0 };195196SYMCRYPT_ASSERT( z < 0 );197198piTmp = SymCryptIntAllocate( SymCryptDigitsFromBits( pCurve->FModBitsize ) );199200peTmp = SymCryptModElementAllocate( pCurve->FMod );201peZ = SymCryptModElementAllocate( pCurve->FMod );202peM = SymCryptModElementAllocate( pCurve->FMod );203peT = SymCryptModElementAllocate( pCurve->FMod );204peX1 = SymCryptModElementAllocate( pCurve->FMod );205peX2 = SymCryptModElementAllocate( pCurve->FMod );206peGX1 = SymCryptModElementAllocate( pCurve->FMod );207peGX2 = SymCryptModElementAllocate( pCurve->FMod );208209if( piTmp == NULL|| peTmp == NULL || peZ == NULL || peM == NULL || peT == NULL ||210peX1 == NULL || peX2 == NULL || peGX1 == NULL || peGX2 == NULL)211{212scError = SYMCRYPT_MEMORY_ALLOCATION_FAILURE;213goto cleanup;214}215216// Convert z to mod element217// Currently we avoid a branching based on the sign of z to make the assignment and assume it will218// be negative which holds for the set of possible values as of now (NIST P256 and NIST P384).219// There is no direct function to create a SYMCRYPT_INT from a signed INT32, so when z is negative220// we change its sign and call SymCryptModElementSetValueNegUInt32221SymCryptModElementSetValueNegUint32(-z, pCurve->FMod, peZ, pbScratch, cbScratch);222223// Set peTmp to 1 for convenience later224SymCryptModElementSetValueUint32( 1, pCurve->FMod, peTmp, pbScratch, cbScratch );225226// m = ( z^2 * u^4 + z * u^2 ) = (z * u^2)(z * u^2 + 1) modulo p227SymCryptModSquare( pCurve->FMod, peU, peM, pbScratch, cbScratch ); // M = u^2228SymCryptModMul( pCurve->FMod, peM, peZ, peM, pbScratch, cbScratch ); // M = z * u^2229SymCryptModAdd( pCurve->FMod, peM, peTmp, peTmp, pbScratch, cbScratch ); // tmp = (z * u^2 + 1)230SymCryptModMul( pCurve->FMod, peM, peTmp, peM, pbScratch, cbScratch ); // M = M * tmp = (z * u^2)(z * u^2 + 1)231232// l = CEQ( m, 0 )233selectionMask = SymCryptModElementIsZero( pCurve->FMod, peM );234235// t = inverse( m ) where inverse ( m ) = m^( p-2 ) modulo p236SymCryptIntSubUint32( SymCryptIntFromModulus( pCurve->FMod ), 2, piTmp );237SymCryptModExp( pCurve->FMod, peM, piTmp, pCurve->FModBitsize, 0, peT, pbScratch, cbScratch );238239//x1 = CSEL( l, ( b / ( z * a ) modulo p ), ( ( - b / a ) * ( 1 + t ) ) modulo p )240// where CSEL(x,y,z) operates in constant time and returns y if x is true and z otherwise.241SymCryptModMul( pCurve->FMod, peZ, pCurve->A, peTmp, pbScratch, cbScratch ); // tmp = z * a242SymCryptModInv( pCurve->FMod, peTmp, peTmp, SYMCRYPT_FLAG_DATA_PUBLIC | SYMCRYPT_FLAG_MODULUS_PRIME, pbScratch, cbScratch ); // tmp = 1/(z * a)243SymCryptModMul( pCurve->FMod, pCurve->B, peTmp, peX1, pbScratch, cbScratch ); // x1A = B * 1/(z * a)244245SymCryptModInv( pCurve->FMod, pCurve->A, peTmp, SYMCRYPT_FLAG_DATA_PUBLIC | SYMCRYPT_FLAG_MODULUS_PRIME, pbScratch, cbScratch ); // tmp = 1/a246SymCryptModMul( pCurve->FMod, pCurve->B, peTmp, peTmp, pbScratch, cbScratch ); // tmp = b * 1/a247SymCryptModNeg( pCurve->FMod, peTmp, peTmp, pbScratch, cbScratch ); // tmp = -(b * 1/a)248249// NB: in this block we're using X2 as the second candidate for CSEL. This allows us to choose the250// correct X1 by copying X2 to X1 if l is false251SymCryptIntSetValueUint32( 1, piTmp );252SymCryptIntToModElement( piTmp, pCurve->FMod, peX2, pbScratch, cbScratch ); // X1B = 1253SymCryptModAdd( pCurve->FMod, peX2, peT, peX2, pbScratch, cbScratch ); // X1B = 1 + t254SymCryptModMul( pCurve->FMod, peX2, peTmp, peX2, pbScratch, cbScratch ); // X1B = -(b * 1/a)(1 + t)255256// Note: we need the binary complement of l since MaskedCopy copies only if the mask is 0xFFFFFFFF,257// and we want the second X1 candidate iff l is false258SymCryptModElementMaskedCopy( pCurve->FMod, peX2, peX1, ~selectionMask );259260// gx1 = ( x1^3 + a * x1 + b ) = (x1^2 + a)*x1 + b modulo p261SymCryptModSquare( pCurve->FMod, peX1, peGX1, pbScratch, cbScratch ); // gx1 = x1^2262SymCryptModAdd( pCurve->FMod, peGX1, pCurve->A, peGX1, pbScratch, cbScratch ); // gx1 = x1^2 + a263SymCryptModMul( pCurve->FMod, peGX1, peX1, peGX1, pbScratch, cbScratch ); // gx1 = (x1^2 + a)*x1264SymCryptModAdd( pCurve->FMod, peGX1, pCurve->B, peGX1, pbScratch, cbScratch ); // gx1 = (x1^2 + a)*x1 + b265266//x2 = ( z * u^2 * x1 ) modulo p267SymCryptModSquare( pCurve->FMod, peU, peX2, pbScratch, cbScratch ); // x2 = u^2268SymCryptModMul( pCurve->FMod, peX2, peZ, peX2, pbScratch, cbScratch ); // x2 = u^2 * z269SymCryptModMul( pCurve->FMod, peX2, peX1, peX2, pbScratch, cbScratch ); // x2 = u^2 * z * x1270271//gx2 = ( x2^3 + a * x2 + b ) = (x2^2 + a)*x2 + b modulo p272SymCryptModSquare( pCurve->FMod, peX2, peGX2, pbScratch, cbScratch ); // gx2 = x2^2273SymCryptModAdd( pCurve->FMod, peGX2, pCurve->A, peGX2, pbScratch, cbScratch ); // gx2 = x2^2 + a274SymCryptModMul( pCurve->FMod, peGX2, peX2, peGX2, pbScratch, cbScratch ); // gx2 = (x2^2 + a)*x2275SymCryptModAdd( pCurve->FMod, peGX2, pCurve->B, peGX2, pbScratch, cbScratch ); // gx2 = (x2^2 + a)*x2 + b276277//l = gx1 is a quadratic residue modulo p278scError = SymCryptModSqrt( pCurve->FMod, peGX1, &selectionMask, NULL, pbScratch, cbScratch );279if( scError != SYMCRYPT_NO_ERROR )280{281goto cleanup;282}283284// v = CSEL( l, gx1, gx2 )285// (Using gx1 as a temporary for v)286SymCryptModElementMaskedCopy( pCurve->FMod, peGX2, peGX1, ~selectionMask );287288// x = CSEL( l, x1, x2 )289// (Using x1 as a temporary for x)290SymCryptModElementMaskedCopy( pCurve->FMod, peX2, peX1, ~selectionMask );291292// y = sqrt( v ) = v^{(P+1)/4}293// (Using gx1 as a temporary for y)294scError = SymCryptModSqrt( pCurve->FMod, peGX1, &selectionMask, peGX1, pbScratch, cbScratch );295296// l = CEQ( LSB( u ), LSB( y ) )297// LSB returns the least significant *BIT* of its argument298SymCryptModElementToInt( pCurve->FMod, peU, piTmp, pbScratch, cbScratch );299UINT32 u = SymCryptIntGetValueLsbits32( piTmp );300301SymCryptModElementToInt( pCurve->FMod, peGX1, piTmp, pbScratch, cbScratch );302UINT32 y = SymCryptIntGetValueLsbits32( piTmp );303304selectionMask = SYMCRYPT_MASK32_EQ( u & 1, y & 1 );305306// P = CSEL( l, ( x, y ), ( x, p - y ) )307// equivalently, y = CSEL( l, y, p - y )308// (p - y) mod p is equivalent to -y mod p, so we end up with309// y = CSEL(l, y, -y)310// We use gx1 for y311SymCryptModNeg( pCurve->FMod, peGX1, peTmp, pbScratch, cbScratch );312SymCryptModElementMaskedCopy( pCurve->FMod, peTmp, peGX1, ~selectionMask );313314SymCryptModElementGetValue( pCurve->FMod, peX1, &pointBuf[0], pCurve->FModBytesize, SYMCRYPT_NUMBER_FORMAT_MSB_FIRST, pbScratch, cbScratch );315SymCryptModElementGetValue( pCurve->FMod, peGX1, &pointBuf[pCurve->FModBytesize], pCurve->FModBytesize, SYMCRYPT_NUMBER_FORMAT_MSB_FIRST, pbScratch, cbScratch );316317scError = SymCryptEcpointSetValue( pCurve,318pointBuf,3192 * pCurve->FModBytesize,320SYMCRYPT_NUMBER_FORMAT_MSB_FIRST,321SYMCRYPT_ECPOINT_FORMAT_XY,322poP,3230,324pbScratch,325cbScratch );326if( scError != SYMCRYPT_NO_ERROR )327{328goto cleanup;329}330331cleanup:332333if( peGX2 != NULL )334{335SymCryptModElementFree( pCurve->FMod, peGX2 );336peGX2 = NULL;337}338339if( peGX1 != NULL )340{341SymCryptModElementFree( pCurve->FMod, peGX1 );342peGX1 = NULL;343}344345if( peX2 != NULL )346{347SymCryptModElementFree( pCurve->FMod, peX2 );348peX2 = NULL;349}350351if( peX1 != NULL )352{353SymCryptModElementFree( pCurve->FMod, peX1 );354peX1 = NULL;355}356357if( peT != NULL )358{359SymCryptModElementFree( pCurve->FMod, peT );360peT = NULL;361}362363if( peM != NULL )364{365SymCryptModElementFree( pCurve->FMod, peM );366peM = NULL;367}368369if( peZ != NULL )370{371SymCryptModElementFree( pCurve->FMod, peZ );372peZ = NULL;373}374375if( peTmp != NULL )376{377SymCryptModElementFree( pCurve->FMod, peTmp );378peTmp = NULL;379}380381if( piTmp != NULL )382{383SymCryptIntFree( piTmp );384piTmp = NULL;385}386387return scError;388}389390SYMCRYPT_ERROR391SymCrypt802_11SaeCustomSetRandMask(392_Inout_ PSYMCRYPT_802_11_SAE_CUSTOM_STATE pState,393_Inout_updates_opt_( cbRand ) PBYTE pbRand,394SIZE_T cbRand,395_Inout_updates_opt_( cbMask) PBYTE pbMask,396SIZE_T cbMask,397_Out_writes_bytes_( cbScratch ) PBYTE pbScratch,398SIZE_T cbScratch )399{400SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR;401402PCSYMCRYPT_ECURVE pcCurve = pState->pCurve;403404SymCryptModElementSetValueUint32( 0, pcCurve->GOrd, pState->peRand, pbScratch, cbScratch );405if( pbRand != NULL )406{407scError = SymCryptModElementSetValue( pbRand, cbRand, SYMCRYPT_NUMBER_FORMAT_MSB_FIRST, pcCurve->GOrd, pState->peRand, pbScratch, cbScratch );408if( scError != SYMCRYPT_NO_ERROR )409{410goto cleanup;411}412}413414if( SymCryptModElementIsZero( pcCurve->GOrd, pState->peRand ) )415{416SymCryptModSetRandom( pcCurve->GOrd, pState->peRand, SYMCRYPT_FLAG_MODRANDOM_ALLOW_MINUSONE, pbScratch, cbScratch );417}418419if( pbRand != NULL )420{421scError = SymCryptModElementGetValue( pcCurve->GOrd, pState->peRand, pbRand, cbRand, SYMCRYPT_NUMBER_FORMAT_MSB_FIRST, pbScratch, cbScratch );422if( scError != SYMCRYPT_NO_ERROR )423{424goto cleanup;425}426}427428SymCryptModElementSetValueUint32( 0, pcCurve->GOrd, pState->peMask, pbScratch, cbScratch );429if( pbMask != NULL )430{431scError = SymCryptModElementSetValue( pbMask, cbMask, SYMCRYPT_NUMBER_FORMAT_MSB_FIRST, pcCurve->GOrd, pState->peMask, pbScratch, cbScratch );432if( scError != SYMCRYPT_NO_ERROR )433{434goto cleanup;435}436}437438if( SymCryptModElementIsZero( pcCurve->GOrd, pState->peMask ) )439{440SymCryptModSetRandom( pcCurve->GOrd, pState->peMask, SYMCRYPT_FLAG_MODRANDOM_ALLOW_MINUSONE, pbScratch, cbScratch );441}442443if( pbMask != NULL )444{445scError = SymCryptModElementGetValue( pcCurve->GOrd, pState->peMask, pbMask, cbMask, SYMCRYPT_NUMBER_FORMAT_MSB_FIRST, pbScratch, cbScratch );446if( scError != SYMCRYPT_NO_ERROR )447{448goto cleanup;449}450}451452//453// The standard calls for checking that peRand and peMask are not 0 or 1, and peRand + peMask is not 0 or 1.454// When the caller specifies the values we don't want to do any checking as they might be helpful in test vectors.455// When this code generates the random values, we avoid 0 or 1 (by not passing the flags allowing 0 and 1).456// We don't check that peRand + peMask > 1 because the probability of that occurring randomly is about 2^{-254} so the457// risk of this happening on any machine ever in the world is much smaller than the risk associated with adding several lines of code.458//459460cleanup:461462return scError;463}464465SYMCRYPT_ERROR466SymCrypt802_11SaeCustomInit(467_Out_ PSYMCRYPT_802_11_SAE_CUSTOM_STATE pState,468_In_reads_( 6 ) PCBYTE pbMac1,469_In_reads_( 6 ) PCBYTE pbMac2,470_In_reads_( cbPassword ) PCBYTE pbPassword,471SIZE_T cbPassword,472_Out_opt_ PBYTE pbCounter,473_Inout_updates_opt_( 32 ) PBYTE pbRand,474_Inout_updates_opt_( 32 ) PBYTE pbMask )475{476SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR;477478BYTE counter;479UINT32 notFoundMask;480UINT32 solutionMask;481UINT32 negMask;482BYTE abSeed[SYMCRYPT_HMAC_SHA256_RESULT_SIZE];483BYTE abValue[SYMCRYPT_HMAC_SHA256_RESULT_SIZE];484BYTE abSeedKey[16]; // Need only 12, but the extra bytes make the code easier.485SYMCRYPT_HMAC_SHA256_EXPANDED_KEY hmacSeedKey;486SYMCRYPT_HMAC_SHA256_EXPANDED_KEY hmacValueKey;487SYMCRYPT_HMAC_SHA256_STATE hmacState;488BYTE abTmp[2];489BYTE pointBuf[ 64 ];490PBYTE pbScratch = NULL;491SIZE_T cbScratch = 0;492UINT64 minMac;493UINT64 maxMac;494495UINT32 nDigits;496PSYMCRYPT_ECURVE pCurve; // Only a cache, pState->pCurve owns the allocation497PSYMCRYPT_INT piTmp = NULL;498PSYMCRYPT_MODELEMENT peX = NULL;499PSYMCRYPT_MODELEMENT peY = NULL;500PSYMCRYPT_MODELEMENT peCubic = NULL;501PSYMCRYPT_MODELEMENT peTmp = NULL;502PSYMCRYPT_ECPOINT poPWECandidate = NULL;503504// Set state to 0 so that our pointers have valid values.505SymCryptWipe( pState, sizeof( *pState ) );506507// Per IEEE 802.11-2016 section 12.4.4.1 the mandatory-to-implement curve is508// number 19 from the IANA Group description for RFC 2409 (IKE)509// The IANA website maps this to a 256-bit Random ECP group in RFC 5903.510// RFC 5903 specifies this group to be identical to the NIST P256 curve.511pCurve = SymCryptEcurveAllocate( SymCryptEcurveParamsNistP256, 0 );512pState->pCurve = pCurve;513if( pCurve == NULL )514{515scError = SYMCRYPT_MEMORY_ALLOCATION_FAILURE;516goto cleanup;517}518519pState->macAlgorithm = SymCryptHmacSha256Algorithm;520521pState->peRand = SymCryptModElementAllocate( pCurve->GOrd );522if( pState->peRand == NULL )523{524scError = SYMCRYPT_MEMORY_ALLOCATION_FAILURE;525goto cleanup;526}527528pState->peMask = SymCryptModElementAllocate( pCurve->GOrd );529if( pState->peMask == NULL )530{531scError = SYMCRYPT_MEMORY_ALLOCATION_FAILURE;532goto cleanup;533}534535pState->poPWE = SymCryptEcpointAllocate( pCurve );536if( pState->poPWE == NULL )537{538scError = SYMCRYPT_MEMORY_ALLOCATION_FAILURE;539goto cleanup;540}541542nDigits = SymCryptDigitsFromBits( PRIME_LENGTH_BITS );543544cbScratch = SYMCRYPT_MAX( SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_MOD_OPERATIONS( nDigits ),545SYMCRYPT_MAX( SYMCRYPT_SCRATCH_BYTES_FOR_MODEXP( nDigits ),546SYMCRYPT_SCRATCH_BYTES_FOR_GETSET_VALUE_ECURVE_OPERATIONS( pCurve ) ) );547pbScratch = SymCryptCallbackAlloc( cbScratch );548549piTmp = SymCryptIntAllocate( nDigits );550peX = SymCryptModElementAllocate( pCurve->FMod );551peY = SymCryptModElementAllocate( pCurve->FMod );552peCubic = SymCryptModElementAllocate( pCurve->FMod );553peTmp = SymCryptModElementAllocate( pCurve->FMod );554poPWECandidate = SymCryptEcpointAllocate( pCurve );555556if( pbScratch == NULL || piTmp == NULL || peX == NULL || peY == NULL || peCubic == NULL || peTmp == NULL || poPWECandidate == NULL )557{558scError = SYMCRYPT_MEMORY_ALLOCATION_FAILURE;559goto cleanup;560}561562SymCryptWipeKnownSize( abSeedKey, sizeof( abSeedKey ) );563memcpy( &abSeedKey[0], pbMac1, 6 );564minMac = SYMCRYPT_LOAD_MSBFIRST64( abSeedKey );565memcpy( &abSeedKey[0], pbMac2, 6 );566maxMac = SYMCRYPT_LOAD_MSBFIRST64( abSeedKey );567568if( minMac > maxMac )569{570// MAC values are public, no side-channel issues with this if()571// Swap the two values572minMac ^= maxMac;573maxMac ^= minMac;574minMac ^= maxMac;575}576577// Now we write the two MACs into the buffer.578// Note the slight overlap, and the use of 14 bytes rather than 12579SYMCRYPT_STORE_MSBFIRST64( &abSeedKey[0], maxMac );580SYMCRYPT_STORE_MSBFIRST64( &abSeedKey[6], minMac ); // This writes up to abSeedKey[14]581582SymCryptHmacSha256ExpandKey( &hmacSeedKey, abSeedKey, 12 );583SymCryptWipeKnownSize( abSeedKey, sizeof( abSeedKey ) ); // Not strictly speaking a secret, but good general hygiene584585notFoundMask = (UINT32)-1;586counter = 0;587588// We exit the loop only after 40 or more iterations589// This greatly reduces the side-channel of how often we run this loop.590while( notFoundMask != 0 || counter < 40 )591{592counter += 1;593if( counter == 0 )594{595scError = SYMCRYPT_INVALID_ARGUMENT;596goto cleanup;597}598599// pwd-seed = Hmac-sha256( MacA || MacB , Password || counter )600SymCryptHmacSha256Init( &hmacState, &hmacSeedKey );601SymCryptHmacSha256Append( &hmacState, pbPassword, cbPassword );602SymCryptHmacSha256Append( &hmacState, &counter, 1 );603SymCryptHmacSha256Result( &hmacState, abSeed );604605// pwd-value606SymCryptHmacSha256ExpandKey( &hmacValueKey, abSeed, sizeof( abSeed ) );607SymCryptHmacSha256Init( &hmacState, &hmacValueKey );608609SYMCRYPT_STORE_LSBFIRST16( abTmp, 1 );610SymCryptHmacSha256Append( &hmacState, abTmp, 2 ); // i value = 1611// Spec is unclear on whether there should be a terminating 0 on the context612// There are 23 characters in the string, so using len=24 gives us a zero613SymCryptHmacSha256Append( &hmacState, (PCBYTE) "SAE Hunting and Pecking", 23 );614615// Pick up the byte representation of p from the parameters616SymCryptHmacSha256Append( &hmacState, (BYTE *)(SymCryptEcurveParamsNistP256 + 1), 32 );617618SYMCRYPT_STORE_LSBFIRST16( abTmp, 256 );619SymCryptHmacSha256Append( &hmacState, abTmp, 2 ); // Length value = 256620SymCryptHmacSha256Result( &hmacState, abValue );621622// Get the pwd-value into an integer623scError = SymCryptIntSetValue( abValue, sizeof( abValue ), SYMCRYPT_NUMBER_FORMAT_MSB_FIRST, piTmp );624if( scError != SYMCRYPT_NO_ERROR )625{626goto cleanup;627}628629// Check that it is less than P630if( !SymCryptIntIsLessThan( piTmp, SymCryptIntFromModulus( pCurve->FMod ) ) )631{632// This is a slight side-channel, but our prime P starts with FFFFFFFF so the probability of633// hitting this case is < 2^-32.634continue;635}636637// Compute x^3 + A*x + B638SymCryptIntToModElement( piTmp, pCurve->FMod, peX, pbScratch, cbScratch );639SymCryptModSquare( pCurve->FMod, peX, peCubic, pbScratch, cbScratch );640SymCryptModAdd( pCurve->FMod, peCubic, pCurve->A, peCubic, pbScratch, cbScratch );641SymCryptModMul( pCurve->FMod, peCubic, peX, peCubic, pbScratch, cbScratch );642SymCryptModAdd( pCurve->FMod, peCubic, pCurve->B, peCubic, pbScratch, cbScratch );643644// Get the quadratic residue of (x^3 + A*x + B) modulo P if it exists645scError = SymCryptModSqrt( pCurve->FMod, peCubic, &solutionMask, peY, pbScratch, cbScratch );646if( scError != SYMCRYPT_NO_ERROR )647{648goto cleanup;649}650651solutionMask &= notFoundMask;652653// Pick Y or -Y according to the LSbits654SymCryptModElementToInt( pCurve->FMod, peY, piTmp, pbScratch, cbScratch );655SymCryptModNeg( pCurve->FMod, peY, peTmp, pbScratch, cbScratch );656657negMask = 0 - ((abSeed[ sizeof( abSeed ) - 1 ] ^ SymCryptIntGetValueLsbits32( piTmp ) ) & 1);658SymCryptModElementMaskedCopy( pCurve->FMod, peTmp, peY, negMask );659660SymCryptModElementGetValue( pCurve->FMod, peX, &pointBuf[ 0], 32, SYMCRYPT_NUMBER_FORMAT_MSB_FIRST, pbScratch, cbScratch );661SymCryptModElementGetValue( pCurve->FMod, peY, &pointBuf[32], 32, SYMCRYPT_NUMBER_FORMAT_MSB_FIRST, pbScratch, cbScratch );662scError = SymCryptEcpointSetValue( pCurve,663pointBuf,664sizeof( pointBuf ),665SYMCRYPT_NUMBER_FORMAT_MSB_FIRST,666SYMCRYPT_ECPOINT_FORMAT_XY,667poPWECandidate,6680,669pbScratch,670cbScratch );671if( scError != SYMCRYPT_NO_ERROR )672{673goto cleanup;674}675676SymCryptEcpointMaskedCopy( pCurve, poPWECandidate, pState->poPWE, solutionMask );677pState->counter |= (BYTE)(counter & solutionMask);678679notFoundMask &= ~solutionMask;680}681682scError = SymCrypt802_11SaeCustomSetRandMask( pState, pbRand, 32, pbMask, 32, pbScratch, cbScratch );683if( scError != SYMCRYPT_NO_ERROR)684{685goto cleanup;686}687688if( pbCounter != NULL )689{690*pbCounter = pState->counter;691}692693cleanup:694695SymCryptWipe( &hmacSeedKey, sizeof( hmacSeedKey ) );696SymCryptWipe( &hmacValueKey, sizeof( hmacValueKey ) );697SymCryptWipe( abSeed, sizeof( abSeed ) );698SymCryptWipe( abValue, sizeof( abValue ) );699SymCryptWipe( pointBuf, sizeof( pointBuf ) );700701if( piTmp != NULL )702{703SymCryptIntFree( piTmp );704piTmp = NULL;705}706707if( peX != NULL )708{709SymCryptModElementFree( pCurve->FMod, peX );710peX = NULL;711}712713if( peY != NULL )714{715SymCryptModElementFree( pCurve->FMod, peY );716peY = NULL;717}718719if( peCubic != NULL )720{721SymCryptModElementFree( pCurve->FMod, peCubic );722peCubic = NULL;723}724725if( peTmp != NULL )726{727SymCryptModElementFree( pCurve->FMod, peTmp );728peTmp = NULL;729}730731if( poPWECandidate != NULL )732{733SymCryptEcpointFree( pCurve, poPWECandidate );734poPWECandidate = NULL;735}736737if( scError != SYMCRYPT_NO_ERROR )738{739SymCrypt802_11SaeCustomDestroy( pState );740}741742if( pbScratch != NULL )743{744SymCryptWipe( pbScratch, cbScratch );745SymCryptCallbackFree( pbScratch );746pbScratch = NULL;747}748749return scError;750}751752753SYMCRYPT_ERROR754SymCrypt802_11SaeCustomCreatePTGeneric(755SYMCRYPT_802_11_SAE_GROUP group,756_In_reads_( cbSsid ) PCBYTE pbSsid,757SIZE_T cbSsid,758_In_reads_( cbPassword ) PCBYTE pbPassword,759SIZE_T cbPassword,760_In_reads_opt_( cbPasswordIdentifier ) PCBYTE pbPasswordIdentifier,761SIZE_T cbPasswordIdentifier,762_Out_writes_( cbPT ) PBYTE pbPT,763SIZE_T cbPT)764{765SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR;766767SIZE_T cbIkm = 0;768SIZE_T cbScratch = 0;769770PBYTE pbPwdValue = NULL;771UINT32 cbPwdValue = 0;772PBYTE pbScratch = NULL;773SYMCRYPT_HKDF_EXPANDED_KEY hkdfKey;774775PSYMCRYPT_ECURVE pCurve = NULL;776PCSYMCRYPT_MAC pMacAlgorithm = NULL;777PSYMCRYPT_INT piU1 = NULL;778PSYMCRYPT_INT piU2 = NULL;779PSYMCRYPT_MODELEMENT peU1 = NULL;780PSYMCRYPT_MODELEMENT peU2 = NULL;781782PSYMCRYPT_ECPOINT poP1 = NULL;783PSYMCRYPT_ECPOINT poP2 = NULL;784PSYMCRYPT_ECPOINT poPT = NULL;785786PCSYMCRYPT_SAE_GROUP_DATA pGroupData = NULL;787788789pGroupData = SymCryptSaeFindGroupData( group );790791// Provided IANA group number must match one of the supported groups792if ( pGroupData == NULL)793{794scError = SYMCRYPT_INVALID_ARGUMENT;795goto cleanup;796}797798// Construct the objects associated with the IANA group number799pCurve = SymCryptEcurveAllocate( *( pGroupData->pCurveParams), 0 );800if( pCurve == NULL )801{802scError = SYMCRYPT_MEMORY_ALLOCATION_FAILURE;803goto cleanup;804}805806pMacAlgorithm = *( pGroupData->macAlgorithm );807808const UINT32 nDigits = SymCryptEcurveDigitsofFieldElement( pCurve );809810cbIkm = cbPassword + cbPasswordIdentifier;811cbScratch = SYMCRYPT_MAX( cbIkm,812SYMCRYPT_MAX( SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_MOD_OPERATIONS( nDigits ),813SYMCRYPT_MAX( SYMCRYPT_SCRATCH_BYTES_FOR_MODEXP( nDigits ),814SYMCRYPT_MAX( SYMCRYPT_SCRATCH_BYTES_FOR_GETSET_VALUE_ECURVE_OPERATIONS( pCurve ),815SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_ECURVE_OPERATIONS( pCurve ) ) ) ) );816pbScratch = SymCryptCallbackAlloc( cbScratch );817818// len = olen( p ) + floor( olen( p ) / 2 )819cbPwdValue = SYMCRYPT_BYTES_FROM_BITS(pCurve->FModBitsize) + SYMCRYPT_BYTES_FROM_BITS(pCurve->FModBitsize) / 2;820821pbPwdValue = SymCryptCallbackAlloc( cbPwdValue );822823piU1 = SymCryptIntAllocate( SymCryptDigitsFromBits( cbPwdValue * 8 ) );824piU2 = SymCryptIntAllocate( SymCryptDigitsFromBits( cbPwdValue * 8 ) );825peU1 = SymCryptModElementAllocate( pCurve->FMod );826peU2 = SymCryptModElementAllocate( pCurve->FMod );827828poP1 = SymCryptEcpointAllocate( pCurve );829poP2 = SymCryptEcpointAllocate( pCurve );830poPT = SymCryptEcpointAllocate( pCurve );831832if( pbScratch == NULL || pbPwdValue == NULL || piU1 == NULL || piU2 == NULL ||833peU1 == NULL || peU2 == NULL || poP1 == NULL || poP2 == NULL || poPT == NULL)834{835scError = SYMCRYPT_MEMORY_ALLOCATION_FAILURE;836goto cleanup;837}838839// pwd-seed = HKDF-Extract( ssid, password [|| identifier] )840// Note that SymCryptHkdfExpandKey corresponds to HKDF-Extract841memcpy( pbScratch, pbPassword, cbPassword );842if( pbPasswordIdentifier )843{844memcpy( pbScratch + cbPassword, pbPasswordIdentifier, cbPasswordIdentifier );845}846847scError = SymCryptHkdfExpandKey( &hkdfKey, pMacAlgorithm, pbScratch, cbIkm, pbSsid, cbSsid );848if( scError != SYMCRYPT_NO_ERROR )849{850goto cleanup;851}852853// pwd-value = HKDF-Expand( pwd-seed, "SAE Hash to Element u1 P1", len )854// Note that SymCryptHkdf derive corresponds to HKDF-Expand855// Salt does not include a null terminator, so the length is 25 chars856scError = SymCryptHkdfDerive( &hkdfKey, (PCBYTE) "SAE Hash to Element u1 P1", 25, pbPwdValue, cbPwdValue );857if( scError != SYMCRYPT_NO_ERROR )858{859goto cleanup;860}861862// u1 = pwd-value modulo p863scError = SymCryptIntSetValue( pbPwdValue, cbPwdValue, SYMCRYPT_NUMBER_FORMAT_MSB_FIRST, piU1 );864if( scError != SYMCRYPT_NO_ERROR )865{866goto cleanup;867}868869SymCryptIntToModElement( piU1, pCurve->FMod, peU1, pbScratch, cbScratch );870871// P1 = SSWU( u1 )872SymCryptSswu( pCurve, pGroupData->z, peU1, poP1, pbScratch, cbScratch );873874// pwd-value = HKDF-Expand( pwd-seed, "SAE Hash to Element u2 P2", len )875scError = SymCryptHkdfDerive( &hkdfKey, (PCBYTE) "SAE Hash to Element u2 P2", 25, pbPwdValue, cbPwdValue );876if( scError != SYMCRYPT_NO_ERROR )877{878goto cleanup;879}880881// u2 = pwd-value modulo p882scError = SymCryptIntSetValue( pbPwdValue, cbPwdValue, SYMCRYPT_NUMBER_FORMAT_MSB_FIRST, piU2 );883if( scError != SYMCRYPT_NO_ERROR )884{885goto cleanup;886}887888SymCryptIntToModElement( piU2, pCurve->FMod, peU2, pbScratch, cbScratch );889890// P2 = SSWU( u2 )891scError = SymCryptSswu( pCurve, pGroupData->z, peU2, poP2, pbScratch, cbScratch );892if( scError != SYMCRYPT_NO_ERROR )893{894goto cleanup;895}896897// PT = P1 + P2898SymCryptEcpointAdd( pCurve, poP1, poP2, poPT, 0, pbScratch, cbScratch );899900scError = SymCryptEcpointGetValue( pCurve,901poPT,902SYMCRYPT_NUMBER_FORMAT_MSB_FIRST,903SYMCRYPT_ECPOINT_FORMAT_XY,904pbPT,905cbPT,9060,907pbScratch,908cbScratch );909SYMCRYPT_ASSERT( scError == SYMCRYPT_NO_ERROR );910911cleanup:912913if( poP2 != NULL )914{915SymCryptEcpointFree( pCurve, poP2 );916poP2 = NULL;917}918919if( poP1 != NULL )920{921SymCryptEcpointFree( pCurve, poP1 );922poP1 = NULL;923}924925if( poPT != NULL )926{927SymCryptEcpointFree( pCurve, poPT );928poPT = NULL;929}930931if( peU2 != NULL )932{933SymCryptModElementFree( pCurve->FMod, peU2 );934peU2 = NULL;935}936937if( peU1 != NULL )938{939SymCryptModElementFree( pCurve->FMod, peU1 );940peU1 = NULL;941}942943if( piU2 != NULL )944{945SymCryptIntFree( piU2 );946piU2 = NULL;947}948949if( piU1 != NULL )950{951SymCryptIntFree( piU1 );952piU1 = NULL;953}954955if( pbPwdValue != NULL )956{957SymCryptWipe( pbPwdValue, cbPwdValue );958SymCryptCallbackFree( pbPwdValue );959pbPwdValue = NULL;960}961962if( pbScratch != NULL )963{964SymCryptWipe( pbScratch, cbScratch );965SymCryptCallbackFree( pbScratch );966pbScratch = NULL;967}968969if ( pCurve != NULL )970{971SymCryptEcurveFree( pCurve );972pCurve = NULL;973}974975return scError;976}977978979SYMCRYPT_ERROR980SymCrypt802_11SaeCustomCreatePT(981_In_reads_( cbSsid ) PCBYTE pbSsid,982SIZE_T cbSsid,983_In_reads_( cbPassword ) PCBYTE pbPassword,984SIZE_T cbPassword,985_In_reads_opt_( cbPasswordIdentifier ) PCBYTE pbPasswordIdentifier,986SIZE_T cbPasswordIdentifier,987_Out_writes_( 64 ) PBYTE pbPT )988{989return SymCrypt802_11SaeCustomCreatePTGeneric( SYMCRYPT_SAE_GROUP_19,990pbSsid,991cbSsid,992pbPassword,993cbPassword,994pbPasswordIdentifier,995cbPasswordIdentifier,996pbPT,99764 );998}99910001001SYMCRYPT_ERROR1002SymCrypt802_11SaeCustomInitH2EGeneric(1003_Out_ PSYMCRYPT_802_11_SAE_CUSTOM_STATE pState,1004SYMCRYPT_802_11_SAE_GROUP group,1005_In_reads_( cbPT ) PCBYTE pbPT,1006SIZE_T cbPT,1007_In_reads_( 6 ) PCBYTE pbMacA,1008_In_reads_( 6 ) PCBYTE pbMacB,1009_Inout_updates_opt_( cbRand ) PBYTE pbRand,1010SIZE_T cbRand,1011_Inout_updates_opt_( cbMask ) PBYTE pbMask,1012SIZE_T cbMask)1013{1014SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR;10151016BYTE hmacKeyBytes[SYMCRYPT_SAE_MAX_HMAC_OUTPUT_SIZE_BYTES] = { 0 };1017BYTE valBytes[SYMCRYPT_SAE_MAX_HMAC_OUTPUT_SIZE_BYTES] = { 0 };1018BYTE macBuffer[16] = { 0 }; // Need only 12, but the extra bytes make the code easier.1019SYMCRYPT_MAC_EXPANDED_KEY hmacKey = { 0 };1020SYMCRYPT_MAC_STATE hmacState = { 0 };10211022SIZE_T cbScratch = 0;1023PBYTE pbScratch = NULL;10241025UINT64 minMac = 0;1026UINT64 maxMac = 0;10271028UINT32 nDigits = 0;10291030PSYMCRYPT_INT piTmp = NULL;1031PSYMCRYPT_MODULUS pmMod = NULL;1032PSYMCRYPT_MODELEMENT peVal = NULL;1033PSYMCRYPT_MODELEMENT peTmp = NULL;1034PSYMCRYPT_ECPOINT poPT = NULL;1035PCSYMCRYPT_SAE_GROUP_DATA pGroupData = NULL;1036PCSYMCRYPT_MAC pMacAlgorithm = NULL;10371038// Set state to 0 so that our pointers have valid values.1039SymCryptWipeKnownSize( pState, sizeof( *pState ) );10401041PSYMCRYPT_ECURVE pCurve = NULL; // Weak reference; curve is owned by pState10421043pGroupData = SymCryptSaeFindGroupData( group );10441045// Provided IANA group number must match one of the supported groups1046if ( pGroupData == NULL )1047{1048scError = SYMCRYPT_INVALID_ARGUMENT;1049goto cleanup;1050}10511052// Construct the objects associated with the IANA group number1053pCurve = SymCryptEcurveAllocate( *( pGroupData->pCurveParams ), 0 );1054if ( pCurve == NULL )1055{1056scError = SYMCRYPT_MEMORY_ALLOCATION_FAILURE;1057goto cleanup;1058}10591060pState->pCurve = pCurve;10611062pMacAlgorithm = *( pGroupData->macAlgorithm );10631064SIZE_T cbHMACOutputSize = pMacAlgorithm->resultSize;10651066pState->peRand = SymCryptModElementAllocate( pCurve->GOrd );1067if( pState->peRand == NULL )1068{1069scError = SYMCRYPT_MEMORY_ALLOCATION_FAILURE;1070goto cleanup;1071}10721073pState->peMask = SymCryptModElementAllocate( pCurve->GOrd );1074if( pState->peMask == NULL )1075{1076scError = SYMCRYPT_MEMORY_ALLOCATION_FAILURE;1077goto cleanup;1078}10791080pState->poPWE = SymCryptEcpointAllocate( pCurve );1081if( pState->poPWE == NULL )1082{1083scError = SYMCRYPT_MEMORY_ALLOCATION_FAILURE;1084goto cleanup;1085}10861087nDigits = SymCryptDigitsFromBits( pCurve->GOrdBitsize );10881089piTmp = SymCryptIntAllocate( nDigits );1090pmMod = SymCryptModulusAllocate( nDigits );1091poPT = SymCryptEcpointAllocate( pCurve );10921093cbScratch = SYMCRYPT_MAX( SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_MOD_OPERATIONS( nDigits ),1094SYMCRYPT_MAX( SYMCRYPT_SCRATCH_BYTES_FOR_GETSET_VALUE_ECURVE_OPERATIONS( pCurve ),1095SYMCRYPT_MAX( SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_ECURVE_OPERATIONS( pCurve ),1096SYMCRYPT_INTERNAL_SCRATCH_BYTES_FOR_SCALAR_ECURVE_OPERATIONS ( pCurve, 1 ) ) ) );1097pbScratch = SymCryptCallbackAlloc( cbScratch );10981099if( piTmp == NULL || pmMod == NULL || poPT == NULL || pbScratch == NULL )1100{1101scError = SYMCRYPT_MEMORY_ALLOCATION_FAILURE;1102goto cleanup;1103}11041105memcpy( &macBuffer[0], pbMacA, 6 );1106minMac = SYMCRYPT_LOAD_MSBFIRST64( macBuffer );1107memcpy( &macBuffer[0], pbMacB, 6 );1108maxMac = SYMCRYPT_LOAD_MSBFIRST64( macBuffer );11091110if( minMac > maxMac )1111{1112// MAC values are public, no side-channel issues with this if()1113// Swap the two values1114minMac ^= maxMac;1115maxMac ^= minMac;1116minMac ^= maxMac;1117}11181119// Now we write the two MACs into the buffer.1120// Note the slight overlap, and the use of 14 bytes rather than 121121SYMCRYPT_STORE_MSBFIRST64( &macBuffer[0], maxMac );1122SYMCRYPT_STORE_MSBFIRST64( &macBuffer[6], minMac ); // This writes up to macBuffer[14]11231124// val = hmac-sha256( 0^n, maxMac || minMac )1125// The HMAC key is is a buffer of all zeros whose length equals the length of the digest from the hash function1126pMacAlgorithm->expandKeyFunc(&hmacKey, hmacKeyBytes, cbHMACOutputSize);11271128pMacAlgorithm->initFunc( &hmacState, &hmacKey );1129pMacAlgorithm->appendFunc( &hmacState, macBuffer, 12 );1130pMacAlgorithm->resultFunc( &hmacState, valBytes );11311132// val = val (#4666)modulo (q - 1) + 11133SymCryptIntSubUint32( SymCryptIntFromModulus(pCurve->GOrd), 1, piTmp );1134SymCryptIntToModulus( piTmp, pmMod, 1, SYMCRYPT_FLAG_DATA_PUBLIC, pbScratch, cbScratch );11351136peVal = SymCryptModElementAllocate( pmMod );1137peTmp = SymCryptModElementAllocate( pmMod );11381139if( peVal == NULL || peTmp == NULL )1140{1141scError = SYMCRYPT_MEMORY_ALLOCATION_FAILURE;1142goto cleanup;1143}11441145scError = SymCryptModElementSetValue( valBytes, cbHMACOutputSize, SYMCRYPT_NUMBER_FORMAT_MSB_FIRST, pmMod, peVal, pbScratch, cbScratch );1146if( scError != SYMCRYPT_NO_ERROR )1147{1148goto cleanup;1149}11501151SymCryptModElementSetValueUint32( 1, pmMod, peTmp, pbScratch, cbScratch );1152SymCryptModAdd( pmMod, peVal, peTmp, peVal, pbScratch, cbScratch );11531154SymCryptModElementToInt( pmMod, peVal, piTmp, pbScratch, cbScratch );11551156scError = SymCryptEcpointSetValue( pCurve,1157pbPT,1158cbPT,1159SYMCRYPT_NUMBER_FORMAT_MSB_FIRST,1160SYMCRYPT_ECPOINT_FORMAT_XY,1161poPT,11620,1163pbScratch,1164cbScratch );1165if( scError != SYMCRYPT_NO_ERROR )1166{1167goto cleanup;1168}11691170scError = SymCryptEcpointScalarMul( pCurve, piTmp, poPT, 0, pState->poPWE, pbScratch, cbScratch );1171if( scError != SYMCRYPT_NO_ERROR )1172{1173goto cleanup;1174}11751176scError = SymCrypt802_11SaeCustomSetRandMask( pState, pbRand, cbRand, pbMask, cbMask, pbScratch, cbScratch );1177if( scError != SYMCRYPT_NO_ERROR )1178{1179goto cleanup;1180}11811182cleanup:11831184if( peTmp != NULL )1185{1186SymCryptModElementFree( pmMod, peTmp );1187peTmp = NULL;1188}11891190if( peVal != NULL )1191{1192SymCryptModElementFree( pmMod, peVal );1193peVal = NULL;1194}11951196if( poPT != NULL )1197{1198SymCryptEcpointFree( pCurve, poPT );1199poPT = NULL;1200}12011202if( pmMod != NULL )1203{1204SymCryptModulusFree( pmMod );1205pmMod = NULL;1206}12071208if( piTmp != NULL )1209{1210SymCryptIntFree( piTmp );1211piTmp = NULL;1212}12131214if( pbScratch != NULL )1215{1216SymCryptWipe( pbScratch, cbScratch );1217SymCryptCallbackFree( pbScratch );1218pbScratch = NULL;1219}12201221if( scError != SYMCRYPT_NO_ERROR )1222{1223SymCrypt802_11SaeCustomDestroy( pState );1224}12251226return scError;1227}12281229SYMCRYPT_ERROR1230SymCrypt802_11SaeCustomInitH2E(1231_Out_ PSYMCRYPT_802_11_SAE_CUSTOM_STATE pState,1232_In_reads_( 64 ) PCBYTE pbPT,1233_In_reads_( 6 ) PCBYTE pbMacA,1234_In_reads_( 6 ) PCBYTE pbMacB,1235_Inout_updates_opt_( 32 ) PBYTE pbRand,1236_Inout_updates_opt_( 32 ) PBYTE pbMask )1237{1238return SymCrypt802_11SaeCustomInitH2EGeneric( pState,1239SYMCRYPT_SAE_GROUP_19,1240pbPT,124164,1242pbMacA,1243pbMacB,1244pbRand,124532,1246pbMask,124732 );1248}124912501251VOID1252SymCrypt802_11SaeCustomDestroy(1253_Inout_ PSYMCRYPT_802_11_SAE_CUSTOM_STATE pState )1254{1255PSYMCRYPT_ECURVE pCurve = pState->pCurve;12561257if( pState->poPWE != NULL )1258{1259SymCryptEcpointFree( pCurve, pState->poPWE );1260}12611262if( pState->peMask != NULL )1263{1264SymCryptModElementFree( pCurve->GOrd, pState->peMask );1265}12661267if( pState->peRand != NULL )1268{1269SymCryptModElementFree( pCurve->GOrd, pState->peRand );1270}12711272if( pCurve != NULL )1273{1274SymCryptEcurveFree( pCurve );1275}12761277SymCryptWipeKnownSize( pState, sizeof( *pState ) );1278}12791280SYMCRYPT_ERROR1281SymCrypt802_11SaeCustomCommitCreateGeneric(1282_In_ PCSYMCRYPT_802_11_SAE_CUSTOM_STATE pState,1283_Out_writes_( cbCommitScalar ) PBYTE pbCommitScalar,1284SIZE_T cbCommitScalar,1285_Out_writes_( cbCommitElement ) PBYTE pbCommitElement,1286SIZE_T cbCommitElement)1287{1288SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR;1289PSYMCRYPT_MODELEMENT peTmp = NULL;1290PSYMCRYPT_INT piTmp = NULL;1291PSYMCRYPT_ECPOINT poPoint = NULL;1292PBYTE pbScratch = NULL;1293SIZE_T cbScratch;1294SIZE_T nDigits;12951296PCSYMCRYPT_ECURVE pCurve = pState->pCurve;12971298nDigits = SymCryptDigitsFromBits( pCurve->FModBitsize );1299cbScratch = SYMCRYPT_MAX( SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_MOD_OPERATIONS( nDigits ),1300SYMCRYPT_MAX( SYMCRYPT_SCRATCH_BYTES_FOR_SCALAR_ECURVE_OPERATIONS( pCurve ),1301SYMCRYPT_SCRATCH_BYTES_FOR_GETSET_VALUE_ECURVE_OPERATIONS( pCurve ) ) );13021303pbScratch = SymCryptCallbackAlloc( cbScratch );13041305peTmp = SymCryptModElementAllocate( pCurve->GOrd );1306piTmp = SymCryptIntAllocate( SymCryptEcurveDigitsofScalarMultiplier( pCurve ) );1307poPoint = SymCryptEcpointAllocate( pCurve );13081309if( peTmp == NULL || piTmp == NULL || poPoint == NULL || pbScratch == NULL )1310{1311scError = SYMCRYPT_MEMORY_ALLOCATION_FAILURE;1312goto cleanup;1313}13141315SymCryptModAdd( pCurve->GOrd, pState->peRand, pState->peMask, peTmp, pbScratch, cbScratch );1316scError = SymCryptModElementGetValue( pCurve->GOrd, peTmp, pbCommitScalar, cbCommitScalar, SYMCRYPT_NUMBER_FORMAT_MSB_FIRST, pbScratch, cbScratch );1317if( scError != SYMCRYPT_NO_ERROR )1318{1319goto cleanup;1320}13211322SymCryptModElementToInt( pCurve->GOrd, pState->peMask, piTmp, pbScratch, cbScratch );1323scError = SymCryptEcpointScalarMul( pCurve,1324piTmp,1325pState->poPWE,13260,1327poPoint,1328pbScratch,1329cbScratch );1330if( scError != SYMCRYPT_NO_ERROR )1331{1332goto cleanup;1333}13341335// Now we have mask * PWE, but we need the negative...1336SymCryptEcpointNegate( pCurve, poPoint, (UINT32)-1, pbScratch, cbScratch );13371338scError = SymCryptEcpointGetValue( pCurve,1339poPoint,1340SYMCRYPT_NUMBER_FORMAT_MSB_FIRST,1341SYMCRYPT_ECPOINT_FORMAT_XY,1342pbCommitElement,1343cbCommitElement,13440,1345pbScratch,1346cbScratch );1347if( scError != SYMCRYPT_NO_ERROR )1348{1349goto cleanup;1350}13511352cleanup:13531354if( piTmp != NULL )1355{1356SymCryptIntFree( piTmp );1357piTmp = NULL;1358}13591360if( peTmp != NULL )1361{1362SymCryptModElementFree( pCurve->GOrd, peTmp );1363peTmp = NULL;1364}13651366if( poPoint != NULL )1367{1368SymCryptEcpointFree( pCurve, poPoint );1369poPoint = NULL;1370}13711372if( pbScratch != NULL )1373{1374SymCryptWipe( pbScratch, cbScratch );1375SymCryptCallbackFree( pbScratch );1376pbScratch = NULL;1377}13781379return scError;1380}13811382SYMCRYPT_ERROR1383SymCrypt802_11SaeCustomCommitCreate(1384_In_ PCSYMCRYPT_802_11_SAE_CUSTOM_STATE pState,1385_Out_writes_( 32 ) PBYTE pbCommitScalar,1386_Out_writes_( 64 ) PBYTE pbCommitElement )1387{1388return SymCrypt802_11SaeCustomCommitCreateGeneric( pState,1389pbCommitScalar,139032,1391pbCommitElement,139264 );1393}13941395SYMCRYPT_ERROR1396SymCrypt802_11SaeCustomCommitProcessGeneric(1397_In_ PCSYMCRYPT_802_11_SAE_CUSTOM_STATE pState,1398_In_reads_( cbPeerCommitScalar ) PCBYTE pbPeerCommitScalar,1399SIZE_T cbPeerCommitScalar,1400_In_reads_( cbPeerCommitElement ) PCBYTE pbPeerCommitElement,1401SIZE_T cbPeerCommitElement,1402_Out_writes_( cbSharedSecret ) PBYTE pbSharedSecret,1403SIZE_T cbSharedSecret,1404_Out_writes_( cbScalarSum ) PBYTE pbScalarSum,1405SIZE_T cbScalarSum )1406{1407SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR;14081409PSYMCRYPT_ECURVE pCurve = pState->pCurve;1410PSYMCRYPT_MODELEMENT peCommitScalarSum = NULL;1411PSYMCRYPT_ECPOINT poPeerCommitElement = NULL;1412PSYMCRYPT_ECPOINT poTmp = NULL;1413PSYMCRYPT_INT piTmp = NULL;1414UINT32 nDigits;14151416PBYTE pbScratch = NULL;1417SIZE_T cbScratch;14181419nDigits = SymCryptDigitsFromBits( pCurve->FModBitsize );1420cbScratch = SYMCRYPT_MAX( SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_MOD_OPERATIONS( nDigits ),1421SYMCRYPT_MAX( SYMCRYPT_SCRATCH_BYTES_FOR_SCALAR_ECURVE_OPERATIONS( pCurve ),1422SYMCRYPT_MAX( SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_ECURVE_OPERATIONS( pCurve ),1423SYMCRYPT_SCRATCH_BYTES_FOR_GETSET_VALUE_ECURVE_OPERATIONS( pCurve ) ) ) );1424pbScratch = SymCryptCallbackAlloc( cbScratch );14251426peCommitScalarSum = SymCryptModElementAllocate( pCurve->GOrd );1427poPeerCommitElement = SymCryptEcpointAllocate( pCurve );1428poTmp = SymCryptEcpointAllocate( pCurve );1429piTmp = SymCryptIntAllocate( SymCryptEcurveDigitsofScalarMultiplier( pCurve ) );14301431if( pbScratch == NULL || peCommitScalarSum == NULL || poPeerCommitElement == NULL || poTmp == NULL || piTmp == NULL )1432{1433scError = SYMCRYPT_MEMORY_ALLOCATION_FAILURE;1434goto cleanup;1435}14361437// piTmp = peer commit value1438scError = SymCryptIntSetValue( pbPeerCommitScalar, cbPeerCommitScalar, SYMCRYPT_NUMBER_FORMAT_MSB_FIRST, piTmp );1439if( scError != SYMCRYPT_NO_ERROR )1440{1441goto cleanup;1442}14431444// The Standard requires a check that the Peer commit value must be 1 < peer-commit < r where r is the group order.1445if( !SymCryptIntIsLessThan( piTmp, SymCryptIntFromModulus( pCurve->GOrd ) ) ||1446SymCryptIntIsEqualUint32( piTmp, 0 ) ||1447SymCryptIntIsEqualUint32( piTmp, 1 ) )1448{1449scError = SYMCRYPT_INVALID_ARGUMENT;1450goto cleanup;1451}14521453SymCryptIntToModElement( piTmp, pCurve->GOrd, peCommitScalarSum, pbScratch, cbScratch );14541455// Now compute the sum of the scalar commit values1456SymCryptModAdd( pCurve->GOrd, peCommitScalarSum, pState->peRand, peCommitScalarSum, pbScratch, cbScratch );1457SymCryptModAdd( pCurve->GOrd, peCommitScalarSum, pState->peMask, peCommitScalarSum, pbScratch, cbScratch );14581459scError = SymCryptEcpointSetValue( pCurve,1460pbPeerCommitElement,1461cbPeerCommitElement,1462SYMCRYPT_NUMBER_FORMAT_MSB_FIRST,1463SYMCRYPT_ECPOINT_FORMAT_XY,1464poPeerCommitElement,14650,1466pbScratch,1467cbScratch );1468if( scError != SYMCRYPT_NO_ERROR )1469{1470goto cleanup;1471}14721473// The EcPointSetValue routine returns an error if either coordinate is >= P.1474// We need to check that the point is on the curve and not the zero point of the curve1475// (The zero point is sometimes called the 'point at infinity'.)1476if( !SymCryptEcpointOnCurve( pCurve, poPeerCommitElement, pbScratch, cbScratch ) ||1477SymCryptEcpointIsZero( pCurve, poPeerCommitElement, pbScratch, cbScratch ) )1478{1479scError = SYMCRYPT_INVALID_ARGUMENT;1480goto cleanup;1481}148214831484scError = SymCryptEcpointScalarMul( pCurve,1485piTmp,1486pState->poPWE,14870,1488poTmp,1489pbScratch,1490cbScratch );1491if( scError != SYMCRYPT_NO_ERROR )1492{1493goto cleanup;1494}14951496SymCryptEcpointAdd( pCurve, poTmp, poPeerCommitElement, poTmp, 0, pbScratch, cbScratch );14971498SymCryptModElementToInt( pCurve->GOrd, pState->peRand, piTmp, pbScratch, cbScratch );1499scError = SymCryptEcpointScalarMul( pCurve,1500piTmp,1501poTmp,15020,1503poTmp,1504pbScratch,1505cbScratch );1506if( scError != SYMCRYPT_NO_ERROR )1507{1508goto cleanup;1509}15101511scError = SymCryptEcpointGetValue( pCurve,1512poTmp,1513SYMCRYPT_NUMBER_FORMAT_MSB_FIRST,1514SYMCRYPT_ECPOINT_FORMAT_X,1515pbSharedSecret,1516cbSharedSecret,15170,1518pbScratch,1519cbScratch );1520if( scError != SYMCRYPT_NO_ERROR )1521{1522goto cleanup;1523}15241525scError = SymCryptModElementGetValue( pCurve->GOrd, peCommitScalarSum, pbScalarSum, cbScalarSum, SYMCRYPT_NUMBER_FORMAT_MSB_FIRST, pbScratch, cbScratch );1526if( scError != SYMCRYPT_NO_ERROR )1527{1528goto cleanup;1529}15301531cleanup:15321533if( peCommitScalarSum != NULL )1534{1535SymCryptModElementFree( pCurve->GOrd, peCommitScalarSum );1536peCommitScalarSum = NULL;1537}15381539if( poPeerCommitElement != NULL )1540{1541SymCryptEcpointFree( pCurve, poPeerCommitElement );1542poPeerCommitElement = NULL;1543}15441545if( poTmp != NULL )1546{1547SymCryptEcpointFree( pCurve, poTmp );1548poTmp = NULL;1549}15501551if( piTmp != NULL )1552{1553SymCryptIntFree( piTmp );1554piTmp = NULL;1555}15561557if( pbScratch != NULL )1558{1559SymCryptWipe( pbScratch, cbScratch );1560SymCryptCallbackFree( pbScratch );1561pbScratch = NULL;1562}15631564return scError;1565}15661567SYMCRYPT_ERROR1568SymCrypt802_11SaeCustomCommitProcess(1569_In_ PCSYMCRYPT_802_11_SAE_CUSTOM_STATE pState,1570_In_reads_( 32 ) PCBYTE pbPeerCommitScalar,1571_In_reads_( 64 ) PCBYTE pbPeerCommitElement,1572_Out_writes_( 32 ) PBYTE pbSharedSecret,1573_Out_writes_( 32 ) PBYTE pbScalarSum )1574{1575return SymCrypt802_11SaeCustomCommitProcessGeneric( pState,1576pbPeerCommitScalar,157732,1578pbPeerCommitElement,157964,1580pbSharedSecret,158132,1582pbScalarSum,158332 );1584}158515861587