diff --git a/PKG-INFO b/PKG-INFO
index 49098c0..92c6343 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,6 +1,6 @@
 Metadata-Version: 1.2
 Name: minikerberos
-Version: 0.2.0
+Version: 0.2.11
 Summary: Kerberos manipulation library in pure Python
 Home-page: https://github.com/skelsec/minikerberos
 Author: Tamas Jos
diff --git a/debian/changelog b/debian/changelog
index 6d57f72..8552f8c 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+python-minikerberos (0.2.11-0kali1) UNRELEASED; urgency=low
+
+  * New upstream release.
+
+ -- Kali Janitor <janitor@kali.org>  Mon, 19 Apr 2021 09:20:38 -0000
+
 python-minikerberos (0.2.0-0kali1) kali-dev; urgency=medium
 
   * Initial release
diff --git a/minikerberos.egg-info/PKG-INFO b/minikerberos.egg-info/PKG-INFO
index 49098c0..92c6343 100644
--- a/minikerberos.egg-info/PKG-INFO
+++ b/minikerberos.egg-info/PKG-INFO
@@ -1,6 +1,6 @@
 Metadata-Version: 1.2
 Name: minikerberos
-Version: 0.2.0
+Version: 0.2.11
 Summary: Kerberos manipulation library in pure Python
 Home-page: https://github.com/skelsec/minikerberos
 Author: Tamas Jos
diff --git a/minikerberos.egg-info/SOURCES.txt b/minikerberos.egg-info/SOURCES.txt
index 94d8875..44aeb1b 100644
--- a/minikerberos.egg-info/SOURCES.txt
+++ b/minikerberos.egg-info/SOURCES.txt
@@ -25,6 +25,7 @@ minikerberos/common/target.py
 minikerberos/common/url.py
 minikerberos/common/utils.py
 minikerberos/crypto/BASE.py
+minikerberos/crypto/MD4.py
 minikerberos/crypto/RC4.py
 minikerberos/crypto/__init__.py
 minikerberos/crypto/hashing.py
@@ -48,10 +49,12 @@ minikerberos/examples/getTGS.py
 minikerberos/examples/getTGT.py
 minikerberos/examples/kirbi2ccache.py
 minikerberos/gssapi/__init__.py
+minikerberos/gssapi/channelbindings.py
 minikerberos/gssapi/gssapi.py
 minikerberos/network/__init__.py
 minikerberos/network/aioclientsocket.py
 minikerberos/network/aioclientsockssocket.py
+minikerberos/network/aioclientwsnetsocket.py
 minikerberos/network/clientsocket.py
 minikerberos/network/selector.py
 minikerberos/protocol/__init__.py
diff --git a/minikerberos.egg-info/requires.txt b/minikerberos.egg-info/requires.txt
index ceb1eaf..05c4cd8 100644
--- a/minikerberos.egg-info/requires.txt
+++ b/minikerberos.egg-info/requires.txt
@@ -1,2 +1,2 @@
 asn1crypto>=1.3.0
-asysocks>=0.0.2
+asysocks>=0.0.11
diff --git a/minikerberos/_version.py b/minikerberos/_version.py
index 92d8523..49fe45a 100644
--- a/minikerberos/_version.py
+++ b/minikerberos/_version.py
@@ -1,5 +1,5 @@
 
-__version__ = "0.2.0"
+__version__ = "0.2.11"
 __banner__ = \
 """
 # minikerberos %s 
diff --git a/minikerberos/aioclient.py b/minikerberos/aioclient.py
index 94fac4b..980b4b3 100644
--- a/minikerberos/aioclient.py
+++ b/minikerberos/aioclient.py
@@ -15,7 +15,7 @@ from minikerberos.common.ccache import CCACHE
 from minikerberos.network.aioclientsocket import AIOKerberosClientSocket
 from minikerberos.protocol.asn1_structs import METHOD_DATA, ETYPE_INFO, ETYPE_INFO2, \
 	PADATA_TYPE, PA_PAC_REQUEST, PA_ENC_TS_ENC, EncryptedData, krb5_pvno, KDC_REQ_BODY, \
-	AS_REQ, KDCOptions, PrincipalName, EncASRepPart, EncTGSRepPart, PrincipalName, Realm, \
+	AS_REQ, TGS_REP, KDCOptions, PrincipalName, EncASRepPart, EncTGSRepPart, PrincipalName, Realm, \
 	Checksum, APOptions, Authenticator, Ticket, AP_REQ, TGS_REQ, CKSUMTYPE, \
 	PA_FOR_USER_ENC, PA_PAC_OPTIONS, PA_PAC_OPTIONSTypes
 
@@ -26,13 +26,12 @@ from minikerberos.protocol.structures import AuthenticatorChecksum
 from minikerberos.gssapi.gssapi import GSSAPIFlags
 from minikerberos.network.selector import KerberosClientSocketSelector
 
-
 class AIOKerberosClient:
-	def __init__(self, ccred, target, ccache = None):
+	def __init__(self, ccred, target):
 		self.usercreds = ccred
 		self.target = target
 		self.ksoc = KerberosClientSocketSelector.select(self.target, True)
-		self.ccache = CCACHE() if ccache is None else ccache
+		self.ccache = CCACHE() if self.usercreds.ccache is None else self.usercreds.ccache
 		self.kerberos_session_key = None
 		self.kerberos_TGT = None
 		self.kerberos_TGT_encpart = None
@@ -119,9 +118,43 @@ class AIOKerberosClient:
 		logger.debug('Sending TGT request to server')
 		rep = await self.ksoc.sendrecv(req.dump())
 		if rep.name == 'KRB_ERROR':
-			raise Exception('Preauth failed! %s' % str(rep))
+			raise KerberosError(rep, 'Preauth failed!')
 		return rep
 
+	def tgt_from_ccache(self, override_etype = None):
+		try:
+			if self.ccache is None:
+				raise Exception('No CCACHE file found')
+			
+			for tgt, keystruct in self.ccache.get_all_tgt():
+				if self.usercreds.ccache_spn_strict_check is True:
+					our_user = str(self.usercreds.username) + '@' + self.usercreds.domain
+					ticket_for = tgt['cname']['name-string'][0] + '@' + tgt['crealm']
+					if ticket_for.upper() == our_user.upper():
+						logger.debug('Found TGT for user %s' % our_user)
+						self.kerberos_TGT = tgt
+						self.kerberos_TGT_encpart = tgt['enc-part']
+						self.kerberos_session_key = Key(keystruct['keytype'], keystruct['keyvalue'])
+						self.kerberos_cipher = _enctype_table[keystruct['keytype']]
+						self.kerberos_cipher_type = keystruct['keytype']
+										
+						return True, None
+				
+				else:
+					self.kerberos_TGT = tgt
+					self.kerberos_TGT_encpart = tgt['enc-part']
+					self.kerberos_session_key = Key(keystruct['keytype'], keystruct['keyvalue'])
+					self.kerberos_cipher = _enctype_table[keystruct['keytype']]
+					self.kerberos_cipher_type = keystruct['keytype']
+					return True, None
+
+			logger.debug('No TGT found for user %s' % our_user)
+			raise Exception('No TGT found for user %s' % our_user) 
+
+		except Exception as e:
+			return None, e
+
+
 	async def get_TGT(self, override_etype = None, decrypt_tgt = True):
 		"""
 		decrypt_tgt: used for asreproast attacks
@@ -130,6 +163,12 @@ class AIOKerberosClient:
 			2. Depending on the response (either error or AS_REP with TGT) we either send another AS_REQ with the encrypted data or return the TGT (or fail miserably)
 			3. PROFIT
 		"""
+
+		#first, let's check if CCACHE has the correct ticket already
+		_, err = self.tgt_from_ccache(override_etype)
+		if err is None:
+			return
+
 		logger.debug('Generating initial TGT without authentication data')
 		now = datetime.datetime.now(datetime.timezone.utc)
 		kdc_req_body = {}
@@ -202,7 +241,33 @@ class AIOKerberosClient:
 		logger.debug('Got valid TGT')
 		
 		return 
-		
+
+	def tgs_from_ccache(self, spn_user, override_etype):
+		try:
+			if self.ccache is None:
+				raise Exception('No CCACHE file found')
+			
+			for tgs, keystruct in self.ccache.get_all_tgs():
+				ticket_for = ('/'.join(tgs['ticket']['sname']['name-string'])) + '@' + tgs['ticket']['realm']
+				if self.usercreds.ccache_spn_strict_check is True:
+					if ticket_for.upper() == str(spn_user).upper():
+						logger.debug('Found TGS for user %s' % ticket_for)
+						key = Key(keystruct['keytype'], keystruct['keyvalue'])
+						tgs = TGS_REP(tgs).native
+						return tgs, tgs['enc-part'], key, None
+				else:
+					# I hope you know what you are doing at this point...
+					key = Key(keystruct['keytype'], keystruct['keyvalue'])
+					tgs = TGS_REP(tgs).native
+					return tgs, tgs['enc-part'], key, None
+
+			logger.debug('No TGS found for user %s' % ticket_for)
+			raise Exception('No TGS found for user %s' % ticket_for) 
+
+			
+		except Exception as e:
+			return None, None, None, e
+
 	async def get_TGS(self, spn_user, override_etype = None, is_linux = False):
 		"""
 		Requests a TGS ticket for the specified user.
@@ -211,7 +276,20 @@ class AIOKerberosClient:
 		spn_user: KerberosTarget: the service user you want to get TGS for.
 		override_etype: None or list of etype values (int) Used mostly for kerberoasting, will override the AP_REQ supported etype values (which is derived from the TGT) to be able to recieve whatever tgs tiecket 
 		"""
-		#construct tgs_req
+		
+		#first, let's check if CCACHE has the correct ticket already
+		tgs, encTGSRepPart, key, err = self.tgs_from_ccache(spn_user, override_etype)
+		if err is None:
+			return tgs, encTGSRepPart, key
+
+		
+		if self.kerberos_TGT is None:
+			#let's check if CCACHE has a TGT for us
+			_, err = self.tgt_from_ccache(override_etype=override_etype)
+			if err is not None:
+				raise Exception('No TGT found in CCACHE!')
+
+		#nope, we need to contact the server
 		logger.debug('Constructing TGS request for user %s' % spn_user.get_formatted_pname())
 		now = datetime.datetime.now(datetime.timezone.utc)
 		kdc_req_body = {}
@@ -240,8 +318,8 @@ class AIOKerberosClient:
 			chksum = {}
 			chksum['cksumtype'] = 0x8003
 			chksum['checksum'] = ac.to_bytes()
-			print(chksum['checksum'])
-			
+
+
 			authenticator_data['cksum'] = Checksum(chksum)
 			authenticator_data['seq-number'] = 0
 		
@@ -269,7 +347,7 @@ class AIOKerberosClient:
 		logger.debug('Constructing TGS request to server')
 		rep = await self.ksoc.sendrecv(req.dump())
 		if rep.name == 'KRB_ERROR':
-			raise Exception('get_TGS failed! %s' % str(rep))
+			raise KerberosError(rep, 'get_TGS failed!')
 		logger.debug('Got TGS reply, decrypting...')
 		tgs = rep.native
 		
@@ -289,7 +367,7 @@ class AIOKerberosClient:
 		"""
 		
 		if not self.kerberos_TGT:
