SECURITY_STATUS nla_decrypt_public_key_hash(rdpNla* nla)
{
	size_t signature_length;
	WINPR_DIGEST_CTX* sha256 = NULL;
	BYTE serverClientHash[WINPR_SHA256_DIGEST_LENGTH];
	SECURITY_STATUS status = SEC_E_INVALID_TOKEN;

	WINPR_ASSERT(nla);

	const BYTE* hashMagic = nla->server ? ClientServerHashMagic : ServerClientHashMagic;
	const BYTE* decryptedHash;
	const size_t hashSize =
	    nla->server ? sizeof(ClientServerHashMagic) : sizeof(ServerClientHashMagic);
	PSecBuffer pubKeyAuth = &nla->pubKeyAuth;

	signature_length = pubKeyAuth->cbBuffer - WINPR_SHA256_DIGEST_LENGTH;

	if ((pubKeyAuth->cbBuffer < WINPR_SHA256_DIGEST_LENGTH) ||
	    (signature_length > nla->ContextSizes.cbSecurityTrailer))
	{
		WLog_ERR(TAG, "unexpected pubKeyAuth buffer size: %" PRIu32 "", pubKeyAuth->cbBuffer);
		goto fail;
	}

	status = nla_decrypt(nla, pubKeyAuth, signature_length);
	if (status != SEC_E_OK)
		goto fail;

	status = SEC_E_INTERNAL_ERROR;
	decryptedHash = &((const BYTE*)pubKeyAuth->pvBuffer)[signature_length];

	/* generate SHA256 of following data: ServerClientHashMagic, Nonce, SubjectPublicKey */
	if (!(sha256 = winpr_Digest_New()))
		goto fail;

	if (!winpr_Digest_Init(sha256, WINPR_MD_SHA256))
		goto fail;

	/* include trailing \0 from hashMagic */
	if (!winpr_Digest_Update(sha256, hashMagic, hashSize))
		goto fail;

	if (!nla_Digest_Update_From_SecBuffer(sha256, &nla->ClientNonce))
		goto fail;

	/* SubjectPublicKey */
	if (!nla_Digest_Update_From_SecBuffer(sha256, &nla->PublicKey))
		goto fail;

	if (!winpr_Digest_Final(sha256, serverClientHash, sizeof(serverClientHash)))
		goto fail;

	/* verify hash */
	if (memcmp(serverClientHash, decryptedHash, WINPR_SHA256_DIGEST_LENGTH) != 0)
	{
		WLog_ERR(TAG, "Could not verify server's hash");
		status = SEC_E_MESSAGE_ALTERED; /* DO NOT SEND CREDENTIALS! */
		goto fail;
	}

	status = SEC_E_OK;
fail:
	winpr_Digest_Free(sha256);
	return status;
}
SECURITY_STATUS nla_decrypt_public_key_hash(rdpNla* nla)
{
	size_t signature_length;
	WINPR_DIGEST_CTX* sha256 = NULL;
	BYTE serverClientHash[WINPR_SHA256_DIGEST_LENGTH];
	SECURITY_STATUS status = SEC_E_INVALID_TOKEN;

	WINPR_ASSERT(nla);

	const BYTE* hashMagic = nla->server ? ClientServerHashMagic : ServerClientHashMagic;
	const BYTE* decryptedHash;
	const size_t hashSize =
	    nla->server ? sizeof(ClientServerHashMagic) : sizeof(ServerClientHashMagic);
	PSecBuffer pubKeyAuth = &nla->pubKeyAuth;

	signature_length = pubKeyAuth->cbBuffer - WINPR_SHA256_DIGEST_LENGTH;

	if ((pubKeyAuth->cbBuffer < WINPR_SHA256_DIGEST_LENGTH) ||
	    (signature_length > nla->ContextSizes.cbSecurityTrailer))
	{
		WLog_ERR(TAG, "unexpected pubKeyAuth buffer size: %" PRIu32 "", pubKeyAuth->cbBuffer);
		goto fail;
	}

	status = nla_decrypt(nla, pubKeyAuth, signature_length);
	if (status != SEC_E_OK)
		goto fail;

	status = SEC_E_INTERNAL_ERROR;
	decryptedHash = &((const BYTE*)pubKeyAuth->pvBuffer)[signature_length];

	 
	if (!(sha256 = winpr_Digest_New()))
		goto fail;

	if (!winpr_Digest_Init(sha256, WINPR_MD_SHA256))
		goto fail;

	 
	if (!winpr_Digest_Update(sha256, hashMagic, hashSize))
		goto fail;

	if (!nla_Digest_Update_From_SecBuffer(sha256, &nla->ClientNonce))
		goto fail;

	 
	if (!nla_Digest_Update_From_SecBuffer(sha256, &nla->PublicKey))
		goto fail;

	if (!winpr_Digest_Final(sha256, serverClientHash, sizeof(serverClientHash)))
		goto fail;

	 
	if (memcmp(serverClientHash, decryptedHash, WINPR_SHA256_DIGEST_LENGTH) != 0)
	{
		WLog_ERR(TAG, "Could not verify server's hash");
		status = SEC_E_MESSAGE_ALTERED;  
		goto fail;
	}

	status = SEC_E_OK;
fail:
	winpr_Digest_Free(sha256);
	return status;
}