#ifndef _xbNETNTLM_
#define _xbNETNTLM_
/*<<<***************************************************************************
The MIT License (MIT)

Copyright(C) 2013 - 2015 Marc Mirti Mancinelli, Christophe Lardau and Philippe Pamart (xdcube.org)

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
////////////////////////////////////////////////////////////////////////////////
#Title: xbNetNTLM
#Project: xdcBase
////////////////////////////////////////////////////////////////////////////////
#Author: Marc MIRTI MANCINELLI
#History:
<12/02/2014: creation.
12/02/2014: this notice inserted.
***************************************************************************>>>*/

#ifndef _xbEXCEPTION_
#	include "xbException.h"
#endif
//#define _xbnetNTLM_verbose
//#define _xbnetNTLM_desVerbose
//#define _xbnetNTLM_clientAs98
#ifdef _DEBUG
#	define _xbnetNTLM_verbose
#endif
#define _xbnetNTLM2_support

#pragma pack( push )
#pragma pack( 1 )

/**********************************************************************************
*                                                                                * 
* NTLM apis :                                                                    * 
*                                                                                * 
**********************************************************************************/
#define xbnetNTLM_AUTH_NAME "NTLM"

#define xbnetNTLM_NONCE_LEN		8

struct xbEXPORT xbnetNTLM_Nonce
{
	xbnetNTLM_Nonce()
	{
		m_bInit = false;
	}
	char key[xbnetNTLM_NONCE_LEN];
	bool m_bInit;
	void Reset()
	{
		m_bInit = false;
	}
};

struct xbEXPORT xbnetNTLM_sspInfo
{
    int			m_msgType,m_flags;
    xbString	m_user;
    xbString	m_host;
    xbString	m_domain;
    xbString	m_lm;
    xbString	m_nt;
	xbnetNTLM_sspInfo()
	{
		m_msgType = -1;
		m_flags = 0;
	}
	void Reset()
	{
		m_msgType = -1;
		m_flags = 0;
		m_lm.Empty();
		m_nt.Empty();
		m_user.Empty();
	}
	bool IsLoginValid() const
	{
		return m_lm.IsValid() && m_user.IsValid();
	}
	bool IsLoginEmpty() const
	{
		return m_lm.IsEmpty() || m_user.IsEmpty();
	}
	void OwnData()
	{
		m_user.OwnData();
		m_host.OwnData();
		m_domain.OwnData();
		m_lm.OwnData();
		m_nt.OwnData();
	}
};

//NTLM client & server methods
void xbEXPORT xbnetNTLM_makeLMandNThashPW(const xbnetNTLM_Nonce &nonce,const xbString &passw,xbString *lmHash,xbString *ntHash);
#ifdef _xbnetNTLM2_support
void xbEXPORT xbnetNTLM2_makeNThashPW(const xbnetNTLM_Nonce &nonce,const xbString &passw,const xbString &lmResponse,xbString *ntHash);
#endif
void xbEXPORT xbnetNTLM_setupDESkey(const uchar *key_56, xbArray<ulong> &arrkeys);

//NTLM client methods
void xbEXPORT xbnetNTLM_clientNewChallenge(const xbnetNTLM_sspInfo *ntlmssp,xbString *pCh,bool bNtlm2);
void xbEXPORT xbnetNTLM_clientGetChallenge(const xbString &authResponse,xbnetNTLM_sspInfo *ntlmssp,
								xbnetNTLM_Nonce *nonce,bool bNtlm2);
class xbnetNTLM_NonceServer;
void xbEXPORT xbnetNTLM_clientAuthenticate(xbnetNTLM_sspInfo *ntlmssp,const xbString &passw,
								const xbnetNTLM_Nonce &nonce,xbString *pAuth,bool bNtlm2,
								xbnetNTLM_NonceServer *pNonceSrv);

//NTLM server only methods
void xbEXPORT xbnetNTLM_serverNewChallenge(LPCSTR pDom,bool bDomIsHost,xbnetNTLM_sspInfo *ntlmssp,
								const xbnetNTLM_Nonce &nonce,xbString *pCh,bool bNtlm2);