-			logger.debug('S4U2self invoked, but TGT is not available! Fetching TGT...')
+			logger.debug('[S4U2self] TGT is not available! Fetching TGT...')
 			self.get_TGT()
 		
 		supp_enc = self.usercreds.get_preferred_enctype(supp_enc_methods)
@@ -324,11 +402,11 @@ class AIOKerberosClient:
 		S4UByteArray += user_to_impersonate.username.encode()
 		S4UByteArray += user_to_impersonate.domain.encode()
 		S4UByteArray += auth_package_name.encode()
-		logger.debug('S4U2self: S4UByteArray: %s' % S4UByteArray.hex())
-		logger.debug('S4U2self: S4UByteArray: %s' % S4UByteArray)
+		logger.debug('[S4U2self] S4UByteArray: %s' % S4UByteArray.hex())
+		logger.debug('[S4U2self] S4UByteArray: %s' % S4UByteArray)
 		
 		chksum_data = _HMACMD5.checksum(self.kerberos_session_key, 17, S4UByteArray)
-		logger.debug('S4U2self: chksum_data: %s' % chksum_data.hex())
+		logger.debug('[S4U2self] chksum_data: %s' % chksum_data.hex())
 		
 		
 		chksum = {}
@@ -366,29 +444,29 @@ class AIOKerberosClient:
 		
 		req = TGS_REQ(krb_tgs_req)
 		
-		logger.debug('Sending S4U2self request to server')
+		logger.debug('[S4U2self] Sending request to server')
 		
 		reply = await self.ksoc.sendrecv(req.dump())
 		if reply.name == 'KRB_ERROR':
+			emsg = 'S4U2self failed!'
 			if reply.native['error-code'] == 16:
-				logger.error('S4U2self: Failed to get S4U2self! Error code (16) indicates that delegation is not enabled for this account!')
-			
-			raise Exception('S4U2self failed! %s' % str(reply))
+				emsg = 'S4U2self: Failed to get S4U2self! Error code (16) indicates that delegation is not enabled for this account!'			
+			raise KerberosError(reply, emsg)
 		
-		logger.debug('Got S4U2self reply, decrypting...')
+		logger.debug('[S4U2self] Got reply, decrypting...')
 		tgs = reply.native
 		
 		encTGSRepPart = EncTGSRepPart.load(self.kerberos_cipher.decrypt(self.kerberos_session_key, 8, tgs['enc-part']['cipher'])).native
 		key = Key(encTGSRepPart['key']['keytype'], encTGSRepPart['key']['keyvalue'])
 		
 		self.ccache.add_tgs(tgs, encTGSRepPart)
-		logger.debug('Got valid TGS reply')
+		logger.debug('[S4U2self] Got valid TGS reply')
 		self.kerberos_TGS = tgs
 		return tgs, encTGSRepPart, key
-				
 		
 	# https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-sfu/c920c148-8a9c-42e9-b8e9-db5755cd281b
 	async def S4U2proxy(self, s4uself_ticket, spn_user, supp_enc_methods = [EncryptionType.DES_CBC_CRC,EncryptionType.DES_CBC_MD4,EncryptionType.DES_CBC_MD5,EncryptionType.DES3_CBC_SHA1,EncryptionType.ARCFOUR_HMAC_MD5,EncryptionType.AES256_CTS_HMAC_SHA1_96,EncryptionType.AES128_CTS_HMAC_SHA1_96]):
+		logger.debug('[S4U2proxy] Impersonating %s' % '/'.join(spn_user.get_principalname()))
 		now = datetime.datetime.now(datetime.timezone.utc)
 		supp_enc = self.usercreds.get_preferred_enctype(supp_enc_methods)
 		
@@ -439,13 +517,24 @@ class AIOKerberosClient:
 		
 		reply = await self.ksoc.sendrecv(req.dump())
 		if reply.name == 'KRB_ERROR':
+			emsg = 'S4U2proxy failed!'
 			if reply.native['error-code'] == 16:
-				logger.error('S4U2proxy: Failed to get S4U2proxy! Error code (16) indicates that delegation is not enabled for this account!')
-			
-			raise Exception('S4U2proxy failed! %s' % str(reply))
+				emsg = 'S4U2proxy: Failed to get S4U2proxy! Error code (16) indicates that delegation is not enabled for this account!'
 			
+			raise KerberosError(reply, emsg)
+		
+		logger.debug('[S4U2proxy] Got server reply, decrypting...')
+		tgs = reply.native
 		
-	def construct_apreq(self, tgs, encTGSRepPart, sessionkey, flags = None, seq_number = 0, ap_opts = []):
+		encTGSRepPart = EncTGSRepPart.load(self.kerberos_cipher.decrypt(self.kerberos_session_key, 8, tgs['enc-part']['cipher'])).native
+		key = Key(encTGSRepPart['key']['keytype'], encTGSRepPart['key']['keyvalue'])
+		
+		self.ccache.add_tgs(tgs, encTGSRepPart)
+		logger.debug('[S4U2proxy] Got valid TGS reply')
+
+		return tgs, encTGSRepPart, key
+		
+	def construct_apreq(self, tgs, encTGSRepPart, sessionkey, flags = None, seq_number = 0, ap_opts = [], cb_data = None):
 		now = datetime.datetime.now(datetime.timezone.utc)
 		authenticator_data = {}
 		authenticator_data['authenticator-vno'] = krb5_pvno
@@ -456,7 +545,10 @@ class AIOKerberosClient:
 		if flags is not None:
 			ac = AuthenticatorChecksum()
 			ac.flags = flags
-			ac.channel_binding = b'\x00'*16
+
+			ac.channel_binding = cb_data
+			if cb_data is None:
+				ac.channel_binding = b'\x00'*16
 			
 			chksum = {}
 			chksum['cksumtype'] = 0x8003
@@ -478,7 +570,7 @@ class AIOKerberosClient:
 		return AP_REQ(ap_req).dump()
 		
 	@staticmethod
-	def construct_apreq_from_ticket(ticket_data, sessionkey, crealm, cname, flags = None, seq_number = 0, ap_opts = []):
+	def construct_apreq_from_ticket(ticket_data, sessionkey, crealm, cname, flags = None, seq_number = 0, ap_opts = [], cb_data = None):
 		"""
 		ticket: bytes of Ticket
 		"""
@@ -492,7 +584,9 @@ class AIOKerberosClient:
 		if flags is not None:
 			ac = AuthenticatorChecksum()
 			ac.flags = flags
-			ac.channel_binding = b'\x00'*16
+			ac.channel_binding = cb_data
+			if cb_data is None:
+				ac.channel_binding = b'\x00'*16
 			
 			chksum = {}
 			chksum['cksumtype'] = 0x8003
@@ -514,5 +608,5 @@ class AIOKerberosClient:
 		return AP_REQ(ap_req).dump()
 		
 	async def getST(self, target_user, service_spn):
-		tgs, encTGSRepPart, key = await self.S4U2self(target_user)
-		return self.S4U2proxy(tgs['ticket'], service_spn)
+		tgs, encTGSRepPart, key  = await self.S4U2self(target_user)
+		return await self.S4U2proxy(tgs['ticket'], service_spn)
diff --git a/minikerberos/client.py b/minikerberos/client.py
index d48adeb..303f7b5 100644
--- a/minikerberos/client.py
+++ b/minikerberos/client.py
@@ -234,7 +234,6 @@ class KerbrosClient:
 			chksum = {}
 			chksum['cksumtype'] = 0x8003
 			chksum['checksum'] = ac.to_bytes()
-			print(chksum['checksum'])
 			
 			authenticator_data['cksum'] = Checksum(chksum)
 			authenticator_data['seq-number'] = 0
diff --git a/minikerberos/common/ccache.py b/minikerberos/common/ccache.py
index 8c71c65..7931ad8 100644
--- a/minikerberos/common/ccache.py
+++ b/minikerberos/common/ccache.py
@@ -98,7 +98,7 @@ class Credential:
 		tgs_realm              = res['realm']
 		if tgs_encryption_type == EncryptionType.AES256_CTS_HMAC_SHA1_96.value:
 			tgs_checksum           = res['enc-part']['cipher'][-12:]
-			tgs_encrypted_data2    = res['enc-part']['cipher'][:-12:]
+			tgs_encrypted_data2    = res['enc-part']['cipher'][:-12]
 			return '$krb5tgs$%s$%s$%s$%s$%s' % (tgs_encryption_type,tgs_name_string,tgs_realm, tgs_checksum.hex(), tgs_encrypted_data2.hex() )
 		else:
 			tgs_checksum           = res['enc-part']['cipher'][:16]
@@ -122,6 +122,24 @@ class Credential:
 		t = EncryptionKey(self.key.to_asn1()).native
 		
 		return tgt_rep, t
+
+	def to_tgs(self):
+		"""
+		Returns the native format of an AS_REP message and the sessionkey in EncryptionKey native format
+		"""
+		enc_part = EncryptedData({'etype': 1, 'cipher': b''})
+		
+		tgt_rep = {}
+		tgt_rep['pvno'] = krb5_pvno
+		tgt_rep['msg-type'] = MESSAGE_TYPE.KRB_AS_REP.value
+		tgt_rep['crealm'] = self.server.realm.to_string()
+		tgt_rep['cname'] = self.client.to_asn1()[0]
+		tgt_rep['ticket'] = Ticket.load(self.ticket.to_asn1()).native
+		tgt_rep['enc-part'] = enc_part.native
+
+		t = EncryptionKey(self.key.to_asn1()).native
+		
+		return tgt_rep, t
 		
 	def to_kirbi(self):
 		filename = '%s@%s_%s' % (self.client.to_string() , self.server.to_string(), hashlib.sha1(self.ticket.to_asn1()).hexdigest()[:8])
@@ -131,11 +149,13 @@ class Credential:
 		krbcredinfo['pname'] = self.client.to_asn1()[0]
 		krbcredinfo['flags'] = core.IntegerBitString(self.tktflags).cast(TicketFlags)
 		if self.time.authtime != 0: #this parameter is not mandatory, and most of the time not present
