void ntlm_compute_message_integrity_check(NTLM_CONTEXT* context, BYTE* mic, UINT32 size) { /* * Compute the HMAC-MD5 hash of ConcatenationOf(NEGOTIATE_MESSAGE, * CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE) using the ExportedSessionKey */ WINPR_HMAC_CTX* hmac = winpr_HMAC_New(); assert(size >= WINPR_MD5_DIGEST_LENGTH); if (!hmac) return; if (winpr_HMAC_Init(hmac, WINPR_MD_MD5, context->ExportedSessionKey, WINPR_MD5_DIGEST_LENGTH)) { winpr_HMAC_Update(hmac, (BYTE*) context->NegotiateMessage.pvBuffer, context->NegotiateMessage.cbBuffer); winpr_HMAC_Update(hmac, (BYTE*) context->ChallengeMessage.pvBuffer, context->ChallengeMessage.cbBuffer); winpr_HMAC_Update(hmac, (BYTE*) context->AuthenticateMessage.pvBuffer, context->AuthenticateMessage.cbBuffer); winpr_HMAC_Final(hmac, mic, WINPR_MD5_DIGEST_LENGTH); } winpr_HMAC_Free(hmac); }
BOOL winpr_HMAC(WINPR_MD_TYPE md, const BYTE* key, size_t keylen, const BYTE* input, size_t ilen, BYTE* output, size_t olen) { BOOL result = FALSE; WINPR_HMAC_CTX *ctx = winpr_HMAC_New(); if (!ctx) return FALSE; if (!winpr_HMAC_Init(ctx, md, key, keylen)) goto out; if (!winpr_HMAC_Update(ctx, input, ilen)) goto out; if (!winpr_HMAC_Final(ctx, output, olen)) goto out; result = TRUE; out: winpr_HMAC_Free(ctx); return result; }
SECURITY_STATUS SEC_ENTRY ntlm_EncryptMessage(PCtxtHandle phContext, ULONG fQOP, PSecBufferDesc pMessage, ULONG MessageSeqNo) { int index; int length; void* data; UINT32 SeqNo; UINT32 value; BYTE digest[WINPR_MD5_DIGEST_LENGTH]; BYTE checksum[8]; BYTE* signature; ULONG version = 1; WINPR_HMAC_CTX* hmac; NTLM_CONTEXT* context; PSecBuffer data_buffer = NULL; PSecBuffer signature_buffer = NULL; SeqNo = MessageSeqNo; context = (NTLM_CONTEXT*) sspi_SecureHandleGetLowerPointer(phContext); for (index = 0; index < (int) pMessage->cBuffers; index++) { if (pMessage->pBuffers[index].BufferType == SECBUFFER_DATA) data_buffer = &pMessage->pBuffers[index]; else if (pMessage->pBuffers[index].BufferType == SECBUFFER_TOKEN) signature_buffer = &pMessage->pBuffers[index]; } if (!data_buffer) return SEC_E_INVALID_TOKEN; if (!signature_buffer) return SEC_E_INVALID_TOKEN; /* Copy original data buffer */ length = data_buffer->cbBuffer; data = malloc(length); if (!data) return SEC_E_INSUFFICIENT_MEMORY; CopyMemory(data, data_buffer->pvBuffer, length); /* Compute the HMAC-MD5 hash of ConcatenationOf(seq_num,data) using the client signing key */ hmac = winpr_HMAC_New(); if (hmac && winpr_HMAC_Init(hmac, WINPR_MD_MD5, context->SendSigningKey, WINPR_MD5_DIGEST_LENGTH)) { Data_Write_UINT32(&value, SeqNo); winpr_HMAC_Update(hmac, (void*) &value, 4); winpr_HMAC_Update(hmac, (void*) data, length); winpr_HMAC_Final(hmac, digest, WINPR_MD5_DIGEST_LENGTH); winpr_HMAC_Free(hmac); } else { winpr_HMAC_Free(hmac); free(data); return SEC_E_INSUFFICIENT_MEMORY; } /* Encrypt message using with RC4, result overwrites original buffer */ if (context->confidentiality) winpr_RC4_Update(context->SendRc4Seal, length, (BYTE*) data, (BYTE*) data_buffer->pvBuffer); else CopyMemory(data_buffer->pvBuffer, data, length); #ifdef WITH_DEBUG_NTLM WLog_DBG(TAG, "Data Buffer (length = %d)", length); winpr_HexDump(TAG, WLOG_DEBUG, data, length); WLog_DBG(TAG, "Encrypted Data Buffer (length = %"PRIu32")", data_buffer->cbBuffer); winpr_HexDump(TAG, WLOG_DEBUG, data_buffer->pvBuffer, data_buffer->cbBuffer); #endif free(data); /* RC4-encrypt first 8 bytes of digest */ winpr_RC4_Update(context->SendRc4Seal, 8, digest, checksum); signature = (BYTE*) signature_buffer->pvBuffer; /* Concatenate version, ciphertext and sequence number to build signature */ Data_Write_UINT32(signature, version); CopyMemory(&signature[4], (void*) checksum, 8); Data_Write_UINT32(&signature[12], SeqNo); context->SendSeqNum++; #ifdef WITH_DEBUG_NTLM WLog_DBG(TAG, "Signature (length = %"PRIu32")", signature_buffer->cbBuffer); winpr_HexDump(TAG, WLOG_DEBUG, signature_buffer->pvBuffer, signature_buffer->cbBuffer); #endif return SEC_E_OK; }