20#include <winpr/config.h>
22#include <winpr/assert.h>
29#include <winpr/ntlm.h>
30#include <winpr/print.h>
31#include <winpr/crypto.h>
32#include <winpr/sysinfo.h>
34#include "ntlm_compute.h"
37#define TAG WINPR_TAG("sspi.NTLM")
39#define NTLM_CheckAndLogRequiredCapacity(tag, s, nmemb, what) \
40 Stream_CheckAndLogRequiredCapacityEx(tag, WLOG_WARN, s, nmemb, 1, "%s(%s:%" PRIuz ") " what, \
41 __func__, __FILE__, (size_t)__LINE__)
43static char NTLM_CLIENT_SIGN_MAGIC[] =
"session key to client-to-server signing key magic constant";
44static char NTLM_SERVER_SIGN_MAGIC[] =
"session key to server-to-client signing key magic constant";
45static char NTLM_CLIENT_SEAL_MAGIC[] =
"session key to client-to-server sealing key magic constant";
46static char NTLM_SERVER_SEAL_MAGIC[] =
"session key to server-to-client sealing key magic constant";
48static const BYTE NTLM_NULL_BUFFER[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
49 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
60 WINPR_ASSERT(versionInfo);
62#if defined(WITH_WINPR_DEPRECATED)
63 OSVERSIONINFOA osVersionInfo = WINPR_C_ARRAY_INIT;
64 osVersionInfo.dwOSVersionInfoSize =
sizeof(OSVERSIONINFOA);
65 if (!GetVersionExA(&osVersionInfo))
67 versionInfo->ProductMajorVersion = (UINT8)osVersionInfo.dwMajorVersion;
68 versionInfo->ProductMinorVersion = (UINT8)osVersionInfo.dwMinorVersion;
69 versionInfo->ProductBuild = (UINT16)osVersionInfo.dwBuildNumber;
77 versionInfo->ProductMajorVersion = 10;
78 versionInfo->ProductMinorVersion = 0;
79 versionInfo->ProductBuild = 22631;
81 ZeroMemory(versionInfo->Reserved,
sizeof(versionInfo->Reserved));
82 versionInfo->NTLMRevisionCurrent = NTLMSSP_REVISION_W2K3;
97 WINPR_ASSERT(versionInfo);
99 if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
102 Stream_Read_UINT8(s, versionInfo->ProductMajorVersion);
103 Stream_Read_UINT8(s, versionInfo->ProductMinorVersion);
104 Stream_Read_UINT16(s, versionInfo->ProductBuild);
105 Stream_Read(s, versionInfo->Reserved,
sizeof(versionInfo->Reserved));
106 Stream_Read_UINT8(s, versionInfo->NTLMRevisionCurrent);
121 WINPR_ASSERT(versionInfo);
123 if (!Stream_CheckAndLogRequiredCapacityEx(
124 TAG, WLOG_WARN, s, 5ull +
sizeof(versionInfo->Reserved), 1ull,
125 "%s(%s:%" PRIuz
") NTLM_VERSION_INFO", __func__, __FILE__, (
size_t)__LINE__))
128 Stream_Write_UINT8(s, versionInfo->ProductMajorVersion);
129 Stream_Write_UINT8(s, versionInfo->ProductMinorVersion);
130 Stream_Write_UINT16(s, versionInfo->ProductBuild);
131 Stream_Write(s, versionInfo->Reserved,
sizeof(versionInfo->Reserved));
132 Stream_Write_UINT8(s, versionInfo->NTLMRevisionCurrent);
140#ifdef WITH_DEBUG_NTLM
143 WINPR_ASSERT(versionInfo);
145 WLog_VRB(TAG,
"VERSION ={");
146 WLog_VRB(TAG,
"\tProductMajorVersion: %" PRIu8
"", versionInfo->ProductMajorVersion);
147 WLog_VRB(TAG,
"\tProductMinorVersion: %" PRIu8
"", versionInfo->ProductMinorVersion);
148 WLog_VRB(TAG,
"\tProductBuild: %" PRIu16
"", versionInfo->ProductBuild);
149 WLog_VRB(TAG,
"\tReserved: 0x%02" PRIX8
"%02" PRIX8
"%02" PRIX8
"", versionInfo->Reserved[0],
150 versionInfo->Reserved[1], versionInfo->Reserved[2]);
151 WLog_VRB(TAG,
"\tNTLMRevisionCurrent: 0x%02" PRIX8
"", versionInfo->NTLMRevisionCurrent);
159 WINPR_ASSERT(challenge);
161 if (!Stream_CheckAndLogRequiredLength(TAG, s, 28))
164 Stream_Read_UINT8(s, challenge->RespType);
165 Stream_Read_UINT8(s, challenge->HiRespType);
166 Stream_Read_UINT16(s, challenge->Reserved1);
167 Stream_Read_UINT32(s, challenge->Reserved2);
168 Stream_Read(s, challenge->Timestamp, 8);
169 Stream_Read(s, challenge->ClientChallenge, 8);
170 Stream_Read_UINT32(s, challenge->Reserved3);
171 size = Stream_Length(s) - Stream_GetPosition(s);
173 if (size > UINT32_MAX)
175 WLog_ERR(TAG,
"NTLMv2_CLIENT_CHALLENGE::cbAvPairs too large, got %" PRIuz
"bytes", size);
179 challenge->cbAvPairs = (UINT32)size;
180 challenge->AvPairs = (
NTLM_AV_PAIR*)malloc(challenge->cbAvPairs);
182 if (!challenge->AvPairs)
184 WLog_ERR(TAG,
"NTLMv2_CLIENT_CHALLENGE::AvPairs failed to allocate %" PRIu32
"bytes",
185 challenge->cbAvPairs);
189 Stream_Read(s, challenge->AvPairs, size);
193static BOOL ntlm_write_ntlm_v2_client_challenge(
wStream* s,
199 WINPR_ASSERT(challenge);
201 if (!NTLM_CheckAndLogRequiredCapacity(TAG, s, 28,
"NTLMv2_CLIENT_CHALLENGE"))
204 Stream_Write_UINT8(s, challenge->RespType);
205 Stream_Write_UINT8(s, challenge->HiRespType);
206 Stream_Write_UINT16(s, challenge->Reserved1);
207 Stream_Write_UINT32(s, challenge->Reserved2);
208 Stream_Write(s, challenge->Timestamp, 8);
209 Stream_Write(s, challenge->ClientChallenge, 8);
210 Stream_Write_UINT32(s, challenge->Reserved3);
211 length = ntlm_av_pair_list_length(challenge->AvPairs, challenge->cbAvPairs);
213 if (!Stream_CheckAndLogRequiredLength(TAG, s, length))
216 Stream_Write(s, challenge->AvPairs, length);
223 WINPR_ASSERT(response);
225 if (!Stream_CheckAndLogRequiredLength(TAG, s, 16))
228 Stream_Read(s, response->Response, 16);
229 return ntlm_read_ntlm_v2_client_challenge(s, &(response->Challenge));
235 WINPR_ASSERT(response);
237 if (!NTLM_CheckAndLogRequiredCapacity(TAG, s, 16ull,
"NTLMv2_RESPONSE"))
240 Stream_Write(s, response->Response, 16);
241 return ntlm_write_ntlm_v2_client_challenge(s, &(response->Challenge));
249static void ntlm_current_time(BYTE* timestamp, WINPR_ATTR_UNUSED
size_t size)
253 WINPR_ASSERT(timestamp);
254 WINPR_ASSERT(size >=
sizeof(ft));
256 GetSystemTimeAsFileTime(&ft);
257 CopyMemory(timestamp, &(ft),
sizeof(ft));
268 WINPR_ASSERT(context);
270 if (memcmp(context->ChallengeTimestamp, NTLM_NULL_BUFFER, 8) != 0)
271 CopyMemory(context->Timestamp, context->ChallengeTimestamp, 8);
273 ntlm_current_time(context->Timestamp,
sizeof(context->Timestamp));
276static BOOL ntlm_fetch_ntlm_v2_hash(
NTLM_CONTEXT* context, BYTE* hash)
279 WINPR_SAM_ENTRY* entry =
nullptr;
281 WINPR_ASSERT(context);
285 WINPR_SAM* sam = SamOpen(context->SamFile, TRUE);
290 if ((credentials->identity.Flags & SEC_WINNT_AUTH_IDENTITY_UNICODE) != 0)
292 entry = SamLookupUserW(sam, (LPWSTR)credentials->identity.User,
293 credentials->identity.UserLength *
sizeof(WCHAR),
294 (LPWSTR)credentials->identity.Domain,
295 credentials->identity.DomainLength *
sizeof(WCHAR));
299 entry = SamLookupUserW(sam, (LPWSTR)credentials->identity.User,
300 credentials->identity.UserLength *
sizeof(WCHAR),
nullptr, 0);
303 else if ((credentials->identity.Flags & SEC_WINNT_AUTH_IDENTITY_ANSI) != 0)
305 entry = SamLookupUserA(
306 sam, (
char*)credentials->identity.User, credentials->identity.UserLength *
sizeof(CHAR),
307 (
char*)credentials->identity.Domain, credentials->identity.DomainLength *
sizeof(CHAR));
311 entry = SamLookupUserA(sam, (
char*)credentials->identity.User,
312 credentials->identity.UserLength *
sizeof(CHAR),
nullptr, 0);
321#ifdef WITH_DEBUG_NTLM
322 WLog_VRB(TAG,
"NTLM Hash:");
323 winpr_HexDump(TAG, WLOG_DEBUG, entry->NtHash, 16);
325 rc = NTOWFv2FromHashW(entry->NtHash, (LPWSTR)credentials->identity.User,
326 credentials->identity.UserLength *
sizeof(WCHAR),
327 (LPWSTR)credentials->identity.Domain,
328 credentials->identity.DomainLength *
sizeof(WCHAR), hash);
331 SamFreeEntry(sam, entry);
334 WLog_ERR(TAG,
"Error: Could not find user in SAM database");
339static int hexchar2nibble(WCHAR wc)
341#if defined(__BIG_ENDIAN__)
348 const BYTE b = cnv.b[0];
373 return wc - L
'a' + 10;
380 return wc - L
'A' + 10;
385static int ntlm_convert_password_hash(
NTLM_CONTEXT* context, BYTE* hash,
size_t hashlen)
387 const size_t required_len = 2ull * hashlen;
389 WINPR_ASSERT(context);
393 const ULONG PasswordHashLength = credentials->identity.PasswordLength;
395 if (PasswordHashLength != required_len)
398 "PasswordHash has invalid length %" PRIu32
" must be exactly %" PRIuz
" bytes",
399 PasswordHashLength, required_len);
403 const WCHAR* PasswordHash = credentials->identity.Password;
404 for (
size_t x = 0; x < hashlen; x++)
406 const int hi = hexchar2nibble(PasswordHash[2 * x]);
409 WLog_ERR(TAG,
"PasswordHash has an invalid value at position %" PRIuz, 2 * x);
412 const int lo = hexchar2nibble(PasswordHash[2 * x + 1]);
415 WLog_ERR(TAG,
"PasswordHash has an invalid value at position %" PRIuz, 2 * x + 1);
418 const BYTE val = (BYTE)((hi << 4) | lo);
425static BOOL ntlm_compute_ntlm_v2_hash(
NTLM_CONTEXT* context, BYTE* hash)
427 WINPR_ASSERT(context);
431#ifdef WITH_DEBUG_NTLM
435 WLog_VRB(TAG,
"Password (length = %" PRIu32
")", credentials->identity.PasswordLength * 2);
436 winpr_HexDump(TAG, WLOG_TRACE, (BYTE*)credentials->identity.Password,
437 credentials->identity.PasswordLength * 2);
438 WLog_VRB(TAG,
"Username (length = %" PRIu32
")", credentials->identity.UserLength * 2);
439 winpr_HexDump(TAG, WLOG_TRACE, (BYTE*)credentials->identity.User,
440 credentials->identity.UserLength * 2);
441 WLog_VRB(TAG,
"Domain (length = %" PRIu32
")", credentials->identity.DomainLength * 2);
442 winpr_HexDump(TAG, WLOG_TRACE, (BYTE*)credentials->identity.Domain,
443 credentials->identity.DomainLength * 2);
446 WLog_VRB(TAG,
"Strange, NTLM_CONTEXT is missing valid credentials...");
448 WLog_VRB(TAG,
"Workstation (length = %" PRIu16
")", context->Workstation.Length);
449 winpr_HexDump(TAG, WLOG_TRACE, (BYTE*)context->Workstation.Buffer, context->Workstation.Length);
450 WLog_VRB(TAG,
"NTOWFv2, NTLMv2 Hash");
451 winpr_HexDump(TAG, WLOG_TRACE, context->NtlmV2Hash, WINPR_MD5_DIGEST_LENGTH);
454 if (memcmp(context->NtlmV2Hash, NTLM_NULL_BUFFER, 16) != 0)
459 else if (memcmp(context->NtlmHash, NTLM_NULL_BUFFER, 16) != 0)
461 if ((credentials->identity.Flags & SEC_WINNT_AUTH_IDENTITY_UNICODE) != 0)
463 return NTOWFv2FromHashW(context->NtlmHash, (LPWSTR)credentials->identity.User,
464 credentials->identity.UserLength * 2,
465 (LPWSTR)credentials->identity.Domain,
466 credentials->identity.DomainLength * 2, hash);
468 else if ((credentials->identity.Flags & SEC_WINNT_AUTH_IDENTITY_ANSI) != 0)
470 return NTOWFv2FromHashA(context->NtlmHash, (
char*)credentials->identity.User,
471 credentials->identity.UserLength,
472 (
char*)credentials->identity.Domain,
473 credentials->identity.DomainLength, hash);
478 else if (credentials->identity.Flags & SEC_WINPR_AUTH_IDENTITY_PASSWORD_HASH)
481 if (ntlm_convert_password_hash(context, context->NtlmHash,
sizeof(context->NtlmHash)) < 0)
484 return NTOWFv2FromHashW(context->NtlmHash, (LPWSTR)credentials->identity.User,
485 credentials->identity.UserLength * 2,
486 (LPWSTR)credentials->identity.Domain,
487 credentials->identity.DomainLength * 2, hash);
489 else if (credentials->identity.Password)
492 (LPWSTR)credentials->identity.Password, credentials->identity.PasswordLength * 2,
493 (LPWSTR)credentials->identity.User, credentials->identity.UserLength * 2,
494 (LPWSTR)credentials->identity.Domain, credentials->identity.DomainLength * 2, hash);
496 else if (context->HashCallback)
498 SecBuffer proofValue = WINPR_C_ARRAY_INIT;
501 if (ntlm_computeProofValue(context, &proofValue) != SEC_E_OK)
504 if (ntlm_computeMicValue(context, &micValue) != SEC_E_OK)
506 sspi_SecBufferFree(&proofValue);
510 const SECURITY_STATUS ret = context->HashCallback(
511 context->HashCallbackArg, &credentials->identity, &proofValue,
512 context->EncryptedRandomSessionKey, context->AUTHENTICATE_MESSAGE.MessageIntegrityCheck,
514 sspi_SecBufferFree(&proofValue);
515 sspi_SecBufferFree(&micValue);
516 return ret == SEC_E_OK;
518 else if (context->UseSamFileDatabase)
520 return ntlm_fetch_ntlm_v2_hash(context, hash);
526SECURITY_STATUS ntlm_compute_lm_v2_response(
NTLM_CONTEXT* context)
528 BYTE* response =
nullptr;
529 BYTE value[WINPR_MD5_DIGEST_LENGTH] = WINPR_C_ARRAY_INIT;
531 WINPR_ASSERT(context);
533 if (context->LmCompatibilityLevel < 2)
535 if (!sspi_SecBufferAlloc(&context->LmChallengeResponse, 24))
536 return SEC_E_INSUFFICIENT_MEMORY;
538 ZeroMemory(context->LmChallengeResponse.pvBuffer, 24);
544 if (!ntlm_compute_ntlm_v2_hash(context, context->NtlmV2Hash))
545 return SEC_E_NO_CREDENTIALS;
548 CopyMemory(value, context->ServerChallenge, 8);
549 CopyMemory(&value[8], context->ClientChallenge, 8);
551 if (!sspi_SecBufferAlloc(&context->LmChallengeResponse, 24))
552 return SEC_E_INSUFFICIENT_MEMORY;
554 response = (BYTE*)context->LmChallengeResponse.pvBuffer;
556 if (!winpr_HMAC(WINPR_MD_MD5, (
void*)context->NtlmV2Hash, WINPR_MD5_DIGEST_LENGTH, (BYTE*)value,
557 WINPR_MD5_DIGEST_LENGTH, response, WINPR_MD5_DIGEST_LENGTH))
558 return SEC_E_ALGORITHM_MISMATCH;
562 CopyMemory(&response[16], context->ClientChallenge, 8);
576SECURITY_STATUS ntlm_compute_ntlm_v2_response(
NTLM_CONTEXT* context)
578 SecBuffer ntlm_v2_temp = WINPR_C_ARRAY_INIT;
579 SecBuffer ntlm_v2_temp_chal = WINPR_C_ARRAY_INIT;
581 WINPR_ASSERT(context);
583 PSecBuffer TargetInfo = &context->ChallengeTargetInfo;
584 SECURITY_STATUS ret = SEC_E_INSUFFICIENT_MEMORY;
586 if (!sspi_SecBufferAlloc(&ntlm_v2_temp, TargetInfo->cbBuffer + 28))
589 ZeroMemory(ntlm_v2_temp.pvBuffer, ntlm_v2_temp.cbBuffer);
591 BYTE* blob = (BYTE*)ntlm_v2_temp.pvBuffer;
594 ret = SEC_E_NO_CREDENTIALS;
595 if (!ntlm_compute_ntlm_v2_hash(context, (BYTE*)context->NtlmV2Hash))
603 CopyMemory(&blob[8], context->Timestamp, 8);
604 CopyMemory(&blob[16], context->ClientChallenge, 8);
606 CopyMemory(&blob[28], TargetInfo->pvBuffer, TargetInfo->cbBuffer);
607#ifdef WITH_DEBUG_NTLM
608 WLog_VRB(TAG,
"NTLMv2 Response Temp Blob");
609 winpr_HexDump(TAG, WLOG_TRACE, ntlm_v2_temp.pvBuffer, ntlm_v2_temp.cbBuffer);
613 ret = SEC_E_INSUFFICIENT_MEMORY;
614 if (!sspi_SecBufferAlloc(&ntlm_v2_temp_chal, ntlm_v2_temp.cbBuffer + 8))
618 BYTE* blob = (BYTE*)ntlm_v2_temp_chal.pvBuffer;
619 CopyMemory(blob, context->ServerChallenge, 8);
620 CopyMemory(&blob[8], ntlm_v2_temp.pvBuffer, ntlm_v2_temp.cbBuffer);
621 if (!winpr_HMAC(WINPR_MD_MD5, (BYTE*)context->NtlmV2Hash, WINPR_MD5_DIGEST_LENGTH,
622 (BYTE*)ntlm_v2_temp_chal.pvBuffer, ntlm_v2_temp_chal.cbBuffer,
623 context->NtProofString, WINPR_MD5_DIGEST_LENGTH))
629 if (!sspi_SecBufferAlloc(&context->NtChallengeResponse, ntlm_v2_temp.cbBuffer + 16))
633 BYTE* blob = (BYTE*)context->NtChallengeResponse.pvBuffer;
634 CopyMemory(blob, context->NtProofString, WINPR_MD5_DIGEST_LENGTH);
635 CopyMemory(&blob[16], ntlm_v2_temp.pvBuffer, ntlm_v2_temp.cbBuffer);
638 if (!winpr_HMAC(WINPR_MD_MD5, (BYTE*)context->NtlmV2Hash, WINPR_MD5_DIGEST_LENGTH,
639 context->NtProofString, WINPR_MD5_DIGEST_LENGTH, context->SessionBaseKey,
640 WINPR_MD5_DIGEST_LENGTH))
644 sspi_SecBufferFree(&ntlm_v2_temp);
645 sspi_SecBufferFree(&ntlm_v2_temp_chal);
657BOOL ntlm_rc4k(BYTE* key,
size_t length, BYTE* plaintext, BYTE* ciphertext)
659 WINPR_RC4_CTX* rc4 = winpr_RC4_New(key, 16);
664 const BOOL rc = winpr_RC4_Update(rc4, length, plaintext, ciphertext);
674BOOL ntlm_generate_client_challenge(
NTLM_CONTEXT* context)
676 WINPR_ASSERT(context);
679 if (memcmp(context->ClientChallenge, NTLM_NULL_BUFFER,
sizeof(context->ClientChallenge)) != 0)
682 return winpr_RAND(context->ClientChallenge,
sizeof(context->ClientChallenge)) >= 0;
690BOOL ntlm_generate_server_challenge(
NTLM_CONTEXT* context)
692 WINPR_ASSERT(context);
694 if (memcmp(context->ServerChallenge, NTLM_NULL_BUFFER,
sizeof(context->ServerChallenge)) != 0)
697 return winpr_RAND(context->ServerChallenge,
sizeof(context->ServerChallenge)) >= 0;
705BOOL ntlm_generate_key_exchange_key(
NTLM_CONTEXT* context)
707 WINPR_ASSERT(context);
708 WINPR_ASSERT(
sizeof(context->KeyExchangeKey) ==
sizeof(context->SessionBaseKey));
711 CopyMemory(context->KeyExchangeKey, context->SessionBaseKey,
sizeof(context->KeyExchangeKey));
720BOOL ntlm_generate_random_session_key(
NTLM_CONTEXT* context)
722 WINPR_ASSERT(context);
723 return winpr_RAND(context->RandomSessionKey,
sizeof(context->RandomSessionKey)) >= 0;
731BOOL ntlm_generate_exported_session_key(
NTLM_CONTEXT* context)
733 WINPR_ASSERT(context);
734 WINPR_ASSERT(
sizeof(context->ExportedSessionKey) >=
sizeof(context->RandomSessionKey));
736 CopyMemory(context->ExportedSessionKey, context->RandomSessionKey,
737 sizeof(context->ExportedSessionKey));
746BOOL ntlm_encrypt_random_session_key(
NTLM_CONTEXT* context)
750 WINPR_ASSERT(context);
751 return ntlm_rc4k(context->KeyExchangeKey, 16, context->RandomSessionKey,
752 context->EncryptedRandomSessionKey);
760BOOL ntlm_decrypt_random_session_key(
NTLM_CONTEXT* context)
762 WINPR_ASSERT(context);
772 if (context->NegotiateKeyExchange)
774 WINPR_ASSERT(
sizeof(context->EncryptedRandomSessionKey) ==
775 sizeof(context->RandomSessionKey));
776 return ntlm_rc4k(context->KeyExchangeKey,
sizeof(context->EncryptedRandomSessionKey),
777 context->EncryptedRandomSessionKey, context->RandomSessionKey);
781 WINPR_ASSERT(
sizeof(context->RandomSessionKey) ==
sizeof(context->KeyExchangeKey));
782 CopyMemory(context->RandomSessionKey, context->KeyExchangeKey,
783 sizeof(context->RandomSessionKey));
798static BOOL ntlm_generate_signing_key(BYTE* exported_session_key,
const SecBuffer* sign_magic,
803 WINPR_ASSERT(exported_session_key);
804 WINPR_ASSERT(sign_magic);
805 WINPR_ASSERT(signing_key);
807 const size_t length = WINPR_MD5_DIGEST_LENGTH + sign_magic->cbBuffer;
808 BYTE* value = (BYTE*)malloc(length);
814 CopyMemory(value, exported_session_key, WINPR_MD5_DIGEST_LENGTH);
815 CopyMemory(&value[WINPR_MD5_DIGEST_LENGTH], sign_magic->pvBuffer, sign_magic->cbBuffer);
817 rc = winpr_Digest(WINPR_MD_MD5, value, length, signing_key, WINPR_MD5_DIGEST_LENGTH);
831BOOL ntlm_generate_client_signing_key(
NTLM_CONTEXT* context)
833 const SecBuffer signMagic = {
sizeof(NTLM_CLIENT_SIGN_MAGIC), 0, NTLM_CLIENT_SIGN_MAGIC };
835 WINPR_ASSERT(context);
836 return ntlm_generate_signing_key(context->ExportedSessionKey, &signMagic,
837 context->ClientSigningKey);
847BOOL ntlm_generate_server_signing_key(
NTLM_CONTEXT* context)
849 const SecBuffer signMagic = {
sizeof(NTLM_SERVER_SIGN_MAGIC), 0, NTLM_SERVER_SIGN_MAGIC };
851 WINPR_ASSERT(context);
852 return ntlm_generate_signing_key(context->ExportedSessionKey, &signMagic,
853 context->ServerSigningKey);
863BOOL ntlm_generate_client_sealing_key(
NTLM_CONTEXT* context)
865 const SecBuffer sealMagic = {
sizeof(NTLM_CLIENT_SEAL_MAGIC), 0, NTLM_CLIENT_SEAL_MAGIC };
867 WINPR_ASSERT(context);
868 return ntlm_generate_signing_key(context->ExportedSessionKey, &sealMagic,
869 context->ClientSealingKey);
879BOOL ntlm_generate_server_sealing_key(
NTLM_CONTEXT* context)
881 const SecBuffer sealMagic = {
sizeof(NTLM_SERVER_SEAL_MAGIC), 0, NTLM_SERVER_SEAL_MAGIC };
883 WINPR_ASSERT(context);
884 return ntlm_generate_signing_key(context->ExportedSessionKey, &sealMagic,
885 context->ServerSealingKey);
895 WINPR_ASSERT(context);
898 context->SendSigningKey = context->ServerSigningKey;
899 context->RecvSigningKey = context->ClientSigningKey;
900 context->SendSealingKey = context->ClientSealingKey;
901 context->RecvSealingKey = context->ServerSealingKey;
902 context->SendRc4Seal =
903 winpr_RC4_New(context->ServerSealingKey,
sizeof(context->ServerSealingKey));
904 context->RecvRc4Seal =
905 winpr_RC4_New(context->ClientSealingKey,
sizeof(context->ClientSealingKey));
909 context->SendSigningKey = context->ClientSigningKey;
910 context->RecvSigningKey = context->ServerSigningKey;
911 context->SendSealingKey = context->ServerSealingKey;
912 context->RecvSealingKey = context->ClientSealingKey;
913 context->SendRc4Seal =
914 winpr_RC4_New(context->ClientSealingKey,
sizeof(context->ClientSealingKey));
915 context->RecvRc4Seal =
916 winpr_RC4_New(context->ServerSealingKey,
sizeof(context->ServerSealingKey));
918 if (!context->SendRc4Seal)
920 WLog_ERR(TAG,
"Failed to allocate context->SendRc4Seal");
923 if (!context->RecvRc4Seal)
925 WLog_ERR(TAG,
"Failed to allocate context->RecvRc4Seal");
931BOOL ntlm_compute_message_integrity_check(
NTLM_CONTEXT* context, BYTE* mic, UINT32 size)
938 WINPR_HMAC_CTX* hmac = winpr_HMAC_New();
940 WINPR_ASSERT(context);
942 WINPR_ASSERT(size >= WINPR_MD5_DIGEST_LENGTH);
944 memset(mic, 0, size);
948 if (!winpr_HMAC_Init(hmac, WINPR_MD_MD5, context->ExportedSessionKey, WINPR_MD5_DIGEST_LENGTH))
951 if (!winpr_HMAC_Update(hmac, (BYTE*)context->NegotiateMessage.pvBuffer,
952 context->NegotiateMessage.cbBuffer))
954 if (!winpr_HMAC_Update(hmac, (BYTE*)context->ChallengeMessage.pvBuffer,
955 context->ChallengeMessage.cbBuffer))
958 if (context->MessageIntegrityCheckOffset > 0)
960 const BYTE* auth = (BYTE*)context->AuthenticateMessage.pvBuffer;
961 const BYTE data[WINPR_MD5_DIGEST_LENGTH] = WINPR_C_ARRAY_INIT;
962 const size_t rest = context->MessageIntegrityCheckOffset +
sizeof(data);
964 if (rest > context->AuthenticateMessage.cbBuffer)
966 if (!winpr_HMAC_Update(hmac, &auth[0], context->MessageIntegrityCheckOffset))
968 if (!winpr_HMAC_Update(hmac, data,
sizeof(data)))
970 if (!winpr_HMAC_Update(hmac, &auth[rest], context->AuthenticateMessage.cbBuffer - rest))
975 if (!winpr_HMAC_Update(hmac, (BYTE*)context->AuthenticateMessage.pvBuffer,
976 context->AuthenticateMessage.cbBuffer))
979 rc = winpr_HMAC_Final(hmac, mic, WINPR_MD5_DIGEST_LENGTH);
982 winpr_HMAC_Free(hmac);