-			krbcredinfo['authtime'] = datetime.datetime.fromtimestamp(self.time.authtime)
-		krbcredinfo['starttime'] = datetime.datetime.fromtimestamp(self.time.starttime)
-		krbcredinfo['endtime'] = datetime.datetime.fromtimestamp(self.time.endtime)
+			krbcredinfo['authtime'] = datetime.datetime.fromtimestamp(self.time.authtime, datetime.timezone.utc)
+		if self.time.starttime != 0:
+			krbcredinfo['starttime'] = datetime.datetime.fromtimestamp(self.time.starttime, datetime.timezone.utc)
+		if self.time.endtime != 0:
+			krbcredinfo['endtime'] = datetime.datetime.fromtimestamp(self.time.endtime, datetime.timezone.utc)
 		if self.time.renew_till != 0: #this parameter is not mandatory, and sometimes it's not present
-			krbcredinfo['renew-till'] = datetime.datetime.fromtimestamp(self.time.authtime)
+			krbcredinfo['renew-till'] = datetime.datetime.fromtimestamp(self.time.authtime, datetime.timezone.utc)
 		krbcredinfo['srealm'] = self.server.realm.to_string()
 		krbcredinfo['sname'] = self.server.to_asn1()[0]
 		
@@ -184,7 +204,7 @@ class Credential:
 		for _ in range(c.num_address):
 			c.addrs.append(Address.parse(reader))
 		c.num_authdata = int.from_bytes(reader.read(4), byteorder='big', signed=False)
-		for i in range(c.num_authdata):
+		for _ in range(c.num_authdata):
 			c.authdata.append(Authdata.parse(reader))
 		c.ticket = CCACHEOctetString.parse(reader)
 		c.second_ticket = CCACHEOctetString.parse(reader)
@@ -196,8 +216,8 @@ class Credential:
 		
 	def summary(self):
 		return [ 
-			'%s@%s' % 	(self.client.to_string(),self.client.realm.to_string()), 
-			'%s@%s' % 	(self.server.to_string(), self.server.realm.to_string()),
+			'%s@%s' % 	(self.client.to_string(separator='/'),self.client.realm.to_string()), 
+			'%s@%s' % 	(self.server.to_string(separator='/'), self.server.realm.to_string()),
 			datetime.datetime.fromtimestamp(self.time.starttime).isoformat() if self.time.starttime != 0 else 'N/A',
 			datetime.datetime.fromtimestamp(self.time.endtime).isoformat() if self.time.endtime != 0 else 'N/A',
 			datetime.datetime.fromtimestamp(self.time.renew_till).isoformat() if self.time.renew_till != 0 else 'N/A',
@@ -272,17 +292,14 @@ class Times:
 	@staticmethod
 	def from_asn1(enc_as_rep_part):
 		t = Times()
-		if 'authtime' in enc_as_rep_part and enc_as_rep_part['authtime']:
-			t.authtime = dt_to_kerbtime(enc_as_rep_part['authtime'])
-		else:
-			t.authtime = 0
-		if 'starttime' in enc_as_rep_part and enc_as_rep_part['starttime']:
-			t.starttime = dt_to_kerbtime(enc_as_rep_part['starttime'])
-		else:
-			t.starttime = 0
-		t.endtime = dt_to_kerbtime(enc_as_rep_part['endtime'])
-		t.renew_till = dt_to_kerbtime(enc_as_rep_part['renew-till'])
-		
+		t.authtime = dt_to_kerbtime(enc_as_rep_part['authtime']) \
+			if 'authtime' in enc_as_rep_part and enc_as_rep_part['authtime'] else 0
+		t.starttime = dt_to_kerbtime(enc_as_rep_part['starttime']) \
+			if 'starttime' in enc_as_rep_part and enc_as_rep_part['starttime'] else 0
+		t.endtime = dt_to_kerbtime(enc_as_rep_part['endtime']) \
+			if 'endtime' in enc_as_rep_part and enc_as_rep_part['endtime'] else 0
+		t.renew_till = dt_to_kerbtime(enc_as_rep_part['renew_till']) \
+			if 'renew_till' in enc_as_rep_part and enc_as_rep_part['renew_till'] else 0
 		return t
 	
 	@staticmethod
@@ -373,12 +390,15 @@ class CCACHEPrincipal:
 			
 		return p
 		
-	def to_string(self):
-		return '-'.join([c.to_string() for c in self.components])
+	def to_string(self, separator = '-'):
+		return separator.join([c.to_string() for c in self.components])
 		
 	def to_asn1(self):
 		t = {'name-type': self.name_type, 'name-string': [name.to_string() for name in self.components]}
-		return t, self.realm.to_string()		
+		return t, self.realm.to_string()
+
+	def to_spn(self):
+		return '/'.join([name.to_string() for name in self.components]) + '@' + self.realm.to_string()
 	
 	@staticmethod
 	def parse(reader):
@@ -595,11 +615,19 @@ class CCACHE:
 		"""
 		tgts = []
 		for cred in self.credentials:
-			if cred.server.to_string().lower().find('krbtgt') != -1:
+			if cred.server.to_string(separator = '/').lower().find('krbtgt') != -1:
 				tgts.append(cred.to_tgt())
 
 		return tgts
 
+	def get_all_tgs(self):
+		tgss = []
+		for cred in self.credentials:
+			if cred.server.to_string(separator = '/').lower().find('krbtgt') == -1:
+				tgss.append(cred.to_tgs())
+
+		return tgss
+
 	def get_hashes(self, all_hashes = False):
 		"""
 		Returns a list of hashes in hashcat-firendly format for tickets with encryption type 23 (which is RC4)
@@ -621,7 +649,6 @@ class CCACHE:
 		
 		hdr_size = int.from_bytes(reader.read(2), byteorder='big', signed=False)
 		c.headers = Header.parse(reader.read(hdr_size))
-		
 		#c.headerlen = 
 		#for i in range(c.headerlen):
 		#	c.headers.append(Header.parse(reader))
@@ -633,7 +660,10 @@ class CCACHE:
 		eof = reader.tell()
 		reader.seek(pos,0)
 		while reader.tell() < eof:
-			c.credentials.append(Credential.parse(reader))
+			cred = Credential.parse(reader)
+			if not (len(cred.server.components) > 0 and cred.server.components[0].to_string() == 'krb5_ccache_conf_data'
+			and cred.server.realm.to_string() == 'X-CACHECONF:'):
+				c.credentials.append(cred)
 		
 		return c
 		
@@ -690,6 +720,12 @@ class CCACHE:
 			filepath = os.path.join(kf_abs, filename)
 			with open(filepath, 'wb') as o:
 				o.write(kirbi.dump())
+
+	def list_targets(self):
+		for cred in self.credentials:
+			target = cred.server
+			yield target.to_spn()
+
 	
 	@staticmethod
 	def from_file(filename):
@@ -706,3 +742,6 @@ class CCACHE:
 		with open(filename, 'wb') as f:
 			f.write(self.to_bytes())
 		
+	@staticmethod
+	def from_bytes(data):
+		return CCACHE.parse(io.BytesIO(data))
\ No newline at end of file
diff --git a/minikerberos/common/constants.py b/minikerberos/common/constants.py
index 64ae24d..e217731 100644
--- a/minikerberos/common/constants.py
+++ b/minikerberos/common/constants.py
@@ -17,4 +17,5 @@ class KerberosSecretType(enum.Enum):
 	DES3 = 'DES3'
 	TDES = 'TDES'
 	CCACHE = 'CCACHE'
-	KEYTAB = 'KEYTAB'
\ No newline at end of file
+	KEYTAB = 'KEYTAB'
+	KIRBI = 'KIRBI'
\ No newline at end of file
diff --git a/minikerberos/common/creds.py b/minikerberos/common/creds.py
index 181bc53..e92bb6c 100644
--- a/minikerberos/common/creds.py
+++ b/minikerberos/common/creds.py
@@ -13,6 +13,7 @@ from minikerberos.protocol.encryption import string_to_key, Enctype
 from minikerberos.protocol.constants import EncryptionType
 from minikerberos.common.ccache import CCACHE
 from minikerberos.common.keytab import Keytab
+from minikerberos.crypto.hashing import md4
 
 
 class KerberosCredential:
@@ -28,6 +29,7 @@ class KerberosCredential:
 		self.kerberos_key_rc4 = None
 		self.kerberos_key_des3 = None
 		self.ccache = None
+		self.ccache_spn_strict_check = True
 
 	def get_preferred_enctype(self, server_enctypes):
 		client_enctypes = self.get_supported_enctypes(as_int=False)
@@ -69,7 +71,8 @@ class KerberosCredential:
 			if self.nt_hash:
 				return bytes.fromhex(self.nt_hash)
 			elif self.password:
-				self.nt_hash = hashlib.new('md4', self.password.encode('utf-16-le')).hexdigest().upper()
+				self.nt_hash = md4(self.password.encode('utf-16-le')).hexdigest().upper()
+				#self.nt_hash = hashlib.new('md4', self.password.encode('utf-16-le')).hexdigest().upper()
 				return bytes.fromhex(self.nt_hash)
 			else:
 				raise Exception('There is no key for RC4 encryption')
@@ -121,6 +124,19 @@ class KerberosCredential:
 		if as_int == True:
 			return [etype.value for etype in supp_enctypes]
 		return [etype for etype in supp_enctypes]
+	
+	@staticmethod
+	def from_krbcred(keytab_file_path: str, principal: str = None, realm: str = None):
+		return KerberosCredential.from_kirbi(keytab_file_path, principal, realm)
+
+	@staticmethod
+	def from_kirbi(keytab_file_path: str, principal: str = None, realm: str = None):
+		cred = KerberosCredential()
+		cred.username = principal
+		cred.domain = realm
+		cred.ccache = CCACHE.from_kirbifile(keytab_file_path)
+		cred.ccache_spn_strict_check = False
+		return cred
 
 	@staticmethod
 	def from_keytab(keytab_file_path: str, principal: str, realm: str):
@@ -156,6 +172,14 @@ class KerberosCredential:
 								cred.add_secret(enctype, keytab_entry.key_contents.hex())
 		return cred
 
+	@staticmethod
+	def from_ccache_file(filepath, principal: str = None, realm: str = None):
+		k = KerberosCredential()
+		k.username = principal
+		k.domain = realm
+		k.ccache = CCACHE.from_file(filepath)
+		return k
+
 	def add_secret(self, st: KerberosSecretType, secret: str):
 		if st == KerberosSecretType.PASSWORD or st == KerberosSecretType.PW or st == KerberosSecretType.PASS:
 			if secret == '' or secret is None:
diff --git a/minikerberos/common/proxy.py b/minikerberos/common/proxy.py
index bb9c950..dcb703a 100644
--- a/minikerberos/common/proxy.py
+++ b/minikerberos/common/proxy.py
@@ -1,8 +1,9 @@
 
 class KerberosProxy:
-	def __init__(self, target = None,creds = None):
+	def __init__(self, target = None,creds = None, type = None):
 		self.target = target
 		self.creds = creds
+		self.type = type
 
 	def __str__(self):
 		t = '===KerberosTarget===\r\n'
diff --git a/minikerberos/common/url.py b/minikerberos/common/url.py
index c99495c..2325992 100644
--- a/minikerberos/common/url.py
+++ b/minikerberos/common/url.py
@@ -1,5 +1,5 @@
 
-
+import getpass
 from minikerberos.common.target import KerberosTarget
 from minikerberos.common.creds import KerberosCredential
 from minikerberos.common.proxy import KerberosProxy
@@ -70,6 +70,8 @@ class KerberosClientURL:
 	def get_creds(self):
 		if self.secret_type == KerberosSecretType.KEYTAB:
 			return KerberosCredential.from_keytab(self.secret, self.username, self.domain)
+		if self.secret_type == KerberosSecretType.KIRBI:
+			return KerberosCredential.from_kirbi(self.secret)
 
 		res = KerberosCredential()
 		res.username = self.username
@@ -120,16 +122,21 @@ class KerberosClientURL:
 
 		res.dc_ip = url.hostname
 		schemes = url.scheme.upper().split('+')
-		if schemes[0] not in ['KERBEROS', 'KERBEROS-TCP, KERBEROS-UDP']:
+		
+		if schemes[0] not in ['KERBEROS', 'KERBEROS-TCP, KERBEROS-UDP', 'KRB5', 'KRB5-UDP', 'KRB5-TCP']:
 			raise Exception('Unknown protocol! %s' % schemes[0])
 
 		if schemes[0].endswith('UDP') is True:
 			res.protocol = KerberosSocketType.UDP
 		
+		ttype = schemes[1]
+		if ttype.find('-') != -1 and ttype.upper().endswith('-PROMPT'):
+			ttype = ttype.split('-')[0]
+			res.secret = getpass.getpass()
 		try:
-			res.secret_type = KerberosSecretType(schemes[1])
+			res.secret_type = KerberosSecretType(ttype)
 		except:
-			raise Exception('Unknown secret type! %s' % schemes[0])
+			raise Exception('Unknown secret type! %s' % ttype)
 		
 		if url.username is not None:
 			if url.username.find('\\') != -1:
@@ -138,16 +145,18 @@ class KerberosClientURL:
 				raise Exception('Domain missing from username!')
 		else:
 			raise Exception('Missing username!')
-
-		res.secret = url.password
+		
+		if res.secret is None:
+			res.secret = url.password
 		if url.port is not None:
 			res.port = int(url.port)
 		
 		query = parse_qs(url.query)
-		proxy_present = False
+		proxy_type = None
 		for k in query:
-			if k.startswith('proxy') is True:
-				proxy_present = True
+			if k == 'proxytype':
+				proxy_type = query[k][0]
+
 			
 			if k in kerberosclienturl_param2var:
 				data = query[k][0]
@@ -160,12 +169,13 @@ class KerberosClientURL:
 							data
 						)
 		
