NTLM / NTLMv2
Server / Proxy
challenge / response
solution

      czech version / česká verze

16.2.2003 NTLMv2 library was released
     You can download test application HERE (click).
     This library supports NTLMv1 and NTLMv2 challenge/response scheme.
     For detailed NTLM and library using description see NTLMv1 library (low pressure).
     Library is compiled as dynamic library (ntlmv2.dll) for loading
     from any other application then VC++ (Delphi, VisualBasic, Oracle etc.)
     or as static library (ntlmv2lib.lib) for direct link to your Visual Studio C++ project.
     Contact geniuz@geniuz.cz
     Follows NTLMv2 library header with easy use instructions:

// Structures
struct _auth_ctxt_struct
{
      BOOL success;
      BYTE context[0x40];
};

typedef enum {
      NAM_AUTO = 0,
      NAM_NTLMv1 = 0x40000,
      NAM_NTLMv2 = 0x80000
} NTLM_AUTH_METHOD;

// Functions description:
// - allocate "ntlm_out" variable as 2000 characters length buffer
// char ntlm_out[2000];
// - allocate _auth_ctxt as _auth_ctxt_struct structure
// _auth_ctxt_struct _auth_ctxt
// - call NTLMv2ClientStep1 function before sending request to proxy or server
// - if you need suppress NTLMv2 and you want use NTLMv1 solution use NAM_NTLMv1 constant as last input parameter

void _stdcall NTLMv2ClientStep1(
      _auth_ctxt_struct* _auth_ctxt, //in
      const char* user, //in
      const char* domain, //in
      const char* password, //in
      char* ntlm_out, //out (2000 bytes)
      NTLM_AUTH_METHOD ntlm_auth_mehotd = NAM_AUTO
);

// check _auth_ctxt.success BOOL value for all is o.k.

// if you connect over proxy:
// - add "Proxy-Authorization: NTLM %ntlm_out%\r\n" to header
// - add "Proxy-Connection: Keep-Alive\r\n" to header
// else
// if you connect directly to server
// - add "Authorization: NTLM %ntlm_out%\r\n" to header
// - add "Connection: Keep-Alive\r\n" to header
// end if

// - send request to proxy or server and receive data from proxy or server
// if you connect over proxy:
// - get "ntlm_in" variable as "Proxy-Authenticate: NTLM %ntlm_in%"\r\n" from returned header
// else
// if you connect directly to server
// - get "ntlm_in" variable as "WWW-Authenticate: NTLM %ntlm_in%"\r\n" from returned header
// end if

// - call NTLMv2ClientStep2 function with obtained Authenticate value as ntlm_in

void _stdcall NTLMv2ClientStep2(
      _auth_ctxt_struct* _auth_ctxt, //in
      const char* ntlm_in, //in
      char* ntlm_out //out (2000 bytes)
);

// check _auth_ctxt.success BOOL value for all is o.k.

// - add "Host: %url%\r\n" to header
// if you connect over proxy:
// - add "Proxy-Authorization: NTLM %ntlm_out%\r\n" to header
// - add "Proxy-Connection: Keep-Alive\r\n" to header
// else
// if you connect directly to server
// - add "Authorization: NTLM %ntlm_out%\r\n" to header
// - add "Connection: Keep-Alive\r\n" to header
// end if
// - send request to server/proxy and receive data from server/proxy


// - call NTLMv2Destroy if you are leaving your application

BOOL _stdcall NTLMv2Destroy();

//future functions support, you can build server side NTLM application with this
//void _stdcall NTLMv2ServerStep1
//void _stdcall NTLMv2ServerStep2





12.1.2002 NTLM library was released

      As far as you are using a connection based on socket (in MFC CSocket a CAsyncSocket class) in your applications and as far as the Microsoft Proxy Server stands in your application with the turned on Windows NT Challenge/Response authentication, your application will probably not be able to be authorize because NTLM authorization is not documented.

      In this situation you can use the library ntlm.dll, which provides the above mentioned service. The library exports two functions:

      int AuthOne( char* domain, char* host, char* reply );
      int AuthTwo( const char* authcode, char* domain, char* host, char* user, char* passwd, char* reply );


      The authorization is divided into two steps. Lets give an example. Imagine you would like to download the content of the internet address http://www.geniuz.cz. In the first step you call the function AuthOne with the parameter of domain, where you have the account, for instance "GENIUZDOMAIN" and with the parameter of guest where you want to get, so "www.geniuz.cz". In reply the NTLM code returns which we put as a headline of requirement: Proxy-Authorization: NTLM reply. The whole headline will look as follows:

      GET http://www.geniuz.cz:80/ HTTP/1.0
      Accept: * / *
      Host: www.geniuz.cz:80
      Proxy-Connection: keep-alive
      Proxy-Authorization: NTLM TlRMTVNTUAABAAAAB7IAAAsACwAtAAAA...
      ______
