diff --git a/.travis.yml b/.travis.yml index 87cb3ff..b920b0a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,6 +5,7 @@ python: - "2.7" - "3.3" - "3.4" + - "3.5" # command to install dependencies install: diff --git a/CHANGES.md b/CHANGES.md index 9f42900..b63c12c 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -17,3 +17,20 @@ Initial public offering. * Bugfix for windows (thanks to @rbcarson for the help) * Added Appveyor continous integration testing on Windows to avoid these problems in future +1.1.0 (Aug 5, 2016) +------------------- + +* Added support for Python 3.5 +* Added requirement for cryptography so we can calculate RC4 values for EncryptedRandomSessionKey and signing and sealing (can we remove this dependency?) +* Major rewrite of how python-ntlm3 handles authentication +* Added support for NTLMv2 auth and fixed up some older auth methods +* Moved code to separate classes to help cleanup the code +* Added support for channel_bindings (CBT) when supplying a certificate hash +* Added support for MIC data for authenticate messages +* Preliminary support for signing and sealing of messages. Needs to be done outside of auth messages and tested more thoroughly +* Removed some methods that weren't being used at all (most were starting to implement these features above but weren't there) +* More comments on each methods relating back to the MS-NLMP document pack on NTLM authentication for easier maintenance +* Created target_info.py to handle AV_PAIRS and putting it in the target info +* Renaming of some variables to match more closely with the Microsoft documentation, makes it easier to understand what is happening +* Rewriting of tests to accommodate these new changes and to cover the new cases +* The methods `create_NTLM_NEGOTIATE_MESSAGE`, `parse_NTLM_CHALLENGE_MESSAGE`, `create_NTLM_AUTHENTICATE_MESSAGE` will no longer be supported in future version. They do not support NTLMv2 auth and are only left for compatibility \ No newline at end of file diff --git a/README.md b/README.md index 2b972b8..33ddb77 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,18 @@ This is a Python 3 compatible fork of the [python-ntlm](https://code.google.com/ About this library ------------------ -This library handles the low-level details of NTLM authentication. Almost all users should use [requests-ntlm](https://github.com/requests/requests-ntlm) instead, which is a plugin to requests that uses this library under the hood and is way easier to use and understand. +This library handles the low-level details of NTLM authentication. This library will create the 3 different message types in NTLM based on the input and produce a base64 encoded value to attach to the HTTP header. + +The goal of this library is to offer full NTLM support including signing and sealing of messages as well as supporting MIC for message integrity and the ability to customise and set limits on the messages sent. Please see Features and Backlog for a list of what is and is not currently supported. + +Features +-------- +* LM, NTLM and NTLMv2 authentication +* NTLM1 and NTLM2 extended session security +* Set the The NTLM Compatibility level when sending messages +* Channel Binding Tokens support, need to pass in the SHA256 hash of the certificate for it to work +* Support for MIC to enhance the integrity of the messages +* (To be Tested) Support for session security with signing and sealing messages after authentication happens Installation ------------ @@ -26,11 +37,135 @@ To install from source, download the source code, then run: Usage ------------ -This library has an identical API as python-ntlm and is a drop-in replacement. To use, include this: +Almost all users should use [requests-ntlm](https://github.com/requests/requests-ntlm) instead of this library. The library requests-ntlm is a plugin that uses this library under the hood and provides an easier function to use and understand. + +If you are set on using python-ntlm3 directly to compute the message structures this is a very basic outline of how it can be done. The code examples are psuedocode and should be adapted for your purpose. + +When initliasing the ntlm context you will have to supply the NTLM compatibility level. The key difference between the different auth levels are the ntlm_compatibility variable supplied when initialising Ntlm. An overview of what each sets is below; +* `0` - LM Auth and NTLMv1 Auth +* `1` - LM Auth and NTLMv1 Auth with Extended Session Security (NTLM2) +* `2` - NTLMv1 Auth with Extended Session Security (NTLM2) +* `3` - NTLMv2 Auth (Default Choice) +* `4` - NTLMv2 Auth +* `5` - NTLMv2 Auth + +Level 3 to 5 are the same from a client perspective but differ with how the server handles the auth which is outside this project's scope. This setting is set independently on that server so choosing 3, 4 or 5 when calling Ntlm will make no difference at all. See [LmCompatibilityLevel](https://technet.microsoft.com/en-us/library/cc960646.aspx) for more details. + +Extended Session Security is a security feature designed to increase the security of LM and NTLMv1 auth. It is no substitution for NTLMv2 but is better than nothing and should be used if possible when you need NTLMv1 compatibility. + +The variables required are outlined below; +* `user_name` - The username to authenticate with, should not have the domain prefix, i.e. USER not DOMAIN\\USER +* `password` - The password of the user to authenticate with +* `domain_name` - The domain of the user, i.e. DOMAIN. Can be blank if not in a domain environment +* `workstation` - The workstation you are running on. Can be blank if you do not wish to send this +* `server_certificate_hash` - (NTLMv2 only) The SHA256 hash of the servers DER encoded certificate. Used to calculate the Channel Binding Tokens and should be added even if it isn't required. Can be blank but auth will fail if the server requires this hash. + + +#### LM Auth/NTLMv1 Auth + +LM and NTLMv1 Auth are older authentication methods that should be avoided where possible. Choosing between these authentication methods are almost identical expect where you specify the ntlm_compatiblity level. + +```python +import socket + +from ntlm3.ntlm import Ntlm + +user_name = 'User' +password = 'Password' +domain_name = 'Domain' # Can be blank if you are not in a domain +workstation = socket.gethostname().upper() # Can be blank if you wish to not send this info + +ntlm_context = Ntlm(ntlm_compatibility=0) # Put the ntlm_compatibility level here, 0-2 for LM Auth/NTLMv1 Auth +negotiate_message = ntlm_context.create_negotiate_message(domain_name, workstation).decode() + +# Attach the negotiate_message to your NTLM/NEGOTIATE HTTP header and send to the server. Get the challenge response back from the server +challenge_message = http.response.headers['HEADERFIELD'] + +authenticate_message = ntlm_context.create_authenticate_message(user_name, password, domain_name, workstation).decode() + +# Attach the authenticate_message ot your NTLM_NEGOTIATE HTTP header and send to the server. You are now authenticated with NTLMv1 +``` + +#### NTLMv2 + +NTLMv2 Auth is the newest NTLM auth method from Microsoft and should be the option chosen by default unless you require an older auth method. The implementation is the same as NTLMv1 but with the addition of the optional `server_certificate_hash` variable and the `ntlm_compatibility` is not specified. + +```python +import socket + +from ntlm3.ntlm import Ntlm + +user_name = 'User' +password = 'Password' +domain_name = 'Domain' # Can be blank if you are not in a domain +workstation = socket.gethostname().upper() # Can be blank if you wish to not send this info +server_certificate_hash = '96B2FC1EC30792619286A0C7FD62863E81A6564E72829CBC0A46F7B1D5D92A18' # Can be blank if you don't want CBT sent + +ntlm_context = Ntlm() +negotiate_message = ntlm_context.create_negotiate_message(domain_name, workstation).decode() + +# Attach the negotiate_message to your NTLM/NEGOTIATE HTTP header and send to the server. Get the challenge response back from the server +challenge_message = http.response.headers['HEADERFIELD'] + +authenticate_message = ntlm_context.create_authenticate_message(user_name, password, domain_name, workstation, server_certificate_hash).decode() + +# Attach the authenticate_message ot your NTLM_NEGOTIATE HTTP header and send to the server. You are now authenticated with NTLMv1 +``` + +#### Signing/Sealing + +All version of NTLM supports signing (integrity) and sealing (confidentiality) of message content. This function can add these improvements to a message that is sent and received from the server. While it does encrypt the data if supported by the server it is only done with RC4 with a 128-bit key which is not very secure and on older systems this key length could be 56 or 40 bit. This functionality while tested and conforms with the Microsoft documentation has yet to be fully tested in an integrated environment. Once again this has not been thoroughly tested and has only passed unit tests and their expections. + +```python +import socket + +from ntlm3.ntlm import Ntlm + +user_name = 'User' +password = 'Password' +domain_name = 'Domain' # Can be blank if you are not in a domain +workstation = socket.gethostname().upper() # Can be blank if you wish to not send this info +msg_data = "Message to send to the server" +server_certificate_hash = '96B2FC1EC30792619286A0C7FD62863E81A6564E72829CBC0A46F7B1D5D92A18' # Can be blank if you don't want CBT sent + +ntlm_context = Ntlm() +negotiate_message = ntlm_context.create_negotiate_message(domain_name, workstation).decode() + +# Attach the negotiate_message to your NTLM/NEGOTIATE HTTP header and send to the server. Get the challenge response back from the server +challenge_message = http.response.headers['HEADERFIELD'] + +authenticate_message = ntlm_context.create_authenticate_message(user_name, password, domain_name, workstation, server_certificate_hash).decode() + +if ntlm_context.session_security is None: + raise Exception("Server does not support signing and sealing") +else: + session_security = ntlm_context.session_security + +# Encrypt the msg with the sealing function and send the message +msg_data, msg_signature = session_security.wrap(msg_data) +request.body = msg_data +request.header = "NTLM %s" % authenticate_message +request.send + +# Receive the response the from the server +response_msg = response.body[bodyindex] +response_signature = response.body[signatureindex] +response_msg = session_security.unwrap(response_msg, response_signature) +``` + +Deprecated methods +------------------ + +As of version 1.1.0 the methods `create_NTLM_NEGOTIATE_MESSAGE`, `parse_NTLM_CHALLENGE_MESSAGE`, `create_NTLM_AUTHENTICATE_MESSAGE` in ntlm.py have been deprecated and will be removed from the next major version of python-ntlm3. - import ntlm3 as ntlm +Please use the Ntlm class in ntlm.py in the future as this brings supports for NTLMv2 authentication and more control over how your messages are sent. Ntlm is also easier to use and understand with the various methods being moved to classes of their own and will potentially allow support for more features such as signing and sealing. -API ----------- -TODO +Backlog +------- +* Remove the old ntlm.py code that has been left there for compatibility in the next major version release. This does not support NTLMv2 auth +* Fully test out signing and sealing of messages over the wire with another library +* Automatically get windows version if running on windows, use default if not that case +* Add param when initialising the ntlm context to throw an exception and cancel auth if the server doesn't support 128-bit keys for sealing +* Add param when initialising the ntlm context to not send the MIC structure for older servers +* Add param to independently verify the target name returned from the server and the value passed in \ No newline at end of file diff --git a/appveyor.yml b/appveyor.yml index 2bdee88..9c84384 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -30,6 +30,13 @@ environment: PYTHON_VERSION: "3.4.1" PYTHON_ARCH: "64" + - PYTHON: "C:\\Python35" + PYTHON_VERSION: "3.5.2" + PYTHON_ARCH: "32" + + - PYTHON: "C:\\Python35-x64" + PYTHON_VERSION: "3.5.2" + PYTHON_ARCH: "64" init: - "ECHO %PYTHON% %PYTHON_VERSION% %PYTHON_ARCH%" diff --git a/examples/simple.py b/examples/simple.py index 913d675..f9b513c 100755 --- a/examples/simple.py +++ b/examples/simple.py @@ -1,6 +1,8 @@ #! /usr/bin/env python """ +This method is deprecated, please avoid using this way as it does not support NTLMv2 and is not considered secure + A simple script to demonstrate how this package works. Run with: diff --git a/ntlm3/HTTPNtlmAuthHandler.py b/ntlm3/HTTPNtlmAuthHandler.py index 227e67e..b441580 100644 --- a/ntlm3/HTTPNtlmAuthHandler.py +++ b/ntlm3/HTTPNtlmAuthHandler.py @@ -17,8 +17,10 @@ import socket import re +from ntlm3.constants import NegotiateFlags from . import ntlm +# TODO: Is this file needed, this is very much what requests-ntlm does and should be brought there. This hasn't been updated ot support NTLMv2 class AbstractNtlmAuthHandler: def __init__(self, password_mgr=None, debuglevel=0): @@ -46,7 +48,7 @@ def retry_using_http_NTLM_auth(self, req, auth_header_field, realm, headers): if len(user_parts) == 1: UserName = user_parts[0] DomainName = '' - type1_flags = ntlm.NTLM_TYPE1_FLAGS & ~ntlm.NTLM_NegotiateOemDomainSupplied + type1_flags = ntlm.NTLM_TYPE1_FLAGS else: DomainName = user_parts[0].upper() UserName = user_parts[1] @@ -90,7 +92,8 @@ def retry_using_http_NTLM_auth(self, req, auth_header_field, realm, headers): r.begin() - r._safe_read(int(r.getheader('content-length'))) + a = r.getheader('Content-Length') + #r._safe_read(int(r.getheader('Content-Length'))) if r.getheader('set-cookie'): # this is important for some web applications that store authentication-related info in cookies (it took a long time to figure out) headers['Cookie'] = r.getheader('set-cookie') diff --git a/ntlm3/U32.py b/ntlm3/U32.py index 8184522..dd1c958 100644 --- a/ntlm3/U32.py +++ b/ntlm3/U32.py @@ -1,156 +1,156 @@ -# This file is part of 'NTLM Authorization Proxy Server' http://sourceforge.net/projects/ntlmaps/ -# Copyright 2001 Dmitry A. Rozmanov -# -# This library is free software: you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation, either -# version 3 of the License, or (at your option) any later version. - -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. - -# You should have received a copy of the GNU Lesser General Public -# License along with this library. If not, see or . - -from __future__ import division -import six - -C = 0x1000000000 - - -def norm(n): - return n & 0xFFFFFFFF - - -class U32: - v = 0 - - def __init__(self, value=0): - if not isinstance(value, six.integer_types): - value = six.byte2int(value) - - self.v = C + norm(abs(int(value))) - - def set(self, value=0): - self.v = C + norm(abs(int(value))) - - def __repr__(self): - return hex(norm(self.v)) - - def __long__(self): - return int(norm(self.v)) - - def __int__(self): - return int(norm(self.v)) - - def __chr__(self): - return chr(norm(self.v)) - - def __add__(self, b): - r = U32() - r.v = C + norm(self.v + b.v) - return r - - def __sub__(self, b): - r = U32() - if self.v < b.v: - r.v = C + norm(0x100000000 - (b.v - self.v)) - else: - r.v = C + norm(self.v - b.v) - return r - - def __mul__(self, b): - r = U32() - r.v = C + norm(self.v * b.v) - return r - - def __div__(self, b): - r = U32() - r.v = C + (norm(self.v) // norm(b.v)) - return r - - def __truediv__(self, b): - r = U32() - r.v = C + (norm(self.v) / norm(b.v)) - return r - - def __mod__(self, b): - r = U32() - r.v = C + (norm(self.v) % norm(b.v)) - return r - - def __neg__(self): - return U32(self.v) - - def __pos__(self): - return U32(self.v) - - def __abs__(self): - return U32(self.v) - - def __invert__(self): - r = U32() - r.v = C + norm(~self.v) - return r - - def __lshift__(self, b): - r = U32() - r.v = C + norm(self.v << b) - return r - - def __rshift__(self, b): - r = U32() - r.v = C + (norm(self.v) >> b) - return r - - def __and__(self, b): - r = U32() - r.v = C + norm(self.v & b.v) - return r - - def __or__(self, b): - r = U32() - r.v = C + norm(self.v | b.v) - return r - - def __xor__(self, b): - r = U32() - r.v = C + norm(self.v ^ b.v) - return r - - def __not__(self): - return U32(not norm(self.v)) - - def truth(self): - return norm(self.v) - - def __cmp__(self, b): - if norm(self.v) > norm(b.v): - return 1 - elif norm(self.v) < norm(b.v): - return -1 - else: - return 0 - - def __lt__(self, other): - return self.v < other.v - - def __gt__(self, other): - return self.v > other.v - - def __eq__(self, other): - return self.v == other.v - - def __le__(self, other): - return self.v <= other.v - - def __ge__(self, other): - return self.v >= other.v - - def __ne__(self, other): - return self.v != other.v - - def __nonzero__(self): - return norm(self.v) +# This file is part of 'NTLM Authorization Proxy Server' http://sourceforge.net/projects/ntlmaps/ +# Copyright 2001 Dmitry A. Rozmanov +# +# This library is free software: you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation, either +# version 3 of the License, or (at your option) any later version. + +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. + +# You should have received a copy of the GNU Lesser General Public +# License along with this library. If not, see or . + +from __future__ import division +import six + +C = 0x1000000000 + + +def norm(n): + return n & 0xFFFFFFFF + + +class U32: + v = 0 + + def __init__(self, value=0): + if not isinstance(value, six.integer_types): + value = six.byte2int(value) + + self.v = C + norm(abs(int(value))) + + def set(self, value=0): + self.v = C + norm(abs(int(value))) + + def __repr__(self): + return hex(norm(self.v)) + + def __long__(self): + return int(norm(self.v)) + + def __int__(self): + return int(norm(self.v)) + + def __chr__(self): + return chr(norm(self.v)) + + def __add__(self, b): + r = U32() + r.v = C + norm(self.v + b.v) + return r + + def __sub__(self, b): + r = U32() + if self.v < b.v: + r.v = C + norm(0x100000000 - (b.v - self.v)) + else: + r.v = C + norm(self.v - b.v) + return r + + def __mul__(self, b): + r = U32() + r.v = C + norm(self.v * b.v) + return r + + def __div__(self, b): + r = U32() + r.v = C + (norm(self.v) // norm(b.v)) + return r + + def __truediv__(self, b): + r = U32() + r.v = C + (norm(self.v) / norm(b.v)) + return r + + def __mod__(self, b): + r = U32() + r.v = C + (norm(self.v) % norm(b.v)) + return r + + def __neg__(self): + return U32(self.v) + + def __pos__(self): + return U32(self.v) + + def __abs__(self): + return U32(self.v) + + def __invert__(self): + r = U32() + r.v = C + norm(~self.v) + return r + + def __lshift__(self, b): + r = U32() + r.v = C + norm(self.v << b) + return r + + def __rshift__(self, b): + r = U32() + r.v = C + (norm(self.v) >> b) + return r + + def __and__(self, b): + r = U32() + r.v = C + norm(self.v & b.v) + return r + + def __or__(self, b): + r = U32() + r.v = C + norm(self.v | b.v) + return r + + def __xor__(self, b): + r = U32() + r.v = C + norm(self.v ^ b.v) + return r + + def __not__(self): + return U32(not norm(self.v)) + + def truth(self): + return norm(self.v) + + def __cmp__(self, b): + if norm(self.v) > norm(b.v): + return 1 + elif norm(self.v) < norm(b.v): + return -1 + else: + return 0 + + def __lt__(self, other): + return self.v < other.v + + def __gt__(self, other): + return self.v > other.v + + def __eq__(self, other): + return self.v == other.v + + def __le__(self, other): + return self.v <= other.v + + def __ge__(self, other): + return self.v >= other.v + + def __ne__(self, other): + return self.v != other.v + + def __nonzero__(self): + return norm(self.v) diff --git a/ntlm3/compat.py b/ntlm3/compat.py deleted file mode 100644 index bf23bc2..0000000 --- a/ntlm3/compat.py +++ /dev/null @@ -1,7 +0,0 @@ - - -def _long(value): - try: - return long(value) - except NameError: # we're Python 3, we don't have longs - return int(value) diff --git a/ntlm3/compute_hash.py b/ntlm3/compute_hash.py new file mode 100644 index 0000000..80c41c6 --- /dev/null +++ b/ntlm3/compute_hash.py @@ -0,0 +1,91 @@ +# This library is free software: you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation, either +# version 3 of the License, or (at your option) any later version. + +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. + +# You should have received a copy of the GNU Lesser General Public +# License along with this library. If not, see or . + +import binascii +import hashlib +import hmac +import re + +from ntlm3 import des + +def _lmowfv1(password): + """ + [MS-NLMP] v28.0 2016-07-14 + + 3.3.1 NTLM v1 Authentication + Same function as LMOWFv1 in document to create a one way hash of the password. Only + used in NTLMv1 auth without session security + + :param password: The password of the user we are trying to authenticate with + :return res: A Lan Manager hash of the password supplied + """ + + # TODO: is the below still needed, can we make a test for it? + # if the password provided is already a hash, we just return the first half + if re.match(r'^[\w]{32}:[\w]{32}$', password): + return binascii.unhexlify(password.split(':')[0]) + + # fix the password length to 14 bytes + password = password.upper() + lm_pw = password + '\0' * (14 - len(password)) + lm_pw = password[0:14] + + # do hash + magic_str = b"KGS!@#$%" # page 56 in [MS-NLMP v28.0] + + res = b'' + dobj = des.DES(lm_pw[0:7]) + res = res + dobj.encrypt(magic_str) + + dobj = des.DES(lm_pw[7:14]) + res = res + dobj.encrypt(magic_str) + + return res + +def _ntowfv1(password): + """ + [MS-NLMP] v28.0 2016-07-14 + + 3.3.1 NTLM v1 Authentication + Same function as NTOWFv1 in document to create a one way hash of the password. Only + used in NTLMv1 auth without session security + + :param password: The password of the user we are trying to authenticate with + :return digest: An NT hash of the password supplied + """ + + # TODO: Is this really needed, can we write a test if it is? + # if the password provided is already a hash, we just return the second half + if re.match(r'^[\w]{32}:[\w]{32}$', password): + return binascii.unhexlify(password.split(':')[1]) + + digest = hashlib.new('md4', password.encode('utf-16le')).digest() + return digest + +def _ntowfv2(user_name, password, domain_name): + """ + [MS-NLMP] v28.0 2016-07-14 + + 3.3.2 NTLM v2 Authentication + Same function as NTOWFv2 (and LMOWFv2) in document to create a one way hash of the password. + This combines some extra security features over the v1 calculations used in NTLMv2 auth. + + :param user_name: The user name of the user we are trying to authenticate with + :param password: The password of the user we are trying to authenticate with + :param domain_name: The domain name of the user account we are authenticated with + :return digest: An NT hash of the parameters supplied + """ + digest = _ntowfv1(password) + digest = hmac.new(digest, (user_name.upper() + domain_name).encode('utf-16le')).digest() + + return digest \ No newline at end of file diff --git a/ntlm3/compute_keys.py b/ntlm3/compute_keys.py new file mode 100644 index 0000000..3ab8799 --- /dev/null +++ b/ntlm3/compute_keys.py @@ -0,0 +1,139 @@ +# This library is free software: you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation, either +# version 3 of the License, or (at your option) any later version. + +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. + +# You should have received a copy of the GNU Lesser General Public +# License along with this library. If not, see or . + +import binascii +import hashlib +import hmac + +from ntlm3 import des +from ntlm3.constants import NegotiateFlags + +def _get_exchange_key_ntlm_v1(negotiate_flags, session_base_key, server_challenge, lm_challenge_response, lm_hash): + """ + [MS-NLMP] v28.0 2016-07-14 + + 4.3.5.1 KXKEY + Calculates the Key Exchange Key for NTLMv1 authentication. Used for signing and sealing messages + + @param negotiate_flags: + @param session_base_key: A session key calculated from the user password challenge + @param server_challenge: A random 8-byte response generated by the server in the CHALLENGE_MESSAGE + @param lm_challenge_response: The LmChallengeResponse value computed in ComputeResponse + @param lm_hash: The LMOWF computed in Compute Response + @return key_exchange_key: The Key Exchange Key (KXKEY) used to sign and seal messages and compute the ExportedSessionKey + """ + if negotiate_flags & NegotiateFlags.NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY: + key_exchange_key = hmac.new(session_base_key, server_challenge + lm_challenge_response[:8]).digest() + elif negotiate_flags & NegotiateFlags.NTLMSSP_NEGOTIATE_LM_KEY: + des_handler = des.DES(lm_hash[:7]) + first_des = des_handler.encrypt(lm_challenge_response[:8]) + des_handler = des.DES(lm_hash[7:8] + binascii.unhexlify('bdbdbdbdbdbdbd')) + second_des = des_handler.encrypt(lm_challenge_response[:8]) + + key_exchange_key = first_des + second_des + elif negotiate_flags & NegotiateFlags.NTLMSSP_REQUEST_NON_NT_SESSION_KEY: + key_exchange_key = lm_hash[:8] + b'\0' * 8 + else: + key_exchange_key = session_base_key + + return key_exchange_key + +def _get_exchange_key_ntlm_v2(session_base_key): + """ + [MS-NLMP] v28.0 2016-07-14 + + 4.3.5.1 KXKEY + Calculates the Key Exchange Key for NTLMv2 authentication. Used for signing and sealing messages. + According to docs, 'If NTLM v2 is used, KeyExchangeKey MUST be set to the given 128-bit SessionBaseKey + + @param session_base_key: A session key calculated from the user password challenge + @return key_exchange_key: The Key Exchange Key (KXKEY) used to sign and seal messages + """ + return session_base_key + +def get_sign_key(exported_session_key, magic_constant): + """ + 3.4.5.2 SIGNKEY + + @param exported_session_key: A 128-bit session key used to derive signing and sealing keys + @param magic_constant: A constant value set in the MS-NLMP documentation (constants.SignSealConstants) + @return sign_key: Key used to sign messages + """ + + sign_key = hashlib.md5(exported_session_key + magic_constant).digest() + + return sign_key + +def get_seal_key(negotiate_flags, exported_session_key, magic_constant): + """ + 3.4.5.3. SEALKEY + Main method to use to calculate the seal_key used to seal (encrypt) messages. This will determine + the correct method below to use based on the compatibility flags set and should be called instead + of the others + + @param exported_session_key: A 128-bit session key used to derive signing and sealing keys + @param negotiate_flags: The negotiate_flags structure sent by the server + @param magic_constant: A constant value set in the MS-NLMP documentation (constants.SignSealConstants) + @return seal_key: Key used to seal messages + """ + + if negotiate_flags & NegotiateFlags.NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY: + seal_key = _get_seal_key_ntlm2(negotiate_flags, exported_session_key, magic_constant) + elif negotiate_flags & NegotiateFlags.NTLMSSP_NEGOTIATE_LM_KEY: + seal_key = _get_seal_key_ntlm1(negotiate_flags, exported_session_key) + else: + seal_key = exported_session_key + + return seal_key + +def _get_seal_key_ntlm1(negotiate_flags, exported_session_key): + """ + 3.4.5.3 SEALKEY + Calculates the seal_key used to seal (encrypt) messages. This for authentication where + NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY has not been negotiated. Will weaken the keys + if NTLMSSP_NEGOTIATE_56 is not negotiated it will default to the 40-bit key + + @param negotiate_flags: The negotiate_flags structure sent by the server + @param exported_session_key: A 128-bit session key used to derive signing and sealing keys + @return seal_key: Key used to seal messages + """ + if negotiate_flags & NegotiateFlags.NTLMSSP_NEGOTIATE_56: + seal_key = exported_session_key[:7] + binascii.unhexlify('a0') + else: + seal_key = exported_session_key[:5] + binascii.unhexlify('e538b0') + + return seal_key + +def _get_seal_key_ntlm2(negotiate_flags, exported_session_key, magic_constant): + """ + 3.4.5.3 SEALKEY + Calculates the seal_key used to seal (encrypt) messages. This for authentication where + NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY has been negotiated. Will weaken the keys + if NTLMSSP_NEGOTIATE_128 is not negotiated, will try NEGOTIATE_56 and then will default + to the 40-bit key + + @param negotiate_flags: The negotiate_flags structure sent by the server + @param exported_session_key: A 128-bit session key used to derive signing and sealing keys + @param magic_constant: A constant value set in the MS-NLMP documentation (constants.SignSealConstants) + @return seal_key: Key used to seal messages + """ + if negotiate_flags & NegotiateFlags.NTLMSSP_NEGOTIATE_128: + seal_key = exported_session_key + elif negotiate_flags & NegotiateFlags.NTLMSSP_NEGOTIATE_56: + seal_key = exported_session_key[:7] + else: + seal_key = exported_session_key[:5] + + seal_key = hashlib.md5(seal_key + magic_constant).digest() + + return seal_key \ No newline at end of file diff --git a/ntlm3/compute_response.py b/ntlm3/compute_response.py new file mode 100644 index 0000000..0ebd935 --- /dev/null +++ b/ntlm3/compute_response.py @@ -0,0 +1,398 @@ +# This library is free software: you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation, either +# version 3 of the License, or (at your option) any later version. + +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. + +# You should have received a copy of the GNU Lesser General Public +# License along with this library. If not, see or . + +import base64 +import calendar +import hashlib +import hmac +import os +import struct +import time + +import ntlm3.compute_hash as comphash +import ntlm3.compute_keys as compkeys +from ntlm3 import des +from ntlm3.constants import NegotiateFlags, AvFlags +from ntlm3.gss_channel_bindings import GssChannelBindingsStruct +from ntlm3.target_info import TargetInfo + +class ComputeResponse(): + """ + Constructor for the response computations. This class will compute the various + nt and lm challenge responses. + + :param user_name: The user name of the user we are trying to authenticate with + :param password: The password of the user we are trying to authenticate with + :param domain_name: The domain name of the user account we are authenticated with, default is None + :param challenge_message: A ChallengeMessage object that was received from the server after the negotiate_message + :param ntlm_compatibility: The Lan Manager Compatibility Level, used to determine what NTLM auth version to use, see Ntlm in ntlm.py for more details + """ + def __init__(self, user_name, password, domain_name, challenge_message, ntlm_compatibility): + self._user_name = user_name + self._password = password + self._domain_name = domain_name + self._challenge_message = challenge_message + self._negotiate_flags = challenge_message.negotiate_flags + self._server_challenge = challenge_message.server_challenge + self._server_target_info = challenge_message.target_info + self._ntlm_compatibility = ntlm_compatibility + self._client_challenge = os.urandom(8) + + def get_lm_challenge_response(self): + """ + [MS-NLMP] v28.0 2016-07-14 + + 3.3.1 - NTLM v1 Authentication + 3.3.2 - NTLM v2 Authentication + + This method returns the LmChallengeResponse key based on the ntlm_compatibility chosen + and the target_info supplied by the CHALLENGE_MESSAGE. It is quite different from what + is set in the document as it combines the NTLMv1, NTLM2 and NTLMv2 methods into one + and calls separate methods based on the ntlm_compatibility flag chosen. + + :return: response (LmChallengeResponse) - The LM response to the server challenge. Computed by the client + """ + if self._negotiate_flags & NegotiateFlags.NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY and self._ntlm_compatibility < 3: + response = ComputeResponse._get_LMv1_with_session_security_response(self._client_challenge) + + elif 0 <= self._ntlm_compatibility <= 1: + response = ComputeResponse._get_LMv1_response(self._password, self._server_challenge) + elif self._ntlm_compatibility == 2: + # Based on the compatibility level we don't want to use LM responses, ignore the session_base_key as it is returned in nt + response, ignore_key = ComputeResponse._get_NTLMv1_response(self._password, self._server_challenge) + else: + """ + [MS-NLMP] v28.0 page 45 - 2016-07-14 + + 3.1.5.12 Client Received a CHALLENGE_MESSAGE from the Server + If NTLMv2 authentication is used and the CHALLENGE_MESSAGE TargetInfo field has an MsvAvTimestamp present, + the client SHOULD NOT send the LmChallengeResponse and SHOULD send Z(24) instead. + """ + + response = ComputeResponse._get_LMv2_response(self._user_name, self._password, self._domain_name, + self._server_challenge, + self._client_challenge) + if self._server_target_info is not None: + timestamp = self._server_target_info[TargetInfo.MSV_AV_TIMESTAMP] + if timestamp is not None: + response = b'\0' * 24 + + return response + + def get_nt_challenge_response(self, lm_challenge_response, server_certificate_hash): + """ + [MS-NLMP] v28.0 2016-07-14 + + 3.3.1 - NTLM v1 Authentication + 3.3.2 - NTLM v2 Authentication + + This method returns the NtChallengeResponse key based on the ntlm_compatibility chosen + and the target_info supplied by the CHALLENGE_MESSAGE. It is quite different from what + is set in the document as it combines the NTLMv1, NTLM2 and NTLMv2 methods into one + and calls separate methods based on the ntlm_compatibility value chosen. + + :param lm_challenge_response: The LmChallengeResponse calculated beforeand, used to get the key_exchange_key value + :param server_certificate_hash: The SHA256 hash of the server certificate (DER encoded) NTLM is authenticated to. + Used in Channel Binding Tokens if present, default value is None. See + AuthenticateMessage in messages.py for more details + :return response: (NtChallengeResponse) - The NT response to the server challenge. Computed by the client + :return session_base_key: (SessionBaseKey) - A session key calculated from the user password challenge + :return target_info: (AV_PAIR) - The AV_PAIR structure used in the nt_challenge calculations + """ + if self._negotiate_flags & NegotiateFlags.NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY and self._ntlm_compatibility < 3: + # The compatibility level is less than 3 which means it doesn't support NTLMv2 but we want extended security so use NTLM2 which is different from NTLMv2 + # [MS-NLMP] - 3.3.1 NTLMv1 Authentication + response, session_base_key = ComputeResponse._get_NTLM2_response(self._password, self._server_challenge, self._client_challenge) + key_exchange_key = compkeys._get_exchange_key_ntlm_v1(self._negotiate_flags, session_base_key, + self._server_challenge, lm_challenge_response, + comphash._lmowfv1(self._password)) + target_info = None + + elif 0 <= self._ntlm_compatibility < 3: + response, session_base_key = ComputeResponse._get_NTLMv1_response(self._password, self._server_challenge) + key_exchange_key = compkeys._get_exchange_key_ntlm_v1(self._negotiate_flags, session_base_key, + self._server_challenge, lm_challenge_response, + comphash._lmowfv1(self._password)) + target_info = None + else: + if self._server_target_info is None: + target_info = TargetInfo() + else: + target_info = self._server_target_info + + if target_info[TargetInfo.MSV_AV_TIMESTAMP] is None: + timestamp = get_windows_timestamp() + else: + timestamp = target_info[TargetInfo.MSV_AV_TIMESTAMP][1] + + # [MS-NLMP] If the CHALLENGE_MESSAGE TargetInfo field has an MsvAvTimestamp present, the client SHOULD provide a MIC + target_info[TargetInfo.MSV_AV_FLAGS] = struct.pack(" or . + +""" + [MS-NLMP] v28.0 2016-07-14 + + 2.2 Message Syntax + The signature field used in NTLM messages +""" +NTLM_SIGNATURE = b'NTLMSSP\0' + +""" + [MS-NLMP] v28.0 2016-07-14 + + 2.2 Message Syntax + The 3 message type options you can have in a message. +""" +class MessageTypes(object): + NTLM_NEGOTIATE = 0x1 + NTLM_CHALLENGE = 0x2 + NTLM_AUTHENTICATE = 0x3 + +""" + [MS-NLMP] v28.0 2016-07-14 + + 2.2.2.1 AV_PAIR (MsvAvFlags) + A 32-bit value indicated server or client configuration +""" +class AvFlags(object): + AUTHENTICATION_CONSTRAINED = 0x1 + MIC_PROVIDED = 0x2 + UNTRUSTED_SPN_SOURCE = 0x4 + +""" + [MS-NLMP] v28.0 2016-07-14 + + 2.2.2.5 NEGOTIATE + During NTLM authentication, each of the following flags is a possible value of the + NegotiateFlags field of the NEGOTIATE_MESSAGE, CHALLENGE_MESSAGE and AUTHENTICATE_MESSAGE, + unless otherwise noted. These flags define client or server NTLM capabilities + supported by the sender. +""" +class NegotiateFlags(object): + NTLMSSP_NEGOTIATE_56 = 0x80000000 + NTLMSSP_NEGOTIATE_KEY_EXCH = 0x40000000 + NTLMSSP_NEGOTIATE_128 = 0x20000000 + NTLMSSP_RESERVED_R1 = 0x10000000 + NTLMSSP_RESERVED_R2 = 0x08000000 + NTLMSSP_RESERVED_R3 = 0x04000000 + NTLMSSP_NEGOTIATE_VERSION = 0x02000000 + NTLMSSP_RESERVED_R4 = 0x01000000 + NTLMSSP_NEGOTIATE_TARGET_INFO = 0x00800000 + NTLMSSP_REQUEST_NON_NT_SESSION_KEY = 0x00400000 + NTLMSSP_RESERVED_R5 = 0x00200000 + NTLMSSP_NEGOTIATE_IDENTITY = 0x00100000 + NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY = 0x00080000 + NTLMSSP_RESERVED_R6 = 0x00040000 + NTLMSSP_TARGET_TYPE_SERVER = 0x00020000 + NTLMSSP_TARGET_TYPE_DOMAIN = 0x00010000 + NTLMSSP_NEGOTIATE_ALWAYS_SIGN = 0x00008000 + NTLMSSP_RESERVED_R7 = 0x00004000 + NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED = 0x00002000 + NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED = 0x00001000 + NTLMSSP_ANOYNMOUS = 0x00000800 + NTLMSSP_RESERVED_R8 = 0x00000400 + NTLMSSP_NEGOTIATE_NTLM = 0x00000200 + NTLMSSP_RESERVED_R9 = 0x00000100 + NTLMSSP_NEGOTIATE_LM_KEY = 0x00000080 + NTLMSSP_NEGOTIATE_DATAGRAM = 0x00000040 + NTLMSSP_NEGOTIATE_SEAL = 0x00000020 + NTLMSSP_NEGOTIATE_SIGN = 0x00000010 + NTLMSSP_RESERVED_R10 = 0x00000008 + NTLMSSP_REQUEST_TARGET = 0x00000004 + NTLMSSP_NEGOTIATE_OEM = 0x00000002 + NTLMSSP_NEGOTIATE_UNICODE = 0x00000001 + +class SignSealConstants(object): + # Magic Contants used to get the signing and sealing key for Extended Session Security + CLIENT_SIGNING = b"session key to client-to-server signing key magic constant\0" + SERVER_SIGNING = b"session key to server-to-client signing key magic constant\0" + CLIENT_SEALING = b"session key to client-to-server sealing key magic constant\0" + SERVER_SEALING = b"session key to server-to-client sealing key magic constant\0" diff --git a/ntlm3/des.py b/ntlm3/des.py index f659740..febe5d7 100644 --- a/ntlm3/des.py +++ b/ntlm3/des.py @@ -1,90 +1,90 @@ -# This file is part of 'NTLM Authorization Proxy Server' http://sourceforge.net/projects/ntlmaps/ -# Copyright 2001 Dmitry A. Rozmanov -# -# This library is free software: you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation, either -# version 3 of the License, or (at your option) any later version. - -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library. If not, see or . -import six -import logging - -from . import des_c - - -log = logging.getLogger(__name__) - - -class DES: - des_c_obj = None - - def __init__(self, key_str): - k = str_to_key56(key_str) - k = key56_to_key64(k) - - key_str = b'' - for i in k: - key_str += six.int2byte(i & 0xFF) - - self.des_c_obj = des_c.DES(key_str) - - def encrypt(self, plain_text): - return self.des_c_obj.encrypt(plain_text) - - def decrypt(self, crypted_text): - return self.des_c_obj.decrypt(crypted_text) - - -DESException = 'DESException' - - -def str_to_key56(key_str): - - if not type(key_str) == six.binary_type: - # TODO rsanders high - figure out how to make this not necessary - key_str = key_str.encode('ascii') - - if len(key_str) < 7: - key_str = key_str + b'\000\000\000\000\000\000\000'[:(7 - len(key_str))] - key_56 = [] - for i in six.iterbytes(key_str[:7]): - key_56.append(i) - - return key_56 - - -def key56_to_key64(key_56): - key = [] - for i in range(8): - key.append(0) - - key[0] = key_56[0] - key[1] = ((key_56[0] << 7) & 0xFF) | (key_56[1] >> 1) - key[2] = ((key_56[1] << 6) & 0xFF) | (key_56[2] >> 2) - key[3] = ((key_56[2] << 5) & 0xFF) | (key_56[3] >> 3) - key[4] = ((key_56[3] << 4) & 0xFF) | (key_56[4] >> 4) - key[5] = ((key_56[4] << 3) & 0xFF) | (key_56[5] >> 5) - key[6] = ((key_56[5] << 2) & 0xFF) | (key_56[6] >> 6) - key[7] = (key_56[6] << 1) & 0xFF - - key = set_key_odd_parity(key) - - return key - - -def set_key_odd_parity(key): - for i in range(len(key)): - for k in range(7): - bit = 0 - t = key[i] >> k - bit = (t ^ bit) & 0x1 - key[i] = (key[i] & 0xFE) | bit - - return key +# This file is part of 'NTLM Authorization Proxy Server' http://sourceforge.net/projects/ntlmaps/ +# Copyright 2001 Dmitry A. Rozmanov +# +# This library is free software: you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation, either +# version 3 of the License, or (at your option) any later version. + +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library. If not, see or . +import logging + +import six + +from ntlm3 import des_c + +log = logging.getLogger(__name__) + + +class DES: + des_c_obj = None + + def __init__(self, key_str): + k = str_to_key56(key_str) + k = key56_to_key64(k) + + key_str = b'' + for i in k: + key_str += six.int2byte(i & 0xFF) + + self.des_c_obj = des_c.DES(key_str) + + def encrypt(self, plain_text): + return self.des_c_obj.encrypt(plain_text) + + def decrypt(self, crypted_text): + return self.des_c_obj.decrypt(crypted_text) + + +DESException = 'DESException' + + +def str_to_key56(key_str): + + if not type(key_str) == six.binary_type: + # TODO rsanders high - figure out how to make this not necessary + key_str = key_str.encode('ascii') + + if len(key_str) < 7: + key_str = key_str + b'\000\000\000\000\000\000\000'[:(7 - len(key_str))] + key_56 = [] + for i in six.iterbytes(key_str[:7]): + key_56.append(i) + + return key_56 + + +def key56_to_key64(key_56): + key = [] + for i in range(8): + key.append(0) + + key[0] = key_56[0] + key[1] = ((key_56[0] << 7) & 0xFF) | (key_56[1] >> 1) + key[2] = ((key_56[1] << 6) & 0xFF) | (key_56[2] >> 2) + key[3] = ((key_56[2] << 5) & 0xFF) | (key_56[3] >> 3) + key[4] = ((key_56[3] << 4) & 0xFF) | (key_56[4] >> 4) + key[5] = ((key_56[4] << 3) & 0xFF) | (key_56[5] >> 5) + key[6] = ((key_56[5] << 2) & 0xFF) | (key_56[6] >> 6) + key[7] = (key_56[6] << 1) & 0xFF + + key = set_key_odd_parity(key) + + return key + + +def set_key_odd_parity(key): + for i in range(len(key)): + for k in range(7): + bit = 0 + t = key[i] >> k + bit = (t ^ bit) & 0x1 + key[i] = (key[i] & 0xFE) | bit + + return key diff --git a/ntlm3/des_c.py b/ntlm3/des_c.py index 6ec1e62..e3dfaee 100644 --- a/ntlm3/des_c.py +++ b/ntlm3/des_c.py @@ -1,255 +1,255 @@ -# This file is part of 'NTLM Authorization Proxy Server' http://sourceforge.net/projects/ntlmaps/ -# Copyright 2001 Dmitry A. Rozmanov -# -# This library is free software: you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation, either -# version 3 of the License, or (at your option) any later version. - -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. - -# You should have received a copy of the GNU Lesser General Public -# License along with this library. If not, see or . -import six - -from .U32 import U32 -from .des_data import des_SPtrans, des_skb - - -def c2l(c): - "char[4] to unsigned long" - l = U32(c[0]) - l = l | (U32(c[1]) << 8) - l = l | (U32(c[2]) << 16) - l = l | (U32(c[3]) << 24) - return l - - -def l2c(l): - "unsigned long to char[4]" - c = [] - c.append(int(l & U32(0xFF))) - c.append(int((l >> 8) & U32(0xFF))) - c.append(int((l >> 16) & U32(0xFF))) - c.append(int((l >> 24) & U32(0xFF))) - return c - - -def D_ENCRYPT(tup, u, t, s): - L, R, S = tup - # print 'LRS1', L, R, S, u, t, '-->', - u = (R ^ s[S]) - t = R ^ s[S + 1] - t = ((t >> 4) + (t << 28)) - L = L ^ (des_SPtrans[1][int((t) & U32(0x3f))] | - des_SPtrans[3][int((t >> 8) & U32(0x3f))] | - des_SPtrans[5][int((t >> 16) & U32(0x3f))] | - des_SPtrans[7][int((t >> 24) & U32(0x3f))] | - des_SPtrans[0][int((u) & U32(0x3f))] | - des_SPtrans[2][int((u >> 8) & U32(0x3f))] | - des_SPtrans[4][int((u >> 16) & U32(0x3f))] | - des_SPtrans[6][int((u >> 24) & U32(0x3f))]) - # print 'LRS:', L, R, S, u, t - return (L, R, S), u, t, s - - -def PERM_OP(tup, n, m): - "tup - (a, b, t)" - a, b, t = tup - t = ((a >> n) ^ b) & m - b = b ^ t - a = a ^ (t << n) - return (a, b, t) - - -def HPERM_OP(tup, n, m): - "tup - (a, t)" - a, t = tup - t = ((a << (16 - n)) ^ a) & m - a = a ^ t ^ (t >> (16 - n)) - return a, t - - -shifts2 = [0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0] - - -class DES: - KeySched = None # des_key_schedule - - def __init__(self, key_str): - self.KeySched = des_set_key(key_str) - - def decrypt(self, str): - # block - UChar[] - block = [] - - for i in six.iterbytes(str): - block.append(i) - - # print block - block = des_ecb_encrypt(block, self.KeySched, 0) - - res = b'' - for i in block: - res = res + six.int2byte(i) - - return res - - def encrypt(self, plaintext): - # block - UChar[] - - block = [] - for i in plaintext: - block.append(i) - - block = des_ecb_encrypt(block, self.KeySched, 1) - - res = b'' - - for i in block: - res += six.int2byte(i) - - return res - - -def des_encript(input, ks, encrypt): - # input - U32[] - # output - U32[] - # ks - des_key_shedule - U32[2][16] - # encrypt - int - # l, r, t, u - U32 - # i - int - # s - U32[] - - l = input[0] - r = input[1] - t = U32(0) - u = U32(0) - - r, l, t = PERM_OP((r, l, t), 4, U32(0x0f0f0f0f)) - l, r, t = PERM_OP((l, r, t), 16, U32(0x0000ffff)) - r, l, t = PERM_OP((r, l, t), 2, U32(0x33333333)) - l, r, t = PERM_OP((l, r, t), 8, U32(0x00ff00ff)) - r, l, t = PERM_OP((r, l, t), 1, U32(0x55555555)) - - t = (r << 1) | (r >> 31) - r = (l << 1) | (l >> 31) - l = t - - s = ks # ??????????????? - # print l, r - if encrypt: - for i in range(0, 32, 4): - rtup, u, t, s = D_ENCRYPT((l, r, i + 0), u, t, s) - l = rtup[0] - r = rtup[1] - rtup, u, t, s = D_ENCRYPT((r, l, i + 2), u, t, s) - r = rtup[0] - l = rtup[1] - else: - for i in range(30, 0, -4): - rtup, u, t, s = D_ENCRYPT((l, r, i - 0), u, t, s) - l = rtup[0] - r = rtup[1] - rtup, u, t, s = D_ENCRYPT((r, l, i - 2), u, t, s) - r = rtup[0] - l = rtup[1] - # print l, r - l = (l >> 1) | (l << 31) - r = (r >> 1) | (r << 31) - - r, l, t = PERM_OP((r, l, t), 1, U32(0x55555555)) - l, r, t = PERM_OP((l, r, t), 8, U32(0x00ff00ff)) - r, l, t = PERM_OP((r, l, t), 2, U32(0x33333333)) - l, r, t = PERM_OP((l, r, t), 16, U32(0x0000ffff)) - r, l, t = PERM_OP((r, l, t), 4, U32(0x0f0f0f0f)) - - output = [l] - output.append(r) - l, r, t, u = U32(0), U32(0), U32(0), U32(0) - return output - - -def des_ecb_encrypt(input, ks, encrypt): - # input - des_cblock - UChar[8] - # output - des_cblock - UChar[8] - # ks - des_key_shedule - U32[2][16] - # encrypt - int - - # print input - l0 = c2l(input[0:4]) - l1 = c2l(input[4:8]) - ll = [l0] - ll.append(l1) - # print ll - ll = des_encript(ll, ks, encrypt) - # print ll - l0 = ll[0] - l1 = ll[1] - output = l2c(l0) - output = output + l2c(l1) - # print output - l0, l1, ll[0], ll[1] = U32(0), U32(0), U32(0), U32(0) - return output - - -def des_set_key(key): - # key - des_cblock - UChar[8] - # schedule - des_key_schedule - - # register unsigned long c,d,t,s; - # register unsigned char *in; - # register unsigned long *k; - # register int i; - - # k = schedule - # in = key - - k = [] - c = c2l(key[0:4]) - d = c2l(key[4:8]) - t = U32(0) - - d, c, t = PERM_OP((d, c, t), 4, U32(0x0f0f0f0f)) - c, t = HPERM_OP((c, t), -2, U32(0xcccc0000)) - d, t = HPERM_OP((d, t), -2, U32(0xcccc0000)) - d, c, t = PERM_OP((d, c, t), 1, U32(0x55555555)) - c, d, t = PERM_OP((c, d, t), 8, U32(0x00ff00ff)) - d, c, t = PERM_OP((d, c, t), 1, U32(0x55555555)) - - d = (((d & U32(0x000000ff)) << 16) | (d & U32(0x0000ff00)) | ((d & U32(0x00ff0000)) >> 16) | ( - (c & U32(0xf0000000)) >> 4)) - c = c & U32(0x0fffffff) - - for i in range(16): - if (shifts2[i]): - c = ((c >> 2) | (c << 26)) - d = ((d >> 2) | (d << 26)) - else: - c = ((c >> 1) | (c << 27)) - d = ((d >> 1) | (d << 27)) - c = c & U32(0x0fffffff) - d = d & U32(0x0fffffff) - - s = des_skb[0][int((c) & U32(0x3f))] | \ - des_skb[1][int(((c >> 6) & U32(0x03)) | ((c >> 7) & U32(0x3c)))] | \ - des_skb[2][int(((c >> 13) & U32(0x0f)) | ((c >> 14) & U32(0x30)))] | \ - des_skb[3][int(((c >> 20) & U32(0x01)) | ((c >> 21) & U32(0x06)) | ((c >> 22) & U32(0x38)))] - - t = des_skb[4][int((d) & U32(0x3f))] | \ - des_skb[5][int(((d >> 7) & U32(0x03)) | ((d >> 8) & U32(0x3c)))] | \ - des_skb[6][int((d >> 15) & U32(0x3f))] | \ - des_skb[7][int(((d >> 21) & U32(0x0f)) | ((d >> 22) & U32(0x30)))] - # print s, t - - k.append(((t << 16) | (s & U32(0x0000ffff))) & U32(0xffffffff)) - s = ((s >> 16) | (t & U32(0xffff0000))) - s = (s << 4) | (s >> 28) - k.append(s & U32(0xffffffff)) - - schedule = k - - return schedule +# This file is part of 'NTLM Authorization Proxy Server' http://sourceforge.net/projects/ntlmaps/ +# Copyright 2001 Dmitry A. Rozmanov +# +# This library is free software: you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation, either +# version 3 of the License, or (at your option) any later version. + +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. + +# You should have received a copy of the GNU Lesser General Public +# License along with this library. If not, see or . +import six + +from ntlm3.U32 import U32 +from ntlm3.des_data import des_SPtrans, des_skb + + +def c2l(c): + "char[4] to unsigned long" + l = U32(c[0]) + l = l | (U32(c[1]) << 8) + l = l | (U32(c[2]) << 16) + l = l | (U32(c[3]) << 24) + return l + + +def l2c(l): + "unsigned long to char[4]" + c = [] + c.append(int(l & U32(0xFF))) + c.append(int((l >> 8) & U32(0xFF))) + c.append(int((l >> 16) & U32(0xFF))) + c.append(int((l >> 24) & U32(0xFF))) + return c + + +def D_ENCRYPT(tup, u, t, s): + L, R, S = tup + # print 'LRS1', L, R, S, u, t, '-->', + u = (R ^ s[S]) + t = R ^ s[S + 1] + t = ((t >> 4) + (t << 28)) + L = L ^ (des_SPtrans[1][int((t) & U32(0x3f))] | + des_SPtrans[3][int((t >> 8) & U32(0x3f))] | + des_SPtrans[5][int((t >> 16) & U32(0x3f))] | + des_SPtrans[7][int((t >> 24) & U32(0x3f))] | + des_SPtrans[0][int((u) & U32(0x3f))] | + des_SPtrans[2][int((u >> 8) & U32(0x3f))] | + des_SPtrans[4][int((u >> 16) & U32(0x3f))] | + des_SPtrans[6][int((u >> 24) & U32(0x3f))]) + # print 'LRS:', L, R, S, u, t + return (L, R, S), u, t, s + + +def PERM_OP(tup, n, m): + "tup - (a, b, t)" + a, b, t = tup + t = ((a >> n) ^ b) & m + b = b ^ t + a = a ^ (t << n) + return (a, b, t) + + +def HPERM_OP(tup, n, m): + "tup - (a, t)" + a, t = tup + t = ((a << (16 - n)) ^ a) & m + a = a ^ t ^ (t >> (16 - n)) + return a, t + + +shifts2 = [0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0] + + +class DES: + KeySched = None # des_key_schedule + + def __init__(self, key_str): + self.KeySched = des_set_key(key_str) + + def decrypt(self, str): + # block - UChar[] + block = [] + + for i in six.iterbytes(str): + block.append(i) + + # print block + block = des_ecb_encrypt(block, self.KeySched, 0) + + res = b'' + for i in block: + res = res + six.int2byte(i) + + return res + + def encrypt(self, plaintext): + # block - UChar[] + + block = [] + for i in plaintext: + block.append(i) + + block = des_ecb_encrypt(block, self.KeySched, 1) + + res = b'' + + for i in block: + res += six.int2byte(i) + + return res + + +def des_encript(input, ks, encrypt): + # input - U32[] + # output - U32[] + # ks - des_key_shedule - U32[2][16] + # encrypt - int + # l, r, t, u - U32 + # i - int + # s - U32[] + + l = input[0] + r = input[1] + t = U32(0) + u = U32(0) + + r, l, t = PERM_OP((r, l, t), 4, U32(0x0f0f0f0f)) + l, r, t = PERM_OP((l, r, t), 16, U32(0x0000ffff)) + r, l, t = PERM_OP((r, l, t), 2, U32(0x33333333)) + l, r, t = PERM_OP((l, r, t), 8, U32(0x00ff00ff)) + r, l, t = PERM_OP((r, l, t), 1, U32(0x55555555)) + + t = (r << 1) | (r >> 31) + r = (l << 1) | (l >> 31) + l = t + + s = ks # ??????????????? + # print l, r + if encrypt: + for i in range(0, 32, 4): + rtup, u, t, s = D_ENCRYPT((l, r, i + 0), u, t, s) + l = rtup[0] + r = rtup[1] + rtup, u, t, s = D_ENCRYPT((r, l, i + 2), u, t, s) + r = rtup[0] + l = rtup[1] + else: + for i in range(30, 0, -4): + rtup, u, t, s = D_ENCRYPT((l, r, i - 0), u, t, s) + l = rtup[0] + r = rtup[1] + rtup, u, t, s = D_ENCRYPT((r, l, i - 2), u, t, s) + r = rtup[0] + l = rtup[1] + # print l, r + l = (l >> 1) | (l << 31) + r = (r >> 1) | (r << 31) + + r, l, t = PERM_OP((r, l, t), 1, U32(0x55555555)) + l, r, t = PERM_OP((l, r, t), 8, U32(0x00ff00ff)) + r, l, t = PERM_OP((r, l, t), 2, U32(0x33333333)) + l, r, t = PERM_OP((l, r, t), 16, U32(0x0000ffff)) + r, l, t = PERM_OP((r, l, t), 4, U32(0x0f0f0f0f)) + + output = [l] + output.append(r) + l, r, t, u = U32(0), U32(0), U32(0), U32(0) + return output + + +def des_ecb_encrypt(input, ks, encrypt): + # input - des_cblock - UChar[8] + # output - des_cblock - UChar[8] + # ks - des_key_shedule - U32[2][16] + # encrypt - int + + # print input + l0 = c2l(input[0:4]) + l1 = c2l(input[4:8]) + ll = [l0] + ll.append(l1) + # print ll + ll = des_encript(ll, ks, encrypt) + # print ll + l0 = ll[0] + l1 = ll[1] + output = l2c(l0) + output = output + l2c(l1) + # print output + l0, l1, ll[0], ll[1] = U32(0), U32(0), U32(0), U32(0) + return output + + +def des_set_key(key): + # key - des_cblock - UChar[8] + # schedule - des_key_schedule + + # register unsigned long c,d,t,s; + # register unsigned char *in; + # register unsigned long *k; + # register int i; + + # k = schedule + # in = key + + k = [] + c = c2l(key[0:4]) + d = c2l(key[4:8]) + t = U32(0) + + d, c, t = PERM_OP((d, c, t), 4, U32(0x0f0f0f0f)) + c, t = HPERM_OP((c, t), -2, U32(0xcccc0000)) + d, t = HPERM_OP((d, t), -2, U32(0xcccc0000)) + d, c, t = PERM_OP((d, c, t), 1, U32(0x55555555)) + c, d, t = PERM_OP((c, d, t), 8, U32(0x00ff00ff)) + d, c, t = PERM_OP((d, c, t), 1, U32(0x55555555)) + + d = (((d & U32(0x000000ff)) << 16) | (d & U32(0x0000ff00)) | ((d & U32(0x00ff0000)) >> 16) | ( + (c & U32(0xf0000000)) >> 4)) + c = c & U32(0x0fffffff) + + for i in range(16): + if (shifts2[i]): + c = ((c >> 2) | (c << 26)) + d = ((d >> 2) | (d << 26)) + else: + c = ((c >> 1) | (c << 27)) + d = ((d >> 1) | (d << 27)) + c = c & U32(0x0fffffff) + d = d & U32(0x0fffffff) + + s = des_skb[0][int((c) & U32(0x3f))] | \ + des_skb[1][int(((c >> 6) & U32(0x03)) | ((c >> 7) & U32(0x3c)))] | \ + des_skb[2][int(((c >> 13) & U32(0x0f)) | ((c >> 14) & U32(0x30)))] | \ + des_skb[3][int(((c >> 20) & U32(0x01)) | ((c >> 21) & U32(0x06)) | ((c >> 22) & U32(0x38)))] + + t = des_skb[4][int((d) & U32(0x3f))] | \ + des_skb[5][int(((d >> 7) & U32(0x03)) | ((d >> 8) & U32(0x3c)))] | \ + des_skb[6][int((d >> 15) & U32(0x3f))] | \ + des_skb[7][int(((d >> 21) & U32(0x0f)) | ((d >> 22) & U32(0x30)))] + # print s, t + + k.append(((t << 16) | (s & U32(0x0000ffff))) & U32(0xffffffff)) + s = ((s >> 16) | (t & U32(0xffff0000))) + s = (s << 4) | (s >> 28) + k.append(s & U32(0xffffffff)) + + schedule = k + + return schedule diff --git a/ntlm3/des_data.py b/ntlm3/des_data.py index d5bee66..789c47c 100644 --- a/ntlm3/des_data.py +++ b/ntlm3/des_data.py @@ -1,348 +1,348 @@ -# This file is part of 'NTLM Authorization Proxy Server' http://sourceforge.net/projects/ntlmaps/ -# Copyright 2001 Dmitry A. Rozmanov -# -# This library is free software: you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation, either -# version 3 of the License, or (at your option) any later version. - -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. - -# You should have received a copy of the GNU Lesser General Public -# License along with this library. If not, see or . - -from .U32 import U32 - -# static unsigned long des_SPtrans[8][64]={ - -des_SPtrans = \ - [ - # nibble 0 - [ - U32(0x00820200), U32(0x00020000), U32(0x80800000), U32(0x80820200), - U32(0x00800000), U32(0x80020200), U32(0x80020000), U32(0x80800000), - U32(0x80020200), U32(0x00820200), U32(0x00820000), U32(0x80000200), - U32(0x80800200), U32(0x00800000), U32(0x00000000), U32(0x80020000), - U32(0x00020000), U32(0x80000000), U32(0x00800200), U32(0x00020200), - U32(0x80820200), U32(0x00820000), U32(0x80000200), U32(0x00800200), - U32(0x80000000), U32(0x00000200), U32(0x00020200), U32(0x80820000), - U32(0x00000200), U32(0x80800200), U32(0x80820000), U32(0x00000000), - U32(0x00000000), U32(0x80820200), U32(0x00800200), U32(0x80020000), - U32(0x00820200), U32(0x00020000), U32(0x80000200), U32(0x00800200), - U32(0x80820000), U32(0x00000200), U32(0x00020200), U32(0x80800000), - U32(0x80020200), U32(0x80000000), U32(0x80800000), U32(0x00820000), - U32(0x80820200), U32(0x00020200), U32(0x00820000), U32(0x80800200), - U32(0x00800000), U32(0x80000200), U32(0x80020000), U32(0x00000000), - U32(0x00020000), U32(0x00800000), U32(0x80800200), U32(0x00820200), - U32(0x80000000), U32(0x80820000), U32(0x00000200), U32(0x80020200), - ], - - # nibble 1 - [ - U32(0x10042004), U32(0x00000000), U32(0x00042000), U32(0x10040000), - U32(0x10000004), U32(0x00002004), U32(0x10002000), U32(0x00042000), - U32(0x00002000), U32(0x10040004), U32(0x00000004), U32(0x10002000), - U32(0x00040004), U32(0x10042000), U32(0x10040000), U32(0x00000004), - U32(0x00040000), U32(0x10002004), U32(0x10040004), U32(0x00002000), - U32(0x00042004), U32(0x10000000), U32(0x00000000), U32(0x00040004), - U32(0x10002004), U32(0x00042004), U32(0x10042000), U32(0x10000004), - U32(0x10000000), U32(0x00040000), U32(0x00002004), U32(0x10042004), - U32(0x00040004), U32(0x10042000), U32(0x10002000), U32(0x00042004), - U32(0x10042004), U32(0x00040004), U32(0x10000004), U32(0x00000000), - U32(0x10000000), U32(0x00002004), U32(0x00040000), U32(0x10040004), - U32(0x00002000), U32(0x10000000), U32(0x00042004), U32(0x10002004), - U32(0x10042000), U32(0x00002000), U32(0x00000000), U32(0x10000004), - U32(0x00000004), U32(0x10042004), U32(0x00042000), U32(0x10040000), - U32(0x10040004), U32(0x00040000), U32(0x00002004), U32(0x10002000), - U32(0x10002004), U32(0x00000004), U32(0x10040000), U32(0x00042000), - ], - - # nibble 2 - [ - U32(0x41000000), U32(0x01010040), U32(0x00000040), U32(0x41000040), - U32(0x40010000), U32(0x01000000), U32(0x41000040), U32(0x00010040), - U32(0x01000040), U32(0x00010000), U32(0x01010000), U32(0x40000000), - U32(0x41010040), U32(0x40000040), U32(0x40000000), U32(0x41010000), - U32(0x00000000), U32(0x40010000), U32(0x01010040), U32(0x00000040), - U32(0x40000040), U32(0x41010040), U32(0x00010000), U32(0x41000000), - U32(0x41010000), U32(0x01000040), U32(0x40010040), U32(0x01010000), - U32(0x00010040), U32(0x00000000), U32(0x01000000), U32(0x40010040), - U32(0x01010040), U32(0x00000040), U32(0x40000000), U32(0x00010000), - U32(0x40000040), U32(0x40010000), U32(0x01010000), U32(0x41000040), - U32(0x00000000), U32(0x01010040), U32(0x00010040), U32(0x41010000), - U32(0x40010000), U32(0x01000000), U32(0x41010040), U32(0x40000000), - U32(0x40010040), U32(0x41000000), U32(0x01000000), U32(0x41010040), - U32(0x00010000), U32(0x01000040), U32(0x41000040), U32(0x00010040), - U32(0x01000040), U32(0x00000000), U32(0x41010000), U32(0x40000040), - U32(0x41000000), U32(0x40010040), U32(0x00000040), U32(0x01010000), - ], - - # nibble 3 - [ - U32(0x00100402), U32(0x04000400), U32(0x00000002), U32(0x04100402), - U32(0x00000000), U32(0x04100000), U32(0x04000402), U32(0x00100002), - U32(0x04100400), U32(0x04000002), U32(0x04000000), U32(0x00000402), - U32(0x04000002), U32(0x00100402), U32(0x00100000), U32(0x04000000), - U32(0x04100002), U32(0x00100400), U32(0x00000400), U32(0x00000002), - U32(0x00100400), U32(0x04000402), U32(0x04100000), U32(0x00000400), - U32(0x00000402), U32(0x00000000), U32(0x00100002), U32(0x04100400), - U32(0x04000400), U32(0x04100002), U32(0x04100402), U32(0x00100000), - U32(0x04100002), U32(0x00000402), U32(0x00100000), U32(0x04000002), - U32(0x00100400), U32(0x04000400), U32(0x00000002), U32(0x04100000), - U32(0x04000402), U32(0x00000000), U32(0x00000400), U32(0x00100002), - U32(0x00000000), U32(0x04100002), U32(0x04100400), U32(0x00000400), - U32(0x04000000), U32(0x04100402), U32(0x00100402), U32(0x00100000), - U32(0x04100402), U32(0x00000002), U32(0x04000400), U32(0x00100402), - U32(0x00100002), U32(0x00100400), U32(0x04100000), U32(0x04000402), - U32(0x00000402), U32(0x04000000), U32(0x04000002), U32(0x04100400), - ], - - # nibble 4 - [ - U32(0x02000000), U32(0x00004000), U32(0x00000100), U32(0x02004108), - U32(0x02004008), U32(0x02000100), U32(0x00004108), U32(0x02004000), - U32(0x00004000), U32(0x00000008), U32(0x02000008), U32(0x00004100), - U32(0x02000108), U32(0x02004008), U32(0x02004100), U32(0x00000000), - U32(0x00004100), U32(0x02000000), U32(0x00004008), U32(0x00000108), - U32(0x02000100), U32(0x00004108), U32(0x00000000), U32(0x02000008), - U32(0x00000008), U32(0x02000108), U32(0x02004108), U32(0x00004008), - U32(0x02004000), U32(0x00000100), U32(0x00000108), U32(0x02004100), - U32(0x02004100), U32(0x02000108), U32(0x00004008), U32(0x02004000), - U32(0x00004000), U32(0x00000008), U32(0x02000008), U32(0x02000100), - U32(0x02000000), U32(0x00004100), U32(0x02004108), U32(0x00000000), - U32(0x00004108), U32(0x02000000), U32(0x00000100), U32(0x00004008), - U32(0x02000108), U32(0x00000100), U32(0x00000000), U32(0x02004108), - U32(0x02004008), U32(0x02004100), U32(0x00000108), U32(0x00004000), - U32(0x00004100), U32(0x02004008), U32(0x02000100), U32(0x00000108), - U32(0x00000008), U32(0x00004108), U32(0x02004000), U32(0x02000008), - ], - - # nibble 5 - [ - U32(0x20000010), U32(0x00080010), U32(0x00000000), U32(0x20080800), - U32(0x00080010), U32(0x00000800), U32(0x20000810), U32(0x00080000), - U32(0x00000810), U32(0x20080810), U32(0x00080800), U32(0x20000000), - U32(0x20000800), U32(0x20000010), U32(0x20080000), U32(0x00080810), - U32(0x00080000), U32(0x20000810), U32(0x20080010), U32(0x00000000), - U32(0x00000800), U32(0x00000010), U32(0x20080800), U32(0x20080010), - U32(0x20080810), U32(0x20080000), U32(0x20000000), U32(0x00000810), - U32(0x00000010), U32(0x00080800), U32(0x00080810), U32(0x20000800), - U32(0x00000810), U32(0x20000000), U32(0x20000800), U32(0x00080810), - U32(0x20080800), U32(0x00080010), U32(0x00000000), U32(0x20000800), - U32(0x20000000), U32(0x00000800), U32(0x20080010), U32(0x00080000), - U32(0x00080010), U32(0x20080810), U32(0x00080800), U32(0x00000010), - U32(0x20080810), U32(0x00080800), U32(0x00080000), U32(0x20000810), - U32(0x20000010), U32(0x20080000), U32(0x00080810), U32(0x00000000), - U32(0x00000800), U32(0x20000010), U32(0x20000810), U32(0x20080800), - U32(0x20080000), U32(0x00000810), U32(0x00000010), U32(0x20080010), - ], - - # nibble 6 - [ - U32(0x00001000), U32(0x00000080), U32(0x00400080), U32(0x00400001), - U32(0x00401081), U32(0x00001001), U32(0x00001080), U32(0x00000000), - U32(0x00400000), U32(0x00400081), U32(0x00000081), U32(0x00401000), - U32(0x00000001), U32(0x00401080), U32(0x00401000), U32(0x00000081), - U32(0x00400081), U32(0x00001000), U32(0x00001001), U32(0x00401081), - U32(0x00000000), U32(0x00400080), U32(0x00400001), U32(0x00001080), - U32(0x00401001), U32(0x00001081), U32(0x00401080), U32(0x00000001), - U32(0x00001081), U32(0x00401001), U32(0x00000080), U32(0x00400000), - U32(0x00001081), U32(0x00401000), U32(0x00401001), U32(0x00000081), - U32(0x00001000), U32(0x00000080), U32(0x00400000), U32(0x00401001), - U32(0x00400081), U32(0x00001081), U32(0x00001080), U32(0x00000000), - U32(0x00000080), U32(0x00400001), U32(0x00000001), U32(0x00400080), - U32(0x00000000), U32(0x00400081), U32(0x00400080), U32(0x00001080), - U32(0x00000081), U32(0x00001000), U32(0x00401081), U32(0x00400000), - U32(0x00401080), U32(0x00000001), U32(0x00001001), U32(0x00401081), - U32(0x00400001), U32(0x00401080), U32(0x00401000), U32(0x00001001), - ], - - # nibble 7 - [ - U32(0x08200020), U32(0x08208000), U32(0x00008020), U32(0x00000000), - U32(0x08008000), U32(0x00200020), U32(0x08200000), U32(0x08208020), - U32(0x00000020), U32(0x08000000), U32(0x00208000), U32(0x00008020), - U32(0x00208020), U32(0x08008020), U32(0x08000020), U32(0x08200000), - U32(0x00008000), U32(0x00208020), U32(0x00200020), U32(0x08008000), - U32(0x08208020), U32(0x08000020), U32(0x00000000), U32(0x00208000), - U32(0x08000000), U32(0x00200000), U32(0x08008020), U32(0x08200020), - U32(0x00200000), U32(0x00008000), U32(0x08208000), U32(0x00000020), - U32(0x00200000), U32(0x00008000), U32(0x08000020), U32(0x08208020), - U32(0x00008020), U32(0x08000000), U32(0x00000000), U32(0x00208000), - U32(0x08200020), U32(0x08008020), U32(0x08008000), U32(0x00200020), - U32(0x08208000), U32(0x00000020), U32(0x00200020), U32(0x08008000), - U32(0x08208020), U32(0x00200000), U32(0x08200000), U32(0x08000020), - U32(0x00208000), U32(0x00008020), U32(0x08008020), U32(0x08200000), - U32(0x00000020), U32(0x08208000), U32(0x00208020), U32(0x00000000), - U32(0x08000000), U32(0x08200020), U32(0x00008000), U32(0x00208020), - ], - ] - -# static unsigned long des_skb[8][64]={ - -des_skb = \ - [ - # for C bits (numbered as per FIPS 46) 1 2 3 4 5 6 - [ - U32(0x00000000), U32(0x00000010), U32(0x20000000), U32(0x20000010), - U32(0x00010000), U32(0x00010010), U32(0x20010000), U32(0x20010010), - U32(0x00000800), U32(0x00000810), U32(0x20000800), U32(0x20000810), - U32(0x00010800), U32(0x00010810), U32(0x20010800), U32(0x20010810), - U32(0x00000020), U32(0x00000030), U32(0x20000020), U32(0x20000030), - U32(0x00010020), U32(0x00010030), U32(0x20010020), U32(0x20010030), - U32(0x00000820), U32(0x00000830), U32(0x20000820), U32(0x20000830), - U32(0x00010820), U32(0x00010830), U32(0x20010820), U32(0x20010830), - U32(0x00080000), U32(0x00080010), U32(0x20080000), U32(0x20080010), - U32(0x00090000), U32(0x00090010), U32(0x20090000), U32(0x20090010), - U32(0x00080800), U32(0x00080810), U32(0x20080800), U32(0x20080810), - U32(0x00090800), U32(0x00090810), U32(0x20090800), U32(0x20090810), - U32(0x00080020), U32(0x00080030), U32(0x20080020), U32(0x20080030), - U32(0x00090020), U32(0x00090030), U32(0x20090020), U32(0x20090030), - U32(0x00080820), U32(0x00080830), U32(0x20080820), U32(0x20080830), - U32(0x00090820), U32(0x00090830), U32(0x20090820), U32(0x20090830), - ], - - # for C bits (numbered as per FIPS 46) 7 8 10 11 12 13 - [ - U32(0x00000000), U32(0x02000000), U32(0x00002000), U32(0x02002000), - U32(0x00200000), U32(0x02200000), U32(0x00202000), U32(0x02202000), - U32(0x00000004), U32(0x02000004), U32(0x00002004), U32(0x02002004), - U32(0x00200004), U32(0x02200004), U32(0x00202004), U32(0x02202004), - U32(0x00000400), U32(0x02000400), U32(0x00002400), U32(0x02002400), - U32(0x00200400), U32(0x02200400), U32(0x00202400), U32(0x02202400), - U32(0x00000404), U32(0x02000404), U32(0x00002404), U32(0x02002404), - U32(0x00200404), U32(0x02200404), U32(0x00202404), U32(0x02202404), - U32(0x10000000), U32(0x12000000), U32(0x10002000), U32(0x12002000), - U32(0x10200000), U32(0x12200000), U32(0x10202000), U32(0x12202000), - U32(0x10000004), U32(0x12000004), U32(0x10002004), U32(0x12002004), - U32(0x10200004), U32(0x12200004), U32(0x10202004), U32(0x12202004), - U32(0x10000400), U32(0x12000400), U32(0x10002400), U32(0x12002400), - U32(0x10200400), U32(0x12200400), U32(0x10202400), U32(0x12202400), - U32(0x10000404), U32(0x12000404), U32(0x10002404), U32(0x12002404), - U32(0x10200404), U32(0x12200404), U32(0x10202404), U32(0x12202404), - ], - - # for C bits (numbered as per FIPS 46) 14 15 16 17 19 20 - [ - U32(0x00000000), U32(0x00000001), U32(0x00040000), U32(0x00040001), - U32(0x01000000), U32(0x01000001), U32(0x01040000), U32(0x01040001), - U32(0x00000002), U32(0x00000003), U32(0x00040002), U32(0x00040003), - U32(0x01000002), U32(0x01000003), U32(0x01040002), U32(0x01040003), - U32(0x00000200), U32(0x00000201), U32(0x00040200), U32(0x00040201), - U32(0x01000200), U32(0x01000201), U32(0x01040200), U32(0x01040201), - U32(0x00000202), U32(0x00000203), U32(0x00040202), U32(0x00040203), - U32(0x01000202), U32(0x01000203), U32(0x01040202), U32(0x01040203), - U32(0x08000000), U32(0x08000001), U32(0x08040000), U32(0x08040001), - U32(0x09000000), U32(0x09000001), U32(0x09040000), U32(0x09040001), - U32(0x08000002), U32(0x08000003), U32(0x08040002), U32(0x08040003), - U32(0x09000002), U32(0x09000003), U32(0x09040002), U32(0x09040003), - U32(0x08000200), U32(0x08000201), U32(0x08040200), U32(0x08040201), - U32(0x09000200), U32(0x09000201), U32(0x09040200), U32(0x09040201), - U32(0x08000202), U32(0x08000203), U32(0x08040202), U32(0x08040203), - U32(0x09000202), U32(0x09000203), U32(0x09040202), U32(0x09040203), - ], - - # for C bits (numbered as per FIPS 46) 21 23 24 26 27 28 - [ - U32(0x00000000), U32(0x00100000), U32(0x00000100), U32(0x00100100), - U32(0x00000008), U32(0x00100008), U32(0x00000108), U32(0x00100108), - U32(0x00001000), U32(0x00101000), U32(0x00001100), U32(0x00101100), - U32(0x00001008), U32(0x00101008), U32(0x00001108), U32(0x00101108), - U32(0x04000000), U32(0x04100000), U32(0x04000100), U32(0x04100100), - U32(0x04000008), U32(0x04100008), U32(0x04000108), U32(0x04100108), - U32(0x04001000), U32(0x04101000), U32(0x04001100), U32(0x04101100), - U32(0x04001008), U32(0x04101008), U32(0x04001108), U32(0x04101108), - U32(0x00020000), U32(0x00120000), U32(0x00020100), U32(0x00120100), - U32(0x00020008), U32(0x00120008), U32(0x00020108), U32(0x00120108), - U32(0x00021000), U32(0x00121000), U32(0x00021100), U32(0x00121100), - U32(0x00021008), U32(0x00121008), U32(0x00021108), U32(0x00121108), - U32(0x04020000), U32(0x04120000), U32(0x04020100), U32(0x04120100), - U32(0x04020008), U32(0x04120008), U32(0x04020108), U32(0x04120108), - U32(0x04021000), U32(0x04121000), U32(0x04021100), U32(0x04121100), - U32(0x04021008), U32(0x04121008), U32(0x04021108), U32(0x04121108), - ], - - # for D bits (numbered as per FIPS 46) 1 2 3 4 5 6 - [ - U32(0x00000000), U32(0x10000000), U32(0x00010000), U32(0x10010000), - U32(0x00000004), U32(0x10000004), U32(0x00010004), U32(0x10010004), - U32(0x20000000), U32(0x30000000), U32(0x20010000), U32(0x30010000), - U32(0x20000004), U32(0x30000004), U32(0x20010004), U32(0x30010004), - U32(0x00100000), U32(0x10100000), U32(0x00110000), U32(0x10110000), - U32(0x00100004), U32(0x10100004), U32(0x00110004), U32(0x10110004), - U32(0x20100000), U32(0x30100000), U32(0x20110000), U32(0x30110000), - U32(0x20100004), U32(0x30100004), U32(0x20110004), U32(0x30110004), - U32(0x00001000), U32(0x10001000), U32(0x00011000), U32(0x10011000), - U32(0x00001004), U32(0x10001004), U32(0x00011004), U32(0x10011004), - U32(0x20001000), U32(0x30001000), U32(0x20011000), U32(0x30011000), - U32(0x20001004), U32(0x30001004), U32(0x20011004), U32(0x30011004), - U32(0x00101000), U32(0x10101000), U32(0x00111000), U32(0x10111000), - U32(0x00101004), U32(0x10101004), U32(0x00111004), U32(0x10111004), - U32(0x20101000), U32(0x30101000), U32(0x20111000), U32(0x30111000), - U32(0x20101004), U32(0x30101004), U32(0x20111004), U32(0x30111004), - ], - - # for D bits (numbered as per FIPS 46) 8 9 11 12 13 14 - [ - U32(0x00000000), U32(0x08000000), U32(0x00000008), U32(0x08000008), - U32(0x00000400), U32(0x08000400), U32(0x00000408), U32(0x08000408), - U32(0x00020000), U32(0x08020000), U32(0x00020008), U32(0x08020008), - U32(0x00020400), U32(0x08020400), U32(0x00020408), U32(0x08020408), - U32(0x00000001), U32(0x08000001), U32(0x00000009), U32(0x08000009), - U32(0x00000401), U32(0x08000401), U32(0x00000409), U32(0x08000409), - U32(0x00020001), U32(0x08020001), U32(0x00020009), U32(0x08020009), - U32(0x00020401), U32(0x08020401), U32(0x00020409), U32(0x08020409), - U32(0x02000000), U32(0x0A000000), U32(0x02000008), U32(0x0A000008), - U32(0x02000400), U32(0x0A000400), U32(0x02000408), U32(0x0A000408), - U32(0x02020000), U32(0x0A020000), U32(0x02020008), U32(0x0A020008), - U32(0x02020400), U32(0x0A020400), U32(0x02020408), U32(0x0A020408), - U32(0x02000001), U32(0x0A000001), U32(0x02000009), U32(0x0A000009), - U32(0x02000401), U32(0x0A000401), U32(0x02000409), U32(0x0A000409), - U32(0x02020001), U32(0x0A020001), U32(0x02020009), U32(0x0A020009), - U32(0x02020401), U32(0x0A020401), U32(0x02020409), U32(0x0A020409), - ], - - # for D bits (numbered as per FIPS 46) 16 17 18 19 20 21 - [ - U32(0x00000000), U32(0x00000100), U32(0x00080000), U32(0x00080100), - U32(0x01000000), U32(0x01000100), U32(0x01080000), U32(0x01080100), - U32(0x00000010), U32(0x00000110), U32(0x00080010), U32(0x00080110), - U32(0x01000010), U32(0x01000110), U32(0x01080010), U32(0x01080110), - U32(0x00200000), U32(0x00200100), U32(0x00280000), U32(0x00280100), - U32(0x01200000), U32(0x01200100), U32(0x01280000), U32(0x01280100), - U32(0x00200010), U32(0x00200110), U32(0x00280010), U32(0x00280110), - U32(0x01200010), U32(0x01200110), U32(0x01280010), U32(0x01280110), - U32(0x00000200), U32(0x00000300), U32(0x00080200), U32(0x00080300), - U32(0x01000200), U32(0x01000300), U32(0x01080200), U32(0x01080300), - U32(0x00000210), U32(0x00000310), U32(0x00080210), U32(0x00080310), - U32(0x01000210), U32(0x01000310), U32(0x01080210), U32(0x01080310), - U32(0x00200200), U32(0x00200300), U32(0x00280200), U32(0x00280300), - U32(0x01200200), U32(0x01200300), U32(0x01280200), U32(0x01280300), - U32(0x00200210), U32(0x00200310), U32(0x00280210), U32(0x00280310), - U32(0x01200210), U32(0x01200310), U32(0x01280210), U32(0x01280310), - ], - - # for D bits (numbered as per FIPS 46) 22 23 24 25 27 28 - [ - U32(0x00000000), U32(0x04000000), U32(0x00040000), U32(0x04040000), - U32(0x00000002), U32(0x04000002), U32(0x00040002), U32(0x04040002), - U32(0x00002000), U32(0x04002000), U32(0x00042000), U32(0x04042000), - U32(0x00002002), U32(0x04002002), U32(0x00042002), U32(0x04042002), - U32(0x00000020), U32(0x04000020), U32(0x00040020), U32(0x04040020), - U32(0x00000022), U32(0x04000022), U32(0x00040022), U32(0x04040022), - U32(0x00002020), U32(0x04002020), U32(0x00042020), U32(0x04042020), - U32(0x00002022), U32(0x04002022), U32(0x00042022), U32(0x04042022), - U32(0x00000800), U32(0x04000800), U32(0x00040800), U32(0x04040800), - U32(0x00000802), U32(0x04000802), U32(0x00040802), U32(0x04040802), - U32(0x00002800), U32(0x04002800), U32(0x00042800), U32(0x04042800), - U32(0x00002802), U32(0x04002802), U32(0x00042802), U32(0x04042802), - U32(0x00000820), U32(0x04000820), U32(0x00040820), U32(0x04040820), - U32(0x00000822), U32(0x04000822), U32(0x00040822), U32(0x04040822), - U32(0x00002820), U32(0x04002820), U32(0x00042820), U32(0x04042820), - U32(0x00002822), U32(0x04002822), U32(0x00042822), U32(0x04042822), - ] - - ] +# This file is part of 'NTLM Authorization Proxy Server' http://sourceforge.net/projects/ntlmaps/ +# Copyright 2001 Dmitry A. Rozmanov +# +# This library is free software: you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation, either +# version 3 of the License, or (at your option) any later version. + +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. + +# You should have received a copy of the GNU Lesser General Public +# License along with this library. If not, see or . + +from ntlm3.U32 import U32 + +# static unsigned long des_SPtrans[8][64]={ + +des_SPtrans = \ + [ + # nibble 0 + [ + U32(0x00820200), U32(0x00020000), U32(0x80800000), U32(0x80820200), + U32(0x00800000), U32(0x80020200), U32(0x80020000), U32(0x80800000), + U32(0x80020200), U32(0x00820200), U32(0x00820000), U32(0x80000200), + U32(0x80800200), U32(0x00800000), U32(0x00000000), U32(0x80020000), + U32(0x00020000), U32(0x80000000), U32(0x00800200), U32(0x00020200), + U32(0x80820200), U32(0x00820000), U32(0x80000200), U32(0x00800200), + U32(0x80000000), U32(0x00000200), U32(0x00020200), U32(0x80820000), + U32(0x00000200), U32(0x80800200), U32(0x80820000), U32(0x00000000), + U32(0x00000000), U32(0x80820200), U32(0x00800200), U32(0x80020000), + U32(0x00820200), U32(0x00020000), U32(0x80000200), U32(0x00800200), + U32(0x80820000), U32(0x00000200), U32(0x00020200), U32(0x80800000), + U32(0x80020200), U32(0x80000000), U32(0x80800000), U32(0x00820000), + U32(0x80820200), U32(0x00020200), U32(0x00820000), U32(0x80800200), + U32(0x00800000), U32(0x80000200), U32(0x80020000), U32(0x00000000), + U32(0x00020000), U32(0x00800000), U32(0x80800200), U32(0x00820200), + U32(0x80000000), U32(0x80820000), U32(0x00000200), U32(0x80020200), + ], + + # nibble 1 + [ + U32(0x10042004), U32(0x00000000), U32(0x00042000), U32(0x10040000), + U32(0x10000004), U32(0x00002004), U32(0x10002000), U32(0x00042000), + U32(0x00002000), U32(0x10040004), U32(0x00000004), U32(0x10002000), + U32(0x00040004), U32(0x10042000), U32(0x10040000), U32(0x00000004), + U32(0x00040000), U32(0x10002004), U32(0x10040004), U32(0x00002000), + U32(0x00042004), U32(0x10000000), U32(0x00000000), U32(0x00040004), + U32(0x10002004), U32(0x00042004), U32(0x10042000), U32(0x10000004), + U32(0x10000000), U32(0x00040000), U32(0x00002004), U32(0x10042004), + U32(0x00040004), U32(0x10042000), U32(0x10002000), U32(0x00042004), + U32(0x10042004), U32(0x00040004), U32(0x10000004), U32(0x00000000), + U32(0x10000000), U32(0x00002004), U32(0x00040000), U32(0x10040004), + U32(0x00002000), U32(0x10000000), U32(0x00042004), U32(0x10002004), + U32(0x10042000), U32(0x00002000), U32(0x00000000), U32(0x10000004), + U32(0x00000004), U32(0x10042004), U32(0x00042000), U32(0x10040000), + U32(0x10040004), U32(0x00040000), U32(0x00002004), U32(0x10002000), + U32(0x10002004), U32(0x00000004), U32(0x10040000), U32(0x00042000), + ], + + # nibble 2 + [ + U32(0x41000000), U32(0x01010040), U32(0x00000040), U32(0x41000040), + U32(0x40010000), U32(0x01000000), U32(0x41000040), U32(0x00010040), + U32(0x01000040), U32(0x00010000), U32(0x01010000), U32(0x40000000), + U32(0x41010040), U32(0x40000040), U32(0x40000000), U32(0x41010000), + U32(0x00000000), U32(0x40010000), U32(0x01010040), U32(0x00000040), + U32(0x40000040), U32(0x41010040), U32(0x00010000), U32(0x41000000), + U32(0x41010000), U32(0x01000040), U32(0x40010040), U32(0x01010000), + U32(0x00010040), U32(0x00000000), U32(0x01000000), U32(0x40010040), + U32(0x01010040), U32(0x00000040), U32(0x40000000), U32(0x00010000), + U32(0x40000040), U32(0x40010000), U32(0x01010000), U32(0x41000040), + U32(0x00000000), U32(0x01010040), U32(0x00010040), U32(0x41010000), + U32(0x40010000), U32(0x01000000), U32(0x41010040), U32(0x40000000), + U32(0x40010040), U32(0x41000000), U32(0x01000000), U32(0x41010040), + U32(0x00010000), U32(0x01000040), U32(0x41000040), U32(0x00010040), + U32(0x01000040), U32(0x00000000), U32(0x41010000), U32(0x40000040), + U32(0x41000000), U32(0x40010040), U32(0x00000040), U32(0x01010000), + ], + + # nibble 3 + [ + U32(0x00100402), U32(0x04000400), U32(0x00000002), U32(0x04100402), + U32(0x00000000), U32(0x04100000), U32(0x04000402), U32(0x00100002), + U32(0x04100400), U32(0x04000002), U32(0x04000000), U32(0x00000402), + U32(0x04000002), U32(0x00100402), U32(0x00100000), U32(0x04000000), + U32(0x04100002), U32(0x00100400), U32(0x00000400), U32(0x00000002), + U32(0x00100400), U32(0x04000402), U32(0x04100000), U32(0x00000400), + U32(0x00000402), U32(0x00000000), U32(0x00100002), U32(0x04100400), + U32(0x04000400), U32(0x04100002), U32(0x04100402), U32(0x00100000), + U32(0x04100002), U32(0x00000402), U32(0x00100000), U32(0x04000002), + U32(0x00100400), U32(0x04000400), U32(0x00000002), U32(0x04100000), + U32(0x04000402), U32(0x00000000), U32(0x00000400), U32(0x00100002), + U32(0x00000000), U32(0x04100002), U32(0x04100400), U32(0x00000400), + U32(0x04000000), U32(0x04100402), U32(0x00100402), U32(0x00100000), + U32(0x04100402), U32(0x00000002), U32(0x04000400), U32(0x00100402), + U32(0x00100002), U32(0x00100400), U32(0x04100000), U32(0x04000402), + U32(0x00000402), U32(0x04000000), U32(0x04000002), U32(0x04100400), + ], + + # nibble 4 + [ + U32(0x02000000), U32(0x00004000), U32(0x00000100), U32(0x02004108), + U32(0x02004008), U32(0x02000100), U32(0x00004108), U32(0x02004000), + U32(0x00004000), U32(0x00000008), U32(0x02000008), U32(0x00004100), + U32(0x02000108), U32(0x02004008), U32(0x02004100), U32(0x00000000), + U32(0x00004100), U32(0x02000000), U32(0x00004008), U32(0x00000108), + U32(0x02000100), U32(0x00004108), U32(0x00000000), U32(0x02000008), + U32(0x00000008), U32(0x02000108), U32(0x02004108), U32(0x00004008), + U32(0x02004000), U32(0x00000100), U32(0x00000108), U32(0x02004100), + U32(0x02004100), U32(0x02000108), U32(0x00004008), U32(0x02004000), + U32(0x00004000), U32(0x00000008), U32(0x02000008), U32(0x02000100), + U32(0x02000000), U32(0x00004100), U32(0x02004108), U32(0x00000000), + U32(0x00004108), U32(0x02000000), U32(0x00000100), U32(0x00004008), + U32(0x02000108), U32(0x00000100), U32(0x00000000), U32(0x02004108), + U32(0x02004008), U32(0x02004100), U32(0x00000108), U32(0x00004000), + U32(0x00004100), U32(0x02004008), U32(0x02000100), U32(0x00000108), + U32(0x00000008), U32(0x00004108), U32(0x02004000), U32(0x02000008), + ], + + # nibble 5 + [ + U32(0x20000010), U32(0x00080010), U32(0x00000000), U32(0x20080800), + U32(0x00080010), U32(0x00000800), U32(0x20000810), U32(0x00080000), + U32(0x00000810), U32(0x20080810), U32(0x00080800), U32(0x20000000), + U32(0x20000800), U32(0x20000010), U32(0x20080000), U32(0x00080810), + U32(0x00080000), U32(0x20000810), U32(0x20080010), U32(0x00000000), + U32(0x00000800), U32(0x00000010), U32(0x20080800), U32(0x20080010), + U32(0x20080810), U32(0x20080000), U32(0x20000000), U32(0x00000810), + U32(0x00000010), U32(0x00080800), U32(0x00080810), U32(0x20000800), + U32(0x00000810), U32(0x20000000), U32(0x20000800), U32(0x00080810), + U32(0x20080800), U32(0x00080010), U32(0x00000000), U32(0x20000800), + U32(0x20000000), U32(0x00000800), U32(0x20080010), U32(0x00080000), + U32(0x00080010), U32(0x20080810), U32(0x00080800), U32(0x00000010), + U32(0x20080810), U32(0x00080800), U32(0x00080000), U32(0x20000810), + U32(0x20000010), U32(0x20080000), U32(0x00080810), U32(0x00000000), + U32(0x00000800), U32(0x20000010), U32(0x20000810), U32(0x20080800), + U32(0x20080000), U32(0x00000810), U32(0x00000010), U32(0x20080010), + ], + + # nibble 6 + [ + U32(0x00001000), U32(0x00000080), U32(0x00400080), U32(0x00400001), + U32(0x00401081), U32(0x00001001), U32(0x00001080), U32(0x00000000), + U32(0x00400000), U32(0x00400081), U32(0x00000081), U32(0x00401000), + U32(0x00000001), U32(0x00401080), U32(0x00401000), U32(0x00000081), + U32(0x00400081), U32(0x00001000), U32(0x00001001), U32(0x00401081), + U32(0x00000000), U32(0x00400080), U32(0x00400001), U32(0x00001080), + U32(0x00401001), U32(0x00001081), U32(0x00401080), U32(0x00000001), + U32(0x00001081), U32(0x00401001), U32(0x00000080), U32(0x00400000), + U32(0x00001081), U32(0x00401000), U32(0x00401001), U32(0x00000081), + U32(0x00001000), U32(0x00000080), U32(0x00400000), U32(0x00401001), + U32(0x00400081), U32(0x00001081), U32(0x00001080), U32(0x00000000), + U32(0x00000080), U32(0x00400001), U32(0x00000001), U32(0x00400080), + U32(0x00000000), U32(0x00400081), U32(0x00400080), U32(0x00001080), + U32(0x00000081), U32(0x00001000), U32(0x00401081), U32(0x00400000), + U32(0x00401080), U32(0x00000001), U32(0x00001001), U32(0x00401081), + U32(0x00400001), U32(0x00401080), U32(0x00401000), U32(0x00001001), + ], + + # nibble 7 + [ + U32(0x08200020), U32(0x08208000), U32(0x00008020), U32(0x00000000), + U32(0x08008000), U32(0x00200020), U32(0x08200000), U32(0x08208020), + U32(0x00000020), U32(0x08000000), U32(0x00208000), U32(0x00008020), + U32(0x00208020), U32(0x08008020), U32(0x08000020), U32(0x08200000), + U32(0x00008000), U32(0x00208020), U32(0x00200020), U32(0x08008000), + U32(0x08208020), U32(0x08000020), U32(0x00000000), U32(0x00208000), + U32(0x08000000), U32(0x00200000), U32(0x08008020), U32(0x08200020), + U32(0x00200000), U32(0x00008000), U32(0x08208000), U32(0x00000020), + U32(0x00200000), U32(0x00008000), U32(0x08000020), U32(0x08208020), + U32(0x00008020), U32(0x08000000), U32(0x00000000), U32(0x00208000), + U32(0x08200020), U32(0x08008020), U32(0x08008000), U32(0x00200020), + U32(0x08208000), U32(0x00000020), U32(0x00200020), U32(0x08008000), + U32(0x08208020), U32(0x00200000), U32(0x08200000), U32(0x08000020), + U32(0x00208000), U32(0x00008020), U32(0x08008020), U32(0x08200000), + U32(0x00000020), U32(0x08208000), U32(0x00208020), U32(0x00000000), + U32(0x08000000), U32(0x08200020), U32(0x00008000), U32(0x00208020), + ], + ] + +# static unsigned long des_skb[8][64]={ + +des_skb = \ + [ + # for C bits (numbered as per FIPS 46) 1 2 3 4 5 6 + [ + U32(0x00000000), U32(0x00000010), U32(0x20000000), U32(0x20000010), + U32(0x00010000), U32(0x00010010), U32(0x20010000), U32(0x20010010), + U32(0x00000800), U32(0x00000810), U32(0x20000800), U32(0x20000810), + U32(0x00010800), U32(0x00010810), U32(0x20010800), U32(0x20010810), + U32(0x00000020), U32(0x00000030), U32(0x20000020), U32(0x20000030), + U32(0x00010020), U32(0x00010030), U32(0x20010020), U32(0x20010030), + U32(0x00000820), U32(0x00000830), U32(0x20000820), U32(0x20000830), + U32(0x00010820), U32(0x00010830), U32(0x20010820), U32(0x20010830), + U32(0x00080000), U32(0x00080010), U32(0x20080000), U32(0x20080010), + U32(0x00090000), U32(0x00090010), U32(0x20090000), U32(0x20090010), + U32(0x00080800), U32(0x00080810), U32(0x20080800), U32(0x20080810), + U32(0x00090800), U32(0x00090810), U32(0x20090800), U32(0x20090810), + U32(0x00080020), U32(0x00080030), U32(0x20080020), U32(0x20080030), + U32(0x00090020), U32(0x00090030), U32(0x20090020), U32(0x20090030), + U32(0x00080820), U32(0x00080830), U32(0x20080820), U32(0x20080830), + U32(0x00090820), U32(0x00090830), U32(0x20090820), U32(0x20090830), + ], + + # for C bits (numbered as per FIPS 46) 7 8 10 11 12 13 + [ + U32(0x00000000), U32(0x02000000), U32(0x00002000), U32(0x02002000), + U32(0x00200000), U32(0x02200000), U32(0x00202000), U32(0x02202000), + U32(0x00000004), U32(0x02000004), U32(0x00002004), U32(0x02002004), + U32(0x00200004), U32(0x02200004), U32(0x00202004), U32(0x02202004), + U32(0x00000400), U32(0x02000400), U32(0x00002400), U32(0x02002400), + U32(0x00200400), U32(0x02200400), U32(0x00202400), U32(0x02202400), + U32(0x00000404), U32(0x02000404), U32(0x00002404), U32(0x02002404), + U32(0x00200404), U32(0x02200404), U32(0x00202404), U32(0x02202404), + U32(0x10000000), U32(0x12000000), U32(0x10002000), U32(0x12002000), + U32(0x10200000), U32(0x12200000), U32(0x10202000), U32(0x12202000), + U32(0x10000004), U32(0x12000004), U32(0x10002004), U32(0x12002004), + U32(0x10200004), U32(0x12200004), U32(0x10202004), U32(0x12202004), + U32(0x10000400), U32(0x12000400), U32(0x10002400), U32(0x12002400), + U32(0x10200400), U32(0x12200400), U32(0x10202400), U32(0x12202400), + U32(0x10000404), U32(0x12000404), U32(0x10002404), U32(0x12002404), + U32(0x10200404), U32(0x12200404), U32(0x10202404), U32(0x12202404), + ], + + # for C bits (numbered as per FIPS 46) 14 15 16 17 19 20 + [ + U32(0x00000000), U32(0x00000001), U32(0x00040000), U32(0x00040001), + U32(0x01000000), U32(0x01000001), U32(0x01040000), U32(0x01040001), + U32(0x00000002), U32(0x00000003), U32(0x00040002), U32(0x00040003), + U32(0x01000002), U32(0x01000003), U32(0x01040002), U32(0x01040003), + U32(0x00000200), U32(0x00000201), U32(0x00040200), U32(0x00040201), + U32(0x01000200), U32(0x01000201), U32(0x01040200), U32(0x01040201), + U32(0x00000202), U32(0x00000203), U32(0x00040202), U32(0x00040203), + U32(0x01000202), U32(0x01000203), U32(0x01040202), U32(0x01040203), + U32(0x08000000), U32(0x08000001), U32(0x08040000), U32(0x08040001), + U32(0x09000000), U32(0x09000001), U32(0x09040000), U32(0x09040001), + U32(0x08000002), U32(0x08000003), U32(0x08040002), U32(0x08040003), + U32(0x09000002), U32(0x09000003), U32(0x09040002), U32(0x09040003), + U32(0x08000200), U32(0x08000201), U32(0x08040200), U32(0x08040201), + U32(0x09000200), U32(0x09000201), U32(0x09040200), U32(0x09040201), + U32(0x08000202), U32(0x08000203), U32(0x08040202), U32(0x08040203), + U32(0x09000202), U32(0x09000203), U32(0x09040202), U32(0x09040203), + ], + + # for C bits (numbered as per FIPS 46) 21 23 24 26 27 28 + [ + U32(0x00000000), U32(0x00100000), U32(0x00000100), U32(0x00100100), + U32(0x00000008), U32(0x00100008), U32(0x00000108), U32(0x00100108), + U32(0x00001000), U32(0x00101000), U32(0x00001100), U32(0x00101100), + U32(0x00001008), U32(0x00101008), U32(0x00001108), U32(0x00101108), + U32(0x04000000), U32(0x04100000), U32(0x04000100), U32(0x04100100), + U32(0x04000008), U32(0x04100008), U32(0x04000108), U32(0x04100108), + U32(0x04001000), U32(0x04101000), U32(0x04001100), U32(0x04101100), + U32(0x04001008), U32(0x04101008), U32(0x04001108), U32(0x04101108), + U32(0x00020000), U32(0x00120000), U32(0x00020100), U32(0x00120100), + U32(0x00020008), U32(0x00120008), U32(0x00020108), U32(0x00120108), + U32(0x00021000), U32(0x00121000), U32(0x00021100), U32(0x00121100), + U32(0x00021008), U32(0x00121008), U32(0x00021108), U32(0x00121108), + U32(0x04020000), U32(0x04120000), U32(0x04020100), U32(0x04120100), + U32(0x04020008), U32(0x04120008), U32(0x04020108), U32(0x04120108), + U32(0x04021000), U32(0x04121000), U32(0x04021100), U32(0x04121100), + U32(0x04021008), U32(0x04121008), U32(0x04021108), U32(0x04121108), + ], + + # for D bits (numbered as per FIPS 46) 1 2 3 4 5 6 + [ + U32(0x00000000), U32(0x10000000), U32(0x00010000), U32(0x10010000), + U32(0x00000004), U32(0x10000004), U32(0x00010004), U32(0x10010004), + U32(0x20000000), U32(0x30000000), U32(0x20010000), U32(0x30010000), + U32(0x20000004), U32(0x30000004), U32(0x20010004), U32(0x30010004), + U32(0x00100000), U32(0x10100000), U32(0x00110000), U32(0x10110000), + U32(0x00100004), U32(0x10100004), U32(0x00110004), U32(0x10110004), + U32(0x20100000), U32(0x30100000), U32(0x20110000), U32(0x30110000), + U32(0x20100004), U32(0x30100004), U32(0x20110004), U32(0x30110004), + U32(0x00001000), U32(0x10001000), U32(0x00011000), U32(0x10011000), + U32(0x00001004), U32(0x10001004), U32(0x00011004), U32(0x10011004), + U32(0x20001000), U32(0x30001000), U32(0x20011000), U32(0x30011000), + U32(0x20001004), U32(0x30001004), U32(0x20011004), U32(0x30011004), + U32(0x00101000), U32(0x10101000), U32(0x00111000), U32(0x10111000), + U32(0x00101004), U32(0x10101004), U32(0x00111004), U32(0x10111004), + U32(0x20101000), U32(0x30101000), U32(0x20111000), U32(0x30111000), + U32(0x20101004), U32(0x30101004), U32(0x20111004), U32(0x30111004), + ], + + # for D bits (numbered as per FIPS 46) 8 9 11 12 13 14 + [ + U32(0x00000000), U32(0x08000000), U32(0x00000008), U32(0x08000008), + U32(0x00000400), U32(0x08000400), U32(0x00000408), U32(0x08000408), + U32(0x00020000), U32(0x08020000), U32(0x00020008), U32(0x08020008), + U32(0x00020400), U32(0x08020400), U32(0x00020408), U32(0x08020408), + U32(0x00000001), U32(0x08000001), U32(0x00000009), U32(0x08000009), + U32(0x00000401), U32(0x08000401), U32(0x00000409), U32(0x08000409), + U32(0x00020001), U32(0x08020001), U32(0x00020009), U32(0x08020009), + U32(0x00020401), U32(0x08020401), U32(0x00020409), U32(0x08020409), + U32(0x02000000), U32(0x0A000000), U32(0x02000008), U32(0x0A000008), + U32(0x02000400), U32(0x0A000400), U32(0x02000408), U32(0x0A000408), + U32(0x02020000), U32(0x0A020000), U32(0x02020008), U32(0x0A020008), + U32(0x02020400), U32(0x0A020400), U32(0x02020408), U32(0x0A020408), + U32(0x02000001), U32(0x0A000001), U32(0x02000009), U32(0x0A000009), + U32(0x02000401), U32(0x0A000401), U32(0x02000409), U32(0x0A000409), + U32(0x02020001), U32(0x0A020001), U32(0x02020009), U32(0x0A020009), + U32(0x02020401), U32(0x0A020401), U32(0x02020409), U32(0x0A020409), + ], + + # for D bits (numbered as per FIPS 46) 16 17 18 19 20 21 + [ + U32(0x00000000), U32(0x00000100), U32(0x00080000), U32(0x00080100), + U32(0x01000000), U32(0x01000100), U32(0x01080000), U32(0x01080100), + U32(0x00000010), U32(0x00000110), U32(0x00080010), U32(0x00080110), + U32(0x01000010), U32(0x01000110), U32(0x01080010), U32(0x01080110), + U32(0x00200000), U32(0x00200100), U32(0x00280000), U32(0x00280100), + U32(0x01200000), U32(0x01200100), U32(0x01280000), U32(0x01280100), + U32(0x00200010), U32(0x00200110), U32(0x00280010), U32(0x00280110), + U32(0x01200010), U32(0x01200110), U32(0x01280010), U32(0x01280110), + U32(0x00000200), U32(0x00000300), U32(0x00080200), U32(0x00080300), + U32(0x01000200), U32(0x01000300), U32(0x01080200), U32(0x01080300), + U32(0x00000210), U32(0x00000310), U32(0x00080210), U32(0x00080310), + U32(0x01000210), U32(0x01000310), U32(0x01080210), U32(0x01080310), + U32(0x00200200), U32(0x00200300), U32(0x00280200), U32(0x00280300), + U32(0x01200200), U32(0x01200300), U32(0x01280200), U32(0x01280300), + U32(0x00200210), U32(0x00200310), U32(0x00280210), U32(0x00280310), + U32(0x01200210), U32(0x01200310), U32(0x01280210), U32(0x01280310), + ], + + # for D bits (numbered as per FIPS 46) 22 23 24 25 27 28 + [ + U32(0x00000000), U32(0x04000000), U32(0x00040000), U32(0x04040000), + U32(0x00000002), U32(0x04000002), U32(0x00040002), U32(0x04040002), + U32(0x00002000), U32(0x04002000), U32(0x00042000), U32(0x04042000), + U32(0x00002002), U32(0x04002002), U32(0x00042002), U32(0x04042002), + U32(0x00000020), U32(0x04000020), U32(0x00040020), U32(0x04040020), + U32(0x00000022), U32(0x04000022), U32(0x00040022), U32(0x04040022), + U32(0x00002020), U32(0x04002020), U32(0x00042020), U32(0x04042020), + U32(0x00002022), U32(0x04002022), U32(0x00042022), U32(0x04042022), + U32(0x00000800), U32(0x04000800), U32(0x00040800), U32(0x04040800), + U32(0x00000802), U32(0x04000802), U32(0x00040802), U32(0x04040802), + U32(0x00002800), U32(0x04002800), U32(0x00042800), U32(0x04042800), + U32(0x00002802), U32(0x04002802), U32(0x00042802), U32(0x04042802), + U32(0x00000820), U32(0x04000820), U32(0x00040820), U32(0x04040820), + U32(0x00000822), U32(0x04000822), U32(0x00040822), U32(0x04040822), + U32(0x00002820), U32(0x04002820), U32(0x00042820), U32(0x04042820), + U32(0x00002822), U32(0x04002822), U32(0x00042822), U32(0x04042822), + ] + + ] diff --git a/ntlm3/gss_channel_bindings.py b/ntlm3/gss_channel_bindings.py new file mode 100644 index 0000000..c4b4e18 --- /dev/null +++ b/ntlm3/gss_channel_bindings.py @@ -0,0 +1,67 @@ +# This library is free software: you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation, either +# version 3 of the License, or (at your option) any later version. + +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. + +# You should have received a copy of the GNU Lesser General Public +# License along with this library. If not, see or . + +import struct + +""" + This is not the easiest structure to understand, ultimately this is a set structure + as defined by Microsoft. Channel Binding Tokens set the SHA256 hash of the server + certificate to the application_data field and then ultimately creates the MD5 hash + to include in the NTLM auth from there. This class is just designed to create the + bindings structure which is then used by compute_response.py to do the rest of the + work. + + For more infor on how this works and how it is derived, this is a great link; + https://blogs.msdn.microsoft.com/openspecification/2013/03/26/ntlm-and-channel-binding-hash-aka-extended-protection-for-authentication/ +""" +class GssChannelBindingsStruct(object): + INITIATOR_ADDTYPE = 'initiator_addtype' + INITIATOR_ADDRESS_LENGTH = 'initiator_address_length' + ACCEPTOR_ADDRTYPE = 'acceptor_addrtype' + ACCEPTOR_ADDRESS_LENGTH = 'acceptor_address_length' + APPLICATION_DATA_LENGTH = 'application_data_length' + INITIATOR_ADDRESS = 'initiator_address' + ACCEPTOR_ADDRESS = 'acceptor_address' + APPLICATION_DATA = 'application_data' + + def __init__(self): + self.fields = {} + self.fields[self.INITIATOR_ADDTYPE] = 0 + self.fields[self.INITIATOR_ADDRESS_LENGTH] = 0 + self.fields[self.ACCEPTOR_ADDRTYPE] = 0 + self.fields[self.ACCEPTOR_ADDRESS_LENGTH] = 0 + self.fields[self.APPLICATION_DATA_LENGTH] = 0 + self.fields[self.INITIATOR_ADDRESS] = b'' + self.fields[self.ACCEPTOR_ADDRESS] = b'' + self.fields[self.APPLICATION_DATA] = b'' + + def __setitem__(self, key, value): + self.fields[key] = value + + def get_data(self): + # Set the lengths of each len field in case they have changed + self.fields[self.INITIATOR_ADDRESS_LENGTH] = len(self.fields[self.INITIATOR_ADDRESS]) + self.fields[self.ACCEPTOR_ADDRESS_LENGTH] = len(self.fields[self.ACCEPTOR_ADDRESS]) + self.fields[self.APPLICATION_DATA_LENGTH] = len(self.fields[self.APPLICATION_DATA]) + + # Add all the values together to create the gss_channel_bindings_struct + data = struct.pack(' or . + +import hmac +import os +import struct + +from ntlm3.compute_response import ComputeResponse +from ntlm3.constants import NegotiateFlags, MessageTypes, NTLM_SIGNATURE, AvFlags +from ntlm3.rc4 import ARC4 +from ntlm3.target_info import TargetInfo + +class NegotiateMessage(object): + EXPECTED_BODY_LENGTH = 40 + + """ + [MS-NLMP] v28.0 2016-07-14 + + 2.2.1.1 NEGOTIATE_MESSAGE + The NEGOTIATE_MESSAGE defines an NTLM Negotiate message that is sent from the client to + the server. This message allows the client to specify its supported NTLM options to + the server. + + :param negotiate_flags: A NEGOTIATE structure that contains a set of bit flags. These flags are the options the client supports + :param domain_name: The domain name of the user to authenticate with, default is None + :param workstation: The worksation of the client machine, default is None + + Attributes: + signature: An 8-byte character array that MUST contain the ASCII string 'NTLMSSP\0' + message_type: A 32-bit unsigned integer that indicates the message type. This field must be set to 0x00000001 + negotiate_flags: A NEGOTIATE structure that contains a set of bit flags. These flags are the options the client supports + version: Contains the windows version info of the client. It is used only debugging purposes and are only set when NTLMSSP_NEGOTIATE_VERSION flag is set + domain_name: A byte-array that contains the name of the client authentication domain that MUST Be encoded in the negotiated character set + workstation: A byte-array that contains the name of the client machine that MUST Be encoded in the negotiated character set + """ + def __init__(self, negotiate_flags, domain_name, workstation): + self.signature = NTLM_SIGNATURE + self.message_type = struct.pack(' or . -import struct import base64 -import hashlib -import hmac -import random -import re -import binascii -from socket import gethostname - -import six - -from . import des - -NTLM_NegotiateUnicode = 0x00000001 -NTLM_NegotiateOEM = 0x00000002 -NTLM_RequestTarget = 0x00000004 -NTLM_Unknown9 = 0x00000008 -NTLM_NegotiateSign = 0x00000010 -NTLM_NegotiateSeal = 0x00000020 -NTLM_NegotiateDatagram = 0x00000040 -NTLM_NegotiateLanManagerKey = 0x00000080 -NTLM_Unknown8 = 0x00000100 -NTLM_NegotiateNTLM = 0x00000200 -NTLM_NegotiateNTOnly = 0x00000400 -NTLM_Anonymous = 0x00000800 -NTLM_NegotiateOemDomainSupplied = 0x00001000 -NTLM_NegotiateOemWorkstationSupplied = 0x00002000 -NTLM_Unknown6 = 0x00004000 -NTLM_NegotiateAlwaysSign = 0x00008000 -NTLM_TargetTypeDomain = 0x00010000 -NTLM_TargetTypeServer = 0x00020000 -NTLM_TargetTypeShare = 0x00040000 -NTLM_NegotiateExtendedSecurity = 0x00080000 -NTLM_NegotiateIdentify = 0x00100000 -NTLM_Unknown5 = 0x00200000 -NTLM_RequestNonNTSessionKey = 0x00400000 -NTLM_NegotiateTargetInfo = 0x00800000 -NTLM_Unknown4 = 0x01000000 -NTLM_NegotiateVersion = 0x02000000 -NTLM_Unknown3 = 0x04000000 -NTLM_Unknown2 = 0x08000000 -NTLM_Unknown1 = 0x10000000 -NTLM_Negotiate128 = 0x20000000 -NTLM_NegotiateKeyExchange = 0x40000000 -NTLM_Negotiate56 = 0x80000000 - -# we send these flags with our type 1 message -NTLM_TYPE1_FLAGS = (NTLM_NegotiateUnicode | - NTLM_NegotiateOEM | - NTLM_RequestTarget | - NTLM_NegotiateNTLM | - NTLM_NegotiateOemDomainSupplied | - NTLM_NegotiateOemWorkstationSupplied | - NTLM_NegotiateAlwaysSign | - NTLM_NegotiateExtendedSecurity | - NTLM_NegotiateVersion | - NTLM_Negotiate128 | - NTLM_Negotiate56) - -NTLM_TYPE2_FLAGS = (NTLM_NegotiateUnicode | - NTLM_RequestTarget | - NTLM_NegotiateNTLM | - NTLM_NegotiateAlwaysSign | - NTLM_NegotiateExtendedSecurity | - NTLM_NegotiateTargetInfo | - NTLM_NegotiateVersion | - NTLM_Negotiate128 | - NTLM_Negotiate56) - -# Indicates that this is the last AV_PAIR in the list. AvLen MUST be 0. -# This type of information MUST be present in the AV pair list. -NTLM_MsvAvEOL = 0 - -# The server's NetBIOS computer name. The name MUST be in Unicode, and is not null-terminated. -# This type of information MUST be present in the AV_pair list. -NTLM_MsvAvNbComputerName = 1 - -# The server's NetBIOS domain name. The name MUST be in Unicode, and is not null-terminated. -# This type of information MUST be present in the AV_pair list. -NTLM_MsvAvNbDomainName = 2 - -# The server's Active Directory DNS computer name. The name MUST be in Unicode, and is not null-terminated. -NTLM_MsvAvDnsComputerName = 3 - -# The server's Active Directory DNS domain name. The name MUST be in Unicode, and is not null-terminated. -NTLM_MsvAvDnsDomainName = 4 - -# The server's Active Directory (AD) DNS forest tree name. The name MUST be in Unicode, and is not null-terminated. -NTLM_MsvAvDnsTreeName = 5 - -# A field containing a 32-bit value indicating server or client configuration. 0x00000001: indicates to the -# client that the account authentication is constrained. 0x00000002: indicates that the client is providing message -# integrity in the MIC field (section 2.2.1.3) in the AUTHENTICATE_MESSAGE. -NTLM_MsvAvFlags = 6 - -# A FILETIME structure ([MS-DTYP] section 2.3.1) in little-endian byte order that contains the server local time.<12> -NTLM_MsvAvTimestamp = 7 - -# A Restriction_Encoding structure (section 2.2.2.2). The Value field contains a structure representing -# the integrity level of the security principal, as well as a MachineID created at computer startup -# to identify the calling machine. <13> -NTLM_MsAvRestrictions = 8 +import socket +import struct + +from ntlm3.constants import NegotiateFlags +from ntlm3.messages import NegotiateMessage, ChallengeMessage, AuthenticateMessage +from ntlm3.session_security import SessionSecurity """ utility functions for Microsoft NTLM authentication @@ -134,282 +39,167 @@ http://www.blackhat.com/presentations/bh-asia-04/bh-jp-04-pdfs/bh-jp-04-seki.pdf """ +class Ntlm(object): + """ + Initialises the NTLM context to use when sending and receiving messages to and from the server. You should be + using this object as it supports NTLMv2 authenticate and it easier to use than before. It also brings in the + ability to use signing and sealing with session_security and generate a MIC structure. + + :param ntlm_compatibility: The Lan Manager Compatibility Level to use withe the auth message - Default 3 + This is set by an Administrator in the registry key + 'HKLM\SYSTEM\CurrentControlSet\Control\Lsa\LmCompatibilityLevel' + The values correspond to the following; + 0 : LM and NTLMv1 + 1 : LM, NTLMv1 and NTLMv1 with Extended Session Security + 2 : NTLMv1 and NTLMv1 with Extended Session Security + 3-5 : NTLMv2 Only + Note: to python-ntlm3 value 3 to 5 are no different as the client supports the same types + + Attributes: + negotiate_flags: A NEGOTIATE structure that contains a set of bit flags. These flags are the options the client supports and are sent in the negotiate_message + ntlm_compatibility: The Lan Manager Compatibility Level, same as the input if supplied + negotiate_message: A NegotiateMessage object that is sent to the server + challenge_message: A ChallengeMessage object that has been created from the server response + authenticate_message: An AuthenticateMessage object that is sent to the server based on the ChallengeMessage + session_security: A SessionSecurity structure that can be used to sign and seal messages sent after the authentication challenge + """ + def __init__(self, ntlm_compatibility=3): + self.ntlm_compatibility = ntlm_compatibility + + # Setting up our flags so the challenge message returns the target info block if supported + self.negotiate_flags = NegotiateFlags.NTLMSSP_NEGOTIATE_TARGET_INFO | \ + NegotiateFlags.NTLMSSP_NEGOTIATE_128 | \ + NegotiateFlags.NTLMSSP_NEGOTIATE_56 | \ + NegotiateFlags.NTLMSSP_NEGOTIATE_UNICODE | \ + NegotiateFlags.NTLMSSP_NEGOTIATE_VERSION | \ + NegotiateFlags.NTLMSSP_NEGOTIATE_KEY_EXCH | \ + NegotiateFlags.NTLMSSP_NEGOTIATE_ALWAYS_SIGN | \ + NegotiateFlags.NTLMSSP_NEGOTIATE_SIGN | \ + NegotiateFlags.NTLMSSP_NEGOTIATE_SEAL + + # Setting the message types based on the ntlm_compatibility level + self._set_ntlm_compatibility_flags(self.ntlm_compatibility) + + self.negotiate_message = None + self.challenge_message = None + self.authenticate_message = None + self.session_security = None + + + def create_negotiate_message(self, domain_name=None, workstation=None): + """ + Create an NTLM NEGOTIATE_MESSAGE + + :param domain_name: The domain name of the user account we are authenticating with, default is None + :param worksation: The workstation we are using to authenticate with, default is None + :return: A base64 encoded string of the NEGOTIATE_MESSAGE + """ + self.negotiate_message = NegotiateMessage(self.negotiate_flags, domain_name, workstation) + + return base64.b64encode(self.negotiate_message.get_data()) + + def parse_challenge_message(self, msg2): + """ + Parse the NTLM CHALLENGE_MESSAGE from the server and add it to the Ntlm context fields + + :param msg2: A base64 encoded string of the CHALLENGE_MESSAGE + """ + msg2 = base64.b64decode(msg2) + self.challenge_message = ChallengeMessage(msg2) + + def create_authenticate_message(self, user_name, password, domain_name=None, workstation=None, server_certificate_hash=None): + """ + Create an NTLM AUTHENTICATE_MESSAGE based on the Ntlm context and the previous messages sent and received + + :param user_name: The user name of the user we are trying to authenticate with + :param password: The password of the user we are trying to authenticate with + :param domain_name: The domain name of the user account we are authenticated with, default is None + :param workstation: The workstation we are using to authenticate with, default is None + :param server_certificate_hash: The SHA256 hash string of the server certificate (DER encoded) NTLM is authenticating to. Used for Channel + Binding Tokens. If nothing is supplied then the CBT hash will not be sent. See messages.py AuthenticateMessage + for more details + :return: A base64 encoded string of the AUTHENTICATE_MESSAGE + """ + self.authenticate_message = AuthenticateMessage(user_name, password, domain_name, workstation, + self.challenge_message, self.ntlm_compatibility, + server_certificate_hash) + self.authenticate_message.add_mic(self.negotiate_message, self.challenge_message) + + # Setups up the session_security context used to sign and seal messages if wanted + if self.negotiate_flags & NegotiateFlags.NTLMSSP_NEGOTIATE_SEAL or self.negotiate_flags & NegotiateFlags.NTLMSSP_NEGOTIATE_SIGN: + self.session_security = SessionSecurity(struct.unpack("= 0) and (ntlm_compatibility <= 5): + if ntlm_compatibility == 0: + self.negotiate_flags |= NegotiateFlags.NTLMSSP_NEGOTIATE_NTLM | \ + NegotiateFlags.NTLMSSP_NEGOTIATE_LM_KEY + elif ntlm_compatibility == 1: + self.negotiate_flags |= NegotiateFlags.NTLMSSP_NEGOTIATE_NTLM | \ + NegotiateFlags.NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY + else: + self.negotiate_flags |= NegotiateFlags.NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY + else: + raise Exception("Unknown ntlm_compatibility level - expecting value between 0 and 5") -def create_NTLM_NEGOTIATE_MESSAGE(user, type1_flags=NTLM_TYPE1_FLAGS): - BODY_LENGTH = 40 - Payload_start = BODY_LENGTH # in bytes - protocol = b'NTLMSSP\0' # name - type = struct.pack(' or . + +class ARC4(object): + state = None + i = 0 + j = 0 + + def __init__(self, key): + # Split up the key into a list + if isinstance(key, str): + key = [ord(c) for c in key] + else: + key = [c for c in key] + + #Key-scheduling algorithm (KSA) + self.state = [n for n in range(256)] + j = 0 + for i in range(256): + j = (j + self.state[i] + key[i % len(key)]) % 256 + self.state[i], self.state[j] = self.state[j], self.state[i] + + def update(self, value): + chars = [] + random_gen = self._random_generator() + for char in value: + if isinstance(value, str): + byte = ord(char) + else: + byte = char + updated_byte = byte ^ next(random_gen) + chars.append(updated_byte) + return bytes(bytearray(chars)) + + def _random_generator(self): + #Pseudo-Random Generation Algorithm (PRGA) + while True: + self.i = (self.i + 1) % 256 + self.j = (self.j + self.state[self.i]) % 256 + self.state[self.i], self.state[self.j] = self.state[self.j], self.state[self.i] + yield self.state[(self.state[self.i] + self.state[self.j]) % 256] diff --git a/ntlm3/session_security.py b/ntlm3/session_security.py new file mode 100644 index 0000000..1fddccd --- /dev/null +++ b/ntlm3/session_security.py @@ -0,0 +1,250 @@ +# This library is free software: you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation, either +# version 3 of the License, or (at your option) any later version. + +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. + +# You should have received a copy of the GNU Lesser General Public +# License along with this library. If not, see or . + +import binascii +import hmac +import struct + +import ntlm3.compute_keys as compkeys +from ntlm3.constants import NegotiateFlags, SignSealConstants +from ntlm3.rc4 import ARC4 + +class _NtlmMessageSignature1(object): + EXPECTED_BODY_LENGTH = 16 + + """ + [MS-NLMP] v28.0 2016-07-14 + + 2.2.2.9.1 NTLMSSP_MESSAGE_SIGNATURE + This version of the NTLMSSP_MESSAGE_SIGNATURE structure MUST be used when the + NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY flag is not negotiated. + + :param random_pad: A 4-byte array that contains the random pad for the emssage + :param checksum: A 4-byte array that contains the checksum for the message + :param seq_num: A 32-bit unsigned integer that contains the NTLM sequence number for this application message + """ + def __init__(self, random_pad, checksum, seq_num): + self.version = struct.pack(" actual1 + +class Test_HashResults(unittest.TestCase): + # 4.2.2.2.2 - LMv1 Response + def test_get_LMv1_response(self): + expected = ntlmv1_lmv1_response + + actual = ComputeResponse._get_LMv1_response(password, server_challenge) + + assert actual == expected + + # 4.2.4.2.1 - LMv2 Response + def test_get_LMv2_response(self): + expected = ntlmv2_lmv2_response + + actual = ComputeResponse._get_LMv2_response(user_name, password, domain_name, server_challenge, client_challenge) + + assert actual == expected + + # 4.2.2.2.1 - NTLMv1 Response + def test_get_NTLMv1_response(self): + expected_response = ntlmv1_ntlmv1_response + expected_key = ntlmv1_session_base_key + + actual_response, actual_key = ComputeResponse._get_NTLMv1_response(password, server_challenge) + + assert actual_response == expected_response + assert actual_key == expected_key + + # 4.2.3.2.2 - NTLMv1 Response + def test_get_NTLM2_response(self): + expected_response = ntlmv1_with_ess_ntlmv1_response + expected_key = ntlmv1_with_ess_session_base_key + + actual_response, actual_key = ComputeResponse._get_NTLM2_response(password, server_challenge, client_challenge) + + assert actual_response == expected_response + assert actual_key == expected_key + + # 4.2.4.1.3 - temp + def test_nt_v2_temp_response(self): + test_target_info = TargetInfo(target_info.get_data()) + + expected = ntlmv2_temp + + actual = ComputeResponse._get_NTLMv2_temp(timestamp, client_challenge, test_target_info) + assert actual == expected + + # 4.2.4.2.2 - NTLMv2 Response + def test_get_NTLMv2_response(self): + test_target_info = target_info + + expected_response = ntlmv2_ntlmv2_response + expected_key = ntlmv2_session_base_key + + actual_response, actual_key = ComputeResponse._get_NTLMv2_response(user_name, password, domain_name, + server_challenge, client_challenge, timestamp, test_target_info) + + assert actual_response == expected_response + assert actual_key == expected_key + + def test_channel_bindings_value(self): + # No example is explicitly set in MS-NLMP, using a random certificate hash and checking with the expected outcome + expected = HexToByte('6E A1 9D F0 66 DA 46 22 05 1F 9C 4F 92 C6 DF 74') + + actual = ComputeResponse._get_channel_bindings_value('E3CA49271E5089CC48CE82109F1324F41DBEDDC29A777410C738F7868C4FF405') + + assert actual == expected + +# Really are the same tests as above with the same expected results but this tests the logic of the lm and nt response method instead of the computation itself +class Test_ChallengeResults(unittest.TestCase): + def test_lm_v1_response(self): + test_challenge_message = ntlmv1_challenge_message + + expected = ntlmv1_lmv1_response + + actual = ComputeResponse(user_name, password, domain_name, test_challenge_message, 1).get_lm_challenge_response() + + assert actual == expected + + @mock.patch('os.urandom', side_effect=mock_random) + def test_lm_v1_with_extended_security_response(self, random_function): + test_challenge_message = ntlmv1_with_ess_challenge_message + + expected = ntlmv1_with_ess_lmv1_response + + actual = ComputeResponse(user_name, password, domain_name, test_challenge_message, 1).get_lm_challenge_response() + + assert actual == expected + + def test_lm_v1_with_ntlm_2_response(self): + test_challenge_message = ntlmv1_challenge_message + + # Not explicity in the example shown but it does expect the same response that we already have set + expected = ntlmv1_ntlmv1_response + + actual = ComputeResponse(user_name, password, domain_name, test_challenge_message, 2).get_lm_challenge_response() + + assert actual == expected + + @mock.patch('os.urandom', side_effect=mock_random) + def test_lm_v2_response(self, random_function): + test_challenge_message = ntlmv2_challenge_message + + expected = ntlmv2_lmv2_response + + actual = ComputeResponse(user_name, password, domain_name, test_challenge_message, 3).get_lm_challenge_response() + + assert actual == expected + + @mock.patch('os.urandom', side_effect=mock_random) + def test_lm_v2_response_with_no_server_target_info_timestamp(self, random_function): + test_target_info = TargetInfo(target_info.get_data()) + test_challenge_message = ntlmv2_challenge_message + test_challenge_message.target_info = test_target_info + + expected = ntlmv2_lmv2_response + + actual = ComputeResponse(user_name, password, domain_name, test_challenge_message, 3).get_lm_challenge_response() + + assert actual == expected + + def test_lm_v2_response_with_server_target_info_timestamp(self): + test_target_info = TargetInfo(target_info.get_data()) + test_target_info[TargetInfo.MSV_AV_TIMESTAMP] = timestamp + test_challenge_message = ntlmv2_challenge_message + test_challenge_message.target_info = test_target_info + + # Not in MS-NLMP, using expected value + expected = HexToByte('00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00' + '00 00 00 00 00 00 00 00') + + actual = ComputeResponse(user_name, password, domain_name, test_challenge_message, + 3).get_lm_challenge_response() + + assert actual == expected + + def test_nt_v1_response(self): + test_challenge_message = ntlmv1_challenge_message + + expected_response = ntlmv1_ntlmv1_response + expected_exchange_key = ntlmv1_key_exchange_key + expected_target_info = None + + actual_response, actual_exchange_key, actual_target_info = ComputeResponse(user_name, password, domain_name, + test_challenge_message, + 1).get_nt_challenge_response(ntlmv1_lmv1_response, None) + + assert actual_response == expected_response + assert actual_exchange_key == expected_exchange_key + assert actual_target_info == expected_target_info + + @mock.patch('os.urandom', side_effect=mock_random) + def test_nt_v1_with_extended_security_response(self, random_function): + test_challenge_message = ntlmv1_with_ess_challenge_message + + expected_response = ntlmv1_with_ess_ntlmv1_response + expected_exchange_key = ntlmv1_with_ess_key_exchange_key + expected_target_info = None + + actual_response, actual_exchange_key, actual_target_info = ComputeResponse(user_name, password, domain_name, + test_challenge_message, + 1).get_nt_challenge_response(ntlmv1_with_ess_lmv1_response, None) + + assert actual_response == expected_response + assert actual_exchange_key == expected_exchange_key + assert actual_target_info == expected_target_info + + @mock.patch('os.urandom', side_effect=mock_random) + @mock.patch('ntlm3.compute_response.get_windows_timestamp', side_effect=mock_timestamp) + def test_nt_v2_response(self, random_function, timestamp_function): + test_target_info = TargetInfo(target_info.get_data()) + test_challenge_message = ntlmv2_challenge_message + test_challenge_message.target_info = test_target_info + + expected_response = ntlmv2_ntlmv2_response + expected_exchange_key = ntlmv2_session_base_key #in ntlmv2 session_base key is the same as exchange_key + expected_target_info = test_target_info + + actual_response, actual_exchange_key, actual_target_info = ComputeResponse(user_name, password, domain_name, + test_challenge_message, + 3).get_nt_challenge_response(ntlmv2_lmv2_response, None) + + assert actual_response == expected_response + assert actual_exchange_key == expected_exchange_key + assert actual_target_info == expected_target_info + + + # The following tests are different from the Microsoft examples, they don't give an example of these scenarios so I have made them up + + @mock.patch('os.urandom', side_effect=mock_random) + @mock.patch('ntlm3.compute_response.get_windows_timestamp', side_effect=mock_timestamp) + def test_nt_v2_response_no_target_info(self, random_function, timestamp_function): + test_challenge_message = ntlmv2_challenge_message + test_challenge_message.target_info = None + + expected_response = HexToByte('39 56 f2 e5 69 d9 af a3 ac 2d 4f 36 7d 38 b9 c5' + '01 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00' + 'aa aa aa aa aa aa aa aa 00 00 00 00 00 00 00 00' + '00 00 00 00') + expected_exchange_key = HexToByte('e3 35 1f 5b e0 a0 2b c2 ee b8 76 52 f7 e0 77 75') + expected_target_info = TargetInfo() + + actual_response, actual_exchange_key, actual_target_info = ComputeResponse(user_name, password, domain_name, + test_challenge_message, + 3).get_nt_challenge_response(ntlmv2_lmv2_response, None) + + assert actual_response == expected_response + assert actual_exchange_key == expected_exchange_key + assert actual_target_info.get_data() == expected_target_info.get_data() + + @mock.patch('os.urandom', side_effect=mock_random) + def test_nt_v2_response_with_timestamp_av_pair(self, random_function): + test_target_info = TargetInfo(target_info.get_data()) + test_target_info[TargetInfo.MSV_AV_TIMESTAMP] = timestamp + test_challenge_message = ntlmv2_challenge_message + test_challenge_message.target_info = test_target_info + + expected_response = HexToByte('5d eb f3 87 1c 28 94 b8 1f 16 42 81 ed bf 0b ff' + '01 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00' + 'aa aa aa aa aa aa aa aa 00 00 00 00 02 00 0c 00' + '44 00 6f 00 6d 00 61 00 69 00 6e 00 01 00 0c 00' + '53 00 65 00 72 00 76 00 65 00 72 00 07 00 08 00' + '00 00 00 00 00 00 00 00 06 00 04 00 02 00 00 00' + '00 00 00 00 00 00 00 00') + expected_exchange_key = HexToByte('9b 37 06 8f 99 7a 06 5f e9 c7 20 63 32 88 d4 8f') + expected_target_info = test_target_info + expected_target_info[TargetInfo.MSV_AV_FLAGS] = struct.pack("