-		if proxy_present is True:
+		if proxy_type is not None:
 			cu = SocksClientURL.from_params(url_str)
-			cu.endpoint_ip = res.dc_ip
-			cu.endpoint_port = res.port
+			cu[-1].endpoint_ip = res.dc_ip
+			cu[-1].endpoint_port = res.port
+
+			res.proxy = KerberosProxy(cu, None, type='SOCKS')
 
-			res.proxy = KerberosProxy(cu.get_target(), cu.get_creds())
 
 		
 		if res.username is None:
diff --git a/minikerberos/common/utils.py b/minikerberos/common/utils.py
index fe09b96..3b37003 100644
--- a/minikerberos/common/utils.py
+++ b/minikerberos/common/utils.py
@@ -1,5 +1,6 @@
 
 import datetime
+from minikerberos.protocol.asn1_structs import KRB_CRED, KrbCredInfo, EncKrbCredPart, EncryptedData
 
 def print_table(lines, separate_head=True):
 	"""Prints a formatted table given a 2 dimensional array"""
@@ -36,12 +37,25 @@ def dt_to_kerbtime(dt):
 
 def TGSTicket2hashcat(res):		
 	tgs_encryption_type    = int(res['ticket']['enc-part']['etype'])
-	tgs_name_string        = res['ticket']['sname']['name-string'][0]
+	tgs_name_string        = '@'.join(res['ticket']['sname']['name-string']) #[0]
 	tgs_realm              = res['ticket']['realm']
-	tgs_checksum           = res['ticket']['enc-part']['cipher'][:16]
-	tgs_encrypted_data2    = res['ticket']['enc-part']['cipher'][16:]
+
+	if tgs_encryption_type == 23:
+		tgs_checksum           = res['ticket']['enc-part']['cipher'][:16]
+		tgs_encrypted_data2    = res['ticket']['enc-part']['cipher'][16:]
+		return '$krb5tgs$%s$*%s$%s$spn*$%s$%s' % (tgs_encryption_type,tgs_name_string,tgs_realm, tgs_checksum.hex(), tgs_encrypted_data2.hex() )
+	
+	elif tgs_encryption_type in [17,18]:
+		# $krb5tgs$17$user$realm$ae8434177efd09be5bc2eff8$90b4ce5b266821adc26c64f71958a475cf9348fce65096190be04f8430c4e0d554c86dd7ad29c275f9e8f15d2dab4565a3d6e21e449dc2f88e52ea0402c7170ba74f4af037c5d7f8db6d53018a564ab590fc23aa1134788bcc4a55f69ec13c0a083291a96b41bffb978f5a160b7edc828382d11aacd89b5a1bfa710b0e591b190bff9062eace4d26187777db358e70efd26df9c9312dbeef20b1ee0d823d4e71b8f1d00d91ea017459c27c32dc20e451ea6278be63cdd512ce656357c942b95438228e
+		# $krb5tgs$18$user$realm$8efd91bb01cc69dd07e46009$7352410d6aafd72c64972a66058b02aa1c28ac580ba41137d5a170467f06f17faf5dfb3f95ecf4fad74821fdc7e63a3195573f45f962f86942cb24255e544ad8d05178d560f683a3f59ce94e82c8e724a3af0160be549b472dd83e6b80733ad349973885e9082617294c6cbbea92349671883eaf068d7f5dcfc0405d97fda27435082b82b24f3be27f06c19354bf32066933312c770424eb6143674756243c1bde78ee3294792dcc49008a1b54f32ec5d5695f899946d42a67ce2fb1c227cb1d2004c0 
+
+		tgs_checksum           = res['ticket']['enc-part']['cipher'][-12:]
+		tgs_encrypted_data2    = res['ticket']['enc-part']['cipher'][:-12]
+		return '$krb5tgs$%s$%s$%s$%s$%s' % (tgs_encryption_type,tgs_name_string,tgs_realm, tgs_checksum.hex(), tgs_encrypted_data2.hex() )
+	
+	else:
+		return 'unknown$enctype$%s' % tgs_encryption_type
 		
-	return '$krb5tgs$%s$*%s$%s$spn*$%s$%s' % (tgs_encryption_type,tgs_name_string,tgs_realm, tgs_checksum.hex(), tgs_encrypted_data2.hex() )
 	
 def TGTTicket2hashcat(res):
 	tgt_encryption_type    = int(res['enc-part']['etype'])
@@ -51,4 +65,32 @@ def TGTTicket2hashcat(res):
 	tgt_encrypted_data2    = res['enc-part']['cipher'][16:]
 	
 	return '$krb5asrep$%s$%s@%s:%s$%s' % (tgt_encryption_type,tgt_name_string, tgt_realm, tgt_checksum.hex(), tgt_encrypted_data2.hex())
