[jcifs] NtlmHttpFilter - authentication

eglass1 at comcast.net eglass1 at comcast.net
Thu Mar 4 10:47:05 GMT 2004

> Good to hear. But NTLMv2? That's another thing that's "looming".

Full NTLMv2 support wouldn't be terribly difficult to implement.  From a cryptographic
standpoint, the LMv2 and NTLMv2 responses are identical:

v2Hash = HMAC-MD5(MD4(password), uppercase(username + domain))

response = HMAC-MD5(v2Hash, challenge + data) + data

In the LMv2 response, "data" is an 8-byte nonce (the "blip", to use Chris's
terminology).  In the NTLMv2 response, "data" is (roughly):

    timestamp + blip + targetInformationBlock

This is referred to as the "blob" in Chris's text.  The target information
block is a list of information identifying the server's identity on the
network (including the server name, FQDN, NetBIOS domain, DNS domain, etc.).
This is sent to the client in the Type 2 message, and is echoed back in the
Type 3.

The problem for someone like us (that doesn't do extended security) is that
we don't have a Type 2 message from the server; we just have the challenge
that we got in the NegProtResponse.  We need to "fake up" an appropriate
target information block to construct the NTLMv2 response for the Type 3
message.  The contents of this block are checked by the server when the
user's authentication target doesn't match that of the server (i.e., user
is in domain "DOMA" and server's primary domain is "DOMB").

With a little bit of effort, we could do that; the required information is
available (i.e. the NetBIOS name and primary domain of the SMB server).  It
would require some moderately impactful changes to NtlmSsp.java and the
filter, however; instead of doing:

    byte[] challenge = SmbSession.getChallenge(dc);
    NtlmSsp.authenticate(request, response, challenge);

you would have to do something like:

    byte[] challenge = SmbSession.getChallenge(dc);
    byte[] targetInfo = SmbSession.getTargetInformation(dc);
    NtlmSsp.authenticate(request, response, challenge, targetInfo);

The target information block would need to contain the NetBIOS name and
domain for the server which generated the challenge.  Likewise,
NtlmPasswordAuthentication would need to be modified to accept the target
information in addition to the challenge.  If you look at the getUnicodeHash
method, you'll see a call to "getNTLMv2Response" commented out; the null
parameter in that call would be the target information block.  You would
probably need to change getUnicodeHash to accept the target information block
as an additional parameter.  My NTLM document has an implementation of
getNTLMv2Response in the example source (albeit a rather inefficient

It really comes down to whether it's worth the effort to implement.  The LMv2
response is always accepted, so our current implementation should work
anywhere NTLMv2 is required.  As a side note, It'd be interesting to see how
clients without extended security construct the NTLMv2 response in the real
world; toggling the LmCompatibilityLevel setting to 3 and accessing a share
should do it, I just don't have any boxes without extended security
capability (NT4 maybe?).


More information about the jcifs mailing list