NTLM Authentication Library
ntlm-auth is a Python library designed to create NTLM authentication structures, supporting NTLMv1 and NTLMv2, MIC for message integrity, channel binding tokens, and message signing/sealing. The current version is 1.5.0, with releases occurring periodically to add features and improve compatibility, though not on a strict schedule.
Warnings
- breaking The `Ntlm` class (e.g., `ntlm_auth.ntlm.Ntlm`) was deprecated in version 1.2.0 in favor of `NtlmContext`. `NtlmContext` provides a more flexible and generic interface for NTLM authentication beyond just HTTP.
- gotcha For optimal performance, especially when dealing with numerous or large NTLM authentication flows, install the optional `cryptography` dependency. Without it, RC4 cipher calls will be significantly slower.
- gotcha Python 3.3 support was dropped in version 1.2.0. Additionally, specific Python 3.0, 3.1, and 3.2 versions are explicitly not supported. Ensure your Python environment meets the `requires_python` criteria for the installed version.
- gotcha Versions prior to 1.5.0 do not include features like `mic_present` property, `sign`, `verify`, and `reset_rc4_state` functions on the `NtlmContext`. If your application requires these advanced NTLM capabilities, ensure you are on version 1.5.0 or later.
Install
-
pip install ntlm-auth -
pip install ntlm-auth[ntlm_context]
Imports
- NtlmContext
from ntlm_auth.ntlm import NtlmContext
Quickstart
from ntlm_auth.ntlm import NtlmContext
import base64
# Replace with your actual username and password
username = "DOMAIN\\username" # or just "username" for local accounts
password = "your_password"
# 1. Client creates a Type 1 Negotiate message
context = NtlmContext(username=username, password=password)
type1_message = context.create_negotiate_message()
print(f"Type 1 (Negotiate) message: {base64.b64encode(type1_message).decode()}")
# 2. Server (simulated) responds with a Type 2 Challenge message
# In a real scenario, this would come from the server
# Example Type 2 challenge bytes (replace with actual server response)
# This is a dummy example, actual challenge bytes would be different.
# You can often capture this from network traffic or server logs.
dummy_type2_challenge_bytes = (
b'\x4e\x54\x4c\x4d\x53\x53\x50\x00\x02\x00\x00\x00\x08\x00\x08\x00\x38\x00\x00\x00\x01\x82\x88\xe2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06\x01\x0c\x00\x00\x00\x00\x0f')
# Client processes the Type 2 message
# The context state is updated with server details.
type2_processed = context.create_challenge_message(dummy_type2_challenge_bytes)
print(f"Type 2 (Challenge) processed, context updated.")
# 3. Client creates a Type 3 Authenticate message
type3_message = context.create_authenticate_message()
print(f"Type 3 (Authenticate) message: {base64.b64encode(type3_message).decode()}")
# This Type 3 message would then be sent to the server for authentication.