-	
+
+def tgt_to_kirbi(tgs, encTGSRepPart):
+	#encTGSRepPart is already decrypted at this point
+	ci = {}
+	ci['key'] = encTGSRepPart['key']
+	ci['prealm'] = tgs['crealm']
+	ci['pname'] = tgs['cname']
+	ci['flags'] = encTGSRepPart['flags']
+	ci['authtime'] = encTGSRepPart['authtime']
+	ci['starttime'] = encTGSRepPart['starttime']
+	ci['endtime'] = encTGSRepPart['endtime']
+	ci['renew-till'] = encTGSRepPart['renew-till']
+	ci['srealm'] = encTGSRepPart['srealm']
+	ci['sname'] = encTGSRepPart['sname']
+
+	ti = {}
+	ti['ticket-info'] = [KrbCredInfo(ci)]
+
+	te = {}
+	te['etype']  = 0
+	te['cipher'] = EncKrbCredPart(ti).dump()
+
+	t = {}
+	t['pvno'] = 5
+	t['msg-type'] = 22
+	t['enc-part'] = EncryptedData(te)
+	t['tickets'] = [tgs['ticket']]
+
+	return KRB_CRED(t)
\ No newline at end of file
diff --git a/minikerberos/crypto/MD4.py b/minikerberos/crypto/MD4.py
new file mode 100644
index 0000000..3b64dda
--- /dev/null
+++ b/minikerberos/crypto/MD4.py
@@ -0,0 +1,181 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+#
+# Copyright © 2019 James Seo <james@equiv.tech> (github.com/kangtastic).
+#
+# This file is released under the WTFPL, version 2 (wtfpl.net).
+#
+# md4.py: An implementation of the MD4 hash algorithm in pure Python 3.
+#
+# Description: Zounds! Yet another rendition of pseudocode from RFC1320!
+#              Bonus points for the algorithm literally being from 1992.
+#
+# Usage: Why would anybody use this? This is self-rolled crypto, and
+#        self-rolled *obsolete* crypto at that. DO NOT USE if you need
+#        something "performant" or "secure". :P
+#
+#        Anyway, from the command line:
+#
+#           $ ./md4.py [messages]
+#
+#        where [messages] are some strings to be hashed.
+#
+#        In Python, use similarly to hashlib (not that it even has MD4):
+#
+#           from .md4 import MD4
+#
+#           digest = MD4("BEES").hexdigest()
+#
+#           print(digest)  # "501af1ef4b68495b5b7e37b15b4cda68"
+#
+#
+# Sample console output:
+#
+#   Testing the MD4 class.
+#
+#   Message:  b''
+#   Expected: 31d6cfe0d16ae931b73c59d7e0c089c0
+#   Actual:   31d6cfe0d16ae931b73c59d7e0c089c0
+#
+#   Message:  b'The quick brown fox jumps over the lazy dog'
+#   Expected: 1bee69a46ba811185c194762abaeae90
+#   Actual:   1bee69a46ba811185c194762abaeae90
+#
+#   Message:  b'BEES'
+#   Expected: 501af1ef4b68495b5b7e37b15b4cda68
+#   Actual:   501af1ef4b68495b5b7e37b15b4cda68
+#
+import struct
+
+
+class MD4:
+	"""An implementation of the MD4 hash algorithm."""
+
+	width = 32
+	mask = 0xFFFFFFFF
+
+	# Unlike, say, SHA-1, MD4 uses little-endian. Fascinating!
+	h = [0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476]
+
+	def __init__(self, msg=None):
+		""":param ByteString msg: The message to be hashed."""
+		if msg is None:
+			msg = b""
+
+		self.msg = msg
+
+		# Pre-processing: Total length is a multiple of 512 bits.
+		ml = len(msg) * 8
+		msg += b"\x80"
+		msg += b"\x00" * (-(len(msg) + 8) % 64)
+		msg += struct.pack("<Q", ml)
+
+		# Process the message in successive 512-bit chunks.
+		self._process([msg[i : i + 64] for i in range(0, len(msg), 64)])
+
+	def __repr__(self):
+		if self.msg:
+			return f"{self.__class__.__name__}({self.msg:s})"
+		return f"{self.__class__.__name__}()"
+
+	def __str__(self):
+		return self.hexdigest()
+
+	def __eq__(self, other):
+		return self.h == other.h
+
+	def bytes(self):
+		""":return: The final hash value as a `bytes` object."""
+		return struct.pack("<4L", *self.h)
+
+	def hexbytes(self):
+		""":return: The final hash value as hexbytes."""
+		return self.hexdigest().encode
+
+	def hexdigest(self):
+		""":return: The final hash value as a hexstring."""
+		return "".join(f"{value:02x}" for value in self.bytes())
+	
+	def digest(self):
+		return self.bytes()
+
+	def _process(self, chunks):
+		for chunk in chunks:
+			X, h = list(struct.unpack("<16I", chunk)), self.h.copy()
+
+			# Round 1.
+			Xi = [3, 7, 11, 19]
+			for n in range(16):
+				i, j, k, l = map(lambda x: x % 4, range(-n, -n + 4))
+				K, S = n, Xi[n % 4]
+				hn = h[i] + MD4.F(h[j], h[k], h[l]) + X[K]
+				h[i] = MD4.lrot(hn & MD4.mask, S)
+
+			# Round 2.
+			Xi = [3, 5, 9, 13]
+			for n in range(16):
+				i, j, k, l = map(lambda x: x % 4, range(-n, -n + 4))
+				K, S = n % 4 * 4 + n // 4, Xi[n % 4]
+				hn = h[i] + MD4.G(h[j], h[k], h[l]) + X[K] + 0x5A827999
+				h[i] = MD4.lrot(hn & MD4.mask, S)
+
+			# Round 3.
+			Xi = [3, 9, 11, 15]
+			Ki = [0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15]
+			for n in range(16):
+				i, j, k, l = map(lambda x: x % 4, range(-n, -n + 4))
+				K, S = Ki[n], Xi[n % 4]
+				hn = h[i] + MD4.H(h[j], h[k], h[l]) + X[K] + 0x6ED9EBA1
+				h[i] = MD4.lrot(hn & MD4.mask, S)
+
+			self.h = [((v + n) & MD4.mask) for v, n in zip(self.h, h)]
+
+	@staticmethod
+	def F(x, y, z):
+		return (x & y) | (~x & z)
+
+	@staticmethod
+	def G(x, y, z):
+		return (x & y) | (x & z) | (y & z)
+
+	@staticmethod
+	def H(x, y, z):
+		return x ^ y ^ z
+
+	@staticmethod
+	def lrot(value, n):
+		lbits, rbits = (value << n) & MD4.mask, value >> (MD4.width - n)
+		return lbits | rbits
+
+
+def main():
+	# Import is intentionally delayed.
+	import sys
+
+	if len(sys.argv) > 1:
+		messages = [msg.encode() for msg in sys.argv[1:]]
+		for message in messages:
+			print(MD4(message).hexdigest())
+	else:
+		messages = [b"", b"The quick brown fox jumps over the lazy dog", b"BEES"]
+		known_hashes = [
+			"31d6cfe0d16ae931b73c59d7e0c089c0",
+			"1bee69a46ba811185c194762abaeae90",
+			"501af1ef4b68495b5b7e37b15b4cda68",
+		]
+
+		print("Testing the MD4 class.")
+		print()
+
+		for message, expected in zip(messages, known_hashes):
+			print("Message: ", message)
+			print("Expected:", expected)
+			print("Actual:  ", MD4(message).hexdigest())
+			print()
+
+
+if __name__ == "__main__":
+	try:
+		main()
+	except KeyboardInterrupt:
+		pass
diff --git a/minikerberos/crypto/hashing.py b/minikerberos/crypto/hashing.py
index a2c5f2e..3cbf37f 100644
--- a/minikerberos/crypto/hashing.py
+++ b/minikerberos/crypto/hashing.py
@@ -2,6 +2,7 @@ import hashlib
 import hmac
 
 from minikerberos.crypto.BASE import hashBASE, hmacBASE
+from minikerberos.crypto.MD4 import MD4 
 
 class md5(hashBASE):
 	def __init__(self, data = None):
@@ -15,17 +16,19 @@ class md5(hashBASE):
 	def hexdigest(self):
 		return self._hash.hexdigest()
 
-class md4(hashBASE):
-	def __init__(self, data = None):
-		hashBASE.__init__(self, data)
-	def setup_hash(self):
-		self._hash = hashlib.new('md4')
-	def update(self, data):
-		return self._hash.update(data)
-	def digest(self):
-		return self._hash.digest()
-	def hexdigest(self):
-		return self._hash.hexdigest()
+#class md4(hashBASE):
+#	def __init__(self, data = None):
+#		hashBASE.__init__(self, data)
+#	def setup_hash(self):
+#		self._hash = hashlib.new('md4')
+#	def update(self, data):
+#		return self._hash.update(data)
+#	def digest(self):
+#		return self._hash.digest()
+#	def hexdigest(self):
+#		return self._hash.hexdigest()
+
+md4 = MD4
 
 class hmac_md5(hmacBASE):
 	def __init__(self, key):
diff --git a/minikerberos/examples/ccache_editor.py b/minikerberos/examples/ccache_editor.py
index adaf81c..2c4279e 100644
--- a/minikerberos/examples/ccache_editor.py
+++ b/minikerberos/examples/ccache_editor.py
@@ -60,7 +60,6 @@ def main():
 		id = args.id
 		temp_cc = CCACHE()
 		temp_cc.file_format_version = cc.file_format_version
-		temp_cc.headerlen = cc.headerlen
 		temp_cc.headers = cc.headers
 		temp_cc.primary_principal = cc.primary_principal
 		i = 0
diff --git a/minikerberos/examples/getTGS.py b/minikerberos/examples/getTGS.py
index 3201732..bfe6675 100644
--- a/minikerberos/examples/getTGS.py
+++ b/minikerberos/examples/getTGS.py
@@ -16,7 +16,7 @@ async def amain(args):
 		raise Exception('SPN must contain @')
 	t, domain = args.spn.split('@')
 	if t.find('/') != -1:
-		service, hostname = args.spn.split('/')
+		service, hostname = t.split('/')
 	else:
 		hostname = t
 		service = None
@@ -31,26 +31,12 @@ async def amain(args):
 	target = cu.get_target()
 	
 	logging.debug('Getting TGT')
-	
-	if not ccred.ccache:
-		client = AIOKerberosClient(ccred, target)
-		logging.debug('Getting TGT')
-		await client.get_TGT()
-		logging.debug('Getting TGS')
-		await client.get_TGS(spn)
-	else:
-		logging.debug('Getting TGS via TGT from CCACHE')
-		for tgt, key in ccred.ccache.get_all_tgt():
-			try:
-				logging.info('Trying to get SPN with %s' % '!'.join(tgt['cname']['name-string']))
-				client = AIOKerberosClient.from_tgt(target, tgt, key)
-				await client.get_TGS(spn)
-				logging.info('Sucsess!')
-			except Exception as e:
-				logging.debug('This ticket is not usable it seems Reason: %s' % e)
-				continue
-			else:
-				break
+
+	client = AIOKerberosClient(ccred, target)
+	logging.debug('Getting TGT')
+	await client.get_TGT()
+	logging.debug('Getting TGS')
+	await client.get_TGS(spn)
 				
 	client.ccache.to_file(args.ccache)
 	logging.info('Done!')
@@ -59,7 +45,7 @@ def main():
 	import argparse
 	
 	parser = argparse.ArgumentParser(description='Polls the kerberos service for a TGS for the sepcified user and specified service', formatter_class=argparse.RawDescriptionHelpFormatter, epilog = kerberos_url_help_epilog)
-	parser.add_argument('kerberos_connection_string', help='the kerberos target string in the following format <domain>/<username>/<secret_type>:<secret>@<domaincontroller-ip>')
+	parser.add_argument('kerberos_connection_url', help='the kerberos target string in the following format <domain>/<username>/<secret_type>:<secret>@<domaincontroller-ip>')
 	parser.add_argument('spn', help='the service principal in format <service>/<server-hostname>@<domain> Example: cifs/fileserver.test.corp@TEST.corp for a TGS ticket to be used for file access on server "fileserver". IMPORTANT: SERVER\'S HOSTNAME MUST BE USED, NOT IP!!!')
 	parser.add_argument('ccache', help='ccache file to store the TGT ticket in')
 	parser.add_argument('-u', action='store_true', help='Use UDP instead of TCP (not tested)')
