MikroWizard Initial commit | MikroMan Welcome to the world :)

This commit is contained in:
sepehr 2024-07-20 15:48:46 +03:30
commit 8c49b9a55d
96 changed files with 12274 additions and 0 deletions

150
py/libs/mschap3/U32.py Normal file
View 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)

View file

97
py/libs/mschap3/des.py Normal file
View 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
View 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

File diff suppressed because it is too large Load diff

253
py/libs/mschap3/md4.py Executable file
View 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
View 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
View 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
View 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
View 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