#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