My shared hosting was adding -always- the "WWW-Authenticate:NTLM" header, but of course i did not liked to add windows users to the web server. So, having seen how it was easy to add a simple basic authentication with the C# attributes why not to add a NTLM authentication attribute.
So the quest started. The first problem was to find how worked the NTLM authentication. Some clue was found on stackoverflow, where some people suggested to look at the Cassini source code, the little developement server offered by visual studio. With a nice C# implementation.
Woooah the source code, ready made, so cool...but... the authentication worked only through the windows identities! That was something i wanted to avoid from start.
I really like C# but when you have to play with buffers it can easily become a nightnare, i love the clean approach of copying a buffer directly on a structure with memcpy, and malloc all that i need.
Then i started investigating further, and i founded Ronald Tschaler's description of the protocol, with a little description of the protocol. The light finally, with a function to calculate the MD4 hash function to calculate the nt password hash. The second problem seemed gone...
Now, to calculate the correctness of the response to the challenge sent by the server to the client (the type 2 message) you need to encode with DES the lm key and the nt key in obscure way. I had on Tschaler page several examples of this with the various partial results. Another further problem is that the LM key is calculated encoding with des the nonce sent as challenge with the lan manager password.
Seeking, lots of trials searching for various DES implementations, obscures CryptoAPI or Crypto++ libraries too costly or with too much dependencies. And i founded Martyn C.Brown implementation of DES in C++, the light is near? Nay!
I messed a while with the various padding, parity checks ECB, CBC, WTF... and then another light appeared, on skullsecurity.org a kinda true implementation of the whole algorithm!! Now all would have been clear!
I wrote a test program, and after some struggle i was able,finally to see values matching Tschaler's description! Wonderful! Now it's easy... add the attribute to the whole thing. Adding a reference to my project and....
IIS seems unable to load native dlls directly, and cope with x86/x64/AnyCPU build configuration
The trick is to add the native dll as a reference to the project without copying it to the output directory, than load them in the AppDomain through Global.Asax. But to cope with every situations two dlls should be created one for x86 and one for x64. Then detecting if the process is a 64bit one or a 32 bit choose the right dll
//This should be called with the names of the dlls private void RegisterDlls(params string[] dllNames) { AppDomain curDomain = AppDomain.CurrentDomain; //The directory must be present in two kinds in two subdirs of the website //at the same level of the "bin" directory: //bin_native/x86 and bin_native/x64 String binDir = Path.Combine(curDomain.BaseDirectory, "bin_native",Environment.Is64BitProcess?"x64":"x86"); String shadowCopyDir = curDomain.DynamicDirectory; foreach (var dllName in dllNames) { String dllSrc = Path.Combine(binDir, dllName + ".dll"); String dllDst = Path.Combine(shadowCopyDir, Path.GetFileName(dllSrc)); try { //The files are copied on the shadow copy areas File.Copy(dllSrc, dllDst, true); //And loaded explicitely! Assembly.LoadFrom(dllDst); } catch (System.Exception ex) { } } }
But NTLM is connection based. The nonce (with the challenge) is sent to the client, the client send the response of the challeng and the server send a 200. But http is connection less, and in IIS you don't have access to the TCP layer, so...no way. Should build an ISAPI filter (native...luckily now it's easy!!)
Here the download of the source plus a C# integration and sample: Download here the latest version.