empty line


The returning headline looks like this:

      Proxy-Authenticate: NTLM TlRMTVNTUAACAAAAFAAUADAAAAA...


      The returned NTLM authentification code is called authcode. In this case we call the second exported function AuthTwo with parameter authcode (for example-"TlRMTVNTUAACAAAAFAAUADAAAAA..."), domain "GENIUZDOMAIN", guest in our case www.geniuz.cz, user e.g. "jankral" and password for instance "jan148#ca". In parameter reply function AuthTwo returns the second NTLM code, which we insert in the headline and afterwards the Proxy returns the demanded page.

      The library is compiled for OS Windows 32 with or without usage of MFC. Recompilation for other platform than Windows is possible. Furthermore, it is possible to obtain a source code. Please do not hesitate to e-mail me on my address for more information concerning the order of the library.

Library price is 249 EUR
Source code price is 499 EUR

geniuz@geniuz.cz

      You can download test program here.

      For a better orientation and imagination most of the source code is presented on this case which is using the library ntlm.dll:

     


//*** ntlm.dll export functions
int AuthOne( char* domain, char* host, char* reply );
int AuthTwo( const char* authcode, char* domain, char* host, char* user, char* passwd, char* reply );

#define MAX_BUFFER_LENGTH 64000

//*** desiderative header line getting
CString GetHeaderStr(CString parsedName, CString header, CString parser = "\r\n", CString spacer = ": ")
{
	int index = -1;
	parsedName += spacer;
	int len = parsedName.GetLength();
	int parslen = parser.GetLength();

	do		index = header.Find( parsedName, index + 1 );
	while	(( index > 0 ? header.Mid(index-parslen,parslen) != parser : false ));

	if( index >= 0 )
	{
		index += len;
		int last = header.Find(parser, index);
		if( last < 0 ) return -1;
		return header.Mid(index, last - index );
	}
	else
		return "";
}

//*** basic header mask
char header_mask[] =
		"GET http://%s:%d/ HTTP/1.0\r\n"
		"Accept: * /*\r\n"
		"Host: %s:%d\r\n"
		"Proxy-Connection: keep-alive\r\n"
		"Proxy-Authorization: NTLM %s\r\n"
		"\r\n";

//*** socket data sending and receiving
bool SendAndReceive( CSocket& socket, char* proxy, int port, CString& header, char* buffer )
{
	if( header.GetLength() != socket.Send( header, header.GetLength() ) )
	{
		AfxMessageBox( "Send error" );
		return false;
	}
	if( 0 > socket.Receive( buffer, MAX_BUFFER_LENGTH ) )
	{
		AfxMessageBox( "Receive error" );
		return false;
	}
	return true;
}

//*** NTLM authorization preview
void Ntlm()
{
	CString header;
	//*** fictive authentication data
	char domain[] = "GENIUZDOMAIN";
	char user[] = "jankral";
	char passwd[] = "jan148#ca";
	char host[] = "www.geniuz.cz";
	char hostport = 80;
	char proxy[] = "PROXY";
	char proxyport = 80;
	char buffer[ MAX_BUFFER_LENGTH ] = "\x00";
	char ntlm[256];

	//*** socket creating
	CSocket socket;
	if( !socket.Create() )
	{ AfxMessageBox( "Create error" ); return; }
	if( !socket.Connect( proxy, proxyport ) )
	{ AfxMessageBox( "Connect error" );	return; }

	//*** first ntlm.dll authetication
	AuthOne( domain, host, ntlm );
	//*** header formating
	header.Format( header_mask, host, hostport, host, hostport, ntlm );
	//*** header sending and reply receiving
	if( !SendAndReceive(socket, proxy, proxyport, header, buffer) ) return;

	//*** authentication code getting from returned header
	CString response = GetHeaderStr( "Proxy-Authenticate", buffer );

	//*** second ntlm.dll authetication
	AuthTwo( response.Mid(5), domain, host, user, passwd, ntlm );
	//*** header formating
	header.Format( header_mask, host, hostport, host, hostport, ntlm );
	//*** header sending and reply receiving
	if( !SendAndReceive(socket, proxy, proxyport, header, buffer) ) return;

	socket.Close();

	//*** right page is in buffer
	AfxMessageBox( buffer );
}