#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iconv.h>
#include <errno.h>
#include <openssl/md4.h>
#include <openssl/hmac.h>
int toUCS2LE( const char *src, size_t srclen, char *dst, size_t dstlen )
{
const char *p = (char *)src ;
char *q = (char *)dst ;
iconv_t ctx = iconv_open( "UCS-2LE", "ASCII" );
int len = iconv( ctx, &p, &srclen, &q, &dstlen );
iconv_close( ctx );
return len;
}
int makeNTLMv2Resnpose( const char *user,
const char *pass,
const char *challange,
int challangelen,
const char *blob,
int bloblen,
const char *domain,
char *response )
{
int i;
int userlen = strlen( user );
int domainlen = strlen( domain );
int passlen = strlen( pass );
char uni_pass[ passlen *2 + 1 ];
char md4digest[ 16 ] ;
char user_domain[ userlen + domainlen ];
char uni_user_domain[ sizeof( user_domain ) *2 ];
char ntlmv2hash[ 16 ] ;
int hashlen = sizeof( ntlmv2hash );
char challange_blob[ challangelen + bloblen ];
char respdigest[ 16 ] ;
int resplen = sizeof( respdigest );
toUCS2LE( pass, passlen, uni_pass, sizeof( uni_pass ) );
MD4( (unsigned char *)uni_pass, passlen*2, (unsigned char *)&md4digest );
//printhex( md4digest, sizeof( md4digest ) );
for( i = 0 ; i < userlen ; i++ )
user_domain[ i ] = toupper( user[i] );
for( i = 0 ; i < domainlen ; i++ )
user_domain[ i+userlen ] = toupper( domain[i] );
user_domain[ userlen+domainlen ] = '\0';
toUCS2LE( user_domain, userlen+domainlen, uni_user_domain, sizeof( uni_user_domain ) );
//printhex( uni_user_domain, sizeof( uni_user_domain ) );
HMAC( EVP_md5(),
(unsigned char *)md4digest, sizeof( md4digest ),
(unsigned char *)uni_user_domain, sizeof( uni_user_domain ),
(unsigned char *)ntlmv2hash, (unsigned int*) &hashlen );
//printhex( ntlmv2hash, sizeof( ntlmv2hash ) );
memcpy( challange_blob, challange, challangelen );
memcpy( challange_blob + challangelen, blob, bloblen );
//printhex( challange_blob, sizeof( challange_blob ) );
HMAC( EVP_md5(),
(unsigned char*) ntlmv2hash, sizeof( ntlmv2hash ),
(unsigned char*)challange_blob, sizeof( challange_blob ),
(unsigned char*)respdigest, (unsigned int *)&resplen );
//printhex( respdigest, sizeof( respdigest ) );
memcpy( response, respdigest, sizeof( respdigest ) );
memcpy( response + sizeof( respdigest ), blob, bloblen );
return 1;
}
#ifdef __SINGLE_TEST__
// special thanks for monyo.
// http://www.monyo.com/technical/samba/translation/ntlm.html
char *domain = "DOMAIN" ;
char *user = "user" ;
char *pass = "SecREt01" ;
char challange[] = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef };
char blob[] = { 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // signature & reserved
0x00, 0x90, 0xd3, 0x36, 0xb7, 0x34, 0xc3, 0x01, // timestamp
0xff, 0xff, 0xff, 0x00, 0x11, 0x22, 0x33, 0x44, // client once
0x00, 0x00, 0x00, 0x00, // unknown 1
0x02, 0x00, 0x0c, 0x00, 0x44, 0x00, 0x4f, 0x00, // target information
0x4d, 0x00, 0x41, 0x00, 0x49, 0x00, 0x4e, 0x00,
0x01, 0x00, 0x0c, 0x00, 0x53, 0x00, 0x45, 0x00,
0x52, 0x00, 0x56, 0x00, 0x45, 0x00, 0x52, 0x00,
0x04, 0x00, 0x14, 0x00, 0x64, 0x00, 0x6f, 0x00,
0x6d, 0x00, 0x61, 0x00, 0x69, 0x00, 0x6e, 0x00,
0x2e, 0x00, 0x63, 0x00, 0x6f, 0x00, 0x6d, 0x00,
0x03, 0x00, 0x22, 0x00, 0x73, 0x00, 0x65, 0x00,
0x72, 0x00, 0x76, 0x00, 0x65, 0x00, 0x72, 0x00,
0x2e, 0x00, 0x64, 0x00, 0x6f, 0x00, 0x6d, 0x00,
0x61, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x2e, 0x00,
0x63, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00 // unknown 2
};
char answer[] = { 0xcb, 0xab, 0xbc, 0xa7, 0x13, 0xeb, 0x79, 0x5d, // hmac-md5
0x04, 0xc9, 0x7a, 0xbc, 0x01, 0xee, 0x49, 0x83,
0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // blob
0x00, 0x90, 0xd3, 0x36, 0xb7, 0x34, 0xc3, 0x01,
0xff, 0xff, 0xff, 0x00, 0x11, 0x22, 0x33, 0x44,
0x00, 0x00, 0x00, 0x00,
0x02, 0x00, 0x0c, 0x00, 0x44, 0x00, 0x4f, 0x00,
0x4d, 0x00, 0x41, 0x00, 0x49, 0x00, 0x4e, 0x00,
0x01, 0x00, 0x0c, 0x00, 0x53, 0x00, 0x45, 0x00,
0x52, 0x00, 0x56, 0x00, 0x45, 0x00, 0x52, 0x00,
0x04, 0x00, 0x14, 0x00, 0x64, 0x00, 0x6f, 0x00,
0x6d, 0x00, 0x61, 0x00, 0x69, 0x00, 0x6e, 0x00,
0x2e, 0x00, 0x63, 0x00, 0x6f, 0x00, 0x6d, 0x00,
0x03, 0x00, 0x22, 0x00, 0x73, 0x00, 0x65, 0x00,
0x72, 0x00, 0x76, 0x00, 0x65, 0x00, 0x72, 0x00,
0x2e, 0x00, 0x64, 0x00, 0x6f, 0x00, 0x6d, 0x00,
0x61, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x2e, 0x00,
0x63, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00
};
int main( )
{
int ret ;
char response[1024];
makeNTLMv2Resnpose( user, pass,
challange, sizeof( challange ),
blob, sizeof( blob ),
domain, response ) ;
ret = memcmp( response, answer, sizeof(answer) );
printf( "%s\n", ( ret ? "wrong" : "OK" ) );
exit( 0 );
}
#endif