diff --git a/minikerberos/gssapi/channelbindings.py b/minikerberos/gssapi/channelbindings.py
new file mode 100644
index 0000000..53baea0
--- /dev/null
+++ b/minikerberos/gssapi/channelbindings.py
@@ -0,0 +1,81 @@
+
+import enum
+import io
+
+# https://www.ietf.org/rfc/rfc2744.txt   3.11. Channel Bindings
+
+class GSS_C_AF(enum.Enum):
+	UNSPEC = 0     #Unspecified address type
+	LOCAL = 1      #Host-local address type
+	INET = 2       #Internet address type (e.g. IP)
+	IMPLINK = 3    #ARPAnet IMP address type
+	PUP = 4        #pup protocols (eg BSP) address type
+	CHAOS = 5      #MIT CHAOS protocol address type
+	NS = 6         #XEROX NS address type
+	NBS = 7        #nbs address type
+	ECMA  = 8      #ECMA address type
+	DATAKIT = 9    #datakit protocols address type
+	CCITT = 10     #CCITT protocols
+	SNA = 11       #IBM SNA address type
+	DECnet = 12    #DECnet address type
+	DLI = 13       #Direct data link interface address type
+	LAT = 14       #LAT address type
+	HYLINK = 15    #NSC Hyperchannel address type
+	APPLETALK= 16  #AppleTalk address type
+	BSC = 17       #BISYNC 2780/3780 address type
+	DSS = 18       #Distributed system services address type
+	OSI = 19       #OSI TP4 address type
+	X25 = 21       #X.25
+	NULLADDR = 255 #No address specified
+
+class ChannelBindingsStruct:
+	def __init__(self):
+		self.initiator_addrtype = None #GSS_C_AF
+		self.initiator_address = None #bytes
+		self.acceptor_addrtype = None #GSS_C_AF
+		self.acceptor_address = None #bytes
+		self.application_data = None #bytes
+
+	@staticmethod
+	def from_bytes(data):
+		return ChannelBindingsStruct.from_buffer(io.BytesIO(data))
+
+	@staticmethod
+	def from_buffer(buff):
+		# TODO: parse the addresses
+		cb = ChannelBindingsStruct()
+		t = buff.read(8)
+		if t != b'\x00' * 8:
+			cb.initiator_addrtype = GSS_C_AF(int.from_bytes(t, byteorder='little', signed = False))
+			initiator_address_length = int.from_bytes(buff.read(4), byteorder='little', signed = False)
+			cb.initiator_address  = buff.read(initiator_address_length)
+		t = buff.read(8)
+		if t != b'\x00' * 8:
+			cb.acceptor_addrtype  = GSS_C_AF(int.from_bytes(buff.read(4), byteorder='little', signed = False))
+			acceptor_address_length = int.from_bytes(buff.read(4), byteorder='little', signed = False)
+			cb.acceptor_address   = buff.read(acceptor_address_length)
+		t = buff.read(8)
+		if t != b'\x00' * 8:
+			application_data_length = int.from_bytes(buff.read(4), byteorder='little', signed = False)
+			cb.application_data   = buff.read(application_data_length)
+		return cb
+
+	def to_bytes(self):
+		if self.initiator_address is None:
+			t = b'\x00' * 8
+		else:
+			t = self.initiator_addrtype.value.to_bytes(4, byteorder='little', signed = False)
+			t += len(self.initiator_address).to_bytes(4, byteorder='little', signed = False)
+			t += self.initiator_address
+		if self.acceptor_address is None:
+			t += b'\x00' * 8
+		else:
+			t += self.acceptor_addrtype
+			t += len(self.acceptor_address).to_bytes(4, byteorder='little', signed = False)
+			t += self.acceptor_address
+		if self.application_data is None:
+			t += b'\x00' * 8
+		else:
+			t += len(self.application_data).to_bytes(4, byteorder='little', signed = False)
+			t += self.application_data
+		return t
\ No newline at end of file
diff --git a/minikerberos/network/aioclientsockssocket.py b/minikerberos/network/aioclientsockssocket.py
index 059cb90..5684a84 100644
--- a/minikerberos/network/aioclientsockssocket.py
+++ b/minikerberos/network/aioclientsockssocket.py
@@ -29,7 +29,7 @@ class AIOKerberosClientSocksSocket:
 		self.in_queue = asyncio.Queue()
 		comms = SocksQueueComms(self.out_queue, self.in_queue)
 
-		self.client = SOCKSClient(comms, self.target.proxy.target, self.target.proxy.creds)
+		self.client = SOCKSClient(comms, self.target.proxy.target)
 		self.proxy_task = asyncio.create_task(self.client.run())
 
 		length = len(data).to_bytes(4, byteorder = 'big', signed = False)
diff --git a/minikerberos/network/aioclientwsnetsocket.py b/minikerberos/network/aioclientwsnetsocket.py
new file mode 100644
index 0000000..7706cf4
--- /dev/null
+++ b/minikerberos/network/aioclientwsnetsocket.py
@@ -0,0 +1,74 @@
+
+#!/usr/bin/env python3
+#
+# Author:
+#  Tamas Jos (@skelsec)
+#
+
+import asyncio
+
+from minikerberos.protocol.asn1_structs import KerberosResponse
+from minikerberos.common.constants import KerberosSocketType
+
+from pyodidewsnet.client import WSNetworkTCP
+
+class AIOKerberosClientWSNETSocket:
+	def __init__(self, target):
+		self.target = target
+		self.out_queue = None
+		self.in_queue = None
+
+		self.proxy_client = None
+		self.proxy_task = None
+		
+	def get_addr_str(self):
+		return '%s:%d' % (self.target.ip, self.target.port)
+
+	async def sendrecv(self, data):
+		self.out_queue = asyncio.Queue()
+		self.in_queue = asyncio.Queue()
+		self.proxy_client = WSNetworkTCP(self.target.ip, int(self.target.port), self.in_queue, self.out_queue)
+		_, err = await self.proxy_client.run()
+		if err is not None:
+			raise err
+
+		length = len(data).to_bytes(4, byteorder = 'big', signed = False)
+		await self.out_queue.put(length+data)
+
+		resp_data = b''
+		resp_data_len = -1
+		while True:
+			data, err = await self.in_queue.get()
+			if data is None:
+				break
+			if err is not None:
+				raise err
+			resp_data += data
+			if resp_data_len == -1:
+				if len(resp_data) > 4:
+					resp_data_len = int.from_bytes(resp_data[:4], byteorder = 'big', signed = False)
+					if resp_data_len == 0:
+						raise Exception('Returned data length is 0! This means the server did not understand our message')
+			
+			if resp_data_len != -1:
+				if len(resp_data) == resp_data_len + 4:
+					resp_data = resp_data[4:]
+					break
+				elif len(resp_data) > resp_data_len + 4:
+					raise Exception('Got too much data somehow')
+				else:
+					continue
+		
+		await self.out_queue.put(None)
+		if resp_data == b'':
+			raise Exception('Connection returned no data!')
+		
+		krb_message = KerberosResponse.load(resp_data)
+		return krb_message
+
+		
+	def __str__(self):
+		t = '===AIOKerberosClientProxySocket AIO===\r\n'
+		t += 'target: %s\r\n' % self.target
+		
+		return t
\ No newline at end of file
diff --git a/minikerberos/network/clientsocket.py b/minikerberos/network/clientsocket.py
index 54fedbf..2aeafdb 100644
--- a/minikerberos/network/clientsocket.py
+++ b/minikerberos/network/clientsocket.py
@@ -10,7 +10,7 @@ class KerberosClientSocket:
 	def __init__(self, target):
 		self.target = target
 		#ip, port = 88, soc_type = KerberosSocketType.TCP
-		self.soc_type = target.soc_type
+		self.soc_type = target.protocol
 		self.dst_ip = target.ip
 		self.dst_port = int(target.port)
 		self.soc = None
diff --git a/minikerberos/protocol/asn1_structs.py b/minikerberos/protocol/asn1_structs.py
index 17351ad..0345801 100644
--- a/minikerberos/protocol/asn1_structs.py
+++ b/minikerberos/protocol/asn1_structs.py
@@ -4,7 +4,13 @@
 #  Tamas Jos (@skelsec)
 #
 
+# Sources used:
 # https://zeroshell.org/kerberos/kerberos-operation/
+# https://tools.ietf.org/html/rfc4120
+# https://tools.ietf.org/html/rfc6113 (FAST extension)
+
+# TODO:
+# https://tools.ietf.org/html/rfc4556
 
 from asn1crypto import core
 import enum
@@ -19,16 +25,6 @@ APPLICATION = 1
 CONTEXT = 2
 krb5_pvno = 5 #-- current Kerberos protocol version number
 
