/*++ Copyright (c) 2000, Microsoft Corporation Module Name: wzcsec.c Abstract: This module contains code for providing security functions Revision History: sachins, Dec 04 2001, Created --*/ #include "precomp.h" #pragma hdrstop UCHAR SHApad1[40] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; UCHAR SHApad2[40] = {0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2}; VOID GetNewKeyFromSHA ( IN UCHAR *StartKey, IN UCHAR *SessionKey, IN DWORD SessionKeyLength, OUT UCHAR *InterimKey ) { A_SHA_CTX Context; UCHAR Digest[A_SHA_DIGEST_LEN]; ZeroMemory(Digest, A_SHA_DIGEST_LEN); A_SHAInit(&Context); A_SHAUpdate(&Context, StartKey, SessionKeyLength); A_SHAUpdate(&Context, SHApad1, 40); A_SHAUpdate(&Context, SessionKey, SessionKeyLength); A_SHAUpdate(&Context, SHApad2, 40); A_SHAFinal(&Context, Digest); CopyMemory (InterimKey, Digest, SessionKeyLength); } #define MAX_TOTAL_KEY_LENGTH 128 #define MAX_TOTAL_IV_LENGTH 64 DWORD GenerateMasterSessionKeys ( PBYTE pbSecret, DWORD cbSecret, PBYTE pbRandom, DWORD cbRandom, PMASTER_SESSION_KEYS pMasterSessionKeys ) { BYTE bPRF1[MAX_TOTAL_KEY_LENGTH]={0}, bPRF2[MAX_TOTAL_IV_LENGTH]={0}; BOOL fResult = FALSE; DWORD dwRetCode = NO_ERROR; do { fResult = PRF ( pbSecret, cbSecret, csz_CLIENT_EAP_ENCRYPTION, strlen (csz_CLIENT_EAP_ENCRYPTION), pbRandom, cbRandom, bPRF1, MAX_TOTAL_KEY_LENGTH ); if (!fResult) { dwRetCode = ERROR_CAN_NOT_COMPLETE; break; } CopyMemory ((PBYTE)pMasterSessionKeys, bPRF1, MAX_TOTAL_KEY_LENGTH); fResult = PRF ( pbSecret, cbSecret, csz_CLIENT_EAP_ENCRYPTION, strlen(csz_CLIENT_EAP_ENCRYPTION), pbRandom, cbRandom, bPRF2, MAX_TOTAL_IV_LENGTH ); if (!fResult) { dwRetCode = ERROR_CAN_NOT_COMPLETE; break; } CopyMemory ((PBYTE)pMasterSessionKeys+MAX_TOTAL_KEY_LENGTH, bPRF2, MAX_TOTAL_IV_LENGTH); } while (FALSE); return dwRetCode; } DWORD DeriveSessionKeys ( PBYTE pbMasterSendKey, PBYTE pbMasterReceiveKey, DWORD dwSessionKeyLength, PSESSION_KEYS pSessionKeys ) { PBYTE pbSendKey = pSessionKeys->bSendKey; PBYTE pbReceiveKey = pSessionKeys->bReceiveKey; DWORD dwEffectiveMasterKeyLength = 0; BOOLEAN fReduceKeysStrength = FALSE; DWORD dwRetCode = NO_ERROR; switch (dwSessionKeyLength*8) { case 40: fReduceKeysStrength = TRUE; case 56: dwEffectiveMasterKeyLength = 8; break; case 104: fReduceKeysStrength = TRUE; case 128: dwEffectiveMasterKeyLength = 16; break; case 168: fReduceKeysStrength = TRUE; case 192: dwEffectiveMasterKeyLength = 24; break; default: dwRetCode = ERROR_INVALID_PARAMETER; break; } if (dwRetCode != NO_ERROR) { return dwRetCode; } do { GetNewKeyFromSHA ( pbMasterSendKey, pbMasterSendKey, dwEffectiveMasterKeyLength, pSessionKeys->bSendKey ); GetNewKeyFromSHA ( pbMasterReceiveKey, pbMasterReceiveKey, dwEffectiveMasterKeyLength, pSessionKeys->bReceiveKey ); if (fReduceKeysStrength) { pbSendKey[0] = pbReceiveKey[0]= 0xD1; pbSendKey[1] = pbReceiveKey[1]= 0x26; pbSendKey[2] = pbReceiveKey[2]= 0x9E; } } while (FALSE); return dwRetCode; } #define NUM_IGNORE_BYTES 3 DWORD GenerateDynamicKeys ( IN PBYTE pbMasterSecret, IN DWORD dwMasterSecretLength, IN PBYTE pbRandom, IN DWORD dwRandomLength, IN DWORD dwDynamicKeyLength, OUT SESSION_KEYS *pSessionKeys ) { MASTER_SESSION_KEYS MasterKeys = {0}; SESSION_KEYS SessionKeys = {0}; BOOLEAN fIgnoreThreeLeadingBytes = FALSE; DWORD dwRetCode = NO_ERROR; do { if (IsBadWritePtr(pSessionKeys, sizeof(SESSION_KEYS))) { dwRetCode = ERROR_INVALID_PARAMETER; break; } switch (dwDynamicKeyLength*8) { case 40: case 104: case 168: fIgnoreThreeLeadingBytes = TRUE; break; } if ((dwRetCode = GenerateMasterSessionKeys ( pbMasterSecret, dwMasterSecretLength, pbRandom, dwRandomLength, &MasterKeys )) != NO_ERROR) { break; } // Use Peer Encryption (P->A) key as the Master Send Key // Use Authenticator Encryption (A->P) key as the Master Receive Key if ((dwRetCode = DeriveSessionKeys ( MasterKeys.bPeerEncryptionKey, MasterKeys.bAuthenticatorEncryptionKey, dwDynamicKeyLength, &SessionKeys )) != NO_ERROR) { break; } ZeroMemory(pSessionKeys, sizeof(SESSION_KEYS)); pSessionKeys->dwKeyLength = dwDynamicKeyLength; memcpy(pSessionKeys->bSendKey, SessionKeys.bSendKey + (fIgnoreThreeLeadingBytes?NUM_IGNORE_BYTES:0), dwDynamicKeyLength); memcpy(pSessionKeys->bReceiveKey, SessionKeys.bReceiveKey + (fIgnoreThreeLeadingBytes?NUM_IGNORE_BYTES:0), dwDynamicKeyLength); } while (FALSE); return dwRetCode; }