bool xbEXPORT xbnetNTLM_serverAuthenticate(const xbString &authResponse,
								xbnetNTLM_sspInfo *ntlmssp,bool bNewChallengeAllowed,bool bNtlm2);

enum xbnetNTLMret //don't indicate reason to client !! only to use for debug purpose.
{
	xbnetNTLM_ntlm2error = -3, //ntlm2 nt resp error 
	xbnetNTLM_nterror = -2, //nt resp error 
	xbnetNTLM_lmerror = -1, //lm resp error
	xbnetNTLM_error = 0,
	xbnetNTLM_ok = 1, //lm & nt resp ok 
	xbnetNTLM_lmok = 2, //lm resp ok 
	xbnetNTLM_ntok = 3, //lm resp ok 
	xbnetNTLM_ntlm2ok = 4, //ntlm2 nt resp ok
};
xbnetNTLMret xbEXPORT xbnetNTLM_serverCheckLMandNTresponses(const xbnetNTLM_sspInfo &ntlmssp,const xbnetNTLM_Nonce &nonce,
										 const xbString &passw,bool bNtlm2,
										 xbString *pLmCalc = NULL,xbString *pNtCalc = NULL);


class xbEXPORT xbnetNTLM_NonceServer
{
public:
	xbnetNTLM_NonceServer()
	{
		m_bInit = false;
	}
	void NewAuth(xbnetNTLM_Nonce *pNonce);	
	void	init();

	xbSectShare	m_sect;
	bool	m_bInit;
	CLSID	m_guid;
	uint	m_nb;
};

/**********************************************************************************
*                                                                                * 
* NTLM messages :                                                                * 
*                                                                                * 
**********************************************************************************/
////////////////////////////////////////////////////////////////////////////////////
//I - The Negotiate Message /Type = 1
////////////////////////////////////////////////////////////////////////////////////
/* The Negotiate Message /Type = 1
The client initializes the authentication protocol by generating a Negotiate message. 
The structure of the Negotiate message follows. 
	
	  typedef struct _NEGOTIATE_MESSAGE 
	  (
	  UCHAR             Signature[sizeof(NTLMSSP_SIGNATURE)];
	  NTLM_MESSAGE_TYPE MessageType;
	  ULONG             NegotiateFlags;
	  ) NEGOTIATE_MESSAGE, *PNEGOTIATE_MESSAGE;
	  
The Signature is a string that specifies the type of Security Support Provider. 
This string is always ASCII regardless of the string types used in the rest of 
the protocol. For NTLM the value follows. 
		  
			
*/
#define xbnetNTLMSSP_SIGNATURE "NTLMSSP"
/*

The message type specifies what type of message is being sent. Each of the three 
protocol messages has a type defined for it. 
  	  
	#define NtLmNegotiate     1
	#define NtLmChallenge     2
	#define NtLmAuthenticate  3
	#define UnknownMessage    8
		
		  
The Negotiate message uses the Message Type NtLmNegotiate. The NegotiateFlags 
field tells the server which options the client requires. The Negotiate flags are 
as follows. 			  
*/

/* flags */
#define xbnetNTLMSSP_NEGOTIATE_UNICODE			0x00000001	// Text strings are in unicode
#define xbnetNTLMSSP_NEGOTIATE_OEM				0x00000002	// Text strings are in OEM
#define xbnetNTLMSSP_REQUEST_TARGET				0x00000004	// Server return its auth realm
#define xbnetNTLMSSP_NEGOTIATE_SIGN				0x00000010	// Request signature capability  
#define xbnetNTLMSSP_NEGOTIATE_SEAL				0x00000020	// Request confidentiality
#define xbnetNTLMSSP_NEGOTIATE_DATAGRAM_STYLE		0x00000040
#define xbnetNTLMSSP_NEGOTIATE_LM					0x00000080	// Use LM session key for sign/seal
#define xbnetNTLMSSP_NEGOTIATE_NETWARE			0x00000100
#define xbnetNTLMSSP_NEGOTIATE_NTLM				0x00000200	// NTLM authentication
#define xbnetNTLMSSP_OEM_DOMAIN_SUPPLIED			0x00001000	//In ntlm server nego message
#define xbnetNTLMSSP_OEM_HOST_SUPPLIED			0x00002000	//In ntlm server nego message
#define xbnetNTLMSSP_NEGOTIATE_THIS_IS_LOCAL_CALL	0x00004000	// client/server on same machine
#define xbnetNTLMSSP_NEGOTIATE_ALWAYS_SIGN		0x00008000	// Sign for all security levels