-"""
-class NegotiationToken(core.Choice):
-	_alternatives = [
-		#('NegTokenInit2', NegTokenInit2, {'implicit': (0,16) }  ), #NegTokenInit2 the '2' in the name is because Microsoft added modifications to the original rfc :)
-		('NegTokenInit2', NegTokenInit2, {'implicit': (0,16) }  ), #NegTokenInit2 the '2' in the name is because Microsoft added modifications to the original rfc :)
-		('negTokenResp', negTokenResp, {'explicit': (2,1) } ),
-		
-]
-"""
-	
 class PADATA_TYPE(core.Enumerated):
 	_map = {
 		0   : 'NONE', #(0),
@@ -97,7 +93,7 @@ class PADATA_TYPE(core.Enumerated):
 class AUTHDATA_TYPE(core.Enumerated):
 	_map = {
 		1 : 'IF-RELEVANT', #1),
-		2 : 'INTENDED-FOR_SERVER', #2),
+		2 : 'INTENDED-FOR-SERVER', #2),
 		3 : 'INTENDED-FOR-APPLICATION-CLASS', #3),
 		4 : 'KDC-ISSUED', #4),
 		5 : 'AND-OR', #5),
@@ -108,6 +104,9 @@ class AUTHDATA_TYPE(core.Enumerated):
 		64 : 'OSF-DCE', #64),
 		65 : 'SESAME', #65),
 		66 : 'OSF-DCE-PKI-CERTID', #66),
+		70 : 'AD-authentication-strength',
+		71 : 'AD-fx-fast-armor',
+		72 : 'AD-fx-fast-used',
 		128 : 'WIN2K-PAC', #128),
 		129 : 'GSS-API-ETYPE-NEGOTIATION', #129), -- Authenticator only
 		-17 : 'SIGNTICKET-OLDER', #-17),
@@ -506,6 +505,86 @@ class AS_REQ(KDC_REQ):
 class TGS_REQ(KDC_REQ):
 	explicit = (APPLICATION, 12)
 
+class FastOptions(core.BitString):
+	_map = {
+		0:  'reserved',
+		1:  'hide-client-names',
+		2:  'critical_2', #forwarded',
+		3:  'critical_3', #proxiable',
+		4:  'critical_4', #proxy',
+		5:  'critical_5', #may-postdate',
+		6:  'critical_6', #postdated',
+		7:  'critical_7', #invalid',
+		8:  'critical_8', #renewable',
+		9:  'critical_9', #initial',
+		10: 'critical_10', #pre-authent',
+		11: 'critical_11', #hw-authent',
+		12: 'critical_12', #transited-policy-checked',
+		13: 'critical_13', #ok-as-delegate',
+		14: 'critical_14', #anonymous',
+		15: 'critical_15', #enc-pa-rep',
+		16: 'kdc-follow-referrals'
+	}
+	# error: KDC_ERR_UNKNOWN_CRITICAL_FAST_OPTIONS   93
+#5.4.1.  FAST Armors
+
+class EncryptedChallenge(EncryptedData):
+	pass
+
+class AUTHENTICATION_SET_ELEM(core.SequenceOf):
+	_fields = [
+		('pa-type', krb5int32, {'tag_type': TAG, 'tag': 0}),
+		('pa-hint', core.OctetString, {'tag_type': TAG, 'tag': 1 , 'optional': True}),
+		('pa-value', core.OctetString, {'tag_type': TAG, 'tag': 1, 'optional': True}),
+	]
+
+class AUTHENTICATION_SET(core.SequenceOf):
+	_child_spec = AUTHENTICATION_SET_ELEM
+
+class KrbFastArmor(core.Sequence):
+	_fields = [
+		('armor-type', krb5int32, {'tag_type': TAG, 'tag': 0}),
+		('armor-value', core.OctetString, {'tag_type': TAG, 'tag': 1}),
+	]
+
+
+class KrbFastArmoredReq(core.Sequence):
+	_fields = [
+		('armor', KrbFastArmor, {'tag_type': TAG, 'tag': 0, 'optional':True}),
+		('req-checksum', Checksum, {'tag_type': TAG, 'tag': 1}),
+		('enc-fast-req', EncryptedData, {'tag_type': TAG, 'tag': 2}), #KrbFastReq #KEY_USAGE_FAST_REQ_CHKSUM          50 #KEY_USAGE_FAST_ENC                 51
+	]
+
+class KrbFastReq(core.Sequence):
+	_fields = [
+		('fast-options', FastOptions, {'tag_type': TAG, 'tag': 0}),
+		('padata', METHOD_DATA, {'tag_type': TAG, 'tag': 1}),
+		('req-body', KDC_REQ_BODY, {'tag_type': TAG, 'tag': 2}),
+	]
+
+
+class KrbFastFinished(core.Sequence):
+	_fields = [
+		('timestamp', KerberosTime, {'tag_type': TAG, 'tag': 0}), 
+		('usec', Microseconds, {'tag_type': TAG, 'tag': 1}), 
+		('crealm', Realm, {'tag_type': TAG, 'tag': 2}), 
+		('cname', PrincipalName, {'tag_type': TAG, 'tag': 3}), 
+		('ticket-checksum', Checksum, {'tag_type': TAG, 'tag': 4}), #KEY_USAGE_FAST_FINISHED            53
+
+	]
+
+class KrbFastArmoredRep(core.Sequence):
+	_fields = [
+		('enc-fast-rep', EncryptedData, {'tag_type': TAG, 'tag': 0}), #KrbFastResponse KEY_USAGE_FAST_REP                 52
+	]
+
+class KrbFastResponse(core.Sequence):
+	_fields = [
+		('padata', METHOD_DATA, {'tag_type': TAG, 'tag': 0}),
+		('strengthen-key', EncryptionKey, {'tag_type': TAG, 'tag': 1, 'optional':True}),
+		('finished', KrbFastFinished, {'tag_type': TAG, 'tag': 2, 'optional':True}), #KrbFastReq #KEY_USAGE_FAST_REQ_CHKSUM          50 #KEY_USAGE_FAST_ENC                 51
+		('nonce', krb5uint32, {'tag_type': TAG, 'tag': 3}),
+	]
 
 #-- padata-type ::= PA-ENC-TIMESTAMP
 #-- padata-value ::= EncryptedData - PA-ENC-TS-ENC
@@ -518,6 +597,18 @@ class PA_PAC_OPTIONSTypes(core.BitString):
 			3: 'resource-based constrained delegation',
 		}
 
+class PA_FX_FAST_REQUEST(core.Choice):
+	_alternatives = [
+		('armored-data', KrbFastArmoredReq, {'explicit': (CONTEXT,0) }  ),
+	]
+
+class PA_FX_FAST_REPLY(core.Choice):
+	_alternatives = [
+		('armored-data', KrbFastArmoredRep, {'explicit': (CONTEXT,0) }  ),
+	]
+
+
+
 class PA_PAC_OPTIONS(core.Sequence):
 	_fields = [
 		('value', PA_PAC_OPTIONSTypes, {'tag_type': TAG, 'tag': 0}),
@@ -785,159 +876,18 @@ class AD_IF_RELEVANT(AuthorizationData):
 	pass
 
 
-#	
-#DOMAIN-X500-COMPRESS	krb5int32 ::= 1
-#
-#-- authorization data primitives
-#
-#AD-IF-RELEVANT ::= AuthorizationData
-#
-#AD-KDCIssued ::= SEQUENCE {
-#	ad-checksum[0]		Checksum,
-#	i-realm[1]		Realm OPTIONAL,
-#	i-sname[2]		PrincipalName OPTIONAL,
-#	elements[3]		AuthorizationData
-#}
-#
-#AD-AND-OR ::= SEQUENCE {
-#	condition-count[0]	INTEGER,
-#	elements[1]		AuthorizationData
-#}
-#
-#AD-MANDATORY-FOR-KDC ::= AuthorizationData
-#
-#-- PA-SAM-RESPONSE-2/PA-SAM-RESPONSE-2
-#
-#PA-SAM-TYPE ::= INTEGER {
-#	PA_SAM_TYPE_ENIGMA(1),		-- Enigma Logic
-#	PA_SAM_TYPE_DIGI_PATH(2),	-- Digital Pathways
-#	PA_SAM_TYPE_SKEY_K0(3),		-- S/key where  KDC has key 0
-#	PA_SAM_TYPE_SKEY(4),		-- Traditional S/Key
-#	PA_SAM_TYPE_SECURID(5),		-- Security Dynamics
-#	PA_SAM_TYPE_CRYPTOCARD(6)	-- CRYPTOCard
-#}
-#
-#PA-SAM-REDIRECT ::= HostAddresses
-#
-#SAMFlags ::= BIT STRING {
-#	use-sad-as-key(0),
-#	send-encrypted-sad(1),
-#	must-pk-encrypt-sad(2)
-#}
-#
-#PA-SAM-CHALLENGE-2-BODY ::= SEQUENCE {
-#	sam-type[0]		krb5int32,
-#	sam-flags[1]		SAMFlags,
-#	sam-type-name[2]	GeneralString OPTIONAL,
-#	sam-track-id[3]		GeneralString OPTIONAL,
-#	sam-challenge-label[4]	GeneralString OPTIONAL,
-#	sam-challenge[5]	GeneralString OPTIONAL,
-#	sam-response-prompt[6]	GeneralString OPTIONAL,
-#	sam-pk-for-sad[7]	EncryptionKey OPTIONAL,
-#	sam-nonce[8]		krb5int32,
-#	sam-etype[9]		krb5int32,
-#	...
-#}
-#
-#PA-SAM-CHALLENGE-2 ::= SEQUENCE {
-#	sam-body[0]		PA-SAM-CHALLENGE-2-BODY,
-#	sam-cksum[1]		SEQUENCE OF Checksum, -- (1..MAX)
-#	...
-#}
-#
-#PA-SAM-RESPONSE-2 ::= SEQUENCE {
-#	sam-type[0]		krb5int32,
-#	sam-flags[1]		SAMFlags,
-#	sam-track-id[2]		GeneralString OPTIONAL,
-#	sam-enc-nonce-or-sad[3]	EncryptedData, -- PA-ENC-SAM-RESPONSE-ENC
-#	sam-nonce[4]		krb5int32,
-#	...
-#}
-#
-#PA-ENC-SAM-RESPONSE-ENC ::= SEQUENCE {
-#	sam-nonce[0]		krb5int32,
-#	sam-sad[1]		GeneralString OPTIONAL,
-#	...
-#}
-#
-#PA-S4U2Self ::= SEQUENCE {
-#	name[0]		PrincipalName,
-#        realm[1]	Realm,
-#        cksum[2]	Checksum,
-#        auth[3]		GeneralString
-#}
-#	
-#	
-#	
-#	
-#	
-#
-#
-#
-#
-#
-#
-## https://github.com/tiran/kkdcpasn1/blob/asn1crypto/pykkdcpasn1.py
-#class EncryptedData(core.Sequence):
-#	"""EncryptedData
-#	* KDC-REQ-BODY
-#	* Ticket
-#	* AP-REQ
-#	* KRB-PRIV
-#	EncryptedData ::= SEQUENCE {
-#		etype		[0] Int32,
-#		kvno		 [1] UInt32 OPTIONAL,
-#		cipher	   [2] OCTET STRING
-#	}
-#	"""
-#	_fields = [
-#		('etype', Int32, {'tag_type': TAG, 'tag': 0}),
-#		('kvno', UInt32, {'tag_type': TAG, 'tag': 1, 'optional': True}),
-#		('cipher', core.OctetString, {'tag_type': TAG, 'tag': 2}),
-#]
-#
-#class EncryptionKey(core.Sequence):
-#	"""
-#	EncryptionKey ::= SEQUENCE {
-#	keytype[0]		krb5int32,
-#	keyvalue[1]		OCTET STRING
-#	}
-#	"""
-#	_fields = [
-#		('keytype', Int32, {'tag_type': TAG, 'tag': 0}),
-#		('keyvalue', core.OctetString, {'tag_type': TAG, 'tag': 1}),
-#]
-#
-#	
-#
-#
-#
-#
+class GSSAPIOID(core.ObjectIdentifier):
+	_map = {
+		'1.2.840.113554.1.2.2': 'krb5',
+	}
+
+	_reverse_map = {
+		'krb5': '1.2.840.113554.1.2.2',
+	}
+
+
+class GSSAPIToken(core.Asn1Value):
+	class_ = 1
+	tag = 0
+	method = 1
 
-#
-#
-#class SequenceOfInt32(core.SequenceOf):
-#	"""SEQUENCE OF Int32 for KDC-REQ-BODY
-#	"""
-#	_child_spec = Int32
-#
-#
-#	
-#class SequenceOfKrbCredInfo(core.SequenceOf):
-#	_child_spec = KrbCredInfo
-#	
-#	
-#class EncKrbCredPart(core.Sequence):
-#	explicit = (1, 29)
-#	
-#	_fields = [
-#		('ticket-info', SequenceOfKrbCredInfo, {'tag_type': TAG, 'tag': 0}),
-#		('nonce', Int32, {'tag_type': TAG, 'tag': 1, 'optional': True}),
-#		('timestamp', KerberosTime , {'tag_type': TAG, 'tag': 2, 'optional': True}),
-#		('usec', Microseconds , {'tag_type': TAG, 'tag': 3, 'optional': True}),
-#		('s-address', HostAddress , {'tag_type': TAG, 'tag': 4, 'optional': True}),
-#		('r-address', HostAddress , {'tag_type': TAG, 'tag': 5, 'optional': True}),
-#	]
-#	
-#
-#
diff --git a/minikerberos/protocol/constants.py b/minikerberos/protocol/constants.py
index a4a626e..01eb6fa 100644
--- a/minikerberos/protocol/constants.py
+++ b/minikerberos/protocol/constants.py
@@ -122,4 +122,56 @@ class PaDataType(enum.Enum):
 	PKU2U_NAME = 148#		__ zhu_pku2u
 	REQ_ENC_PA_REP = 149#	__
 	SPAKE = 151#	__https://datatracker.ietf.org/doc/draft-ietf-kitten-krb-spake-preauth/?include_text=1
-	SUPPORTED_ETYPES = 165 #)	__ MS_KILE
\ No newline at end of file
+	SUPPORTED_ETYPES = 165 #)	__ MS_KILE
+
+
+# Full list of key_usage numbers: https://tools.ietf.org/html/rfc4120#section-7.5.1
+# 
+class KEY_USAGE(enum.Enum):
+	AS_REQ_PA_ENC_TS = 1
+	KDC_REP_TICKET = 2
+	AS_REP_ENCPART = 3
+	TGS_REQ_AD_SESSKEY = 4
+	TGS_REQ_AD_SUBKEY = 5
+	TGS_REQ_AUTH_CKSUM = 6
+	TGS_REQ_AUTH = 7
+	TGS_REP_ENCPART_SESSKEY = 8
+	TGS_REP_ENCPART_SUBKEY = 9
+	AP_REQ_AUTH_CKSUM = 10
+	AP_REQ_AUTH = 11
+	AP_REP_ENCPART = 12
+	KRB_PRIV_ENCPART = 13
+	KRB_CRED_ENCPART = 14
+	KRB_SAFE_CKSUM = 15
+	APP_DATA_ENCRYPT = 16
+	APP_DATA_CKSUM = 17
+	KRB_ERROR_CKSUM = 18
+	AD_KDCISSUED_CKSUM = 19
+	AD_MTE = 20
+	AD_ITE = 21
+
+	GSS_TOK_MIC = 22
+	GSS_TOK_WRAP_INTEG = 23
+	GSS_TOK_WRAP_PRIV = 24
+
+	PA_SAM_CHALLENGE_CKSUM = 25
+	#PA_SAM_CHALLENGE_TRACKID  26 #/** Note conflict with @ref KRB5_KEYUSAGE_PA_S4U_X509_USER_REQUEST */
+	#PA_SAM_RESPONSE           27 #/** Note conflict with @ref KRB5_KEYUSAGE_PA_S4U_X509_USER_REPLY */
+	
+	PA_S4U_X509_USER_REQUEST = 26 #/* Defined in [MS-SFU] *//** Note conflict with @ref KRB5_KEYUSAGE_PA_SAM_CHALLENGE_TRACKID */
+	PA_S4U_X509_USER_REPLY = 27 #/** Note conflict with @ref KRB5_KEYUSAGE_PA_SAM_RESPONSE */
+
+	AD_SIGNEDPATH = -21
+	IAKERB_FINISHED = 42
+	PA_PKINIT_KX = 44
+	PA_OTP_REQUEST = 45 
+
+	FAST_REQ_CHKSUM = 50
+	FAST_ENC = 51
+	FAST_REP = 52
+	FAST_FINISHED = 53
+	ENC_CHALLENGE_CLIENT = 54
+	ENC_CHALLENGE_KDC = 55
+	AS_REQ = 56
+	CAMMAC = 64
+	SPAKE = 65
\ No newline at end of file
diff --git a/minikerberos/protocol/encryption.py b/minikerberos/protocol/encryption.py
index 9edcf93..8fb7609 100644
--- a/minikerberos/protocol/encryption.py
+++ b/minikerberos/protocol/encryption.py
@@ -58,6 +58,7 @@ from minikerberos.crypto.AES import *
 from minikerberos.crypto.DES import DES3, DES_CBC, DES_ECB
 from minikerberos.crypto.RC4 import RC4 as ARC4
 from minikerberos.crypto.DES import DES
+from minikerberos.crypto.hashing import md4
 
 
 def get_random_bytes(lenBytes):
@@ -517,7 +518,9 @@ class _RC4(_EnctypeProfile):
 	@classmethod
 	def string_to_key(cls, string, salt, params):
 		utf16string = string.decode('UTF-8').encode('UTF-16LE')
-		return Key(cls.enctype, hashlib.new('md4', utf16string).digest())
+		#return Key(cls.enctype, hashlib.new('md4', utf16string).digest())
+		data = md4(utf16string).digest() #hashlib.new('md4', utf16string).digest()
+		return Key(cls.enctype, data)
 
 	@classmethod
 	def encrypt(cls, key, keyusage, plaintext, confounder):
diff --git a/minikerberos/protocol/errors.py b/minikerberos/protocol/errors.py
index 6833db4..58ce215 100644
--- a/minikerberos/protocol/errors.py
+++ b/minikerberos/protocol/errors.py
@@ -6,16 +6,24 @@
 import enum
 
 class KerberosError(Exception):
-	def __init__(self, krb_err_msg):
+	def __init__(self, krb_err_msg, extra_msg = ''):
 		self.krb_err_msg = krb_err_msg.native
-		self.errorcode = KerberosErrorCode(self.krb_err_msg['error-code'])
-		self.errormsg = KerberosErrorMessage[self.errorcode.name]
+		self.errorcode = KerberosErrorCode.ERR_NOT_FOUND
+		self.errormsg = 'Error code not found! Err code: %s' % self.krb_err_msg['error-code']
+		try:
+			self.errorcode = KerberosErrorCode(self.krb_err_msg['error-code'])
+			self.errormsg = KerberosErrorMessage[self.errorcode.name]
+		except:
+			pass
+		self.extra_msg = extra_msg
 		
-		super(Exception, self).__init__('%s Error Core: %d' % (self.errormsg.value, self.errorcode.value)) 
+		super(Exception, self).__init__('%s Error Code: %d Reason: %s ' % (extra_msg, self.errorcode.value, self.errormsg.value))
+	
 		
 
 # https://technet.microsoft.com/en-us/library/bb463166.aspx
 class KerberosErrorCode(enum.Enum):
+	ERR_NOT_FOUND = 0xFFFFFF
 	KDC_ERR_NONE = 0x0 #No error
 	KDC_ERR_NAME_EXP = 0x1 #Client's entry in KDC database has expired
 	KDC_ERR_SERVICE_EXP = 0x2 #Server's entry in KDC database has expired
diff --git a/minikerberos/protocol/structures.py b/minikerberos/protocol/structures.py
index 78f4479..3f05ee5 100644
--- a/minikerberos/protocol/structures.py
+++ b/minikerberos/protocol/structures.py
@@ -1,5 +1,8 @@
 import io
 import enum
+import base64
+
+from minikerberos.protocol.asn1_structs import GSSAPIOID, GSSAPIToken
 
 #https://tools.ietf.org/html/rfc4121#section-4.1.1.1
 class ChecksumFlags(enum.IntFlag):
@@ -24,7 +27,7 @@ class AuthenticatorChecksum:
 		
 	@staticmethod
 	def from_bytes(data):
-		AuthenticatorChecksum.from_buffer(io.BytesIO(data))
+		return AuthenticatorChecksum.from_buffer(io.BytesIO(data))
 		
 	@staticmethod
 	def from_buffer(buffer):
@@ -33,9 +36,9 @@ class AuthenticatorChecksum:
 		ac.channel_binding = buffer.read(ac.length_of_binding) #according to the latest RFC this is 16 bytes long always
 		ac.flags = ChecksumFlags(int.from_bytes(buffer.read(4), byteorder = 'little', signed = False))
 		if ac.flags & ChecksumFlags.GSS_C_DELEG_FLAG:
-			ac.delegation = bool(int.from_bytes(buffer.read(1), byteorder = 'little', signed = False))
-			ac.delegation_length = int.from_bytes(2, byteorder = 'little', signed = False)
-			ac.delegation_data = int.from_bytes(ac.delegation_length, byteorder = 'little', signed = False)
+			ac.delegation = bool(int.from_bytes(buffer.read(2), byteorder = 'little', signed = False))
+			ac.delegation_length = int.from_bytes(buffer.read(2), byteorder = 'little', signed = False)
+			ac.delegation_data = buffer.read(ac.delegation_length)
 		ac.extensions = buffer.read()
 		return ac
 		
@@ -45,9 +48,32 @@ class AuthenticatorChecksum:
 		t += self.channel_binding
 		t += self.flags.to_bytes(4, byteorder = 'little', signed = False)
 		if self.flags & ChecksumFlags.GSS_C_DELEG_FLAG:
-			t += int(self.delegation).to_bytes(1, byteorder = 'little', signed = False)
+			t += int(self.delegation).to_bytes(2, byteorder = 'little', signed = False)
 			t += len(self.delegation_data.to_bytes()).to_bytes(2, byteorder = 'little', signed = False)
 			t += self.delegation_data.to_bytes()
 		if self.extensions:
 			t += self.extensions.to_bytes()
-		return t
\ No newline at end of file
+		return t
+
+
+# KRB5Token TOK_ID values.
+class KRB5TokenTokID(enum.IntFlag):
+	KRB_AP_REQ = 0x0100
+	KRB_AP_REP = 0x0200
+	KRB_ERROR = 0x0300
+
+	def get_bytes(self):
+		return self.value.to_bytes(2, byteorder='big')
+
+
+# https://tools.ietf.org/html/rfc4121#section-4.1
+class KRB5Token:
+	def __init__(self, inner_token):
+		self.oid = GSSAPIOID('krb5')
+		self.inner_token = inner_token
+
+	def get_apreq_token(self, encoding='utf-8'):
+		token = self.oid.dump()
+		token += KRB5TokenTokID.KRB_AP_REQ.get_bytes()
+		token += self.inner_token
+		return str(base64.b64encode(GSSAPIToken(contents=token).dump()), encoding)
diff --git a/minikerberos/security.py b/minikerberos/security.py
index b434224..981a454 100644
--- a/minikerberos/security.py
+++ b/minikerberos/security.py
@@ -88,7 +88,7 @@ class APREPRoast:
 			return TGTTicket2hashcat(kcomm.kerberos_TGT)
 		except Exception as e:
 			logger.debug('Error while roasting client %s/%s Reason: %s' % (cred.domain, cred.username, str(e)))
-
+			raise e
 
 class Kerberoast:
 	def __init__(self, target: KerberosTarget, cred: KerberosCredential):
@@ -102,6 +102,7 @@ class Kerberoast:
 		except Exception as e:
 			logger.exception('a')
 			logger.debug('Error logging in! Reason: %s' % (str(e)))
+			raise e
 
 		results = []
 		for spn in spns:
diff --git a/setup.py b/setup.py
index b14bed5..3ff2806 100644
--- a/setup.py
+++ b/setup.py
@@ -45,7 +45,7 @@ setup(
 	),
 	install_requires=[
 		'asn1crypto>=1.3.0',
-		'asysocks>=0.0.2',
+		'asysocks>=0.0.11',
 	],
 
 	entry_points={