MikroWizard Initial commit | MikroMan Welcome to the world :)
This commit is contained in:
commit
8c49b9a55d
96 changed files with 12274 additions and 0 deletions
150
py/libs/mschap3/U32.py
Normal file
150
py/libs/mschap3/U32.py
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
# U32.py implements 32-bit unsigned int class for Python
|
||||
# Version 1.0
|
||||
# Copyright (C) 2001-2002 Dmitry 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 2.1 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, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
# e-mail: dima@xenon.spb.ru
|
||||
#
|
||||
#====================================================================
|
||||
|
||||
C = 0x1000000000
|
||||
|
||||
#--------------------------------------------------------------------
|
||||
def norm(n):
|
||||
return n & 0xFFFFFFFF
|
||||
|
||||
#====================================================================
|
||||
class U32:
|
||||
v = 0
|
||||
|
||||
#--------------------------------------------------------------------
|
||||
def __init__(self, value = 0):
|
||||
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))
|
||||
|
||||
__index__ = __int__
|
||||
|
||||
#--------------------------------------------------------------------
|
||||
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 __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 __bool__(self):
|
||||
return norm(self.v)
|
||||
|
||||
0
py/libs/mschap3/__init__.py
Normal file
0
py/libs/mschap3/__init__.py
Normal file
97
py/libs/mschap3/des.py
Normal file
97
py/libs/mschap3/des.py
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
# This file is part of 'NTLM Authorization Proxy Server' http://sourceforge.net/projects/ntlmaps/
|
||||
# Copyright 2001 Dmitry A. Rozmanov <dima@xenon.spb.ru>
|
||||
#
|
||||
# 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 <http://www.gnu.org/licenses/> or <http://www.gnu.org/licenses/lgpl.txt>.
|
||||
from . import des_c
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------
|
||||
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 += bytes((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)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------
|
||||
# Some Helpers
|
||||
# ---------------------------------------------------------------------
|
||||
|
||||
DESException = "DESException"
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------
|
||||
def str_to_key56(key_str):
|
||||
""""""
|
||||
if type(key_str) != type(""):
|
||||
# rise DESException, 'ERROR. Wrong key type.'
|
||||
pass
|
||||
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 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
|
||||
358
py/libs/mschap3/des_c.py
Normal file
358
py/libs/mschap3/des_c.py
Normal file
|
|
@ -0,0 +1,358 @@
|
|||
# This file is part of 'NTLM Authorization Proxy Server' http://sourceforge.net/projects/ntlmaps/
|
||||
# Copyright 2001 Dmitry A. Rozmanov <dima@xenon.spb.ru>
|
||||
#
|
||||
# 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 <http://www.gnu.org/licenses/> or <http://www.gnu.org/licenses/lgpl.txt>.
|
||||
|
||||
from .U32 import U32
|
||||
from .des_data import des_SPtrans, des_skb
|
||||
|
||||
# --NON ASCII COMMENT ELIDED--
|
||||
# typedef unsigned char des_cblock[8];
|
||||
# define HDRSIZE 4
|
||||
|
||||
|
||||
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 c2ln(c, l1, l2, n):
|
||||
"char[n] to two unsigned long???"
|
||||
c = c + n
|
||||
l1, l2 = U32(0), U32(0)
|
||||
|
||||
f = 0
|
||||
if n == 8:
|
||||
l2 = l2 | (U32(c[7]) << 24)
|
||||
f = 1
|
||||
if f or (n == 7):
|
||||
l2 = l2 | (U32(c[6]) << 16)
|
||||
f = 1
|
||||
if f or (n == 6):
|
||||
l2 = l2 | (U32(c[5]) << 8)
|
||||
f = 1
|
||||
if f or (n == 5):
|
||||
l2 = l2 | U32(c[4])
|
||||
f = 1
|
||||
if f or (n == 4):
|
||||
l1 = l1 | (U32(c[3]) << 24)
|
||||
f = 1
|
||||
if f or (n == 3):
|
||||
l1 = l1 | (U32(c[2]) << 16)
|
||||
f = 1
|
||||
if f or (n == 2):
|
||||
l1 = l1 | (U32(c[1]) << 8)
|
||||
f = 1
|
||||
if f or (n == 1):
|
||||
l1 = l1 | U32(c[0])
|
||||
return (l1, l2)
|
||||
|
||||
|
||||
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 n2l(c, l):
|
||||
"network to host long"
|
||||
l = U32(c[0] << 24)
|
||||
l = l | (U32(c[1]) << 16)
|
||||
l = l | (U32(c[2]) << 8)
|
||||
l = l | (U32(c[3]))
|
||||
return l
|
||||
|
||||
|
||||
def l2n(l, c):
|
||||
"host to network long"
|
||||
c = []
|
||||
c.append(int((l >> 24) & U32(0xFF)))
|
||||
c.append(int((l >> 16) & U32(0xFF)))
|
||||
c.append(int((l >> 8) & U32(0xFF)))
|
||||
c.append(int((l) & U32(0xFF)))
|
||||
return c
|
||||
|
||||
|
||||
def l2cn(l1, l2, c, n):
|
||||
""""""
|
||||
for i in range(n):
|
||||
c.append(0x00)
|
||||
f = 0
|
||||
if f or (n == 8):
|
||||
c[7] = int((l2 >> 24) & U32(0xFF))
|
||||
f = 1
|
||||
if f or (n == 7):
|
||||
c[6] = int((l2 >> 16) & U32(0xFF))
|
||||
f = 1
|
||||
if f or (n == 6):
|
||||
c[5] = int((l2 >> 8) & U32(0xFF))
|
||||
f = 1
|
||||
if f or (n == 5):
|
||||
c[4] = int((l2) & U32(0xFF))
|
||||
f = 1
|
||||
if f or (n == 4):
|
||||
c[3] = int((l1 >> 24) & U32(0xFF))
|
||||
f = 1
|
||||
if f or (n == 3):
|
||||
c[2] = int((l1 >> 16) & U32(0xFF))
|
||||
f = 1
|
||||
if f or (n == 2):
|
||||
c[1] = int((l1 >> 8) & U32(0xFF))
|
||||
f = 1
|
||||
if f or (n == 1):
|
||||
c[0] = int((l1) & U32(0xFF))
|
||||
f = 1
|
||||
return c[:n]
|
||||
|
||||
|
||||
# array of data
|
||||
# static unsigned long des_SPtrans[8][64]={
|
||||
# static unsigned long des_skb[8][64]={
|
||||
|
||||
|
||||
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):
|
||||
# key - UChar[8]
|
||||
key = []
|
||||
# ~ for i in key_str: key.append(ord(i))
|
||||
# print 'key:', key
|
||||
self.KeySched = des_set_key(key_str)
|
||||
# print 'schedule:', self.KeySched, len(self.KeySched)
|
||||
|
||||
def decrypt(self, str):
|
||||
# block - UChar[]
|
||||
block = []
|
||||
for i in str:
|
||||
block.append(ord(i))
|
||||
# print block
|
||||
block = des_ecb_encrypt(block, self.KeySched, 0)
|
||||
res = b""
|
||||
for i in block:
|
||||
res = res + (chr(i))
|
||||
return res
|
||||
|
||||
def encrypt(self, str):
|
||||
# block - UChar[]
|
||||
block = []
|
||||
for i in str:
|
||||
block.append(i)
|
||||
block = des_ecb_encrypt(block, self.KeySched, 1)
|
||||
res = b""
|
||||
for i in block:
|
||||
res = res + bytes((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
|
||||
1098
py/libs/mschap3/des_data.py
Normal file
1098
py/libs/mschap3/des_data.py
Normal file
File diff suppressed because it is too large
Load diff
253
py/libs/mschap3/md4.py
Executable file
253
py/libs/mschap3/md4.py
Executable file
|
|
@ -0,0 +1,253 @@
|
|||
# md4.py implements md4 hash class for Python
|
||||
# Version 1.0
|
||||
# Copyright (C) 2001-2002 Dmitry Rozmanov
|
||||
#
|
||||
# based on md4.c from "the Python Cryptography Toolkit, version 1.0.0
|
||||
# Copyright (C) 1995, A.M. Kuchling"
|
||||
#
|
||||
# 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 2.1 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, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
# e-mail: dima@xenon.spb.ru
|
||||
#
|
||||
#====================================================================
|
||||
|
||||
# MD4 validation data
|
||||
|
||||
md4_test= [
|
||||
('', 0x31d6cfe0d16ae931b73c59d7e0c089c0),
|
||||
("a", 0xbde52cb31de33e46245e05fbdbd6fb24),
|
||||
("abc", 0xa448017aaf21d8525fc10ae87aa6729d),
|
||||
("message digest", 0xd9130a8164549fe818874806e1c7014b),
|
||||
("abcdefghijklmnopqrstuvwxyz", 0xd79e1c308aa5bbcdeea8ed63df412da9),
|
||||
("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
|
||||
0x043f8582f241db351ce627e153e7f0e4),
|
||||
("12345678901234567890123456789012345678901234567890123456789012345678901234567890",
|
||||
0xe33b4ddc9c38f2199c3e7b164fcc0536),
|
||||
]
|
||||
|
||||
#====================================================================
|
||||
from .U32 import U32
|
||||
|
||||
#--------------------------------------------------------------------
|
||||
class MD4:
|
||||
A = None
|
||||
B = None
|
||||
C = None
|
||||
D = None
|
||||
count, len1, len2 = None, None, None
|
||||
buf = []
|
||||
|
||||
#-----------------------------------------------------
|
||||
def __init__(self):
|
||||
|
||||
|
||||
self.A = U32(0x67452301)
|
||||
self.B = U32(0xefcdab89)
|
||||
self.C = U32(0x98badcfe)
|
||||
self.D = U32(0x10325476)
|
||||
self.count, self.len1, self.len2 = U32(0), U32(0), U32(0)
|
||||
self.buf = [0x00] * 64
|
||||
|
||||
#-----------------------------------------------------
|
||||
def __repr__(self):
|
||||
r = 'A = %s, \nB = %s, \nC = %s, \nD = %s.\n' % (self.A.__repr__(), self.B.__repr__(), self.C.__repr__(), self.D.__repr__())
|
||||
r = r + 'count = %s, \nlen1 = %s, \nlen2 = %s.\n' % (self.count.__repr__(), self.len1.__repr__(), self.len2.__repr__())
|
||||
for i in range(4):
|
||||
for j in range(16):
|
||||
r = r + '%4s ' % hex(self.buf[i+j])
|
||||
r = r + '\n'
|
||||
|
||||
return r
|
||||
#-----------------------------------------------------
|
||||
def make_copy(self):
|
||||
|
||||
dest = new()
|
||||
|
||||
dest.len1 = self.len1
|
||||
dest.len2 = self.len2
|
||||
dest.A = self.A
|
||||
dest.B = self.B
|
||||
dest.C = self.C
|
||||
dest.D = self.D
|
||||
dest.count = self.count
|
||||
for i in range(int(self.count)):
|
||||
dest.buf[i] = self.buf[i]
|
||||
|
||||
return dest
|
||||
|
||||
#-----------------------------------------------------
|
||||
def update(self, str):
|
||||
|
||||
buf = []
|
||||
for i in str: buf.append(ord(i))
|
||||
ilen = U32(len(buf))
|
||||
|
||||
# check if the first length is out of range
|
||||
# as the length is measured in bits then multiplay it by 8
|
||||
if (int(self.len1 + (ilen << 3)) < int(self.len1)):
|
||||
self.len2 = self.len2 + U32(1)
|
||||
|
||||
self.len1 = self.len1 + (ilen << 3)
|
||||
self.len2 = self.len2 + (ilen >> 29)
|
||||
|
||||
L = U32(0)
|
||||
bufpos = 0
|
||||
while (int(ilen) > 0):
|
||||
if (64 - int(self.count)) < int(ilen): L = U32(64 - int(self.count))
|
||||
else: L = ilen
|
||||
for i in range(int(L)): self.buf[i + int(self.count)] = buf[i + bufpos]
|
||||
self.count = self.count + L
|
||||
ilen = ilen - L
|
||||
bufpos = bufpos + int(L)
|
||||
|
||||
if (int(self.count) == 64):
|
||||
self.count = U32(0)
|
||||
X = []
|
||||
i = 0
|
||||
for j in range(16):
|
||||
X.append(U32(self.buf[i]) + (U32(self.buf[i+1]) << 8) + \
|
||||
(U32(self.buf[i+2]) << 16) + (U32(self.buf[i+3]) << 24))
|
||||
i = i + 4
|
||||
|
||||
A = self.A
|
||||
B = self.B
|
||||
C = self.C
|
||||
D = self.D
|
||||
|
||||
A = f1(A,B,C,D, 0, 3, X)
|
||||
D = f1(D,A,B,C, 1, 7, X)
|
||||
C = f1(C,D,A,B, 2,11, X)
|
||||
B = f1(B,C,D,A, 3,19, X)
|
||||
A = f1(A,B,C,D, 4, 3, X)
|
||||
D = f1(D,A,B,C, 5, 7, X)
|
||||
C = f1(C,D,A,B, 6,11, X)
|
||||
B = f1(B,C,D,A, 7,19, X)
|
||||
A = f1(A,B,C,D, 8, 3, X)
|
||||
D = f1(D,A,B,C, 9, 7, X)
|
||||
C = f1(C,D,A,B,10,11, X)
|
||||
B = f1(B,C,D,A,11,19, X)
|
||||
A = f1(A,B,C,D,12, 3, X)
|
||||
D = f1(D,A,B,C,13, 7, X)
|
||||
C = f1(C,D,A,B,14,11, X)
|
||||
B = f1(B,C,D,A,15,19, X)
|
||||
|
||||
A = f2(A,B,C,D, 0, 3, X)
|
||||
D = f2(D,A,B,C, 4, 5, X)
|
||||
C = f2(C,D,A,B, 8, 9, X)
|
||||
B = f2(B,C,D,A,12,13, X)
|
||||
A = f2(A,B,C,D, 1, 3, X)
|
||||
D = f2(D,A,B,C, 5, 5, X)
|
||||
C = f2(C,D,A,B, 9, 9, X)
|
||||
B = f2(B,C,D,A,13,13, X)
|
||||
A = f2(A,B,C,D, 2, 3, X)
|
||||
D = f2(D,A,B,C, 6, 5, X)
|
||||
C = f2(C,D,A,B,10, 9, X)
|
||||
B = f2(B,C,D,A,14,13, X)
|
||||
A = f2(A,B,C,D, 3, 3, X)
|
||||
D = f2(D,A,B,C, 7, 5, X)
|
||||
C = f2(C,D,A,B,11, 9, X)
|
||||
B = f2(B,C,D,A,15,13, X)
|
||||
|
||||
A = f3(A,B,C,D, 0, 3, X)
|
||||
D = f3(D,A,B,C, 8, 9, X)
|
||||
C = f3(C,D,A,B, 4,11, X)
|
||||
B = f3(B,C,D,A,12,15, X)
|
||||
A = f3(A,B,C,D, 2, 3, X)
|
||||
D = f3(D,A,B,C,10, 9, X)
|
||||
C = f3(C,D,A,B, 6,11, X)
|
||||
B = f3(B,C,D,A,14,15, X)
|
||||
A = f3(A,B,C,D, 1, 3, X)
|
||||
D = f3(D,A,B,C, 9, 9, X)
|
||||
C = f3(C,D,A,B, 5,11, X)
|
||||
B = f3(B,C,D,A,13,15, X)
|
||||
A = f3(A,B,C,D, 3, 3, X)
|
||||
D = f3(D,A,B,C,11, 9, X)
|
||||
C = f3(C,D,A,B, 7,11, X)
|
||||
B = f3(B,C,D,A,15,15, X)
|
||||
|
||||
self.A = self.A + A
|
||||
self.B = self.B + B
|
||||
self.C = self.C + C
|
||||
self.D = self.D + D
|
||||
|
||||
#-----------------------------------------------------
|
||||
def digest(self):
|
||||
|
||||
res = [0x00] * 16
|
||||
s = [0x00] * 8
|
||||
padding = [0x00] * 64
|
||||
padding[0] = 0x80
|
||||
padlen, oldlen1, oldlen2 = U32(0), U32(0), U32(0)
|
||||
|
||||
temp = self.make_copy()
|
||||
|
||||
oldlen1 = temp.len1
|
||||
oldlen2 = temp.len2
|
||||
if (56 <= int(self.count)): padlen = U32(56 - int(self.count) + 64)
|
||||
else: padlen = U32(56 - int(self.count))
|
||||
|
||||
temp.update(int_array2str(padding[:int(padlen)]))
|
||||
|
||||
s[0]= (oldlen1) & U32(0xFF)
|
||||
s[1]=((oldlen1) >> 8) & U32(0xFF)
|
||||
s[2]=((oldlen1) >> 16) & U32(0xFF)
|
||||
s[3]=((oldlen1) >> 24) & U32(0xFF)
|
||||
s[4]= (oldlen2) & U32(0xFF)
|
||||
s[5]=((oldlen2) >> 8) & U32(0xFF)
|
||||
s[6]=((oldlen2) >> 16) & U32(0xFF)
|
||||
s[7]=((oldlen2) >> 24) & U32(0xFF)
|
||||
temp.update(int_array2str(s))
|
||||
|
||||
res[ 0]= temp.A & U32(0xFF)
|
||||
res[ 1]=(temp.A >> 8) & U32(0xFF)
|
||||
res[ 2]=(temp.A >> 16) & U32(0xFF)
|
||||
res[ 3]=(temp.A >> 24) & U32(0xFF)
|
||||
res[ 4]= temp.B & U32(0xFF)
|
||||
res[ 5]=(temp.B >> 8) & U32(0xFF)
|
||||
res[ 6]=(temp.B >> 16) & U32(0xFF)
|
||||
res[ 7]=(temp.B >> 24) & U32(0xFF)
|
||||
res[ 8]= temp.C & U32(0xFF)
|
||||
res[ 9]=(temp.C >> 8) & U32(0xFF)
|
||||
res[10]=(temp.C >> 16) & U32(0xFF)
|
||||
res[11]=(temp.C >> 24) & U32(0xFF)
|
||||
res[12]= temp.D & U32(0xFF)
|
||||
res[13]=(temp.D >> 8) & U32(0xFF)
|
||||
res[14]=(temp.D >> 16) & U32(0xFF)
|
||||
res[15]=(temp.D >> 24) & U32(0xFF)
|
||||
|
||||
return int_array2str(res)
|
||||
|
||||
#====================================================================
|
||||
# helpers
|
||||
def F(x, y, z): return (((x) & (y)) | ((~x) & (z)))
|
||||
def G(x, y, z): return (((x) & (y)) | ((x) & (z)) | ((y) & (z)))
|
||||
def H(x, y, z): return ((x) ^ (y) ^ (z))
|
||||
|
||||
def ROL(x, n): return (((x) << n) | ((x) >> (32-n)))
|
||||
|
||||
def f1(a, b, c, d, k, s, X): return ROL(a + F(b, c, d) + X[k], s)
|
||||
def f2(a, b, c, d, k, s, X): return ROL(a + G(b, c, d) + X[k] + U32(0x5a827999), s)
|
||||
def f3(a, b, c, d, k, s, X): return ROL(a + H(b, c, d) + X[k] + U32(0x6ed9eba1), s)
|
||||
|
||||
#--------------------------------------------------------------------
|
||||
# helper function
|
||||
def int_array2str(array):
|
||||
nstr = ''
|
||||
for i in array:
|
||||
nstr = nstr + str(chr(i))
|
||||
return nstr
|
||||
#--------------------------------------------------------------------
|
||||
# To be able to use md4.new() instead of md4.MD4()
|
||||
new = MD4
|
||||
271
py/libs/mschap3/mppe.py
Executable file
271
py/libs/mschap3/mppe.py
Executable file
|
|
@ -0,0 +1,271 @@
|
|||
from . import mschap
|
||||
import hashlib
|
||||
import random
|
||||
|
||||
SHSpad1 = \
|
||||
b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + \
|
||||
b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + \
|
||||
b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + \
|
||||
b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
|
||||
|
||||
SHSpad2 = \
|
||||
b"\xf2\xf2\xf2\xf2\xf2\xf2\xf2\xf2\xf2\xf2" + \
|
||||
b"\xf2\xf2\xf2\xf2\xf2\xf2\xf2\xf2\xf2\xf2" + \
|
||||
b"\xf2\xf2\xf2\xf2\xf2\xf2\xf2\xf2\xf2\xf2" + \
|
||||
b"\xf2\xf2\xf2\xf2\xf2\xf2\xf2\xf2\xf2\xf2"
|
||||
|
||||
Magic1 = \
|
||||
b"\x54\x68\x69\x73\x20\x69\x73\x20\x74" + \
|
||||
b"\x68\x65\x20\x4d\x50\x50\x45\x20\x4d" + \
|
||||
b"\x61\x73\x74\x65\x72\x20\x4b\x65\x79"
|
||||
|
||||
Magic2 = \
|
||||
b"\x4f\x6e\x20\x74\x68\x65\x20\x63\x6c\x69" + \
|
||||
b"\x65\x6e\x74\x20\x73\x69\x64\x65\x2c\x20" + \
|
||||
b"\x74\x68\x69\x73\x20\x69\x73\x20\x74\x68" + \
|
||||
b"\x65\x20\x73\x65\x6e\x64\x20\x6b\x65\x79" + \
|
||||
b"\x3b\x20\x6f\x6e\x20\x74\x68\x65\x20\x73" + \
|
||||
b"\x65\x72\x76\x65\x72\x20\x73\x69\x64\x65" + \
|
||||
b"\x2c\x20\x69\x74\x20\x69\x73\x20\x74\x68" + \
|
||||
b"\x65\x20\x72\x65\x63\x65\x69\x76\x65\x20" + \
|
||||
b"\x6b\x65\x79\x2e"
|
||||
|
||||
Magic3 = \
|
||||
b"\x4f\x6e\x20\x74\x68\x65\x20\x63\x6c\x69" + \
|
||||
b"\x65\x6e\x74\x20\x73\x69\x64\x65\x2c\x20" + \
|
||||
b"\x74\x68\x69\x73\x20\x69\x73\x20\x74\x68" + \
|
||||
b"\x65\x20\x72\x65\x63\x65\x69\x76\x65\x20" + \
|
||||
b"\x6b\x65\x79\x3b\x20\x6f\x6e\x20\x74\x68" + \
|
||||
b"\x65\x20\x73\x65\x72\x76\x65\x72\x20\x73" + \
|
||||
b"\x69\x64\x65\x2c\x20\x69\x74\x20\x69\x73" + \
|
||||
b"\x20\x74\x68\x65\x20\x73\x65\x6e\x64\x20" + \
|
||||
b"\x6b\x65\x79\x2e"
|
||||
|
||||
|
||||
def mppe_chap2_gen_keys(password, nt_response,nthash=False):
|
||||
"""
|
||||
3.3. Generating 128-bit Session Keys
|
||||
|
||||
When used in conjunction with MS-CHAP-2 authentication, the initial
|
||||
MPPE session keys are derived from the peer's Windows NT password.
|
||||
|
||||
The first step is to obfuscate the peer's password using
|
||||
NtPasswordHash() function as described in [8].
|
||||
|
||||
NtPasswordHash(Password, PasswordHash)
|
||||
|
||||
The first 16 octets of the result are then hashed again using the MD4
|
||||
algorithm.
|
||||
|
||||
PasswordHashHash = md4(PasswordHash)
|
||||
|
||||
The first 16 octets of this second hash are used together with the
|
||||
NT-Response field from the MS-CHAP-2 Response packet [8] as the basis
|
||||
for the master session key:
|
||||
|
||||
GetMasterKey(PasswordHashHash, NtResponse, MasterKey)
|
||||
|
||||
Once the master key has been generated, it is used to derive two
|
||||
128-bit master session keys, one for sending and one for receiving:
|
||||
|
||||
GetAsymmetricStartKey(MasterKey, MasterSendKey, 16, TRUE, TRUE)
|
||||
GetAsymmetricStartKey(MasterKey, MasterReceiveKey, 16, FALSE, TRUE)
|
||||
|
||||
The master session keys are never used to encrypt or decrypt data;
|
||||
they are only used in the derivation of transient session keys. The
|
||||
initial transient session keys are obtained by calling the function
|
||||
GetNewKeyFromSHA() (described in [3]):
|
||||
|
||||
GetNewKeyFromSHA(MasterSendKey, MasterSendKey, 16, SendSessionKey)
|
||||
GetNewKeyFromSHA(MasterReceiveKey, MasterReceiveKey, 16,
|
||||
ReceiveSessionKey)
|
||||
|
||||
Finally, the RC4 tables are initialized using the new session keys:
|
||||
|
||||
rc4_key(SendRC4key, 16, SendSessionKey)
|
||||
rc4_key(ReceiveRC4key, 16, ReceiveSessionKey)
|
||||
"""
|
||||
if nthash:
|
||||
password_hash=bytes.fromhex(nthash).decode('iso8859-1',errors='ignore')
|
||||
else:
|
||||
password_hash = mschap.nt_password_hash(password)
|
||||
password_hash_hash = mschap.hash_nt_password_hash(password_hash).encode()
|
||||
master_key = get_master_key(password_hash_hash, nt_response)
|
||||
master_send_key = get_asymetric_start_key(master_key, 16, True, True)
|
||||
master_recv_key = get_asymetric_start_key(master_key, 16, False, True)
|
||||
return master_send_key, master_recv_key
|
||||
|
||||
|
||||
def get_master_key(password_hash_hash, nt_response):
|
||||
"""
|
||||
GetMasterKey(
|
||||
IN 16-octet PasswordHashHash,
|
||||
IN 24-octet NTResponse,
|
||||
OUT 16-octet MasterKey )
|
||||
{
|
||||
20-octet Digest
|
||||
|
||||
ZeroMemory(Digest, sizeof(Digest));
|
||||
|
||||
/*
|
||||
* SHSInit(), SHSUpdate() and SHSFinal()
|
||||
* are an implementation of the Secure Hash Standard [7].
|
||||
*/
|
||||
|
||||
SHSInit(Context);
|
||||
SHSUpdate(Context, PasswordHashHash, 16);
|
||||
SHSUpdate(Context, NTResponse, 24);
|
||||
SHSUpdate(Context, Magic1, 27);
|
||||
SHSFinal(Context, Digest);
|
||||
|
||||
MoveMemory(MasterKey, Digest, 16);
|
||||
}
|
||||
|
||||
"""
|
||||
sha_hash = hashlib.sha1()
|
||||
sha_hash.update(password_hash_hash)
|
||||
sha_hash.update(nt_response)
|
||||
sha_hash.update(Magic1)
|
||||
return sha_hash.digest()[:16]
|
||||
|
||||
|
||||
def get_asymetric_start_key(master_key, session_key_length, is_send, is_server):
|
||||
"""
|
||||
|
||||
VOID
|
||||
GetAsymetricStartKey(
|
||||
IN 16-octet MasterKey,
|
||||
OUT 8-to-16 octet SessionKey,
|
||||
IN INTEGER SessionKeyLength,
|
||||
IN BOOLEAN IsSend,
|
||||
IN BOOLEAN IsServer )
|
||||
{
|
||||
|
||||
20-octet Digest;
|
||||
|
||||
ZeroMemory(Digest, 20);
|
||||
|
||||
if (IsSend) {
|
||||
if (IsServer) {
|
||||
s = Magic3
|
||||
} else {
|
||||
s = Magic2
|
||||
}
|
||||
} else {
|
||||
if (IsServer) {
|
||||
|
||||
s = Magic2
|
||||
} else {
|
||||
s = Magic3
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* SHSInit(), SHSUpdate() and SHSFinal()
|
||||
* are an implementation of the Secure Hash Standard [7].
|
||||
*/
|
||||
|
||||
SHSInit(Context);
|
||||
SHSUpdate(Context, MasterKey, 16);
|
||||
SHSUpdate(Context, SHSpad1, 40);
|
||||
SHSUpdate(Context, s, 84);
|
||||
SHSUpdate(Context, SHSpad2, 40);
|
||||
SHSFinal(Context, Digest);
|
||||
|
||||
MoveMemory(SessionKey, Digest, SessionKeyLength);
|
||||
}
|
||||
"""
|
||||
if is_send:
|
||||
if is_server:
|
||||
s = Magic3
|
||||
else:
|
||||
s = Magic2
|
||||
else:
|
||||
if is_server:
|
||||
s = Magic2
|
||||
else:
|
||||
s = Magic3
|
||||
sha_hash = hashlib.sha1()
|
||||
sha_hash.update(master_key)
|
||||
sha_hash.update(SHSpad1)
|
||||
sha_hash.update(s)
|
||||
sha_hash.update(SHSpad2)
|
||||
return sha_hash.digest()[:session_key_length]
|
||||
|
||||
|
||||
def create_plain_text(key):
|
||||
key_len = len(key)
|
||||
key=key.decode(errors='ignore')
|
||||
while (len(key) + 1) % 16: key += "\000"
|
||||
return chr(key_len) + key
|
||||
|
||||
|
||||
def create_salts():
|
||||
send_salt = create_salt()
|
||||
recv_salt = create_salt()
|
||||
while send_salt == recv_salt: recv_salt = create_salt()
|
||||
return (send_salt, recv_salt)
|
||||
|
||||
|
||||
def create_salt():
|
||||
return chr(128 + random.randrange(0, 128)) + chr(random.randrange(0, 256))
|
||||
|
||||
def gen_radius_encrypt_keys(send_key, recv_key, secret, request_authenticator):
|
||||
send_salt, recv_salt = create_salts()
|
||||
_send_key = send_salt + radius_encrypt_keys(
|
||||
create_plain_text(send_key),
|
||||
secret,
|
||||
request_authenticator,
|
||||
send_salt
|
||||
)
|
||||
_recv_key = recv_salt + radius_encrypt_keys(
|
||||
create_plain_text(recv_key),
|
||||
secret,
|
||||
request_authenticator,
|
||||
recv_salt
|
||||
)
|
||||
|
||||
return _send_key, _recv_key
|
||||
|
||||
|
||||
def radius_encrypt_keys(plain_text, secret, request_authenticator, salt):
|
||||
"""
|
||||
Construct a plaintext version of the String field by concate-
|
||||
nating the Key-Length and Key sub-fields. If necessary, pad
|
||||
the resulting string until its length (in octets) is an even
|
||||
multiple of 16. It is recommended that zero octets (0x00) be
|
||||
used for padding. Call this plaintext P.
|
||||
|
||||
Call the shared secret S, the pseudo-random 128-bit Request
|
||||
Authenticator (from the corresponding Access-Request packet) R,
|
||||
and the contents of the Salt field A. Break P into 16 octet
|
||||
chunks p(1), p(2)...p(i), where i = len(P)/16. Call the
|
||||
ciphertext blocks c(1), c(2)...c(i) and the final ciphertext C.
|
||||
Intermediate values b(1), b(2)...c(i) are required. Encryption
|
||||
is performed in the following manner ('+' indicates
|
||||
concatenation):
|
||||
|
||||
b(1) = MD5(S + R + A) c(1) = p(1) xor b(1) C = c(1)
|
||||
b(2) = MD5(S + c(1)) c(2) = p(2) xor b(2) C = C + c(2)
|
||||
. .
|
||||
. .
|
||||
. .
|
||||
b(i) = MD5(S + c(i-1)) c(i) = p(i) xor b(i) C = C + c(i)
|
||||
|
||||
The resulting encrypted String field will contain
|
||||
c(1)+c(2)+...+c(i).
|
||||
"""
|
||||
i = int(len(plain_text) / 16)
|
||||
b = hashlib.new("md5", secret + request_authenticator + salt.encode(errors='ignore')).digest()
|
||||
c = xor(plain_text[:16], b)
|
||||
result = c
|
||||
for x in range(1, i):
|
||||
b = hashlib.new("md5", secret + c.encode().digest())
|
||||
c = xor(plain_text[x * 16:(x + 1) * 16], b)
|
||||
result += c
|
||||
return result
|
||||
|
||||
|
||||
def xor(str1, str2):
|
||||
str2=str2.decode(errors='ignore')
|
||||
return ''.join(map(lambda s1, s2: chr(ord(s1) ^ ord(s2)), str1, str2))
|
||||
131
py/libs/mschap3/mschap.py
Normal file
131
py/libs/mschap3/mschap.py
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
#!/usr/bin/env python3
|
||||
# coding=utf-8
|
||||
|
||||
|
||||
from . import des
|
||||
from . import md4
|
||||
import hashlib
|
||||
from . import utils
|
||||
from Crypto.Hash import MD4
|
||||
|
||||
|
||||
def challenge_hash(peer_challenge, authenticator_challenge, username):
|
||||
"""ChallengeHash"""
|
||||
sha_hash = hashlib.sha1()
|
||||
sha_hash.update(peer_challenge)
|
||||
sha_hash.update(authenticator_challenge)
|
||||
sha_hash.update(username)
|
||||
return sha_hash.digest()[:8]
|
||||
|
||||
|
||||
def nt_password_hash(passwd):
|
||||
"""NtPasswordHash"""
|
||||
pw = utils.str2unicode(passwd)
|
||||
|
||||
md4_context = md4.new()
|
||||
md4_context.update(pw)
|
||||
# hashObject = MD4.new(passwd.encode('utf-8'))
|
||||
# digest = hashObject.digest().decode()
|
||||
return md4_context.digest()
|
||||
|
||||
|
||||
def hash_nt_password_hash(password_hash):
|
||||
"""HashNtPasswordHash"""
|
||||
md4_context = md4.new()
|
||||
md4_context.update(password_hash)
|
||||
return md4_context.digest()
|
||||
|
||||
|
||||
def generate_nt_response_mschap(challenge, password):
|
||||
password_hash = nt_password_hash(password)
|
||||
return challenge_response(challenge, password_hash)
|
||||
|
||||
|
||||
def generate_nt_response_mschap2(authenticator_challenge, peer_challenge, username, password,nthash=False):
|
||||
"""GenerateNTResponse"""
|
||||
challenge = challenge_hash(peer_challenge, authenticator_challenge, username)
|
||||
if nthash:
|
||||
password_hash = bytes.fromhex(nthash).decode('iso8859-1',errors='ignore')
|
||||
else:
|
||||
password_hash = nt_password_hash(password)
|
||||
return challenge_response(challenge, password_hash)
|
||||
|
||||
|
||||
|
||||
def challenge_response(challenge, password_hash):
|
||||
"""ChallengeResponse"""
|
||||
zpassword_hash = password_hash.ljust(21, '\0')
|
||||
zpassword_hash = [ord(x) for x in zpassword_hash]
|
||||
|
||||
|
||||
response = b""
|
||||
des_obj = des.DES(zpassword_hash[0:7])
|
||||
response += des_obj.encrypt(challenge)
|
||||
|
||||
des_obj = des.DES(zpassword_hash[7:14])
|
||||
response += des_obj.encrypt(challenge)
|
||||
|
||||
des_obj = des.DES(zpassword_hash[14:21])
|
||||
response += des_obj.encrypt(challenge)
|
||||
return response
|
||||
|
||||
|
||||
def generate_authenticator_response(password, nt_response, peer_challenge, authenticator_challenge, username,nthash=False):
|
||||
"""GenerateAuthenticatorResponse"""
|
||||
Magic1 = b"\x4D\x61\x67\x69\x63\x20\x73\x65\x72\x76\x65\x72\x20\x74\x6F\x20\x63\x6C\x69\x65\x6E\x74\x20\x73\x69\x67\x6E\x69\x6E\x67\x20\x63\x6F\x6E\x73\x74\x61\x6E\x74"
|
||||
Magic2 = b"\x50\x61\x64\x20\x74\x6F\x20\x6D\x61\x6B\x65\x20\x69\x74\x20\x64\x6F\x20\x6D\x6F\x72\x65\x20\x74\x68\x61\x6E\x20\x6F\x6E\x65\x20\x69\x74\x65\x72\x61\x74\x69\x6F\x6E"
|
||||
if nthash:
|
||||
password_hash = bytes.fromhex(nthash).decode('iso8859-1',errors='ignore')
|
||||
else:
|
||||
password_hash = nt_password_hash(password)
|
||||
password_hash_hash = hash_nt_password_hash(password_hash)
|
||||
allenc=['iso8859-1']
|
||||
for enc in allenc:
|
||||
sha_hash = hashlib.sha1()
|
||||
sha_hash.update(password_hash_hash.encode(enc,errors='ignore'))
|
||||
sha_hash.update(nt_response)
|
||||
sha_hash.update(Magic1)
|
||||
digest = sha_hash.digest()
|
||||
challenge = challenge_hash(peer_challenge, authenticator_challenge, username)
|
||||
|
||||
sha_hash = hashlib.sha1()
|
||||
sha_hash.update(digest)
|
||||
sha_hash.update(challenge)
|
||||
sha_hash.update(Magic2)
|
||||
digest = sha_hash.digest()
|
||||
|
||||
|
||||
return "\x01S=" + convert_to_hex_string(digest)
|
||||
|
||||
|
||||
def check_authenticator_response(password, nt_response, peer_challenge, authenticator_challenge, user_name, received_response):
|
||||
"""CheckAuthenticatorResponse"""
|
||||
my_resppnse = generate_authenticator_response(password, nt_response, peer_challenge, authenticator_challenge, user_name)
|
||||
|
||||
return my_resppnse == received_response
|
||||
|
||||
def convert_to_hex_string(string):
|
||||
string=string.decode('iso8859-1',errors='ignore')
|
||||
hex_str = ""
|
||||
for c in string:
|
||||
hex_tmp = hex(ord(c))[2:]
|
||||
if len(hex_tmp) == 1:
|
||||
hex_tmp = "0" + hex_tmp
|
||||
hex_str += hex_tmp
|
||||
return hex_str.upper()
|
||||
|
||||
def lm_password_hash(password):
|
||||
|
||||
ucase_password = password.upper()[:14]
|
||||
while len(ucase_password) < 14:
|
||||
ucase_password += "\0"
|
||||
password_hash = des_hash(ucase_password[:7])
|
||||
password_hash += des_hash(ucase_password[7:])
|
||||
return password_hash
|
||||
|
||||
|
||||
def des_hash(clear):
|
||||
"""DesEncrypt"""
|
||||
des_obj = des.DES(clear)
|
||||
return des_obj.encrypt(r"KGS!@#$%")
|
||||
|
||||
587
py/libs/mschap3/ntlm.py
Normal file
587
py/libs/mschap3/ntlm.py
Normal file
|
|
@ -0,0 +1,587 @@
|
|||
# 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 <http://www.gnu.org/licenses/> or <http://www.gnu.org/licenses/lgpl.txt>.
|
||||
|
||||
import struct
|
||||
import base64
|
||||
import hashlib
|
||||
import hmac
|
||||
import random
|
||||
import re
|
||||
import binascii
|
||||
from socket import gethostname
|
||||
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
|
||||
)
|
||||
|
||||
NTLM_MsvAvEOL = 0 # 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_MsvAvNbComputerName = 1 # 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_MsvAvNbDomainName = 2 # 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_MsvAvDnsComputerName = 3 # The server's Active Directory DNS computer name. The name MUST be in Unicode, and is not null-terminated.
|
||||
NTLM_MsvAvDnsDomainName = 4 # The server's Active Directory DNS domain name. The name MUST be in Unicode, and is not null-terminated.
|
||||
NTLM_MsvAvDnsTreeName = 5 # The server's Active Directory (AD) DNS forest tree name. The name MUST be in Unicode, and is not null-terminated.
|
||||
NTLM_MsvAvFlags = 6 # 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_MsvAvTimestamp = 7 # A FILETIME structure ([MS-DTYP] section 2.3.1) in little-endian byte order that contains the server local time.<12>
|
||||
NTLM_MsAvRestrictions = 8 # 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>
|
||||
|
||||
|
||||
"""
|
||||
utility functions for Microsoft NTLM authentication
|
||||
|
||||
References:
|
||||
[MS-NLMP]: NT LAN Manager (NTLM) Authentication Protocol Specification
|
||||
http://download.microsoft.com/download/a/e/6/ae6e4142-aa58-45c6-8dcf-a657e5900cd3/%5BMS-NLMP%5D.pdf
|
||||
|
||||
[MS-NTHT]: NTLM Over HTTP Protocol Specification
|
||||
http://download.microsoft.com/download/a/e/6/ae6e4142-aa58-45c6-8dcf-a657e5900cd3/%5BMS-NTHT%5D.pdf
|
||||
|
||||
Cntlm Authentication Proxy
|
||||
http://cntlm.awk.cz/
|
||||
|
||||
NTLM Authorization Proxy Server
|
||||
http://sourceforge.net/projects/ntlmaps/
|
||||
|
||||
Optimized Attack for NTLM2 Session Response
|
||||
http://www.blackhat.com/presentations/bh-asia-04/bh-jp-04-pdfs/bh-jp-04-seki.pdf
|
||||
"""
|
||||
|
||||
|
||||
def dump_NegotiateFlags(NegotiateFlags):
|
||||
if NegotiateFlags & NTLM_NegotiateUnicode:
|
||||
print("NTLM_NegotiateUnicode set")
|
||||
if NegotiateFlags & NTLM_NegotiateOEM:
|
||||
print("NTLM_NegotiateOEM set")
|
||||
if NegotiateFlags & NTLM_RequestTarget:
|
||||
print("NTLM_RequestTarget set")
|
||||
if NegotiateFlags & NTLM_Unknown9:
|
||||
print("NTLM_Unknown9 set")
|
||||
if NegotiateFlags & NTLM_NegotiateSign:
|
||||
print("NTLM_NegotiateSign set")
|
||||
if NegotiateFlags & NTLM_NegotiateSeal:
|
||||
print("NTLM_NegotiateSeal set")
|
||||
if NegotiateFlags & NTLM_NegotiateDatagram:
|
||||
print("NTLM_NegotiateDatagram set")
|
||||
if NegotiateFlags & NTLM_NegotiateLanManagerKey:
|
||||
print("NTLM_NegotiateLanManagerKey set")
|
||||
if NegotiateFlags & NTLM_Unknown8:
|
||||
print("NTLM_Unknown8 set")
|
||||
if NegotiateFlags & NTLM_NegotiateNTLM:
|
||||
print("NTLM_NegotiateNTLM set")
|
||||
if NegotiateFlags & NTLM_NegotiateNTOnly:
|
||||
print("NTLM_NegotiateNTOnly set")
|
||||
if NegotiateFlags & NTLM_Anonymous:
|
||||
print("NTLM_Anonymous set")
|
||||
if NegotiateFlags & NTLM_NegotiateOemDomainSupplied:
|
||||
print("NTLM_NegotiateOemDomainSupplied set")
|
||||
if NegotiateFlags & NTLM_NegotiateOemWorkstationSupplied:
|
||||
print("NTLM_NegotiateOemWorkstationSupplied set")
|
||||
if NegotiateFlags & NTLM_Unknown6:
|
||||
print("NTLM_Unknown6 set")
|
||||
if NegotiateFlags & NTLM_NegotiateAlwaysSign:
|
||||
print("NTLM_NegotiateAlwaysSign set")
|
||||
if NegotiateFlags & NTLM_TargettypeDomain:
|
||||
print("NTLM_TargettypeDomain set")
|
||||
if NegotiateFlags & NTLM_TargettypeServer:
|
||||
print("NTLM_TargettypeServer set")
|
||||
if NegotiateFlags & NTLM_TargettypeShare:
|
||||
print("NTLM_TargettypeShare set")
|
||||
if NegotiateFlags & NTLM_NegotiateExtendedSecurity:
|
||||
print("NTLM_NegotiateExtendedSecurity set")
|
||||
if NegotiateFlags & NTLM_NegotiateIdentify:
|
||||
print("NTLM_NegotiateIdentify set")
|
||||
if NegotiateFlags & NTLM_Unknown5:
|
||||
print("NTLM_Unknown5 set")
|
||||
if NegotiateFlags & NTLM_RequestNonNTSessionKey:
|
||||
print("NTLM_RequestNonNTSessionKey set")
|
||||
if NegotiateFlags & NTLM_NegotiateTargetInfo:
|
||||
print("NTLM_NegotiateTargetInfo set")
|
||||
if NegotiateFlags & NTLM_Unknown4:
|
||||
print("NTLM_Unknown4 set")
|
||||
if NegotiateFlags & NTLM_NegotiateVersion:
|
||||
print("NTLM_NegotiateVersion set")
|
||||
if NegotiateFlags & NTLM_Unknown3:
|
||||
print("NTLM_Unknown3 set")
|
||||
if NegotiateFlags & NTLM_Unknown2:
|
||||
print("NTLM_Unknown2 set")
|
||||
if NegotiateFlags & NTLM_Unknown1:
|
||||
print("NTLM_Unknown1 set")
|
||||
if NegotiateFlags & NTLM_Negotiate128:
|
||||
print("NTLM_Negotiate128 set")
|
||||
if NegotiateFlags & NTLM_NegotiateKeyExchange:
|
||||
print("NTLM_NegotiateKeyExchange set")
|
||||
if NegotiateFlags & NTLM_Negotiate56:
|
||||
print("NTLM_Negotiate56 set")
|
||||
|
||||
|
||||
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("<I", 1) # type 1
|
||||
|
||||
flags = struct.pack("<I", type1_flags)
|
||||
Workstation = bytes(gethostname().upper(), "ascii")
|
||||
user_parts = user.split("\\", 1)
|
||||
DomainName = bytes(user_parts[0].upper(), "ascii")
|
||||
EncryptedRandomSessionKey = ""
|
||||
|
||||
WorkstationLen = struct.pack("<H", len(Workstation))
|
||||
WorkstationMaxLen = struct.pack("<H", len(Workstation))
|
||||
WorkstationBufferOffset = struct.pack("<I", Payload_start)
|
||||
Payload_start += len(Workstation)
|
||||
DomainNameLen = struct.pack("<H", len(DomainName))
|
||||
DomainNameMaxLen = struct.pack("<H", len(DomainName))
|
||||
DomainNameBufferOffset = struct.pack("<I", Payload_start)
|
||||
Payload_start += len(DomainName)
|
||||
ProductMajorVersion = struct.pack("<B", 5)
|
||||
ProductMinorVersion = struct.pack("<B", 1)
|
||||
ProductBuild = struct.pack("<H", 2600)
|
||||
VersionReserved1 = struct.pack("<B", 0)
|
||||
VersionReserved2 = struct.pack("<B", 0)
|
||||
VersionReserved3 = struct.pack("<B", 0)
|
||||
NTLMRevisionCurrent = struct.pack("<B", 15)
|
||||
|
||||
msg1 = (
|
||||
protocol
|
||||
+ type
|
||||
+ flags
|
||||
+ DomainNameLen
|
||||
+ DomainNameMaxLen
|
||||
+ DomainNameBufferOffset
|
||||
+ WorkstationLen
|
||||
+ WorkstationMaxLen
|
||||
+ WorkstationBufferOffset
|
||||
+ ProductMajorVersion
|
||||
+ ProductMinorVersion
|
||||
+ ProductBuild
|
||||
+ VersionReserved1
|
||||
+ VersionReserved2
|
||||
+ VersionReserved3
|
||||
+ NTLMRevisionCurrent
|
||||
)
|
||||
|
||||
assert BODY_LENGTH == len(msg1), "BODY_LENGTH: %d != msg1: %d" % (
|
||||
BODY_LENGTH,
|
||||
len(msg1),
|
||||
)
|
||||
msg1 += Workstation + DomainName
|
||||
msg1 = base64.b64encode(msg1)
|
||||
return msg1.decode()
|
||||
|
||||
|
||||
def parse_NTLM_CHALLENGE_MESSAGE(msg2):
|
||||
""""""
|
||||
msg2 = base64.b64decode(bytes(msg2, "ascii"))
|
||||
Signature = msg2[0:8]
|
||||
msg_type = struct.unpack("<I", msg2[8:12])[0]
|
||||
assert msg_type == 2
|
||||
TargetNameLen = struct.unpack("<H", msg2[12:14])[0]
|
||||
TargetNameMaxLen = struct.unpack("<H", msg2[14:16])[0]
|
||||
TargetNameOffset = struct.unpack("<I", msg2[16:20])[0]
|
||||
TargetName = msg2[TargetNameOffset : TargetNameOffset + TargetNameMaxLen]
|
||||
NegotiateFlags = struct.unpack("<I", msg2[20:24])[0]
|
||||
ServerChallenge = msg2[24:32]
|
||||
if NegotiateFlags & NTLM_NegotiateTargetInfo:
|
||||
Reserved = msg2[32:40]
|
||||
TargetInfoLen = struct.unpack("<H", msg2[40:42])[0]
|
||||
TargetInfoMaxLen = struct.unpack("<H", msg2[42:44])[0]
|
||||
TargetInfoOffset = struct.unpack("<I", msg2[44:48])[0]
|
||||
TargetInfo = msg2[TargetInfoOffset : TargetInfoOffset + TargetInfoLen]
|
||||
i = 0
|
||||
TimeStamp = "\0" * 8
|
||||
while i < TargetInfoLen:
|
||||
AvId = struct.unpack("<H", TargetInfo[i : i + 2])[0]
|
||||
AvLen = struct.unpack("<H", TargetInfo[i + 2 : i + 4])[0]
|
||||
AvValue = TargetInfo[i + 4 : i + 4 + AvLen]
|
||||
i = i + 4 + AvLen
|
||||
if AvId == NTLM_MsvAvTimestamp:
|
||||
TimeStamp = AvValue
|
||||
# ~ print AvId, AvValue.decode('utf-16')
|
||||
return (ServerChallenge, NegotiateFlags)
|
||||
|
||||
|
||||
def create_NTLM_AUTHENTICATE_MESSAGE(nonce, user, domain, password, NegotiateFlags):
|
||||
""""""
|
||||
is_unicode = NegotiateFlags & NTLM_NegotiateUnicode
|
||||
is_NegotiateExtendedSecurity = NegotiateFlags & NTLM_NegotiateExtendedSecurity
|
||||
|
||||
flags = struct.pack("<I", NTLM_TYPE2_FLAGS)
|
||||
|
||||
BODY_LENGTH = 72
|
||||
Payload_start = BODY_LENGTH # in bytes
|
||||
|
||||
Workstation = bytes(gethostname().upper(), "ascii")
|
||||
DomainName = bytes(domain.upper(), "ascii")
|
||||
UserName = bytes(user, "ascii")
|
||||
EncryptedRandomSessionKey = b""
|
||||
if is_unicode:
|
||||
Workstation = bytes(gethostname().upper(), "utf-16-le")
|
||||
DomainName = bytes(domain.upper(), "utf-16-le")
|
||||
UserName = bytes(user, "utf-16-le")
|
||||
EncryptedRandomSessionKey = bytes("", "utf-16-le")
|
||||
LmChallengeResponse = calc_resp(create_LM_hashed_password_v1(password), nonce)
|
||||
NtChallengeResponse = calc_resp(create_NT_hashed_password_v1(password), nonce)
|
||||
|
||||
if is_NegotiateExtendedSecurity:
|
||||
pwhash = create_NT_hashed_password_v1(password, UserName, DomainName)
|
||||
ClientChallenge = b""
|
||||
for i in range(8):
|
||||
ClientChallenge += bytes((random.getrandbits(8),))
|
||||
(NtChallengeResponse, LmChallengeResponse) = ntlm2sr_calc_resp(
|
||||
pwhash, nonce, ClientChallenge
|
||||
) # ='\x39 e3 f4 cd 59 c5 d8 60')
|
||||
Signature = b"NTLMSSP\0"
|
||||
Messagetype = struct.pack("<I", 3) # type 3
|
||||
|
||||
DomainNameLen = struct.pack("<H", len(DomainName))
|
||||
DomainNameMaxLen = struct.pack("<H", len(DomainName))
|
||||
DomainNameOffset = struct.pack("<I", Payload_start)
|
||||
Payload_start += len(DomainName)
|
||||
|
||||
UserNameLen = struct.pack("<H", len(UserName))
|
||||
UserNameMaxLen = struct.pack("<H", len(UserName))
|
||||
UserNameOffset = struct.pack("<I", Payload_start)
|
||||
Payload_start += len(UserName)
|
||||
|
||||
WorkstationLen = struct.pack("<H", len(Workstation))
|
||||
WorkstationMaxLen = struct.pack("<H", len(Workstation))
|
||||
WorkstationOffset = struct.pack("<I", Payload_start)
|
||||
Payload_start += len(Workstation)
|
||||
|
||||
LmChallengeResponseLen = struct.pack("<H", len(LmChallengeResponse))
|
||||
LmChallengeResponseMaxLen = struct.pack("<H", len(LmChallengeResponse))
|
||||
LmChallengeResponseOffset = struct.pack("<I", Payload_start)
|
||||
Payload_start += len(LmChallengeResponse)
|
||||
|
||||
NtChallengeResponseLen = struct.pack("<H", len(NtChallengeResponse))
|
||||
NtChallengeResponseMaxLen = struct.pack("<H", len(NtChallengeResponse))
|
||||
NtChallengeResponseOffset = struct.pack("<I", Payload_start)
|
||||
Payload_start += len(NtChallengeResponse)
|
||||
|
||||
EncryptedRandomSessionKeyLen = struct.pack("<H", len(EncryptedRandomSessionKey))
|
||||
EncryptedRandomSessionKeyMaxLen = struct.pack("<H", len(EncryptedRandomSessionKey))
|
||||
EncryptedRandomSessionKeyOffset = struct.pack("<I", Payload_start)
|
||||
Payload_start += len(EncryptedRandomSessionKey)
|
||||
NegotiateFlags = flags
|
||||
|
||||
ProductMajorVersion = struct.pack("<B", 5)
|
||||
ProductMinorVersion = struct.pack("<B", 1)
|
||||
ProductBuild = struct.pack("<H", 2600)
|
||||
VersionReserved1 = struct.pack("<B", 0)
|
||||
VersionReserved2 = struct.pack("<B", 0)
|
||||
VersionReserved3 = struct.pack("<B", 0)
|
||||
NTLMRevisionCurrent = struct.pack("<B", 15)
|
||||
|
||||
MIC = struct.pack("<IIII", 0, 0, 0, 0)
|
||||
msg3 = (
|
||||
Signature
|
||||
+ Messagetype
|
||||
+ LmChallengeResponseLen
|
||||
+ LmChallengeResponseMaxLen
|
||||
+ LmChallengeResponseOffset
|
||||
+ NtChallengeResponseLen
|
||||
+ NtChallengeResponseMaxLen
|
||||
+ NtChallengeResponseOffset
|
||||
+ DomainNameLen
|
||||
+ DomainNameMaxLen
|
||||
+ DomainNameOffset
|
||||
+ UserNameLen
|
||||
+ UserNameMaxLen
|
||||
+ UserNameOffset
|
||||
+ WorkstationLen
|
||||
+ WorkstationMaxLen
|
||||
+ WorkstationOffset
|
||||
+ EncryptedRandomSessionKeyLen
|
||||
+ EncryptedRandomSessionKeyMaxLen
|
||||
+ EncryptedRandomSessionKeyOffset
|
||||
+ NegotiateFlags
|
||||
+ ProductMajorVersion
|
||||
+ ProductMinorVersion
|
||||
+ ProductBuild
|
||||
+ VersionReserved1
|
||||
+ VersionReserved2
|
||||
+ VersionReserved3
|
||||
+ NTLMRevisionCurrent
|
||||
)
|
||||
assert BODY_LENGTH == len(msg3), "BODY_LENGTH: %d != msg3: %d" % (
|
||||
BODY_LENGTH,
|
||||
len(msg3),
|
||||
)
|
||||
Payload = (
|
||||
DomainName
|
||||
+ UserName
|
||||
+ Workstation
|
||||
+ LmChallengeResponse
|
||||
+ NtChallengeResponse
|
||||
+ EncryptedRandomSessionKey
|
||||
)
|
||||
msg3 += Payload
|
||||
msg3 = base64.b64encode(msg3)
|
||||
return msg3.decode()
|
||||
|
||||
|
||||
def calc_resp(password_hash, server_challenge):
|
||||
"""calc_resp generates the LM response given a 16-byte password hash and the
|
||||
challenge from the type-2 message.
|
||||
@param password_hash
|
||||
16-byte password hash
|
||||
@param server_challenge
|
||||
8-byte challenge from type-2 message
|
||||
returns
|
||||
24-byte buffer to contain the LM response upon return
|
||||
"""
|
||||
# padding with zeros to make the hash 21 bytes long
|
||||
password_hash = password_hash + b"\0" * (21 - len(password_hash))
|
||||
res = b""
|
||||
dobj = des.DES(password_hash[0:7])
|
||||
res = res + dobj.encrypt(server_challenge[0:8])
|
||||
|
||||
dobj = des.DES(password_hash[7:14])
|
||||
res = res + dobj.encrypt(server_challenge[0:8])
|
||||
|
||||
dobj = des.DES(password_hash[14:21])
|
||||
res = res + dobj.encrypt(server_challenge[0:8])
|
||||
return res
|
||||
|
||||
|
||||
def ComputeResponse(
|
||||
ResponseKeyNT,
|
||||
ResponseKeyLM,
|
||||
ServerChallenge,
|
||||
ServerName,
|
||||
ClientChallenge="\xaa" * 8,
|
||||
Time="\0" * 8,
|
||||
):
|
||||
LmChallengeResponse = (
|
||||
hmac.new(ResponseKeyLM, ServerChallenge + ClientChallenge).digest()
|
||||
+ ClientChallenge
|
||||
)
|
||||
|
||||
Responserversion = b"\x01"
|
||||
HiResponserversion = b"\x01"
|
||||
temp = (
|
||||
Responserversion
|
||||
+ HiResponserversion
|
||||
+ b"\0" * 6
|
||||
+ Time
|
||||
+ ClientChallenge
|
||||
+ b"\0" * 4
|
||||
+ ServerChallenge
|
||||
+ b"\0" * 4
|
||||
)
|
||||
NTProofStr = hmac.new(ResponseKeyNT, ServerChallenge + temp).digest()
|
||||
NtChallengeResponse = NTProofStr + temp
|
||||
|
||||
SessionBaseKey = hmac.new(ResponseKeyNT, NTProofStr).digest()
|
||||
return (NtChallengeResponse, LmChallengeResponse)
|
||||
|
||||
|
||||
def ntlm2sr_calc_resp(ResponseKeyNT, ServerChallenge, ClientChallenge=b"\xaa" * 8):
|
||||
import hashlib
|
||||
|
||||
LmChallengeResponse = ClientChallenge + b"\0" * 16
|
||||
sess = hashlib.md5(ServerChallenge + ClientChallenge).digest()
|
||||
NtChallengeResponse = calc_resp(ResponseKeyNT, sess[0:8])
|
||||
return (NtChallengeResponse, LmChallengeResponse)
|
||||
|
||||
|
||||
def create_LM_hashed_password_v1(passwd):
|
||||
"setup LanManager password"
|
||||
"create LanManager hashed password"
|
||||
# if the passwd provided is already a hash, we just return the first half
|
||||
if re.match(r"^[\w]{32}:[\w]{32}$", passwd):
|
||||
return binascii.unhexlify(passwd.split(":")[0])
|
||||
|
||||
# fix the password length to 14 bytes
|
||||
passwd = passwd.upper()
|
||||
lm_pw = passwd + "\0" * (14 - len(passwd))
|
||||
lm_pw = bytes(passwd[0:14], "utf8")
|
||||
|
||||
# do hash
|
||||
magic_str = b"KGS!@#$%" # page 57 in [MS-NLMP]
|
||||
|
||||
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 create_NT_hashed_password_v1(passwd, user=None, domain=None):
|
||||
"create NT hashed password"
|
||||
# if the passwd provided is already a hash, we just return the second half
|
||||
if re.match(r"^[\w]{32}:[\w]{32}$", passwd):
|
||||
return binascii.unhexlify(passwd.split(":")[1])
|
||||
|
||||
digest = hashlib.new("md4", passwd.encode("utf-16le")).digest()
|
||||
return digest
|
||||
|
||||
|
||||
def create_NT_hashed_password_v2(passwd, user, domain):
|
||||
"create NT hashed password"
|
||||
digest = create_NT_hashed_password_v1(passwd)
|
||||
|
||||
return hmac.new(digest, (user.upper() + domain).encode("utf-16le")).digest()
|
||||
return digest
|
||||
|
||||
|
||||
def create_sessionbasekey(password):
|
||||
return hashlib.new("md4", create_NT_hashed_password_v1(password)).digest()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
from binascii import unhexlify, hexlify
|
||||
|
||||
def ByteToHex(byteStr):
|
||||
"""
|
||||
Convert a byte string to it's hex string representation e.g. for output.
|
||||
"""
|
||||
return " ".join(["%02X" % x for x in byteStr])
|
||||
|
||||
def HexToByte(hexStr):
|
||||
"""
|
||||
Convert a string hex byte values into a byte string. The Hex Byte values may
|
||||
or may not be space separated.
|
||||
"""
|
||||
hexStr = "".join(hexStr.split(" "))
|
||||
|
||||
return unhexlify(hexStr)
|
||||
|
||||
ServerChallenge = HexToByte("01 23 45 67 89 ab cd ef")
|
||||
ClientChallenge = b"\xaa" * 8
|
||||
Time = b"\x00" * 8
|
||||
Workstation = "COMPUTER".encode("utf-16-le")
|
||||
ServerName = "Server".encode("utf-16-le")
|
||||
User = "User"
|
||||
Domain = "Domain"
|
||||
Password = "Password"
|
||||
RandomSessionKey = "\55" * 16
|
||||
assert HexToByte(
|
||||
"e5 2c ac 67 41 9a 9a 22 4a 3b 10 8f 3f a6 cb 6d"
|
||||
) == create_LM_hashed_password_v1(
|
||||
Password
|
||||
) # [MS-NLMP] page 72
|
||||
assert HexToByte(
|
||||
"a4 f4 9c 40 65 10 bd ca b6 82 4e e7 c3 0f d8 52"
|
||||
) == create_NT_hashed_password_v1(
|
||||
Password
|
||||
) # [MS-NLMP] page 73
|
||||
assert HexToByte(
|
||||
"d8 72 62 b0 cd e4 b1 cb 74 99 be cc cd f1 07 84"
|
||||
) == create_sessionbasekey(Password)
|
||||
assert HexToByte(
|
||||
"67 c4 30 11 f3 02 98 a2 ad 35 ec e6 4f 16 33 1c 44 bd be d9 27 84 1f 94"
|
||||
) == calc_resp(create_NT_hashed_password_v1(Password), ServerChallenge)
|
||||
assert HexToByte(
|
||||
"98 de f7 b8 7f 88 aa 5d af e2 df 77 96 88 a1 72 de f1 1c 7d 5c cd ef 13"
|
||||
) == calc_resp(create_LM_hashed_password_v1(Password), ServerChallenge)
|
||||
|
||||
(NTLMv1Response, LMv1Response) = ntlm2sr_calc_resp(
|
||||
create_NT_hashed_password_v1(Password), ServerChallenge, ClientChallenge
|
||||
)
|
||||
assert (
|
||||
HexToByte(
|
||||
"aa aa aa aa aa aa aa aa 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"
|
||||
)
|
||||
== LMv1Response
|
||||
) # [MS-NLMP] page 75
|
||||
assert (
|
||||
HexToByte(
|
||||
"75 37 f8 03 ae 36 71 28 ca 45 82 04 bd e7 ca f8 1e 97 ed 26 83 26 72 32"
|
||||
)
|
||||
== NTLMv1Response
|
||||
)
|
||||
|
||||
assert HexToByte(
|
||||
"0c 86 8a 40 3b fd 7a 93 a3 00 1e f2 2e f0 2e 3f"
|
||||
) == create_NT_hashed_password_v2(
|
||||
Password, User, Domain
|
||||
) # [MS-NLMP] page 76
|
||||
ResponseKeyLM = ResponseKeyNT = create_NT_hashed_password_v2(Password, User, Domain)
|
||||
(NTLMv2Response, LMv2Response) = ComputeResponse(
|
||||
ResponseKeyNT, ResponseKeyLM, ServerChallenge, ServerName, ClientChallenge, Time
|
||||
)
|
||||
assert (
|
||||
HexToByte(
|
||||
"86 c3 50 97 ac 9c ec 10 25 54 76 4a 57 cc cc 19 aa aa aa aa aa aa aa aa"
|
||||
)
|
||||
== LMv2Response
|
||||
) # [MS-NLMP] page 76
|
||||
assert (
|
||||
"TlRMTVNTUAABAAAAB7IIogYABgAwAAAACAAIACgAAAAFASgKAAAAD1dTMDQyMzc4RE9NQUlO"
|
||||
== create_NTLM_NEGOTIATE_MESSAGE("DOMAIN\\User")
|
||||
)
|
||||
|
||||
# expected failure
|
||||
# According to the spec in section '3.3.2 NTLM v2 Authentication' the NTLMv2Response should be longer than the value given on page 77 (this suggests a mistake in the spec)
|
||||
# ~ assert HexToByte("68 cd 0a b8 51 e5 1c 96 aa bc 92 7b eb ef 6a 1c") == NTLMv2Response, "\nExpected: 68 cd 0a b8 51 e5 1c 96 aa bc 92 7b eb ef 6a 1c\nActual: %s" % ByteToHex(NTLMv2Response) # [MS-NLMP] page 77
|
||||
125
py/libs/mschap3/utils.py
Executable file
125
py/libs/mschap3/utils.py
Executable file
|
|
@ -0,0 +1,125 @@
|
|||
# This file is part of 'NTLM Authorization Proxy Server'
|
||||
# Copyright 2001 Dmitry A. Rozmanov <dima@xenon.spb.ru>
|
||||
#
|
||||
# NTLM APS is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# NTLM APS 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 General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with the sofware; see the file COPYING. If not, write to the
|
||||
# Free Software Foundation, Inc.,
|
||||
# 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
|
||||
#
|
||||
|
||||
import string
|
||||
|
||||
hd = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',]
|
||||
|
||||
#--------------------------------------------------------------------------------------------
|
||||
def str2hex_num(str):
|
||||
res = 0
|
||||
for i in str:
|
||||
res = res << 8
|
||||
res = res + int(ord(i))
|
||||
return hex(res)
|
||||
|
||||
#--------------------------------------------------------------------------------------------
|
||||
def str2hex(str, delimiter=''):
|
||||
res = ''
|
||||
for i in str:
|
||||
res = res + hd[ord(i)/16]
|
||||
res = res + hd[ord(i) - ((ord(i)/16) * 16)]
|
||||
res = res + delimiter
|
||||
return res
|
||||
|
||||
#--------------------------------------------------------------------------------------------
|
||||
def str2dec(str, delimiter=''):
|
||||
res = ''
|
||||
for i in str:
|
||||
res = res + '%3d' % ord(i)
|
||||
res = res + delimiter
|
||||
return res
|
||||
|
||||
|
||||
#--------------------------------------------------------------------------------------------
|
||||
def hex2str(hex_str):
|
||||
res = ''
|
||||
for i in range(0, len(hex_str), 2):
|
||||
res = res + (chr(hd.index(hex_str[i]) * 16 + hd.index(hex_str[i+1])))
|
||||
return res
|
||||
|
||||
#--------------------------------------------------------------------------------------------
|
||||
def str2prn_str(bin_str, delimiter=''):
|
||||
""
|
||||
res = ''
|
||||
for i in bin_str:
|
||||
if ord(i) > 31: res = res + i
|
||||
else: res = res + '.'
|
||||
res = res + delimiter
|
||||
return res
|
||||
|
||||
#--------------------------------------------------------------------------------------------
|
||||
def byte2bin_str(char):
|
||||
""
|
||||
res = ''
|
||||
t = ord(char)
|
||||
while t > 0:
|
||||
t1 = t / 2
|
||||
if t != 2 * t1: res = '1' + res
|
||||
else: res = '0' + res
|
||||
t = t1
|
||||
if len(res) < 8: res = '0' * (8 - len(res)) + res
|
||||
|
||||
return res
|
||||
|
||||
#--------------------------------------------------------------------------------------------
|
||||
def str2lst(str):
|
||||
res = []
|
||||
for i in str:
|
||||
res.append(ord(i))
|
||||
return res
|
||||
|
||||
#--------------------------------------------------------------------------------------------
|
||||
def lst2str(lst):
|
||||
res = ''
|
||||
for i in lst:
|
||||
res = res + chr(i & 0xFF)
|
||||
return res
|
||||
|
||||
#--------------------------------------------------------------------------------------------
|
||||
def int2chrs(number_int):
|
||||
""
|
||||
return chr(number_int & 0xFF) + chr((number_int >> 8) & 0xFF)
|
||||
|
||||
#--------------------------------------------------------------------------------------------
|
||||
def bytes2int(bytes):
|
||||
""
|
||||
return ord(bytes[1]) * 256 + ord(bytes[0])
|
||||
|
||||
#--------------------------------------------------------------------------------------------
|
||||
def int2hex_str(number_int16):
|
||||
""
|
||||
res = '0x'
|
||||
ph = int(number_int16) / 256
|
||||
res = res + hd[ph/16]
|
||||
res = res + hd[ph - ((ph/16) * 16)]
|
||||
|
||||
pl = int(number_int16) - (ph * 256)
|
||||
res = res + hd[pl/16]
|
||||
res = res + hd[pl - ((pl/16) * 16)]
|
||||
|
||||
return res
|
||||
|
||||
#--------------------------------------------------------------------------------------------
|
||||
def str2unicode(string):
|
||||
"converts ascii string to dumb unicode"
|
||||
res = ''
|
||||
for i in string:
|
||||
res = res + i + '\000'
|
||||
return res
|
||||
Loading…
Add table
Add a link
Reference in a new issue