/* challenge NTLMSSP_request flags */
#define NTLMSSP_CHALLENGE_TARGET_IS_DOMAIN		0x00010000
#define NTLMSSP_CHALLENGE_TARGET_IS_SERVER		0x00020000
#define NTLMSSP_CHALLENGE_TARGET_IS_SHARE		0x00040000

#define xbnetNTLMSSP_NEGOTIATE_NTLM2				0x00080000

/* these NTLMSSP_are marked as "extra" fields */
#define NTLMSSP_REQUEST_INIT_RESPONSE			0x00100000
#define NTLMSSP_REQUEST_ACCEPT_RESPONSE			0x00200000
#define NTLMSSP_REQUEST_NON_NT_SESSION_KEY		0x00400000

#define xbnetNTLMSSP_NEGOTIATE_TARGET_INFO		0x00800000 //to impl on server side

#define xbnetNTLMSSP_NEGOTIATE_128				0x20000000
#define xbnetNTLMSSP_NEGOTIATE_KEY_EXCH			0x40000000
#define xbnetNTLMSSP_NEGOTIATE_56					0x80000000


#define xbnetNTLMSSP_NEGOTIATE_SERVERBASE			0x00008200

#ifdef _xbnetNTLM2_support
#	define xbnetNTLMSSP_NEGOTIATE2_SERVERBASE		0x00088200
#endif

#define xbnetNTLMSSP_NEGOTIATE_CLIENTBASE			0x00008204
#ifdef _xbnetNTLM2_support
#	define xbnetNTLMSSP_NEGOTIATE2_CLIENTBASE		0x00088204
#endif

#ifdef _xbnetNTLM_clientAs98
#	define xbnetNTLMSSP_NEGOTIATE_CLIENTDFLT		0x00008206
#	define xbnetNTLMSSP_USER_AGENT	"Mozilla/4.0 (compatible; MSIE 5.5; Windows 98)"
#	ifdef _xbnetNTLM2_support
#		error ntlm2 supported only in unicode mode
#	endif
#else
#	define xbnetNTLMSSP_NEGOTIATE_CLIENTDFLT		0x00008207
#	define xbnetNTLMSSP_USER_AGENT	"Mozilla/4.0 (compatible; MSIE 5.5; Windows NT5)"
#	ifdef _xbnetNTLM2_support
#		define xbnetNTLMSSP_NEGOTIATE2_CLIENTDFLT	0x00088205 //Try with 0x20008207 ie5 flags value: 0xa08a8205
#	endif
#endif

#define xbnetNTLMSSP_NEGOTIATE_OK(flg) \
	((flg & xbnetNTLMSSP_NEGOTIATE_NTLM) \
&& ((flg & xbnetNTLMSSP_NEGOTIATE_UNICODE) || (flg & xbnetNTLMSSP_NEGOTIATE_OEM)))
//#define xbnetNTLMSSP_NEGOTIATE_OK2(flg) \
//			(flg & xbnetNTLMSSP_NEGOTIATE_NTLM)
struct xbEXPORT xbnetNTLM_msgNego 
{
	char protocol[8];
	uchar type; /* 1 */
	uchar zero1[3];
	ulong flags;
	
	short dom_len;
	short dom_lenmax;
	long dom_off;
	
	short host_len;
	short host_lenmax;
	long host_off;
	//data ...
};


