Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
After 10+ hours of debugging, I finally found why NTLMv1 seemed to be failing... and reason is incredibly stupid and frustrating.
The DES encryption algorithm that is used in the NTLM protocol is a non-standard algorithm, in that it uses a special process to "expand" 56-bit (7-byte) keys to 64-bit (8-byte) keys. While implementing the LM hashing algorithm originally, I made sure to include that expansion process. Unfortunately, I had made the original LM hasher way before putting together all of the other pieces that integrate to create a full NTLMv1 "Authenticate Message" encoding process. Because I had spent so much time in between those implementations, I didn't remember to include that special key expansion and normalization process when using the DES encrypter to generate part of the LM/NT responses.
This is one of those "bugs" that is caused by oversight when fleshing out an implementation. Damn.
Anyway, in order to fix this bug, I've simply abstracted the key expansion bits into a common key processing piece that gets optionally called for all DES encryption processes, since that's the way that DES encryption is always used in the NTLM protocol.
Also, I had forgotten a small part of the processing originally that is intended to normalize keys by setting a parity bit for each byte in a DES key. Thanks to some prior art (referenced in the method doc-block), that is now implemented.
Finally, thanks to some integration testing, I another oversight in the design of the LM hashing and DES encryption usage: I was generating a random "initialization vector" and providing it to the DES encrypter when using an ECB cipher mode... which doesn't make any sense, as the DES-ECB encryption cipher doesn't use a provided initialization vector (oops!). So, in order to "fix" that unnecessary operation, I've simply removed the old initialization vector generation when using DES-ECB. When doing so, I realized that the
LmHasher
no longer needed theRandomByteGeneratorInterface
dependency, as it was no longer being used, so I removed it! The nice thing about this removal is that we'll no longer be generating random bytes when we don't need to, which will allow us to remove unnecessary calls that were actually taking up I/O time and entropy, so this is an optimization all around too. 😄Do to these new abstractions and dependency removals, the changes in this PR are actually breaking backwards compatibility. Luckily the library is still in a pre-1.0 "unstable" version phase, so a BC break like this is allowed (and somewhat expected).
Anyway, I'm beat now. My past several hours have had so much reverse engineering through message decoding that I'm absolutely toast. 🍞 So I'm out for tonight.
PS: I've done some integration tests, and now both the NTLMv1 and NTLMv2 processes work against an Exchange 2010 server running on Windows Server 2008. 😃