I am trying to develop a PHP function to calculate NTLMv2 hash by providing server & client challenge, domain, account and password. The resulting hash appears to be not correct. Can someone guide me about the correct way:

Here is the algorithm in PHP language:

function GenerateNTMLv2($password, $account, $domain, $client_challenge, $server_challenge) {

    $hash = mhash(MHASH_MD4, $password);
    $hash = mhash(MHASH_MD5, strtoupper($account) . $domain, $hash); 
    $hash = mhash(MHASH_MD5, $client_challenge . $server_challenge, $hash);

    return strtoupper(bin2hex($hash));

I have provided the following parameters:

$client_challenge =  '0101000000000000DF5ED1178FBACE012FDEE788AA2574CE0000000002001200430041004E00440059004C0041004E00440001001200430041004E00440059004C0041004E00440004001200630061006E00640079006C0061006E00640003001200630061006E00640079006C0061006E006400060004000300000007000800DF5ED1178FBACE0108003000300000000000000001000000002000004C60DD0226C932C69BAF540769C9E4DA53ABF77A8D56DBA0F9AA214EEEBB30AE0A001000000000000000000000000000000000000900240063006900660073002F003100390032002E003100360038002E0030002E003200320038000000000000000000';
$server_challenge = 'FFC7C728CAAC8BE8';
$domain = 'SOFTECH';
$account = 'asim';

The function returns the following NTLMv2 hash: 48335EFCA9A07EA12B9EBBC2AEE30C8E

Where as the HASH must be: 3780B32F46FA60CE1431264A525B0D60

Can anyone suggest the correct algorithm?

  • You really shouldn't be implementing this yourself, in PHP (or really any language). There are just too many ways this can go wrong, and while it would still "work" it might possible (or even trivial) to break it. As an anecdote, I recently reviewed a client's custom implementation of the NTLMv2 protocol, and found numerous trivial ways to bypass it (and another couple of not so trivial ways). You would be much better off finding a standard library that does this for you, or just rely on the webserver to handle it. – AviD Sep 28 '13 at 19:15

I sorted out the correct algorithm for PHP. Thanks for the contribution. Following is the code:

function GenerateNTMLv2($password, $account, $domain, $client_challenge, $server_challenge) {

    $unicode_password= iconv ( 'UTF-8', 'UTF-16LE', $password );

    $NTLM_Key = mhash ( MHASH_MD4, $unicode_password);
    $NTLM_Hash = mhash ( MHASH_MD5, iconv ( 'UTF-8', 'UTF-16LE', strtoupper ( $account ) . $domain ), $NTLM_Key );
    $NTLM_Chal_Hash = mhash ( MHASH_MD5, pack ( "H*", $server_challenge . $client_challenge ), $NTLM_Hash );

    return strtoupper ( bin2hex ( $NTLM_Chal_Hash ) );
| improve this answer | |

You probably have encoding issues:

  • Beware that hash function process bytes but your strings may contain characters or even hexadecimal digits. For instance, your $client_challenge is a string which begins with 0101, probably meaning that it should begin with two bytes of value 1, but chances are that the hash function took it as the encoding of four characters, probably as four bytes of values 48, 49, 48 and 49 (ASCII codes for digits 0 and 1).

  • At least the first MD4 ought to be computed over the password encoded in little-endian UTF-16 and I seriously doubt mhash() would do that for you.

PHP is quite underspecified in these matters, so I recommend that you first prototype the code with a language where bytes are bytes and encoding matters can be handled explicitly; Java and C# come to mind. Once you have a function which computes the right value in such a language, you can print out intermediate results to be compared with your PHP code, so that you may pinpoint the problem.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.