////////////////////////////////////////////////////////////////////////////////////
//II - The Challenge Message /Type = 2
////////////////////////////////////////////////////////////////////////////////////
/* The Challenge Message /Type = 2

In response to a negotiate message, the server will generate a challenge message. 
The challenge message contains a signature, a message type, the target name, 
a negotiated capability flags word, and a challenge as follows. 
  
	
	  
typedef _CHALLENGE_MESSAGE 
(
	UCHAR             Signature[sizeof(NTLM_SIGNATURE)];
	NTLM_MESSAGE_TYPE MessageType;
	STRING            TargetName;
	ULONG             NegotiateFlags;
	UCHAR             Challenge[MSV1_0_CHALLENGE_LENGTH];
) CHALLENGE_MESSAGE, *PCHALLENGE_MESSAGE;
		
										
The Signature is a string that specifies the type of Security Support Provider. 
This string is always ASCII regardless of the string types used in the rest of 
the protocol. For NTLM the value follows. 



#define NTLMSSP_SIGNATURE "NTLMSSP"


The Challenge message uses the Message Type NtLmChallenge. The TargetName field 
contains the authentication realm of the server if the NTLMSSP_REQUEST_TARGET 
flag is set in the negotiate message. The NegotiateFlags field tells the client
which options the server requires. The Negotiate flags for the server are the same 
as for the client with the addition of the following. 
																										  
														
*/

struct xbEXPORT xbnetNTLM_msgChallenge
{
	char	protocol[8];
	uchar	type; /* 2 */
	uchar	zero1[3];
	
	short	target_len;
	short	target_lenmax;
	long	target_off;
	
	ulong	flags;
	
	uchar	nonce[8];
	uchar	zero[8];
	
	short	info_len;
	short	info_lenmax;
	long	info_off;
};


////////////////////////////////////////////////////////////////////////////////////
//III - The Authenticate Message /Type = 3
////////////////////////////////////////////////////////////////////////////////////
/*
struct xbnetNTLM_msgChallenge
(
	char	protocol[8];
	uchar type;
	uchar target[7];
	ulong msg_len;
	ushort flags;
	uchar zero2[2];

	uchar nonce[8];
	uchar zero3[8];
);
  
After initializing the authentication protocol, the server challenges the client. 
The client in response generates an authenticate message. This message contains a 
signature, a message type, the optional LM challenge response, and the optional 
NT challenge response, the optional domain name, the user name, and the optional 
workstation name as follows. 
			
typedef _AUTHENTICATE_MESSAGE 
(
	UCHAR             Signature[sizeof(NTLM_SIGNATURE)];
	NTLM_MESSAGE_TYPE MessageType;
	SECURITY_BUFFER   LmChallengeResponse;
	SECURITY_BUFFER   NtChallengeResponse;
	SECURITY_BUFFER   DomainName;
	SECURITY_BUFFER   UserName;
	SECURITY_BUFFER   Workstation;
	SECURITY_BUFFER   SessionKey; 
	ULONG             NegotiateFlags;
) AUTHENTICATE_MESSAGE, *PAUTHENTICATE_MESSAGE;
										
										  
The Authenticate message contains a new type SECURITY_BUFFER. This type is defined 
as follows. 
											
typedef struct _SECURITY_BUFFER 
(
	USHORT Length;
	USHORT MaximumLength;
	ULONG  Buffer;
) SECURITY_BUFFER;
												  
													
The length field specifies the length of the data in the Buffer. The MaximumLength 
field specifies the total allocated length of the Buffer. The Buffer field contains 
a byte offset of the data from the beginning of the message. If the Buffer contains 
a NULL string, then the Length, MaximumLength and Buffer fields will all be set to 
zero. If the string is a UNICODE value then the Length and Buffer fields must be a 
multiple of 2. 

The Signature is a string that specifies the type of Security Support Provider. 
This string is always ASCII regardless of the string types used in the rest of 
the protocol. For NTLM the value follows. 


#define NTLMSSP_SIGNATURE "NTLMSSP"
															  
*/

struct xbEXPORT xbnetNTLM_msgAuthenticate 
{
	char protocol[8];
	uchar type; /* 3 */
	uchar zero1[3];
	
	short lm_len;
	short lm_lenmax;
	long lm_off;
	
	short nt_len;
	short nt_lenmax;
	long nt_off;
	
	short dom_len;
	short dom_lenmax;
	long dom_off;
	
	short user_len;
	short user_lenmax;
	long user_off;
	
	short host_len;
	short host_lenmax;
	long host_off;
	
	long zero2;
	long msg_len;
	
	ulong flags;
	//data ...
};

