python实现mschap2

需要pycrypto包

# coding=utf-8
from Crypto.Hash import SHA, MD4
from Crypto.Cipher import DES


DEBUG = False


def challenge_hash(PeerChallenge, AuthenticatorChallenge, UserName):
    sha = SHA.new()
    sha.update(PeerChallenge)
    sha.update(AuthenticatorChallenge)
    sha.update(UserName)
    return sha.digest()[:8]


def Nt_password_hash(Password):
    return MD4.new(Password).digest()


def str7_to_key56(key_str):
    key_56 = []
    for i in key_str[:7]:
        key_56.append(ord(i))
    return key_56


def key56_to_key64(key_56):
    key = []
    for i in range(8):
        key.append(0)

    key[0] = key_56[0]
    for i in range(1, 7):
        key[i] = ((key_56[i - 1] << (8 - i)) & 0xFF) | (key_56[i] >> i)
    key[7] = (key_56[6] << 1) & 0xFF

    key = set_key_odd_parity(key)

    return key


def set_key_odd_parity(key):
    global bit
    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


def lst_to_str(lst):
    res = ''
    for i in lst:
        res = res + chr(i & 0xFF)

    return res


def generate_key(key56):
    return lst_to_str(key56_to_key64(str7_to_key56(key56)))


def challenge_response(challenge, password_hash):
    while (len(password_hash) <= 21):
        password_hash += "\x00"

    # PasswordHash is the key
    return DES.new(generate_key(password_hash[0:7]), DES.MODE_ECB).encrypt(challenge) + \
           DES.new(generate_key(password_hash[7:14]), DES.MODE_ECB).encrypt(challenge) + \
           DES.new(generate_key(password_hash[14:21]), DES.MODE_ECB).encrypt(challenge)


def generate_NT_response(authenticator_challenge, peer_challenge, user_name, password):
    challenge = challenge_hash(peer_challenge, authenticator_challenge, user_name)
    password_hash = Nt_password_hash(password)

    if DEBUG:
        print "Challenge:" + to_hex(challenge)
        print "PasswordHash:" + to_hex(password_hash)

    return challenge_response(challenge, password_hash)


# convert string to hex
def to_hex(s):
    hexString = ""
    for c in s:
        h = hex(ord(c)).replace('0x', '')
        if len(h) == 1:
            h = '0' + h
        hexString += h + ' '
    return hexString[:-1]


if __name__ == "__main__":
    authenticator_challenge = "\xB3\x02\xF3\xAB\x49\x03\x46\xD1\x62\x38\x1E\xD0\x40\xF5\xE9\x91"
    # authenticator_challenge = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
    peer_challenge = "\x48\xFB\x92\xCB\xA0\xCA\x39\x6D\x15\xCF\x2A\x08\xFC\xFA\x86\xA2"
    user_name = "freegg"
    password = "qwerasdf"

    print "挑战随机数:" + to_hex(authenticator_challenge)
    print "对等挑战随机数:" + to_hex(peer_challenge)
    print "用户名:" + user_name
    print "密码:" + password

    password_unicode = ""
    for ch in password:
        password_unicode += ch + "\x00"

    if DEBUG:
        print "密码unicode:" + to_hex(password_unicode)

    response = generate_NT_response(authenticator_challenge, peer_challenge, user_name, password_unicode)

    print "挑战响应值:" + to_hex(response)