/**********************************************************************************
*                                                                                * 
* Crypto apis :                                                                  * 
*                                                                                * 
**********************************************************************************/
////////////////////////////////////////////////////////////////////////////////////
//DES crypto  
////////////////////////////////////////////////////////////////////////////////////
void xbEXPORT xbnetDES(const xbString &key, const xbString &_message, bool encrypt, LPCSTR iv, xbString *pRet);
void xbEXPORT xbnetDES_createKeys(const xbString &strkey,xbArray<ulong> &arrkeys);
void xbEXPORT xbnetDES(const xbArray<ulong> &arrkeys, const xbString &_message, bool encrypt, LPCSTR iv, xbString *pRet);

////////////////////////////////////////////////////////////////////////////////////
//MD4 crypto
////////////////////////////////////////////////////////////////////////////////////
struct  xbEXPORT xbnetMD4_CTX
{
	ulong state[4];        /* state (ABCD) */
	ulong count[2];        /* number of bits, modulo 2^64 (lsb first) */
	uchar buffer[64];      /* input buffer */
};

void xbEXPORT xbnetMD4_init(xbnetMD4_CTX *ctx);
void xbEXPORT xbnetMD4_update(xbnetMD4_CTX *ctx, const uchar *input, uint inputLen);
void xbEXPORT xbnetMD4_final(xbnetMD4_CTX *ctx, uchar digest[16]);


////////////////////////////////////////////////////////////////////////////////////
//MD5 crypto
////////////////////////////////////////////////////////////////////////////////////
struct xbnetMD5_CTX
{
	ulong state[4];                                   /* state (ABCD) */
	ulong count[2];        /* number of bits, modulo 2^64 (lsb first) */
	unsigned char buffer[64];                         /* input buffer */
};

void xbEXPORT xbnetMD5_init(xbnetMD5_CTX *ctx);
void xbEXPORT xbnetMD5_update(xbnetMD5_CTX *ctx, const uchar *input, uint inputLen);
void xbEXPORT xbnetMD5_final(xbnetMD5_CTX *ctx, uchar digest[16]);

struct xbEXPORT xbnetHmacMD5_CTX
{
	struct xbnetMD5_CTX ctx;
	uchar k_ipad[65];    
	uchar k_opad[65];
	
};
void xbEXPORT xbnetHmacMD5_init(xbnetHmacMD5_CTX *ctx, const uchar*  key, int key_len);
void xbEXPORT xbnetHmacMD5_msinit(xbnetHmacMD5_CTX *ctx,const uchar* key, int key_len);
void xbEXPORT xbnetHmacMD5_update(xbnetHmacMD5_CTX *ctx, const uchar* text, int text_len);
void xbEXPORT xbnetHmacMD5_final(xbnetHmacMD5_CTX *ctx, uchar *digest);
void xbEXPORT xbnetHmacMD5_make(const uchar key[16], uchar* data, int data_len, uchar* digest);

////////////////////////////////////////////////////////////////////////////////////
//SHA-1 crypto
////////////////////////////////////////////////////////////////////////////////////
enum
{
	shaSuccess = 0,
		shaNull,            /* Null pointer parameter */
		shaInputTooLong,    /* input data too long */
		shaStateError       /* called Input after Result */
};

#define xbnetSHA1hashSize 20

/*
*  This structure will hold context information for the SHA-1
*  hashing operation
*/
struct xbEXPORT xbnetSHA1_CTX
{
	ulong			Intermediate_Hash[xbnetSHA1hashSize/4]; /* Message Digest  */
	
	ulong			Length_Low;            /* Message length in bits      */
	ulong			Length_High;           /* Message length in bits      */
	
	/* Index into message block array   */
	int				Message_Block_Index;
	uchar			Message_Block[64];      /* 512-bit message blocks      */
	
	int Computed;               /* Is the digest computed?         */
	int Corrupted;             /* Is the message digest corrupted? */
};

/*
*  Function Prototypes
*/

int xbEXPORT xbnetSHA1_init(  xbnetSHA1_CTX *);
int xbEXPORT xbnetSHA1_update(  xbnetSHA1_CTX *,
				   const uchar *,
				   unsigned int);
int xbEXPORT xbnetSHA1_final( xbnetSHA1_CTX *,
				  uchar Message_Digest[xbnetSHA1hashSize]);



#pragma pack( pop )
#endif
