Codebase list msldap / 68bbea6
New upstream release. Kali Janitor 2 years ago
49 changed file(s) with 1334 addition(s) and 2735 deletion(s). Raw diff Collapse all Expand all
00 Metadata-Version: 1.2
11 Name: msldap
2 Version: 0.3.30
2 Version: 0.3.38
33 Summary: Python library to play with MS LDAP
44 Home-page: https://github.com/skelsec/msldap
55 Author: Tamas Jos
0 [![Documentation Status](https://readthedocs.org/projects/msldap/badge/?version=latest)](https://msldap.readthedocs.io/en/latest/?badge=latest)
0 ![Supported Python versions](https://img.shields.io/badge/python-3.6+-blue.svg) [![Documentation Status](https://readthedocs.org/projects/msldap/badge/?version=latest)](https://msldap.readthedocs.io/en/latest/?badge=latest) [![Twitter](https://img.shields.io/twitter/follow/skelsec?label=skelsec&style=social)](https://twitter.com/intent/follow?screen_name=skelsec)
11
2 # msldap client
3 ![Documentation Status](https://user-images.githubusercontent.com/19204702/81515211-3761e880-9333-11ea-837f-bcbe2a67ee48.gif )
2 :triangular_flag_on_post: This is the public repository of msldap, for latest version and updates please consider supporting us through https://porchetta.industries/
43
54 # msldap
65 LDAP library for MS AD
6 ![Documentation Status](https://user-images.githubusercontent.com/19204702/81515211-3761e880-9333-11ea-837f-bcbe2a67ee48.gif )
7
8 ## :triangular_flag_on_post: Sponsors
9
10 If you want to sponsors this project and have the latest updates on this project, latest issues fixed, latest features, please support us on https://porchetta.industries/
11
12 ## Official Discord Channel
13
14 Come hang out on Discord!
15
16 [![Porchetta Industries](https://discordapp.com/api/guilds/736724457258745996/widget.png?style=banner3)](https://discord.gg/ycGXUxy)
17
718
819 # Documentation
920 [Awesome documentation here!](https://msldap.readthedocs.io/en/latest/)
5970 - kerberos-aes (dc option param must be used)
6071 - kerberos-keytab (dc option param must be used)
6172 - kerberos-ccache (dc option param must be used)
73 - kerberos-pfx (dc option param must be used)
74 - kerberos-pem (dc option param must be used)
75 - kerberos-certstore (dc option param must be used, windows only)
6276 - sspi-ntlm (windows only!)
6377 - sspi-kerberos (windows only!)
6478 - anonymous
95109 ```
96110
97111 # Kudos
98
112 Certificate services functionality was based on [certi](https://github.com/zer1t0/certi) created by @zer1t0
0 msldap (0.3.38-0kali1) UNRELEASED; urgency=low
1
2 * New upstream release.
3
4 -- Kali Janitor <[email protected]> Wed, 30 Mar 2022 00:15:12 -0000
5
06 msldap (0.3.30-0kali1) kali-dev; urgency=medium
17
28 [ Kali Janitor ]
00
1 __version__ = "0.3.30"
1 __version__ = "0.3.38"
22 __banner__ = \
33 """
44 # msldap %s
55
66 from minikerberos.protocol.constants import EncryptionType
77 from minikerberos.protocol import encryption
8 from minikerberos.crypto.hashing import md5, hmac_md5
9 from minikerberos.crypto.RC4 import RC4
8 from unicrypto.hashlib import md5
9 from unicrypto import hmac # import md5, hmac_md5
10 from unicrypto.symmetric import RC4
1011
1112 #TODO: RC4 support!
1213
204205 else:
205206 mic.SND_SEQ = sequenceNumber.to_bytes(4, 'big', signed = False) + b'\xff'*4
206207
207 Ksign_ctx = hmac_md5(self.session_key.contents)
208 Ksign_ctx = hmac.new(self.session_key.contents, digestmod='md5')
208209 Ksign_ctx.update(b'signaturekey\0')
209210 Ksign = Ksign_ctx.digest()
210211
211212 id = 15
212213 temp = md5( id.to_bytes(4, 'little', signed = False) + mic.to_bytes()[:8] ).digest()
213 chksum_ctx = hmac_md5(Ksign)
214 chksum_ctx = hmac.new(Ksign, digestmod='md5')
214215 chksum_ctx.update(temp)
215216 mic.SGN_CKSUM = chksum_ctx.digest()[:8]
216217
217218 id = 0
218 temp = hmac_md5(self.session_key.contents)
219 temp = hmac.new(self.session_key.contents, digestmod='md5')
219220 temp.update(id.to_bytes(4, 'little', signed = False))
220221
221 Kseq_ctx = hmac_md5(temp.digest())
222 Kseq_ctx = hmac.new(temp.digest(), digestmod='md5')
222223 Kseq_ctx.update(mic.SGN_CKSUM)
223224 Kseq = Kseq_ctx.digest()
224225
263264 # #testing purposes only, pls remove
264265
265266
266 temp = hmac_md5(self.session_key.contents)
267 temp = hmac.new(self.session_key.contents, digestmod='md5')
267268 temp.update(b'signaturekey\0')
268269 Ksign = temp.digest()
269270
275276 klocal += bytes([b ^ 0xf0])
276277
277278 id = 0
278 temp = hmac_md5(klocal)
279 temp = hmac.new(klocal, digestmod='md5')
279280 temp.update(id.to_bytes(4, 'little', signed = False))
280 temp = hmac_md5(temp.digest())
281 temp = hmac.new(temp.digest(), digestmod='md5')
281282 temp.update(seq_num.to_bytes(4, 'big', signed = False))
282283 Kcrypt = temp.digest()
283284
284 temp = hmac_md5(Ksign)
285 temp = hmac.new(Ksign, digestmod='md5')
285286 temp.update(Sgn_Cksum)
286287 token.SGN_CKSUM = temp.digest()[:8]
287288
288289 id = 0
289 temp = hmac_md5(self.session_key.contents)
290 temp = hmac.new(self.session_key.contents, digestmod='md5')
290291 temp.update(id.to_bytes(4, 'little', signed = False))
291 temp = hmac_md5(temp.digest())
292 temp = hmac.new(temp.digest(), digestmod='md5')
292293 temp.update(token.SGN_CKSUM)
293294 Kseq = temp.digest()
294295
308309 wrap = GSSWRAP_RC4.from_bytes(hdr)
309310
310311 id = 0
311 temp = hmac_md5(self.session_key.contents)
312 temp = hmac.new(self.session_key.contents, digestmod='md5')
312313 temp.update(id.to_bytes(4, 'little', signed = False))
313 temp = hmac_md5(temp.digest())
314 temp = hmac.new(temp.digest(), digestmod='md5')
314315 temp.update(wrap.SGN_CKSUM)
315316 Kseq = temp.digest()
316317
317318 snd_seq = RC4(Kseq).encrypt(wrap.SND_SEQ)
318319
319320 id = 0
320 temp = hmac_md5(klocal)
321 temp = hmac.new(klocal, digestmod='md5')
321322 temp.update(id.to_bytes(4, 'little', signed = False))
322 temp = hmac_md5(temp.digest())
323 temp = hmac.new(temp.digest(), digestmod='md5')
323324 temp.update(snd_seq[:4])
324325 Kcrypt = temp.digest()
325326
330331 id = 13
331332 Sgn_Cksum_calc = md5(id.to_bytes(4, 'little', signed = False) + wrap.to_bytes()[:8] + dec_cofounder + dec_data).digest()
332333
333 temp = hmac_md5(Ksign)
334 temp = hmac.new(Ksign, digestmod='md5')
334335 temp.update(Sgn_Cksum_calc)
335336 Sgn_Cksum_calc = temp.digest()[:8]
336337
1414 from msldap.authentication.kerberos.gssapi import get_gssapi, GSSWrapToken, KRB5_MECH_INDEP_TOKEN
1515 from minikerberos.protocol.asn1_structs import AP_REQ, AP_REP, TGS_REP
1616 from minikerberos.protocol.encryption import Enctype, Key, _enctype_table
17 from pyodidewsnet.sspiproxyws import SSPIProxyWS
17 from wsnet.operator.sspiproxy import WSNETSSPIProxy
1818
1919
2020 # mutual auth not supported
5151 self.settings = settings
5252 self.mode = 'CLIENT'
5353 url = '%s://%s:%s' % (self.settings.proto, self.settings.host, self.settings.port)
54 self.sspi = SSPIProxyWS(url, self.settings.agent_id)
54 self.sspi = WSNETSSPIProxy(url, self.settings.agent_id)
5555 self.client = None
5656 self.target = None
5757 self.gssapi = None
1414 from msldap.authentication.kerberos.gssapi import get_gssapi, GSSWrapToken, KRB5_MECH_INDEP_TOKEN
1515 from minikerberos.protocol.asn1_structs import AP_REQ, AP_REP, TGS_REP
1616 from minikerberos.protocol.encryption import Enctype, Key, _enctype_table
17 from pyodidewsnet.clientauth import WSNETAuth
17 from wsnet.pyodide.clientauth import WSNETAuth
1818
1919
2020 # mutual auth not supported
0 import io
1 import os
2 import hmac
30 import datetime
41
5 from msldap.crypto.symmetric import DES
6 from msldap.crypto.hashing import *
2 from unicrypto.symmetric import DES
3 from unicrypto import hmac
4 from unicrypto.hashlib import md5, md4
75 from msldap.authentication.ntlm.structures.challenge_response import *
8
6 from msldap.authentication.ntlm.structures.negotiate_flags import NegotiateFlags
97
108 class NTLMCredentials:
119 @staticmethod
158156 else:
159157 raise Exception('Unknown cred type!')
160158
161 hm = hmac_md5(lm_hash)
159 hm = hmac.new(lm_hash, digestmod='md5')
162160 hm.update(bytes.fromhex(self.ServerChallenge))
163161 hm.update(bytes.fromhex(self.ChallengeFromClinet))
164162
185183 else:
186184 nt_hash = bytes.fromhex(self.credentials.nt_hash)
187185
188 hm = hmac_md5(self.SessionBaseKey)
186 hm = hmac.new(self.SessionBaseKey, digestmod='md5')
189187 hm.update(self.ServerChallenge)
190188 hm.update(self.LMResponse.to_bytes()[:8])
191189
414412 cc = NTLMv2ClientChallenge.construct(timestamp, client_challenge, server_details)
415413 temp = cc.to_bytes()
416414
417 hm = hmac_md5(nt_hash_v2)
415 hm = hmac.new(nt_hash_v2, digestmod='md5')
418416 hm.update(server_challenge)
419417 hm.update(temp)
420418
425423 ntlm_creds.NTResponse.ChallengeFromClinet = cc
426424
427425
428 hm = hmac_md5(nt_hash_v2)
426 hm = hmac.new(nt_hash_v2, digestmod='md5')
429427 hm.update(server_challenge)
430428 hm.update(client_challenge)
431429
434432 ntlm_creds.LMResponse.ChallengeFromClinet = client_challenge
435433
436434
437 hm = hmac_md5(nt_hash_v2)
435 hm = hmac.new(nt_hash_v2, digestmod='md5')
438436 hm.update(NTProofStr)
439437 ntlm_creds.SessionBaseKey = hm.digest()
440438
476474 # print(self.ServerChallenge)
477475 # print(self.ChallengeFromClinet)
478476
479 hm = hmac_md5(nt_hash)
477 hm = hmac.new(nt_hash, digestmod='md5')
480478 hm.update(bytes.fromhex(self.ServerChallenge))
481479 hm.update(bytes.fromhex(self.ChallengeFromClinet))
482480
511509
512510 def NTOWFv2(Passwd, User, UserDom, PasswdHash = None):
513511 if PasswdHash is not None:
514 fp = hmac_md5(PasswdHash)
512 fp = hmac.new(PasswdHash, digestmod='md5')
515513 else:
516 fp = hmac_md5(NTOWFv1(Passwd))
514 fp = hmac.new(NTOWFv1(Passwd), digestmod='md5')
517515 fp.update((User.upper() + UserDom).encode('utf-16le'))
518516 return fp.digest()
519517
00 import os
11 import struct
2 import hmac
3 import copy
4 import hashlib
5
6 #from aiosmb.commons.connection.credential import SMBNTLMCredential
7 #from aiosmb.commons.serverinfo import NTLMServerInfo
2
83 from msldap.authentication.ntlm.templates.server import NTLMServerTemplates
94 from msldap.authentication.ntlm.templates.client import NTLMClientTemplates
105 from msldap.authentication.ntlm.structures.negotiate_flags import NegotiateFlags
1510 from msldap.authentication.ntlm.messages.challenge import NTLMChallenge
1611 from msldap.authentication.ntlm.messages.authenticate import NTLMAuthenticate
1712 from msldap.authentication.ntlm.creds_calc import *
18 from msldap.crypto.symmetric import RC4
13 from unicrypto.symmetric import RC4
14 from unicrypto import hmac
15 from unicrypto import hashlib
1916
2017
2118 class NTLMHandlerSettings:
163160 msg = NTLMSSP_MESSAGE_SIGNATURE()
164161 if NegotiateFlags.NEGOTIATE_KEY_EXCH in self.ntlmChallenge.NegotiateFlags:
165162 tt = struct.pack('<i', seqNum) + message
166 t = hmac_md5(signingKey)
163 t = hmac.new(signingKey, digestmod='md5')
167164 t.update(tt)
168165
169166 msg.Checksum = handle(t.digest()[:8])
170167 msg.SeqNum = seqNum
171168 seqNum += 1
172169 else:
173 t = hmac_md5(signingKey)
170 t = hmac.new(signingKey, digestmod='md5')
174171 t.update(struct.pack('<i',seqNum)+message)
175172 msg.Checksum = t.digest()[:8]
176173 msg.SeqNum = seqNum
00 from msldap import logger
11 from msldap.authentication.ntlm.native import NTLMAUTHHandler, NTLMHandlerSettings
2 from pyodidewsnet.sspiproxyws import SSPIProxyWS
2 from wsnet.operator.sspiproxy import WSNETSSPIProxy
33 import enum
44
55 class ISC_REQ(enum.IntFlag):
3232 self.settings = settings
3333 self.mode = None #'CLIENT'
3434 url = '%s://%s:%s' % (self.settings.proto, self.settings.host, self.settings.port)
35 self.sspi = SSPIProxyWS(url, self.settings.agent_id)
35 self.sspi = WSNETSSPIProxy(url, self.settings.agent_id)
3636 self.operator = None
3737 self.client = None
3838 self.target = None
00 from msldap import logger
11 from msldap.authentication.ntlm.native import NTLMAUTHHandler, NTLMHandlerSettings
2 from pyodidewsnet.clientauth import WSNETAuth
2 from wsnet.pyodide.clientauth import WSNETAuth
33 import enum
44
55 class ISC_REQ(enum.IntFlag):
33 # Tamas Jos (@skelsec)
44 #
55
6 from codecs import lookup
67 import copy
78 import asyncio
89
1516 from msldap.connection import MSLDAPClientConnection
1617 from msldap.protocol.messages import Control
1718 from msldap.ldap_objects import *
19 from msldap.commons.utils import KNOWN_SIDS
1820
1921 from winacl.dtyp.security_descriptor import SECURITY_DESCRIPTOR
2022 from winacl.dtyp.ace import ACCESS_ALLOWED_OBJECT_ACE, ADS_ACCESS_MASK
3739 :rtype: dict
3840
3941 """
40 def __init__(self, target, creds):
42 def __init__(self, target, creds, connection = None, keepalive = False):
4143 self.creds = creds
4244 self.target = target
43
44 self.ldap_query_page_size = self.target.ldap_query_page_size
45 self.keepalive = keepalive
46 self.ldap_query_page_size = 1000
47 if self.target is not None:
48 self.ldap_query_page_size = self.target.ldap_query_page_size
49
50 self.ldap_query_ratelimit = 0
51 if self.target is not None:
52 self.ldap_query_ratelimit = self.target.ldap_query_ratelimit
53
4554 self._tree = None
4655 self._ldapinfo = None
47 self._con = None
56 self._con = connection
57 self.__keepalive_task = None
58 self.keepalive_period = 10
59 self.disconnected_evt = None
60 self._sid_cache = {} #SID -> (domain, user)
61 self._domainsid_cache = {} # SID -> domain
4862
4963 async def __aenter__(self):
5064 return self
5266 async def __aexit__(self, exc_type, exc, traceback):
5367 await asyncio.wait_for(self.disconnect(), timeout = 1)
5468
69 async def __keepalive(self):
70 try:
71 while not self.disconnected_evt.is_set():
72 if self._con is not None:
73 ldap_filter = r'(distinguishedName=%s)' % self._tree
74 async for entry, err in self.pagedsearch(ldap_filter, MSADInfo_ATTRS):
75 if err is not None:
76 return None, err
77 await asyncio.sleep(self.keepalive_period)
78
79
80 except asyncio.CancelledError:
81 return
82
83 except Exception as e:
84 print('Keepalive exception: %s' % e)
85 await self.disconnect()
86
5587 async def disconnect(self):
5688 try:
89 if self.__keepalive_task is not None:
90 self.__keepalive_task.cancel()
5791 if self._con is not None:
5892 await self._con.disconnect()
93
94 self.disconnected_evt.set()
5995
6096 except Exception as e:
6197 return False, e
6298
6399 async def connect(self):
64100 try:
65 self._con = MSLDAPClientConnection(self.target, self.creds)
66 _, err = await self._con.connect()
67 if err is not None:
68 raise err
69 res, err = await self._con.bind()
70 if err is not None:
71 return False, err
101 self.disconnected_evt = asyncio.Event()
102 if self._con is None:
103 self._con = MSLDAPClientConnection(self.target, self.creds)
104 _, err = await self._con.connect()
105 if err is not None:
106 raise err
107 res, err = await self._con.bind()
108 if err is not None:
109 return False, err
72110 res, err = await self._con.get_serverinfo()
73111 if err is not None:
74112 raise err
75113 self._serverinfo = res
76114 self._tree = res['defaultNamingContext']
77115 self._ldapinfo, err = await self.get_ad_info()
116 self._domainsid_cache[self._ldapinfo.objectSid] = self._ldapinfo.name
117 if self.keepalive is True:
118 self.__keepalive_task = asyncio.create_task(self.__keepalive())
78119 if err is not None:
79120 raise err
80121 return True, None
84125 def get_server_info(self):
85126 return self._serverinfo
86127
87 async def pagedsearch(self, query, attributes, controls = None):
128 async def pagedsearch(self, query, attributes, controls = None, tree = None):
88129 """
89130 Performs a paged search on the AD, using the filter and attributes as a normal query does.
90131 !The LDAP connection MUST be active before invoking this function!
111152 print('Theconnection is in stopped state!')
112153 return
113154
114 if self._tree is None:
155 if tree is None:
156 tree = self._tree
157 if tree is None:
115158 raise Exception('BIND first!')
116159 t = []
117160 for x in attributes:
130173 controls = t
131174
132175 async for entry, err in self._con.pagedsearch(
133 self._tree,
176 tree,
134177 query,
135178 attributes = attributes,
136179 size_limit = self.ldap_query_page_size,
137180 controls = controls,
138 rate_limit=self.target.ldap_query_ratelimit
181 rate_limit=self.ldap_query_ratelimit
139182 ):
140183
141184 if err is not None:
169212 size_limit = self.ldap_query_page_size,
170213 search_scope=LEVEL,
171214 controls = None,
172 rate_limit=self.target.ldap_query_ratelimit
215 rate_limit=self.ldap_query_ratelimit
173216 ):
174217 if err is not None:
175218 raise err
292335 size_limit = self.ldap_query_page_size,
293336 search_scope=BASE,
294337 controls = None,
295 rate_limit=self.target.ldap_query_ratelimit
338 rate_limit=self.ldap_query_ratelimit
296339 ):
297340 if err is not None:
298341 yield None, err
644687 return None, err
645688
646689 return entry['attributes']['objectSid'], None
647
690
691 async def get_tokengroups_user(self, samaccountname):
692 ldap_filter = r'(sAMAccountName=%s)' % escape_filter_chars(samaccountname)
693 user_dn = None
694 async for entry, err in self.pagedsearch(ldap_filter, ['distinguishedName']):
695 if err is not None:
696 return None, err
697
698 user_dn = entry['attributes']['distinguishedName']
699
700 if user_dn is None:
701 return None, Exception('User not found! %s' % samaccountname)
702
703 tokengroup = []
704 async for sids, err in self.get_tokengroups(user_dn):
705 if err is not None:
706 return None, err
707 tokengroup.append(sids)
708
709 return tokengroup, None
710
648711 async def get_tokengroups(self, dn):
649712 """
650713 Yields SIDs of groups that the given DN is a member of.
662725 attributes = attributes,
663726 size_limit = self.ldap_query_page_size,
664727 search_scope=BASE,
665 rate_limit=self.target.ldap_query_ratelimit
728 rate_limit=self.ldap_query_ratelimit
666729 ):
667730 if err is not None:
668731 yield None, err
699762 attributes = [b'tokenGroups'],
700763 size_limit = self.ldap_query_page_size,
701764 search_scope=BASE,
702 rate_limit=self.target.ldap_query_ratelimit
765 rate_limit=self.ldap_query_ratelimit
703766 ):
704767
705768 #print(entry2)
11471210 return True, None
11481211 except Exception as e:
11491212 return False, e
1213
1214 async def list_root_cas(self):
1215 try:
1216 ldap_filter = "(objectClass=certificationAuthority)"
1217 tree = "CN=Certification Authorities,CN=Public Key Services,CN=Services,CN=Configuration,%s" % self._ldapinfo.distinguishedName
1218 async for entry, err in self.pagedsearch(ldap_filter, attributes = MSADCA_ATTRS, tree = tree):
1219 if err is not None:
1220 yield None, err
1221 return
1222 yield MSADCA.from_ldap(entry, 'ROOTCA'), None
1223
1224 except Exception as e:
1225 yield None, e
1226 return
1227
1228 async def list_ntcas(self):
1229 try:
1230 ldap_filter = "(objectClass=certificationAuthority)"
1231 tree = "CN=NTAuthCertificates,CN=Public Key Services,CN=Services,CN=Configuration,%s" % self._ldapinfo.distinguishedName
1232 async for entry, err in self.pagedsearch(ldap_filter, attributes = MSADCA_ATTRS, tree = tree):
1233 if err is not None:
1234 yield None, err
1235 return
1236 yield MSADCA.from_ldap(entry, 'NTCA'), None
1237
1238 except Exception as e:
1239 yield None, e
1240 return
1241
1242 async def list_aiacas(self):
1243 try:
1244 ldap_filter = "(objectClass=certificationAuthority)"
1245 tree = "CN=AIA,CN=Public Key Services,CN=Services,CN=Configuration,%s" % self._ldapinfo.distinguishedName
1246 async for entry, err in self.pagedsearch(ldap_filter, attributes = MSADCA_ATTRS, tree = tree):
1247 if err is not None:
1248 yield None, err
1249 return
1250 yield MSADCA.from_ldap(entry, 'AIACA'), None
1251
1252 except Exception as e:
1253 yield None, e
1254 return
1255
1256 async def list_enrollment_services(self):
1257 try:
1258 ldap_filter = "(objectCategory=pKIEnrollmentService)"
1259 tree = "CN=Configuration,%s" % self._ldapinfo.distinguishedName
1260
1261 async for entry, err in self.pagedsearch(ldap_filter, attributes = MSADEnrollmentService_ATTRS, tree = tree):
1262 if err is not None:
1263 yield None, err
1264 return
1265 yield MSADEnrollmentService.from_ldap(entry), None
1266
1267 except Exception as e:
1268 yield None, e
1269 return
1270
1271 async def list_certificate_templates(self, name = None):
1272 try:
1273 req_flags = SDFlagsRequestValue({'Flags' : SDFlagsRequest.DACL_SECURITY_INFORMATION|SDFlagsRequest.GROUP_SECURITY_INFORMATION|SDFlagsRequest.OWNER_SECURITY_INFORMATION})
1274 controls = [('1.2.840.113556.1.4.801', True, req_flags.dump())]
1275
1276 ldap_filter = "(objectCategory=pKICertificateTemplate)"
1277 if name is not None:
1278 ldap_filter = "(&(objectCategory=pKICertificateTemplate)(name=%s))" % name
1279 tree = "CN=Configuration,%s" % self._ldapinfo.distinguishedName
1280
1281 async for entry, err in self.pagedsearch(ldap_filter, attributes = MSADCertificateTemplate_ATTRS, controls=controls, tree = tree):
1282 if err is not None:
1283 yield None, err
1284 return
1285 yield MSADCertificateTemplate.from_ldap(entry), None
1286
1287 except Exception as e:
1288 yield None, e
1289 return
1290
1291 async def resolv_sd(self, sd):
1292 "Resolves all SIDs found in security descriptor, returns lookup table"
1293 try:
1294 if isinstance(sd, bytes):
1295 sd = SECURITY_DESCRIPTOR.from_bytes(sd)
1296
1297 lookup_table = {}
1298 sids = {}
1299 sids[str(sd.Owner)] = 1
1300 sids[str(sd.Group)] = 1
1301 if sd.Dacl is not None:
1302 for ace in sd.Dacl.aces:
1303 sids[str(ace.Sid)] = 1
1304 if sd.Sacl is not None:
1305 for ace in sd.Sacl.aces:
1306 sids[str(ace.Sid)] = 1
1307
1308 for sid in sids:
1309 domain, username, err = await self.resolv_sid(sid)
1310 if err is not None:
1311 raise err
1312 lookup_table[sid] = (domain, username)
1313
1314 return lookup_table, None
1315
1316 except Exception as e:
1317 return None, e
1318
1319 async def resolv_sid(self, sid, use_cache = True):
1320 """Performs a SID lookup for object and returns the domain name and the samaccountname"""
1321 try:
1322 sid = str(sid).upper()
1323 if sid in KNOWN_SIDS:
1324 return "BUILTIN", KNOWN_SIDS[sid], None
1325 domain = None
1326 username = None
1327 domainsid = sid.rsplit('-',1)[0]
1328 if domainsid not in self._domainsid_cache:
1329 logger.debug('Domain SID "%s" was not found! ' % domainsid)
1330 return '???', '???', None
1331 domain = self._domainsid_cache[domainsid]
1332 if sid in self._sid_cache:
1333 username = self._sid_cache[sid]
1334
1335 else:
1336 ldap_filter = r'(objectSid=%s)' % sid
1337 async for entry, err in self.pagedsearch(ldap_filter, attributes = ['sAMAccountName']):
1338 if err is not None:
1339 return None, None, err
1340 username = entry['attributes'].get('sAMAccountName')
1341
1342 if username is None:
1343 return domain, '???', None
1344 #raise Exception('User not found! %s' % sid)
1345
1346 if use_cache is True:
1347 self._sid_cache[sid] = username
1348 return domain, username, None
1349 except Exception as e:
1350 return None, None, e
1351
1352 async def whoami(self):
1353 return await self._con.whoami()
1354
1355 async def whoamifull(self):
1356 """Full whoami"""
1357 #TODO: it can be the case that the server returns the SID of the user
1358 # implement that path!
1359 result = {}
1360 try:
1361 res, err = await self.whoami()
1362 if err is not None:
1363 raise err
1364 result['raw'] = res
1365 if res.startswith('u:') is True:
1366 domain, samaccountname = res[2:].split('\\', 1)
1367 result['domain'] = domain
1368 result['samaccountname'] = samaccountname
1369 user, err = await self.get_user(samaccountname)
1370 if err is not None:
1371 raise err
1372 result['sid'] = str(user.objectSid)
1373 result['groups'] = {}
1374 async for group_sid, err in self.get_tokengroups(user.distinguishedName):
1375 if err is not None:
1376 raise err
1377 result['groups'][group_sid] = ('NA','NA')
1378 domain, username, err = await self.resolv_sid(group_sid)
1379 if err is not None:
1380 raise err
1381 result['groups'][group_sid] = (domain, username)
1382
1383 return result, None
1384 except:
1385 return result, None
11501386
11511387 #async def get_permissions_for_dn(self, dn):
11521388 # """
225225 LDAPAuthProtocol.KERBEROS_PASSWORD,
226226 LDAPAuthProtocol.KERBEROS_CCACHE,
227227 LDAPAuthProtocol.KERBEROS_KEYTAB,
228 LDAPAuthProtocol.KERBEROS_KIRBI]:
228 LDAPAuthProtocol.KERBEROS_KIRBI,
229 LDAPAuthProtocol.KERBEROS_PFX,
230 LDAPAuthProtocol.KERBEROS_PEM,
231 LDAPAuthProtocol.KERBEROS_CERTSTORE]:
229232
230233 if self.target is None:
231234 raise Exception('Target must be specified with Kerberos!')
243246 kc = KerberosCredential.from_ccache_file(self.creds.password, self.creds.username, self.creds.domain)
244247 elif self.creds.auth_method == LDAPAuthProtocol.KERBEROS_KEYTAB:
245248 kc = KerberosCredential.from_kirbi(self.creds.password, self.creds.username, self.creds.domain)
249 elif self.creds.auth_method == LDAPAuthProtocol.KERBEROS_PFX:
250 kc = KerberosCredential.from_pfx_file(self.creds.username, self.creds.password, username = self.creds.altname, domain = self.creds.altdomain)
251 self.creds.username = kc.username
252 self.creds.domain = kc.domain
253 self.target.domain = kc.domain
254 elif self.creds.auth_method == LDAPAuthProtocol.KERBEROS_PEM:
255 kc = KerberosCredential.from_pem_file(self.creds.username, self.creds.password, username = self.creds.altname, domain = self.creds.altdomain)
256 self.creds.username = kc.username
257 self.creds.domain = kc.domain
258 self.target.domain = kc.domain
259 elif self.creds.auth_method == LDAPAuthProtocol.KERBEROS_CERTSTORE:
260 # username is the CN of the certificate
261 # secret is the name of the certstore, default: MY
262 certstore = self.creds.secret
263 if self.creds.secret is None:
264 certstore = 'MY'
265 kc = KerberosCredential.from_windows_certstore(self.creds.username, certstore, username = self.creds.altname, domain = self.creds.altdomain)
266 self.creds.username = kc.username
267 self.creds.domain = kc.domain
268 self.target.domain = kc.domain
269
246270 else:
247271 kc = KerberosCredential()
248272 kc.username = self.creds.username
268292 kcred.enctypes = [23]
269293
270294 elif self.creds.auth_method == LDAPAuthProtocol.KERBEROS_CCACHE:
271 kc.ccache = self.creds.password
272295 kcred.enctypes = [23,17,18] # TODO: fix this
273296 elif self.creds.auth_method == LDAPAuthProtocol.KERBEROS_KEYTAB:
274297 kc.keytab = self.creds.password
275298 kcred.enctypes = [23,17,18] # TODO: fix this
276299 elif self.creds.auth_method == LDAPAuthProtocol.KERBEROS_KIRBI:
277300 kcred.enctypes = [23,17,18] # TODO: fix this
301 elif self.creds.auth_method in [LDAPAuthProtocol.KERBEROS_PFX, LDAPAuthProtocol.KERBEROS_CERTSTORE, LDAPAuthProtocol.KERBEROS_PEM]:
302 kcred.enctypes = [17,18]
278303 else:
279304 raise Exception('No suitable secret type found to set up kerberos!')
280305
3434 KERBEROS_PASSWORD = 'KERBEROS_PASSWORD'
3535 KERBEROS_CCACHE = 'KERBEROS_CCACHE'
3636 KERBEROS_KEYTAB = 'KERBEROS_KEYTAB'
37 KERBEROS_KIRBI = 'KERBEROS_KIRBI'
37 KERBEROS_KIRBI = 'KERBEROS_KIRBI'
38 KERBEROS_PFX = 'KERBEROS_PFX'
39 KERBEROS_PEM = 'KERBEROS_PEM'
40 KERBEROS_CERTSTORE = 'KERBEROS_CERTSTORE'
3841 MULTIPLEXOR_KERBEROS = 'MULTIPLEXOR_KERBEROS'
3942 MULTIPLEXOR_NTLM = 'MULTIPLEXOR_NTLM'
4043 MULTIPLEXOR_SSL_KERBEROS = 'MULTIPLEXOR_SSL_KERBEROS'
5659 LDAPAuthProtocol.KERBEROS_CCACHE ,
5760 LDAPAuthProtocol.KERBEROS_KEYTAB ,
5861 LDAPAuthProtocol.KERBEROS_KIRBI ,
62 LDAPAuthProtocol.KERBEROS_PFX ,
63 LDAPAuthProtocol.KERBEROS_PEM ,
64 LDAPAuthProtocol.KERBEROS_CERTSTORE ,
5965 LDAPAuthProtocol.SSPI_NTLM ,
6066 LDAPAuthProtocol.SSPI_KERBEROS,
6167 LDAPAuthProtocol.MULTIPLEXOR_KERBEROS,
7682 LDAPAuthProtocol.KERBEROS_CCACHE ,
7783 LDAPAuthProtocol.KERBEROS_KEYTAB ,
7884 LDAPAuthProtocol.KERBEROS_KIRBI ,
85 LDAPAuthProtocol.KERBEROS_PFX ,
86 LDAPAuthProtocol.KERBEROS_PEM ,
87 LDAPAuthProtocol.KERBEROS_CERTSTORE ,
7988 ]
8089
8190 class MSLDAPCredential:
97106 :param encrypt: Use protocol-level encryption. Doesnt work on LDAPS
98107 :type encrypt: bool
99108 """
100 def __init__(self, domain=None, username= None, password = None, auth_method = None, settings = None, etypes = None, encrypt = False):
109 def __init__(self, domain=None, username= None, password = None, auth_method = None, settings = None, etypes = None, encrypt = False, altname = None, altdomain = None):
101110 self.auth_method = auth_method
102111 self.domain = domain
103112 self.username = username
107116 self.settings = settings
108117 self.etypes = etypes
109118 self.encrypt = encrypt
119 self.altname = altname
120 self.altdomain = altdomain
110121
111122 def get_msuser(self):
112123 if not self.domain:
77 import enum
88
99 import platform
10 try:
11 import ssl
12 except:
13 if platform.system() == 'Emscripten':
14 pass
10 import ssl
11
1512
1613 class LDAPProtocol(enum.Enum):
1714 TCP = 'TCP'
3936 :type ldap_query_page_size: int
4037 :param ldap_query_ratelimit: rate limit of paged queries. This will cause a sleep (in seconds) between fetching of each page of the query
4138 :type ldap_query_ratelimit: float
39 :param dc_ip: Ip address of the kerberos server (if kerberos is used)
40 :type dc_ip: str
4241 """
43 def __init__(self, host, port = 389, proto = LDAPProtocol.TCP, tree = None, proxy = None, timeout = 10, ldap_query_page_size = 1000, ldap_query_ratelimit = 0):
42 def __init__(self, host, port = 389, proto = LDAPProtocol.TCP, tree = None, proxy = None, timeout = 10, ldap_query_page_size = 1000, ldap_query_ratelimit = 0, dc_ip:str = None):
4443 self.proto = proto
4544 self.host = host
4645 self.tree = tree
4746 self.port = port
4847 self.proxy = proxy
4948 self.timeout = timeout
50 self.dc_ip = None
49 self.dc_ip = dc_ip
5150 self.serverip = None
5251 self.domain = None
5352 self.sslctx = None
99 import getpass
1010 import base64
1111 import enum
12 import copy
1213 from urllib.parse import urlparse, parse_qs
1314
1415 from msldap.commons.credential import MSLDAPCredential, LDAPAuthProtocol, MSLDAP_KERBEROS_PROTOCOLS
9293 ldap://TEST\\victim:[email protected]/DC=test,DC=corp/?timeout=99&proxytype=socks5&proxyhost=127.0.0.1&proxyport=1080&proxytimeout=44
9394 """
9495
95 def __init__(self, url):
96 def __init__(self, url, credential:MSLDAPCredential = None, target:MSLDAPTarget = None ):
97 self.credential = credential
98 self.target = target
9699 self.url = url
97100 self.ldap_scheme = None
98101 self.auth_scheme = None
103106 self.encrypt = False
104107 self.auth_settings = {}
105108 self.etypes = None
109 self.altname = None
110 self.altdomain = None
106111
107112 self.ldap_proto = None
108113 self.ldap_host = None
117122
118123 self.__pwpreprocess = None
119124
120 self.parse()
125 if url is not None:
126 self.parse()
121127
122128
123129 def get_credential(self):
127133 :return: Credential object
128134 :rtype: :class:`MSLDAPCredential`
129135 """
136 if self.credential is not None:
137 return copy.deepcopy(self.credential)
130138 t = MSLDAPCredential(
131139 domain=self.domain,
132140 username=self.username,
133141 password = self.password,
134142 auth_method=self.auth_scheme,
135 settings = self.auth_settings
143 settings = self.auth_settings,
144 altname=self.altname,
145 altdomain=self.altdomain
136146 )
137147 t.encrypt = self.encrypt
138148 t.etypes = self.etypes
146156 :return: Target object
147157 :rtype: :class:`MSLDAPTarget`
148158 """
159 if self.target is not None:
160 return copy.deepcopy(self.target)
161
149162 target = MSLDAPTarget(
150163 self.ldap_host,
151164 port = self.ldap_port,
160173 target.proxy = self.proxy
161174 target.serverip = self.serverip
162175 return target
176
177 def __str__(self):
178 t = '==== MSLDAPURLDecoder ====\r\n'
179 for k in self.__dict__:
180 val = self.__dict__[k]
181 if isinstance(val, enum.IntFlag):
182 val = val
183 elif isinstance(val, enum.Enum):
184 val = val.name
185
186 t += '%s: %s\r\n' % (k, str(val))
187
188 return t
189
163190
164191 def get_client(self):
165192 """
342369 self.target_ratelimit = float(query[k][0])
343370 elif k == 'pagesize':
344371 self.target_pagesize = int(query[k][0])
372 elif k == 'altname':
373 self.altname = query[k][0]
374 elif k == 'altdomain':
375 self.altdomain = query[k][0]
345376 #elif k.startswith('same'):
346377 # self.auth_settings[k[len('same'):]] = query[k]
347378
1414 def datetime2timestamp(dt):
1515 delta = dt - datetime.datetime(1601, 1, 1)
1616 ns = int((delta / datetime.timedelta(microseconds=1)) * 10)
17 return ns.to_bytes(8, 'little', signed = False)
17 return ns.to_bytes(8, 'little', signed = False)
18
19 def wrap(s, w):
20 return [s[i:i + w] for i in range(0, len(s), w)]
21
22 def print_cert(cert, offset=0):
23 cert = cert['tbs_certificate']
24 blanks = " " * offset
25 msg = [
26 "Cert Subject: %s" % cert['subject']['common_name'],
27 "Cert Serial: %s" % cert['serial_number'],
28 "Cert Start: %s" % cert['validity']['not_before'],
29 "Cert End: %s" % cert['validity']['not_after'],
30 "Cert Issuer: %s" % cert['issuer']['common_name'],
31 ]
32 return "{}{}".format(blanks, "\n{}".format(blanks).join(msg))
33
34 KNOWN_SIDS = {
35 "S-1-0": "Null Authority",
36 "S-1-0-0": "Nobody",
37 "S-1-1": "World Authority",
38 "S-1-1-0": "Everyone",
39 "S-1-2": "Local Authority",
40 "S-1-2-0": "Local",
41 "S-1-3": "Creator Authority",
42 "S-1-3-0": "Creator Owner",
43 "S-1-3-1": "Creator Group",
44 "S-1-3-4": "Owner Rights",
45 "S-1-4": "Non-unique Authority",
46 "S-1-5": "NT Authority",
47 "S-1-5-1": "Dialup",
48 "S-1-5-2": "Network",
49 "S-1-5-3": "Batch",
50 "S-1-5-4": "Interactive",
51 "S-1-5-5-X-Y": "Logon Session",
52 "S-1-5-6": "Service",
53 "S-1-5-7": "Anonymous",
54 "S-1-5-9": "Enterprise Domain Controllers",
55 "S-1-5-10": "Principal Self",
56 "S-1-5-11": "Authenticated Users",
57 "S-1-5-12": "Restricted Code",
58 "S-1-5-13": "Terminal Server Users",
59 "S-1-5-14": "Remote Interactive Logon",
60 "S-1-5-17": "IUSR",
61 "S-1-5-18": "Local System",
62 "S-1-5-19": "NT Authority Local Service",
63 "S-1-5-20": "NT Authority Network Service",
64 "S-1-5-32-544": "Administrators",
65 "S-1-5-32-545": "Users",
66 "S-1-5-32-546": "Guests",
67 "S-1-5-32-547": "Power Users",
68 "S-1-5-32-548": "Account Operators",
69 "S-1-5-32-549": "Server Operators",
70 "S-1-5-32-550": "Print Operators",
71 "S-1-5-32-551": "Backup Operators",
72 "S-1-5-32-552": "Replicators",
73 "S-1-5-32-582": "Storage Replica Administrators",
74 "S-1-5-64-10": "NTLM Authentication",
75 "S-1-5-64-14": "SChannel Authentication",
76 "S-1-5-64-21": "Digest Authentication",
77 "S-1-5-80": "NT Service",
78 }
66 protocolOp, AuthenticationChoice, SaslCredentials, \
77 SearchRequest, AttributeDescription, Filter, Filters, \
88 Controls, Control, SearchControlValue, AddRequest, \
9 ModifyRequest, DelRequest
9 ModifyRequest, DelRequest, ExtendedRequest, ExtendedResponse
1010
1111 from msldap.protocol.utils import calcualte_length
1212 from msldap.protocol.typeconversion import convert_result, convert_attributes, encode_attributes, encode_changes
2222 from minikerberos.gssapi.channelbindings import ChannelBindingsStruct
2323
2424 class MSLDAPClientConnection:
25 def __init__(self, target, creds):
26 if target is None:
27 raise Exception('Target cant be none!')
25 def __init__(self, target, creds, auth=None):
2826 self.target = target
2927 self.creds = creds
30 self.auth = AuthenticatorBuilder(self.creds, self.target).build()
28 if auth is not None:
29 self.auth = auth
30 else:
31 self.auth = AuthenticatorBuilder(self.creds, self.target).build()
3132 self.connected = False
3233 self.bind_ok = False
3334 self.__sign_messages = False
5455 try:
5556 while True:
5657 message_data, err = await self.network.in_queue.get()
58 if message_data is None and err is None:
59 return
60
5761 if err is not None:
5862 logger.debug('Client terminating bc __handle_incoming got an error!')
5963 raise err
206210
207211 logger.debug('Disconnecting!')
208212 self.bind_ok = False
213 await self.network.in_queue.put((None,None))
214 await self.network.out_queue.put(None)
215 await asyncio.sleep(0)
216
217 if self.network is not None:
218 await self.network.terminate()
219
209220 if self.handle_incoming_task is not None:
210221 self.handle_incoming_task.cancel()
211 if self.network is not None:
212 await self.network.terminate()
213222
214223
215224 def __bind_success(self):
419428 else:
420429 raise Exception('Not implemented authentication method: %s' % self.creds.auth_method.name)
421430 except Exception as e:
431 await self.disconnect()
422432 return False, e
423433
424434 async def add(self, entry, attributes):
704714 except Exception as e:
705715 yield (None, e)
706716
717 async def whoami(self):
718 if self.status != MSLDAPClientStatus.RUNNING:
719 return None, Exception('Connection not running! Probably encountered an error')
720
721 ext = {
722 'requestName': b'1.3.6.1.4.1.4203.1.11.3',
723 }
724 br = { 'extendedReq' : ExtendedRequest(ext)}
725 msg = { 'protocolOp' : protocolOp(br)}
726
727 msg_id = await self.send_message(msg)
728 res = await self.recv_message(msg_id)
729 res = res[0]
730 if isinstance(res, Exception):
731 return None, res
732 if res.native['protocolOp']['resultCode'] != 'success':
733 return False, LDAPBindException(
734 res['protocolOp']['resultCode'],
735 res['protocolOp']['diagnosticMessage']
736 )
737 return res.native['protocolOp']['responseValue'].decode(), None
738
739
707740
708741 async def get_serverinfo(self):
709742 if self.status != MSLDAPClientStatus.RUNNING:
+0
-107
msldap/crypto/AES.py less more
0 """
1 The idea here is to offer compatibility with 3rd party libraries by extending wrappers for ech encryption mode
2 This is needed because the pure python implementation for encryption and hashing algorithms are quite slow
3
4 currently it's not the perfect wrapper, needs to be extended
5 """
6
7 from msldap.crypto.BASE import symmetricBASE, cipherMODE
8 from msldap.crypto.pure.AES import AESModeOfOperationECB, AESModeOfOperationCBC, AESModeOfOperationCTR
9 try:
10 from Crypto.Cipher import AES as _pyCryptoAES
11 except:
12 pass
13
14 try:
15 from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
16 from cryptography.hazmat.primitives import padding
17 from cryptography.hazmat.backends import default_backend
18 except:
19 pass
20
21 class pureAES(symmetricBASE):
22 def __init__(self, key, mode = cipherMODE.ECB, IV = None, pad = None, padMode = None):
23 self.key = key
24 self.mode = mode
25 self.IV = IV
26 self.pad = pad
27 self.padMode = padMode
28
29 symmetricBASE.__init__(self)
30
31 def setup_cipher(self):
32 if self.mode == cipherMODE.ECB:
33 self._cipher = AESModeOfOperationECB(self.key)
34 elif self.mode == cipherMODE.CBC:
35 self._cipher = AESModeOfOperationCBC(self.key, iv = self.IV)
36 elif self.mode == cipherMODE.CTR:
37 self._cipher = AESModeOfOperationCTR(self.key, iv = self.IV)
38 else:
39 raise Exception('Unknown cipher mode!')
40
41 def encrypt(self, data):
42 return self._cipher.encrypt(data)
43 def decrypt(self, data):
44 return self._cipher.decrypt(data)
45
46 class pyCryptoAES(symmetricBASE):
47 def __init__(self, key, mode = cipherMODE.ECB, IV = None, pad = None, padMode = None):
48 self.key = key
49 self.mode = mode
50 self.IV = IV
51 self.pad = pad
52 self.padMode = padMode
53
54 symmetricBASE.__init__(self)
55
56 def setup_cipher(self):
57 if self.mode == cipherMODE.ECB:
58 self._cipher = _pyCryptoAES.new(self.key, _pyCryptoAES.MODE_ECB)
59
60 elif self.mode == cipherMODE.CBC:
61 self._cipher = _pyCryptoAES.new(self.key, _pyCryptoAES.MODE_CBC, self.IV)
62 elif self.mode == cipherMODE.CTR:
63 self._cipher = _pyCryptoAES.new(self.key, _pyCryptoAES.MODE_CTR, self.IV)
64 else:
65 raise Exception('Unknown cipher mode!')
66
67 def encrypt(self, data):
68 return self._cipher.encrypt(data)
69 def decrypt(self, data):
70 return self._cipher.decrypt(data)
71
72 class cryptographyAES(symmetricBASE):
73 def __init__(self, key, mode = cipherMODE.ECB, IV = None, pad = None, padMode = None):
74 self.IV = IV
75 #the python cryptography module sets the IV in the operational mode!!!
76 if mode == cipherMODE.ECB:
77 self.IV = modes.ECB()
78 elif mode == cipherMODE.CBC:
79 self.IV = modes.CBC(IV)
80 elif mode == cipherMODE.CBC:
81 self.IV = modes.CTR(IV)
82 else:
83 raise Exception('Unknown cipher mode!')
84
85 self.key = key
86
87 """ TODO padding
88 if self.padMode is not None:
89 """
90
91 self.encryptor = None
92 self.decryptor = None
93 symmetricBASE.__init__(self)
94
95 def setup_cipher(self):
96 algorithm = algorithms.AES(self.key)
97 self._cipher = Cipher(algorithm, mode=self.IV, backend=default_backend())
98 self.encryptor = self._cipher.encryptor()
99 self.decryptor = self._cipher.decryptor()
100
101 def encrypt(self, data):
102 return self.encryptor.update(data)
103
104
105 def decrypt(self, data):
106 return self.decryptor.update(data)
+0
-73
msldap/crypto/BASE.py less more
0 from abc import ABC, abstractmethod
1 import enum
2
3 class cipherMODE(enum.Enum):
4 ECB = enum.auto()
5 CBC = enum.auto()
6 CTR = enum.auto()
7
8 class symmetricBASE():
9 def __init__(self):
10 self._cipher = None
11 self.setup_cipher()
12
13 @abstractmethod
14 def setup_cipher(self):
15 #create the hash object here
16 pass
17
18 @abstractmethod
19 def encrypt(self, data):
20 pass
21
22 @abstractmethod
23 def decrypt(self):
24 pass
25
26 class hashBASE():
27 def __init__(self, data):
28 self._hash = None
29 self.setup_hash()
30
31 if data is not None:
32 self._hash.update(data)
33
34 @abstractmethod
35 def setup_hash(self):
36 #create the hash object here
37 pass
38
39 @abstractmethod
40 def update(self, data):
41 pass
42
43 @abstractmethod
44 def digest(self):
45 pass
46
47 @abstractmethod
48 def hexdigest(self):
49 pass
50
51 class hmacBASE():
52 def __init__(self, key):
53 self._key = key
54 self._hash = None
55 self.setup_hash()
56
57 @abstractmethod
58 def setup_hash(self):
59 #create the hash object here
60 pass
61
62 @abstractmethod
63 def update(self, data):
64 pass
65
66 @abstractmethod
67 def digest(self):
68 pass
69
70 @abstractmethod
71 def hexdigest(self):
72 pass
+0
-89
msldap/crypto/DES.py less more
0 """
1 The idea here is to offer compatibility with 3rd party libraries by extending wrappers for ech encryption mode
2 This is needed because the pure python implementation for encryption and hashing algorithms are quite slow
3
4 currently it's not the perfect wrapper, needs to be extended
5 """
6
7 from msldap.crypto.BASE import symmetricBASE, cipherMODE
8 import msldap.crypto.pure.DES.DES as _pyDES
9 try:
10 from Crypto.Cipher import DES as _pyCryptoDES
11 except:
12 pass
13
14 try:
15 from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
16 from cryptography.hazmat.backends import default_backend
17 except:
18 pass
19
20
21 # from impacket
22 def expand_DES_key(key):
23 # Expand the key from a 7-byte password key into a 8-byte DES key
24 key = key[:7]
25 key += b'\x00'*(7-len(key))
26 s = (((key[0] >> 1) & 0x7f) << 1).to_bytes(1, byteorder = 'big')
27 s += (((key[0] & 0x01) << 6 | ((key[1] >> 2) & 0x3f)) << 1).to_bytes(1, byteorder = 'big')
28 s += (((key[1] & 0x03) << 5 | ((key[2] >> 3) & 0x1f)) << 1).to_bytes(1, byteorder = 'big')
29 s += (((key[2] & 0x07) << 4 | ((key[3] >> 4) & 0x0f)) << 1).to_bytes(1, byteorder = 'big')
30 s += (((key[3] & 0x0f) << 3 | ((key[4] >> 5) & 0x07)) << 1).to_bytes(1, byteorder = 'big')
31 s += (((key[4] & 0x1f) << 2 | ((key[5] >> 6) & 0x03)) << 1).to_bytes(1, byteorder = 'big')
32 s += (((key[5] & 0x3f) << 1 | ((key[6] >> 7) & 0x01)) << 1).to_bytes(1, byteorder = 'big')
33 s += ( (key[6] & 0x7f) << 1).to_bytes(1, byteorder = 'big')
34 return s
35 #
36
37 class pureDES(symmetricBASE):
38 def __init__(self, key, mode = cipherMODE.ECB, IV = None):
39 self.key = key
40 if len(key) == 7:
41 self.key = expand_DES_key(key)
42
43 self.mode = mode
44 self.IV = IV
45 symmetricBASE.__init__(self)
46
47 def setup_cipher(self):
48 if self.mode == cipherMODE.ECB:
49 mode = _pyDES.ECB
50 elif self.mode == cipherMODE.CBC:
51 mode = _pyDES.CBC
52 else:
53 raise Exception('Unknown cipher mode!')
54
55 self._cipher = _pyDES.des(self.key, mode, self.IV)
56
57 def encrypt(self, data):
58 return self._cipher.encrypt(data)
59 def decrypt(self, data):
60 return self._cipher.decrypt(data)
61
62
63
64 class pyCryptoDES(symmetricBASE):
65 def __init__(self, key, mode = cipherMODE.ECB, IV = None):
66 self.key = key
67 if len(key) == 7:
68 self.key = __expand_DES_key(key)
69
70 self.mode = mode
71 self.IV = IV
72 symmetricBASE.__init__(self)
73
74 def setup_cipher(self):
75 if self.mode == cipherMODE.ECB:
76 self._cipher = _pyCryptoDES.new(self.key)
77 elif self.mode == cipherMODE.CBC:
78 self._cipher = _pyCryptoDES.new(self.key, _pyCryptoDES.MODE_CBC, self.IV)
79 else:
80 raise Exception('Unknown cipher mode!')
81
82
83
84 def encrypt(self, data):
85 return self._cipher.encrypt(data)
86 def decrypt(self, data):
87 return self._cipher.decrypt(data)
88
+0
-181
msldap/crypto/MD4.py less more
0 #!/usr/bin/env python3
1 # -*- coding: utf-8 -*-
2 #
3 # Copyright © 2019 James Seo <[email protected]> (github.com/kangtastic).
4 #
5 # This file is released under the WTFPL, version 2 (wtfpl.net).
6 #
7 # md4.py: An implementation of the MD4 hash algorithm in pure Python 3.
8 #
9 # Description: Zounds! Yet another rendition of pseudocode from RFC1320!
10 # Bonus points for the algorithm literally being from 1992.
11 #
12 # Usage: Why would anybody use this? This is self-rolled crypto, and
13 # self-rolled *obsolete* crypto at that. DO NOT USE if you need
14 # something "performant" or "secure". :P
15 #
16 # Anyway, from the command line:
17 #
18 # $ ./md4.py [messages]
19 #
20 # where [messages] are some strings to be hashed.
21 #
22 # In Python, use similarly to hashlib (not that it even has MD4):
23 #
24 # from .md4 import MD4
25 #
26 # digest = MD4("BEES").hexdigest()
27 #
28 # print(digest) # "501af1ef4b68495b5b7e37b15b4cda68"
29 #
30 #
31 # Sample console output:
32 #
33 # Testing the MD4 class.
34 #
35 # Message: b''
36 # Expected: 31d6cfe0d16ae931b73c59d7e0c089c0
37 # Actual: 31d6cfe0d16ae931b73c59d7e0c089c0
38 #
39 # Message: b'The quick brown fox jumps over the lazy dog'
40 # Expected: 1bee69a46ba811185c194762abaeae90
41 # Actual: 1bee69a46ba811185c194762abaeae90
42 #
43 # Message: b'BEES'
44 # Expected: 501af1ef4b68495b5b7e37b15b4cda68
45 # Actual: 501af1ef4b68495b5b7e37b15b4cda68
46 #
47 import struct
48
49
50 class MD4:
51 """An implementation of the MD4 hash algorithm."""
52
53 width = 32
54 mask = 0xFFFFFFFF
55
56 # Unlike, say, SHA-1, MD4 uses little-endian. Fascinating!
57 h = [0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476]
58
59 def __init__(self, msg=None):
60 """:param ByteString msg: The message to be hashed."""
61 if msg is None:
62 msg = b""
63
64 self.msg = msg
65
66 # Pre-processing: Total length is a multiple of 512 bits.
67 ml = len(msg) * 8
68 msg += b"\x80"
69 msg += b"\x00" * (-(len(msg) + 8) % 64)
70 msg += struct.pack("<Q", ml)
71
72 # Process the message in successive 512-bit chunks.
73 self._process([msg[i : i + 64] for i in range(0, len(msg), 64)])
74
75 def __repr__(self):
76 if self.msg:
77 return f"{self.__class__.__name__}({self.msg:s})"
78 return f"{self.__class__.__name__}()"
79
80 def __str__(self):
81 return self.hexdigest()
82
83 def __eq__(self, other):
84 return self.h == other.h
85
86 def bytes(self):
87 """:return: The final hash value as a `bytes` object."""
88 return struct.pack("<4L", *self.h)
89
90 def hexbytes(self):
91 """:return: The final hash value as hexbytes."""
92 return self.hexdigest().encode
93
94 def hexdigest(self):
95 """:return: The final hash value as a hexstring."""
96 return "".join(f"{value:02x}" for value in self.bytes())
97
98 def digest(self):
99 return self.bytes()
100
101 def _process(self, chunks):
102 for chunk in chunks:
103 X, h = list(struct.unpack("<16I", chunk)), self.h.copy()
104
105 # Round 1.
106 Xi = [3, 7, 11, 19]
107 for n in range(16):
108 i, j, k, l = map(lambda x: x % 4, range(-n, -n + 4))
109 K, S = n, Xi[n % 4]
110 hn = h[i] + MD4.F(h[j], h[k], h[l]) + X[K]
111 h[i] = MD4.lrot(hn & MD4.mask, S)
112
113 # Round 2.
114 Xi = [3, 5, 9, 13]
115 for n in range(16):
116 i, j, k, l = map(lambda x: x % 4, range(-n, -n + 4))
117 K, S = n % 4 * 4 + n // 4, Xi[n % 4]
118 hn = h[i] + MD4.G(h[j], h[k], h[l]) + X[K] + 0x5A827999
119 h[i] = MD4.lrot(hn & MD4.mask, S)
120
121 # Round 3.
122 Xi = [3, 9, 11, 15]
123 Ki = [0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15]
124 for n in range(16):
125 i, j, k, l = map(lambda x: x % 4, range(-n, -n + 4))
126 K, S = Ki[n], Xi[n % 4]
127 hn = h[i] + MD4.H(h[j], h[k], h[l]) + X[K] + 0x6ED9EBA1
128 h[i] = MD4.lrot(hn & MD4.mask, S)
129
130 self.h = [((v + n) & MD4.mask) for v, n in zip(self.h, h)]
131
132 @staticmethod
133 def F(x, y, z):
134 return (x & y) | (~x & z)
135
136 @staticmethod
137 def G(x, y, z):
138 return (x & y) | (x & z) | (y & z)
139
140 @staticmethod
141 def H(x, y, z):
142 return x ^ y ^ z
143
144 @staticmethod
145 def lrot(value, n):
146 lbits, rbits = (value << n) & MD4.mask, value >> (MD4.width - n)
147 return lbits | rbits
148
149
150 def main():
151 # Import is intentionally delayed.
152 import sys
153
154 if len(sys.argv) > 1:
155 messages = [msg.encode() for msg in sys.argv[1:]]
156 for message in messages:
157 print(MD4(message).hexdigest())
158 else:
159 messages = [b"", b"The quick brown fox jumps over the lazy dog", b"BEES"]
160 known_hashes = [
161 "31d6cfe0d16ae931b73c59d7e0c089c0",
162 "1bee69a46ba811185c194762abaeae90",
163 "501af1ef4b68495b5b7e37b15b4cda68",
164 ]
165
166 print("Testing the MD4 class.")
167 print()
168
169 for message, expected in zip(messages, known_hashes):
170 print("Message: ", message)
171 print("Expected:", expected)
172 print("Actual: ", MD4(message).hexdigest())
173 print()
174
175
176 if __name__ == "__main__":
177 try:
178 main()
179 except KeyboardInterrupt:
180 pass
+0
-68
msldap/crypto/RC4.py less more
0 """
1 The idea here is to offer compatibility with 3rd party libraries by extending wrappers for ech encryption mode
2 This is needed because the pure python implementation for encryption and hashing algorithms are quite slow
3
4 currently it's not the perfect wrapper, needs to be extended
5 """
6
7 from msldap.crypto.BASE import symmetricBASE, cipherMODE
8 from msldap.crypto.pure.RC4.RC4 import RC4 as _pureRC4
9 try:
10 from Crypto.Cipher import ARC4 as _pyCryptoRC4
11 except Exception as e:
12 #print(e)
13 pass
14
15 try:
16 from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
17 from cryptography.hazmat.backends import default_backend
18 except:
19 pass
20
21 class pureRC4(symmetricBASE):
22 def __init__(self, key):
23 if not isinstance(key, bytes):
24 raise Exception('Key needs to be bytes!')
25 self.key = key
26 symmetricBASE.__init__(self)
27
28 def setup_cipher(self):
29 self._cipher = _pureRC4(self.key)
30
31 def encrypt(self, data):
32 return self._cipher.encrypt(data)
33 def decrypt(self, data):
34 return self._cipher.decrypt(data)
35
36 class pyCryptoRC4(symmetricBASE):
37 def __init__(self, key):
38 self.key = key
39 symmetricBASE.__init__(self)
40
41 def setup_cipher(self):
42 self._cipher = _pyCryptoRC4.new(self.key)
43
44 def encrypt(self, data):
45 return self._cipher.encrypt(data)
46 def decrypt(self, data):
47 return self._cipher.decrypt(data)
48
49 class cryptographyRC4(symmetricBASE):
50 def __init__(self, key):
51 if not isinstance(key, bytes):
52 raise Exception('Key needs to be bytes!')
53 self.key = key
54 self.encryptor = None
55 self.decryptor = None
56 symmetricBASE.__init__(self)
57
58 def setup_cipher(self):
59 algorithm = algorithms.ARC4(self.key)
60 self._cipher = Cipher(algorithm, mode=None, backend=default_backend())
61 self.encryptor = self._cipher.encryptor()
62 self.decryptor = self._cipher.decryptor()
63
64 def encrypt(self, data):
65 return self.encryptor.update(data)
66 def decrypt(self, data):
67 return self.decryptor.update(data)
+0
-108
msldap/crypto/TDES.py less more
0 """
1 The idea here is to offer compatibility with 3rd party libraries by extending wrappers for ech encryption mode
2 This is needed because the pure python implementation for encryption and hashing algorithms are quite slow
3
4 currently it's not the perfect wrapper, needs to be extended
5 """
6
7 from msldap.crypto.BASE import symmetricBASE, cipherMODE, padMode
8 import msldap.crypto.pure.DES.DES as _pyDES
9 try:
10 from Crypto.Cipher import DES3 as _pyCryptoDES3
11 except:
12 pass
13
14 try:
15 from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
16 from cryptography.hazmat.primitives import padding
17 from cryptography.hazmat.backends import default_backend
18 except:
19 pass
20
21 class pureTDES(symmetricBASE):
22 def __init__(self, key, mode = cipherMODE.ECB, IV = None, pad = None, padMode = None):
23 symmetricBASE.__init__(self)
24 if not isinstance(key, bytes):
25 raise Exception('Key needs to be bytes!')
26
27 self.mode = mode
28 self.IV = IV
29 self.pad = pad
30 self.padMode = padMode
31
32 def setup_cipher(self):
33 if self.mode == cipherMODE.ECB:
34 mode = _pyDes.ECB
35 self._cipher = _pyDES.triple_des(self.key, mode)
36 elif self.mode == cipherMODE.CBC:
37 mode = _pyDES.CBC
38 if padMode is None:
39 self._cipher = _pyDES.triple_des(self.key, mode, self.IV, self.pad, self.padmode)
40 else:
41 self._cipher = _pyDES.triple_des(self.key, mode, self.IV)
42 else:
43 raise Exception('Unknown cipher mode!')
44
45 def encrypt(self, data):
46 return self._cipher.encrypt(data)
47 def decrypt(self, data):
48 return self._cipher.decrypt(data)
49
50 class pyCryptoTDES(symmetricBASE):
51 def __init__(self, key, mode = cipherMODE.ECB, IV = None, pad = None, padMode = None):
52 self.key = key
53 self.mode = mode
54 self.IV = IV
55 self.pad = pad
56 self.padMode = padMode
57
58 symmetricBASE.__init__(self)
59
60 def setup_cipher(self):
61 if self.mode == cipherMODE.ECB:
62 self._cipher = _pyCryptoDES3.new(self.key, _pyCryptoDES3.MODE_ECB)
63
64 elif self.mode == cipherMODE.CBC:
65 self._cipher = _pyCryptoDES3.new(self.key, _pyCryptoDES3.MODE_CBC, self.IV)
66 else:
67 raise Exception('Unknown cipher mode!')
68
69 def encrypt(self, data):
70 return self._cipher.encrypt(data)
71 def decrypt(self, data):
72 return self._cipher.decrypt(data)
73
74 class cryptographyTDES(symmetricBASE):
75 def __init__(self, key, mode = cipherMODE.ECB, IV = None, pad = None, padMode = None):
76 if not isinstance(key, bytes):
77 raise Exception('Key needs to be bytes!')
78 self.IV = IV
79 if mode == cipherMode.ECB:
80 self.IV = modes.ECB()
81 elif mode == cipherMODE.CBC:
82 self.IV = modes.CBC(IV)
83 else:
84 raise Exception('Unknown cipher mode!')
85 self.key = key
86
87 """ TODO padding
88 if self.padMode is not None:
89 """
90
91 self.encryptor = None
92 self.decryptor = None
93 symmetricBASE.__init__(self)
94
95 def setup_cipher(self):
96 algorithm = algorithms.TripleDES(self.key)
97 self._cipher = Cipher(algorithm, mode=self.IV, backend=default_backend())
98 self.encryptor = self._cipher.encryptor()
99 self.decryptor = self._cipher.decryptor()
100
101 def encrypt(self, data):
102 return self.encryptor.update(data)
103
104
105 def decrypt(self, data):
106 return self.decryptor.update(data)
107
+0
-0
msldap/crypto/__init__.py less more
(Empty file)
+0
-55
msldap/crypto/hashing.py less more
0 import hashlib
1 import hmac
2
3 from msldap.crypto.BASE import hashBASE, hmacBASE
4 from msldap.crypto.MD4 import MD4
5
6 class md5(hashBASE):
7 def __init__(self, data = None):
8 hashBASE.__init__(self, data)
9 def setup_hash(self):
10 self._hash = hashlib.new('md5')
11 def update(self, data):
12 return self._hash.update(data)
13 def digest(self):
14 return self._hash.digest()
15 def hexdigest(self):
16 return self._hash.hexdigest()
17
18 #class md4(hashBASE):
19 # def __init__(self, data = None):
20 # hashBASE.__init__(self, data)
21 # def setup_hash(self):
22 # self._hash = hashlib.new('md4')
23 # def update(self, data):
24 # return self._hash.update(data)
25 # def digest(self):
26 # return self._hash.digest()
27 # def hexdigest(self):
28 # return self._hash.hexdigest()
29
30 md4 = MD4
31
32 class hmac_md5(hmacBASE):
33 def __init__(self, key):
34 hmacBASE.__init__(self, key)
35 def setup_hash(self):
36 self._hmac = hmac.new(self._key, digestmod = hashlib.md5)
37 def update(self, data):
38 return self._hmac.update(data)
39 def digest(self):
40 return self._hmac.digest()
41 def hexdigest(self):
42 return self._hmac.hexdigest()
43
44 class sha256():
45 def __init__(self, data = None):
46 hashBASE.__init__(self, data)
47 def setup_hash(self):
48 self._hash = hashlib.new('sha256')
49 def update(self, data):
50 return self._hash.update(data)
51 def digest(self):
52 return self._hash.digest()
53 def hexdigest(self):
54 return self._hash.hexdigest()
+0
-591
msldap/crypto/pure/AES/AES.py less more
0
1 #https://github.com/ricmoo/pyaes/blob/master/pyaes/aes.py
2 # The MIT License (MIT)
3 #
4 # Copyright (c) 2014 Richard Moore
5 #
6 # Permission is hereby granted, free of charge, to any person obtaining a copy
7 # of this software and associated documentation files (the "Software"), to deal
8 # in the Software without restriction, including without limitation the rights
9 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 # copies of the Software, and to permit persons to whom the Software is
11 # furnished to do so, subject to the following conditions:
12 #
13 # The above copyright notice and this permission notice shall be included in
14 # all copies or substantial portions of the Software.
15 #
16 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 # THE SOFTWARE.
23
24 # This is a pure-Python implementation of the AES algorithm and AES common
25 # modes of operation.
26
27 # See: https://en.wikipedia.org/wiki/Advanced_Encryption_Standard
28
29 # Honestly, the best description of the modes of operations are the wonderful
30 # diagrams on Wikipedia. They explain in moments what my words could never
31 # achieve. Hence the inline documentation here is sparer than I'd prefer.
32 # See: https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation
33
34 # Also useful, PyCrypto, a crypto library implemented in C with Python bindings:
35 # https://www.dlitz.net/software/pycrypto/
36
37
38 # Supported key sizes:
39 # 128-bit
40 # 192-bit
41 # 256-bit
42
43
44 # Supported modes of operation:
45 # ECB - Electronic Codebook
46 # CBC - Cipher-Block Chaining
47 # CFB - Cipher Feedback
48 # OFB - Output Feedback
49 # CTR - Counter
50
51
52 # See the README.md for API details and general information.
53
54
55 import copy
56 import struct
57
58 __all__ = ["AES", "AESModeOfOperationCTR", "AESModeOfOperationCBC", "AESModeOfOperationCFB",
59 "AESModeOfOperationECB", "AESModeOfOperationOFB", "AESModesOfOperation", "Counter"]
60
61
62 def _compact_word(word):
63 return (word[0] << 24) | (word[1] << 16) | (word[2] << 8) | word[3]
64
65 def _string_to_bytes(text):
66 return list(ord(c) for c in text)
67
68 def _bytes_to_string(binary):
69 return "".join(chr(b) for b in binary)
70
71 def _concat_list(a, b):
72 return a + b
73
74
75 # Python 3 compatibility
76 try:
77 xrange
78 except Exception:
79 xrange = range
80
81 # Python 3 supports bytes, which is already an array of integers
82 def _string_to_bytes(text):
83 if isinstance(text, bytes):
84 return text
85 return [ord(c) for c in text]
86
87 # In Python 3, we return bytes
88 def _bytes_to_string(binary):
89 return bytes(binary)
90
91 # Python 3 cannot concatenate a list onto a bytes, so we bytes-ify it first
92 def _concat_list(a, b):
93 return a + bytes(b)
94
95
96 # Based *largely* on the Rijndael implementation
97 # See: http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf
98 class AES(object):
99 '''Encapsulates the AES block cipher.
100
101 You generally should not need this. Use the AESModeOfOperation classes
102 below instead.'''
103
104 # Number of rounds by keysize
105 number_of_rounds = {16: 10, 24: 12, 32: 14}
106
107 # Round constant words
108 rcon = [ 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91 ]
109
110 # S-box and Inverse S-box (S is for Substitution)
111 S = [ 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 ]
112 Si =[ 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d ]
113
114 # Transformations for encryption
115 T1 = [ 0xc66363a5, 0xf87c7c84, 0xee777799, 0xf67b7b8d, 0xfff2f20d, 0xd66b6bbd, 0xde6f6fb1, 0x91c5c554, 0x60303050, 0x02010103, 0xce6767a9, 0x562b2b7d, 0xe7fefe19, 0xb5d7d762, 0x4dababe6, 0xec76769a, 0x8fcaca45, 0x1f82829d, 0x89c9c940, 0xfa7d7d87, 0xeffafa15, 0xb25959eb, 0x8e4747c9, 0xfbf0f00b, 0x41adadec, 0xb3d4d467, 0x5fa2a2fd, 0x45afafea, 0x239c9cbf, 0x53a4a4f7, 0xe4727296, 0x9bc0c05b, 0x75b7b7c2, 0xe1fdfd1c, 0x3d9393ae, 0x4c26266a, 0x6c36365a, 0x7e3f3f41, 0xf5f7f702, 0x83cccc4f, 0x6834345c, 0x51a5a5f4, 0xd1e5e534, 0xf9f1f108, 0xe2717193, 0xabd8d873, 0x62313153, 0x2a15153f, 0x0804040c, 0x95c7c752, 0x46232365, 0x9dc3c35e, 0x30181828, 0x379696a1, 0x0a05050f, 0x2f9a9ab5, 0x0e070709, 0x24121236, 0x1b80809b, 0xdfe2e23d, 0xcdebeb26, 0x4e272769, 0x7fb2b2cd, 0xea75759f, 0x1209091b, 0x1d83839e, 0x582c2c74, 0x341a1a2e, 0x361b1b2d, 0xdc6e6eb2, 0xb45a5aee, 0x5ba0a0fb, 0xa45252f6, 0x763b3b4d, 0xb7d6d661, 0x7db3b3ce, 0x5229297b, 0xdde3e33e, 0x5e2f2f71, 0x13848497, 0xa65353f5, 0xb9d1d168, 0x00000000, 0xc1eded2c, 0x40202060, 0xe3fcfc1f, 0x79b1b1c8, 0xb65b5bed, 0xd46a6abe, 0x8dcbcb46, 0x67bebed9, 0x7239394b, 0x944a4ade, 0x984c4cd4, 0xb05858e8, 0x85cfcf4a, 0xbbd0d06b, 0xc5efef2a, 0x4faaaae5, 0xedfbfb16, 0x864343c5, 0x9a4d4dd7, 0x66333355, 0x11858594, 0x8a4545cf, 0xe9f9f910, 0x04020206, 0xfe7f7f81, 0xa05050f0, 0x783c3c44, 0x259f9fba, 0x4ba8a8e3, 0xa25151f3, 0x5da3a3fe, 0x804040c0, 0x058f8f8a, 0x3f9292ad, 0x219d9dbc, 0x70383848, 0xf1f5f504, 0x63bcbcdf, 0x77b6b6c1, 0xafdada75, 0x42212163, 0x20101030, 0xe5ffff1a, 0xfdf3f30e, 0xbfd2d26d, 0x81cdcd4c, 0x180c0c14, 0x26131335, 0xc3ecec2f, 0xbe5f5fe1, 0x359797a2, 0x884444cc, 0x2e171739, 0x93c4c457, 0x55a7a7f2, 0xfc7e7e82, 0x7a3d3d47, 0xc86464ac, 0xba5d5de7, 0x3219192b, 0xe6737395, 0xc06060a0, 0x19818198, 0x9e4f4fd1, 0xa3dcdc7f, 0x44222266, 0x542a2a7e, 0x3b9090ab, 0x0b888883, 0x8c4646ca, 0xc7eeee29, 0x6bb8b8d3, 0x2814143c, 0xa7dede79, 0xbc5e5ee2, 0x160b0b1d, 0xaddbdb76, 0xdbe0e03b, 0x64323256, 0x743a3a4e, 0x140a0a1e, 0x924949db, 0x0c06060a, 0x4824246c, 0xb85c5ce4, 0x9fc2c25d, 0xbdd3d36e, 0x43acacef, 0xc46262a6, 0x399191a8, 0x319595a4, 0xd3e4e437, 0xf279798b, 0xd5e7e732, 0x8bc8c843, 0x6e373759, 0xda6d6db7, 0x018d8d8c, 0xb1d5d564, 0x9c4e4ed2, 0x49a9a9e0, 0xd86c6cb4, 0xac5656fa, 0xf3f4f407, 0xcfeaea25, 0xca6565af, 0xf47a7a8e, 0x47aeaee9, 0x10080818, 0x6fbabad5, 0xf0787888, 0x4a25256f, 0x5c2e2e72, 0x381c1c24, 0x57a6a6f1, 0x73b4b4c7, 0x97c6c651, 0xcbe8e823, 0xa1dddd7c, 0xe874749c, 0x3e1f1f21, 0x964b4bdd, 0x61bdbddc, 0x0d8b8b86, 0x0f8a8a85, 0xe0707090, 0x7c3e3e42, 0x71b5b5c4, 0xcc6666aa, 0x904848d8, 0x06030305, 0xf7f6f601, 0x1c0e0e12, 0xc26161a3, 0x6a35355f, 0xae5757f9, 0x69b9b9d0, 0x17868691, 0x99c1c158, 0x3a1d1d27, 0x279e9eb9, 0xd9e1e138, 0xebf8f813, 0x2b9898b3, 0x22111133, 0xd26969bb, 0xa9d9d970, 0x078e8e89, 0x339494a7, 0x2d9b9bb6, 0x3c1e1e22, 0x15878792, 0xc9e9e920, 0x87cece49, 0xaa5555ff, 0x50282878, 0xa5dfdf7a, 0x038c8c8f, 0x59a1a1f8, 0x09898980, 0x1a0d0d17, 0x65bfbfda, 0xd7e6e631, 0x844242c6, 0xd06868b8, 0x824141c3, 0x299999b0, 0x5a2d2d77, 0x1e0f0f11, 0x7bb0b0cb, 0xa85454fc, 0x6dbbbbd6, 0x2c16163a ]
116 T2 = [ 0xa5c66363, 0x84f87c7c, 0x99ee7777, 0x8df67b7b, 0x0dfff2f2, 0xbdd66b6b, 0xb1de6f6f, 0x5491c5c5, 0x50603030, 0x03020101, 0xa9ce6767, 0x7d562b2b, 0x19e7fefe, 0x62b5d7d7, 0xe64dabab, 0x9aec7676, 0x458fcaca, 0x9d1f8282, 0x4089c9c9, 0x87fa7d7d, 0x15effafa, 0xebb25959, 0xc98e4747, 0x0bfbf0f0, 0xec41adad, 0x67b3d4d4, 0xfd5fa2a2, 0xea45afaf, 0xbf239c9c, 0xf753a4a4, 0x96e47272, 0x5b9bc0c0, 0xc275b7b7, 0x1ce1fdfd, 0xae3d9393, 0x6a4c2626, 0x5a6c3636, 0x417e3f3f, 0x02f5f7f7, 0x4f83cccc, 0x5c683434, 0xf451a5a5, 0x34d1e5e5, 0x08f9f1f1, 0x93e27171, 0x73abd8d8, 0x53623131, 0x3f2a1515, 0x0c080404, 0x5295c7c7, 0x65462323, 0x5e9dc3c3, 0x28301818, 0xa1379696, 0x0f0a0505, 0xb52f9a9a, 0x090e0707, 0x36241212, 0x9b1b8080, 0x3ddfe2e2, 0x26cdebeb, 0x694e2727, 0xcd7fb2b2, 0x9fea7575, 0x1b120909, 0x9e1d8383, 0x74582c2c, 0x2e341a1a, 0x2d361b1b, 0xb2dc6e6e, 0xeeb45a5a, 0xfb5ba0a0, 0xf6a45252, 0x4d763b3b, 0x61b7d6d6, 0xce7db3b3, 0x7b522929, 0x3edde3e3, 0x715e2f2f, 0x97138484, 0xf5a65353, 0x68b9d1d1, 0x00000000, 0x2cc1eded, 0x60402020, 0x1fe3fcfc, 0xc879b1b1, 0xedb65b5b, 0xbed46a6a, 0x468dcbcb, 0xd967bebe, 0x4b723939, 0xde944a4a, 0xd4984c4c, 0xe8b05858, 0x4a85cfcf, 0x6bbbd0d0, 0x2ac5efef, 0xe54faaaa, 0x16edfbfb, 0xc5864343, 0xd79a4d4d, 0x55663333, 0x94118585, 0xcf8a4545, 0x10e9f9f9, 0x06040202, 0x81fe7f7f, 0xf0a05050, 0x44783c3c, 0xba259f9f, 0xe34ba8a8, 0xf3a25151, 0xfe5da3a3, 0xc0804040, 0x8a058f8f, 0xad3f9292, 0xbc219d9d, 0x48703838, 0x04f1f5f5, 0xdf63bcbc, 0xc177b6b6, 0x75afdada, 0x63422121, 0x30201010, 0x1ae5ffff, 0x0efdf3f3, 0x6dbfd2d2, 0x4c81cdcd, 0x14180c0c, 0x35261313, 0x2fc3ecec, 0xe1be5f5f, 0xa2359797, 0xcc884444, 0x392e1717, 0x5793c4c4, 0xf255a7a7, 0x82fc7e7e, 0x477a3d3d, 0xacc86464, 0xe7ba5d5d, 0x2b321919, 0x95e67373, 0xa0c06060, 0x98198181, 0xd19e4f4f, 0x7fa3dcdc, 0x66442222, 0x7e542a2a, 0xab3b9090, 0x830b8888, 0xca8c4646, 0x29c7eeee, 0xd36bb8b8, 0x3c281414, 0x79a7dede, 0xe2bc5e5e, 0x1d160b0b, 0x76addbdb, 0x3bdbe0e0, 0x56643232, 0x4e743a3a, 0x1e140a0a, 0xdb924949, 0x0a0c0606, 0x6c482424, 0xe4b85c5c, 0x5d9fc2c2, 0x6ebdd3d3, 0xef43acac, 0xa6c46262, 0xa8399191, 0xa4319595, 0x37d3e4e4, 0x8bf27979, 0x32d5e7e7, 0x438bc8c8, 0x596e3737, 0xb7da6d6d, 0x8c018d8d, 0x64b1d5d5, 0xd29c4e4e, 0xe049a9a9, 0xb4d86c6c, 0xfaac5656, 0x07f3f4f4, 0x25cfeaea, 0xafca6565, 0x8ef47a7a, 0xe947aeae, 0x18100808, 0xd56fbaba, 0x88f07878, 0x6f4a2525, 0x725c2e2e, 0x24381c1c, 0xf157a6a6, 0xc773b4b4, 0x5197c6c6, 0x23cbe8e8, 0x7ca1dddd, 0x9ce87474, 0x213e1f1f, 0xdd964b4b, 0xdc61bdbd, 0x860d8b8b, 0x850f8a8a, 0x90e07070, 0x427c3e3e, 0xc471b5b5, 0xaacc6666, 0xd8904848, 0x05060303, 0x01f7f6f6, 0x121c0e0e, 0xa3c26161, 0x5f6a3535, 0xf9ae5757, 0xd069b9b9, 0x91178686, 0x5899c1c1, 0x273a1d1d, 0xb9279e9e, 0x38d9e1e1, 0x13ebf8f8, 0xb32b9898, 0x33221111, 0xbbd26969, 0x70a9d9d9, 0x89078e8e, 0xa7339494, 0xb62d9b9b, 0x223c1e1e, 0x92158787, 0x20c9e9e9, 0x4987cece, 0xffaa5555, 0x78502828, 0x7aa5dfdf, 0x8f038c8c, 0xf859a1a1, 0x80098989, 0x171a0d0d, 0xda65bfbf, 0x31d7e6e6, 0xc6844242, 0xb8d06868, 0xc3824141, 0xb0299999, 0x775a2d2d, 0x111e0f0f, 0xcb7bb0b0, 0xfca85454, 0xd66dbbbb, 0x3a2c1616 ]
117 T3 = [ 0x63a5c663, 0x7c84f87c, 0x7799ee77, 0x7b8df67b, 0xf20dfff2, 0x6bbdd66b, 0x6fb1de6f, 0xc55491c5, 0x30506030, 0x01030201, 0x67a9ce67, 0x2b7d562b, 0xfe19e7fe, 0xd762b5d7, 0xabe64dab, 0x769aec76, 0xca458fca, 0x829d1f82, 0xc94089c9, 0x7d87fa7d, 0xfa15effa, 0x59ebb259, 0x47c98e47, 0xf00bfbf0, 0xadec41ad, 0xd467b3d4, 0xa2fd5fa2, 0xafea45af, 0x9cbf239c, 0xa4f753a4, 0x7296e472, 0xc05b9bc0, 0xb7c275b7, 0xfd1ce1fd, 0x93ae3d93, 0x266a4c26, 0x365a6c36, 0x3f417e3f, 0xf702f5f7, 0xcc4f83cc, 0x345c6834, 0xa5f451a5, 0xe534d1e5, 0xf108f9f1, 0x7193e271, 0xd873abd8, 0x31536231, 0x153f2a15, 0x040c0804, 0xc75295c7, 0x23654623, 0xc35e9dc3, 0x18283018, 0x96a13796, 0x050f0a05, 0x9ab52f9a, 0x07090e07, 0x12362412, 0x809b1b80, 0xe23ddfe2, 0xeb26cdeb, 0x27694e27, 0xb2cd7fb2, 0x759fea75, 0x091b1209, 0x839e1d83, 0x2c74582c, 0x1a2e341a, 0x1b2d361b, 0x6eb2dc6e, 0x5aeeb45a, 0xa0fb5ba0, 0x52f6a452, 0x3b4d763b, 0xd661b7d6, 0xb3ce7db3, 0x297b5229, 0xe33edde3, 0x2f715e2f, 0x84971384, 0x53f5a653, 0xd168b9d1, 0x00000000, 0xed2cc1ed, 0x20604020, 0xfc1fe3fc, 0xb1c879b1, 0x5bedb65b, 0x6abed46a, 0xcb468dcb, 0xbed967be, 0x394b7239, 0x4ade944a, 0x4cd4984c, 0x58e8b058, 0xcf4a85cf, 0xd06bbbd0, 0xef2ac5ef, 0xaae54faa, 0xfb16edfb, 0x43c58643, 0x4dd79a4d, 0x33556633, 0x85941185, 0x45cf8a45, 0xf910e9f9, 0x02060402, 0x7f81fe7f, 0x50f0a050, 0x3c44783c, 0x9fba259f, 0xa8e34ba8, 0x51f3a251, 0xa3fe5da3, 0x40c08040, 0x8f8a058f, 0x92ad3f92, 0x9dbc219d, 0x38487038, 0xf504f1f5, 0xbcdf63bc, 0xb6c177b6, 0xda75afda, 0x21634221, 0x10302010, 0xff1ae5ff, 0xf30efdf3, 0xd26dbfd2, 0xcd4c81cd, 0x0c14180c, 0x13352613, 0xec2fc3ec, 0x5fe1be5f, 0x97a23597, 0x44cc8844, 0x17392e17, 0xc45793c4, 0xa7f255a7, 0x7e82fc7e, 0x3d477a3d, 0x64acc864, 0x5de7ba5d, 0x192b3219, 0x7395e673, 0x60a0c060, 0x81981981, 0x4fd19e4f, 0xdc7fa3dc, 0x22664422, 0x2a7e542a, 0x90ab3b90, 0x88830b88, 0x46ca8c46, 0xee29c7ee, 0xb8d36bb8, 0x143c2814, 0xde79a7de, 0x5ee2bc5e, 0x0b1d160b, 0xdb76addb, 0xe03bdbe0, 0x32566432, 0x3a4e743a, 0x0a1e140a, 0x49db9249, 0x060a0c06, 0x246c4824, 0x5ce4b85c, 0xc25d9fc2, 0xd36ebdd3, 0xacef43ac, 0x62a6c462, 0x91a83991, 0x95a43195, 0xe437d3e4, 0x798bf279, 0xe732d5e7, 0xc8438bc8, 0x37596e37, 0x6db7da6d, 0x8d8c018d, 0xd564b1d5, 0x4ed29c4e, 0xa9e049a9, 0x6cb4d86c, 0x56faac56, 0xf407f3f4, 0xea25cfea, 0x65afca65, 0x7a8ef47a, 0xaee947ae, 0x08181008, 0xbad56fba, 0x7888f078, 0x256f4a25, 0x2e725c2e, 0x1c24381c, 0xa6f157a6, 0xb4c773b4, 0xc65197c6, 0xe823cbe8, 0xdd7ca1dd, 0x749ce874, 0x1f213e1f, 0x4bdd964b, 0xbddc61bd, 0x8b860d8b, 0x8a850f8a, 0x7090e070, 0x3e427c3e, 0xb5c471b5, 0x66aacc66, 0x48d89048, 0x03050603, 0xf601f7f6, 0x0e121c0e, 0x61a3c261, 0x355f6a35, 0x57f9ae57, 0xb9d069b9, 0x86911786, 0xc15899c1, 0x1d273a1d, 0x9eb9279e, 0xe138d9e1, 0xf813ebf8, 0x98b32b98, 0x11332211, 0x69bbd269, 0xd970a9d9, 0x8e89078e, 0x94a73394, 0x9bb62d9b, 0x1e223c1e, 0x87921587, 0xe920c9e9, 0xce4987ce, 0x55ffaa55, 0x28785028, 0xdf7aa5df, 0x8c8f038c, 0xa1f859a1, 0x89800989, 0x0d171a0d, 0xbfda65bf, 0xe631d7e6, 0x42c68442, 0x68b8d068, 0x41c38241, 0x99b02999, 0x2d775a2d, 0x0f111e0f, 0xb0cb7bb0, 0x54fca854, 0xbbd66dbb, 0x163a2c16 ]
118 T4 = [ 0x6363a5c6, 0x7c7c84f8, 0x777799ee, 0x7b7b8df6, 0xf2f20dff, 0x6b6bbdd6, 0x6f6fb1de, 0xc5c55491, 0x30305060, 0x01010302, 0x6767a9ce, 0x2b2b7d56, 0xfefe19e7, 0xd7d762b5, 0xababe64d, 0x76769aec, 0xcaca458f, 0x82829d1f, 0xc9c94089, 0x7d7d87fa, 0xfafa15ef, 0x5959ebb2, 0x4747c98e, 0xf0f00bfb, 0xadadec41, 0xd4d467b3, 0xa2a2fd5f, 0xafafea45, 0x9c9cbf23, 0xa4a4f753, 0x727296e4, 0xc0c05b9b, 0xb7b7c275, 0xfdfd1ce1, 0x9393ae3d, 0x26266a4c, 0x36365a6c, 0x3f3f417e, 0xf7f702f5, 0xcccc4f83, 0x34345c68, 0xa5a5f451, 0xe5e534d1, 0xf1f108f9, 0x717193e2, 0xd8d873ab, 0x31315362, 0x15153f2a, 0x04040c08, 0xc7c75295, 0x23236546, 0xc3c35e9d, 0x18182830, 0x9696a137, 0x05050f0a, 0x9a9ab52f, 0x0707090e, 0x12123624, 0x80809b1b, 0xe2e23ddf, 0xebeb26cd, 0x2727694e, 0xb2b2cd7f, 0x75759fea, 0x09091b12, 0x83839e1d, 0x2c2c7458, 0x1a1a2e34, 0x1b1b2d36, 0x6e6eb2dc, 0x5a5aeeb4, 0xa0a0fb5b, 0x5252f6a4, 0x3b3b4d76, 0xd6d661b7, 0xb3b3ce7d, 0x29297b52, 0xe3e33edd, 0x2f2f715e, 0x84849713, 0x5353f5a6, 0xd1d168b9, 0x00000000, 0xeded2cc1, 0x20206040, 0xfcfc1fe3, 0xb1b1c879, 0x5b5bedb6, 0x6a6abed4, 0xcbcb468d, 0xbebed967, 0x39394b72, 0x4a4ade94, 0x4c4cd498, 0x5858e8b0, 0xcfcf4a85, 0xd0d06bbb, 0xefef2ac5, 0xaaaae54f, 0xfbfb16ed, 0x4343c586, 0x4d4dd79a, 0x33335566, 0x85859411, 0x4545cf8a, 0xf9f910e9, 0x02020604, 0x7f7f81fe, 0x5050f0a0, 0x3c3c4478, 0x9f9fba25, 0xa8a8e34b, 0x5151f3a2, 0xa3a3fe5d, 0x4040c080, 0x8f8f8a05, 0x9292ad3f, 0x9d9dbc21, 0x38384870, 0xf5f504f1, 0xbcbcdf63, 0xb6b6c177, 0xdada75af, 0x21216342, 0x10103020, 0xffff1ae5, 0xf3f30efd, 0xd2d26dbf, 0xcdcd4c81, 0x0c0c1418, 0x13133526, 0xecec2fc3, 0x5f5fe1be, 0x9797a235, 0x4444cc88, 0x1717392e, 0xc4c45793, 0xa7a7f255, 0x7e7e82fc, 0x3d3d477a, 0x6464acc8, 0x5d5de7ba, 0x19192b32, 0x737395e6, 0x6060a0c0, 0x81819819, 0x4f4fd19e, 0xdcdc7fa3, 0x22226644, 0x2a2a7e54, 0x9090ab3b, 0x8888830b, 0x4646ca8c, 0xeeee29c7, 0xb8b8d36b, 0x14143c28, 0xdede79a7, 0x5e5ee2bc, 0x0b0b1d16, 0xdbdb76ad, 0xe0e03bdb, 0x32325664, 0x3a3a4e74, 0x0a0a1e14, 0x4949db92, 0x06060a0c, 0x24246c48, 0x5c5ce4b8, 0xc2c25d9f, 0xd3d36ebd, 0xacacef43, 0x6262a6c4, 0x9191a839, 0x9595a431, 0xe4e437d3, 0x79798bf2, 0xe7e732d5, 0xc8c8438b, 0x3737596e, 0x6d6db7da, 0x8d8d8c01, 0xd5d564b1, 0x4e4ed29c, 0xa9a9e049, 0x6c6cb4d8, 0x5656faac, 0xf4f407f3, 0xeaea25cf, 0x6565afca, 0x7a7a8ef4, 0xaeaee947, 0x08081810, 0xbabad56f, 0x787888f0, 0x25256f4a, 0x2e2e725c, 0x1c1c2438, 0xa6a6f157, 0xb4b4c773, 0xc6c65197, 0xe8e823cb, 0xdddd7ca1, 0x74749ce8, 0x1f1f213e, 0x4b4bdd96, 0xbdbddc61, 0x8b8b860d, 0x8a8a850f, 0x707090e0, 0x3e3e427c, 0xb5b5c471, 0x6666aacc, 0x4848d890, 0x03030506, 0xf6f601f7, 0x0e0e121c, 0x6161a3c2, 0x35355f6a, 0x5757f9ae, 0xb9b9d069, 0x86869117, 0xc1c15899, 0x1d1d273a, 0x9e9eb927, 0xe1e138d9, 0xf8f813eb, 0x9898b32b, 0x11113322, 0x6969bbd2, 0xd9d970a9, 0x8e8e8907, 0x9494a733, 0x9b9bb62d, 0x1e1e223c, 0x87879215, 0xe9e920c9, 0xcece4987, 0x5555ffaa, 0x28287850, 0xdfdf7aa5, 0x8c8c8f03, 0xa1a1f859, 0x89898009, 0x0d0d171a, 0xbfbfda65, 0xe6e631d7, 0x4242c684, 0x6868b8d0, 0x4141c382, 0x9999b029, 0x2d2d775a, 0x0f0f111e, 0xb0b0cb7b, 0x5454fca8, 0xbbbbd66d, 0x16163a2c ]
119
120 # Transformations for decryption
121 T5 = [ 0x51f4a750, 0x7e416553, 0x1a17a4c3, 0x3a275e96, 0x3bab6bcb, 0x1f9d45f1, 0xacfa58ab, 0x4be30393, 0x2030fa55, 0xad766df6, 0x88cc7691, 0xf5024c25, 0x4fe5d7fc, 0xc52acbd7, 0x26354480, 0xb562a38f, 0xdeb15a49, 0x25ba1b67, 0x45ea0e98, 0x5dfec0e1, 0xc32f7502, 0x814cf012, 0x8d4697a3, 0x6bd3f9c6, 0x038f5fe7, 0x15929c95, 0xbf6d7aeb, 0x955259da, 0xd4be832d, 0x587421d3, 0x49e06929, 0x8ec9c844, 0x75c2896a, 0xf48e7978, 0x99583e6b, 0x27b971dd, 0xbee14fb6, 0xf088ad17, 0xc920ac66, 0x7dce3ab4, 0x63df4a18, 0xe51a3182, 0x97513360, 0x62537f45, 0xb16477e0, 0xbb6bae84, 0xfe81a01c, 0xf9082b94, 0x70486858, 0x8f45fd19, 0x94de6c87, 0x527bf8b7, 0xab73d323, 0x724b02e2, 0xe31f8f57, 0x6655ab2a, 0xb2eb2807, 0x2fb5c203, 0x86c57b9a, 0xd33708a5, 0x302887f2, 0x23bfa5b2, 0x02036aba, 0xed16825c, 0x8acf1c2b, 0xa779b492, 0xf307f2f0, 0x4e69e2a1, 0x65daf4cd, 0x0605bed5, 0xd134621f, 0xc4a6fe8a, 0x342e539d, 0xa2f355a0, 0x058ae132, 0xa4f6eb75, 0x0b83ec39, 0x4060efaa, 0x5e719f06, 0xbd6e1051, 0x3e218af9, 0x96dd063d, 0xdd3e05ae, 0x4de6bd46, 0x91548db5, 0x71c45d05, 0x0406d46f, 0x605015ff, 0x1998fb24, 0xd6bde997, 0x894043cc, 0x67d99e77, 0xb0e842bd, 0x07898b88, 0xe7195b38, 0x79c8eedb, 0xa17c0a47, 0x7c420fe9, 0xf8841ec9, 0x00000000, 0x09808683, 0x322bed48, 0x1e1170ac, 0x6c5a724e, 0xfd0efffb, 0x0f853856, 0x3daed51e, 0x362d3927, 0x0a0fd964, 0x685ca621, 0x9b5b54d1, 0x24362e3a, 0x0c0a67b1, 0x9357e70f, 0xb4ee96d2, 0x1b9b919e, 0x80c0c54f, 0x61dc20a2, 0x5a774b69, 0x1c121a16, 0xe293ba0a, 0xc0a02ae5, 0x3c22e043, 0x121b171d, 0x0e090d0b, 0xf28bc7ad, 0x2db6a8b9, 0x141ea9c8, 0x57f11985, 0xaf75074c, 0xee99ddbb, 0xa37f60fd, 0xf701269f, 0x5c72f5bc, 0x44663bc5, 0x5bfb7e34, 0x8b432976, 0xcb23c6dc, 0xb6edfc68, 0xb8e4f163, 0xd731dcca, 0x42638510, 0x13972240, 0x84c61120, 0x854a247d, 0xd2bb3df8, 0xaef93211, 0xc729a16d, 0x1d9e2f4b, 0xdcb230f3, 0x0d8652ec, 0x77c1e3d0, 0x2bb3166c, 0xa970b999, 0x119448fa, 0x47e96422, 0xa8fc8cc4, 0xa0f03f1a, 0x567d2cd8, 0x223390ef, 0x87494ec7, 0xd938d1c1, 0x8ccaa2fe, 0x98d40b36, 0xa6f581cf, 0xa57ade28, 0xdab78e26, 0x3fadbfa4, 0x2c3a9de4, 0x5078920d, 0x6a5fcc9b, 0x547e4662, 0xf68d13c2, 0x90d8b8e8, 0x2e39f75e, 0x82c3aff5, 0x9f5d80be, 0x69d0937c, 0x6fd52da9, 0xcf2512b3, 0xc8ac993b, 0x10187da7, 0xe89c636e, 0xdb3bbb7b, 0xcd267809, 0x6e5918f4, 0xec9ab701, 0x834f9aa8, 0xe6956e65, 0xaaffe67e, 0x21bccf08, 0xef15e8e6, 0xbae79bd9, 0x4a6f36ce, 0xea9f09d4, 0x29b07cd6, 0x31a4b2af, 0x2a3f2331, 0xc6a59430, 0x35a266c0, 0x744ebc37, 0xfc82caa6, 0xe090d0b0, 0x33a7d815, 0xf104984a, 0x41ecdaf7, 0x7fcd500e, 0x1791f62f, 0x764dd68d, 0x43efb04d, 0xccaa4d54, 0xe49604df, 0x9ed1b5e3, 0x4c6a881b, 0xc12c1fb8, 0x4665517f, 0x9d5eea04, 0x018c355d, 0xfa877473, 0xfb0b412e, 0xb3671d5a, 0x92dbd252, 0xe9105633, 0x6dd64713, 0x9ad7618c, 0x37a10c7a, 0x59f8148e, 0xeb133c89, 0xcea927ee, 0xb761c935, 0xe11ce5ed, 0x7a47b13c, 0x9cd2df59, 0x55f2733f, 0x1814ce79, 0x73c737bf, 0x53f7cdea, 0x5ffdaa5b, 0xdf3d6f14, 0x7844db86, 0xcaaff381, 0xb968c43e, 0x3824342c, 0xc2a3405f, 0x161dc372, 0xbce2250c, 0x283c498b, 0xff0d9541, 0x39a80171, 0x080cb3de, 0xd8b4e49c, 0x6456c190, 0x7bcb8461, 0xd532b670, 0x486c5c74, 0xd0b85742 ]
122 T6 = [ 0x5051f4a7, 0x537e4165, 0xc31a17a4, 0x963a275e, 0xcb3bab6b, 0xf11f9d45, 0xabacfa58, 0x934be303, 0x552030fa, 0xf6ad766d, 0x9188cc76, 0x25f5024c, 0xfc4fe5d7, 0xd7c52acb, 0x80263544, 0x8fb562a3, 0x49deb15a, 0x6725ba1b, 0x9845ea0e, 0xe15dfec0, 0x02c32f75, 0x12814cf0, 0xa38d4697, 0xc66bd3f9, 0xe7038f5f, 0x9515929c, 0xebbf6d7a, 0xda955259, 0x2dd4be83, 0xd3587421, 0x2949e069, 0x448ec9c8, 0x6a75c289, 0x78f48e79, 0x6b99583e, 0xdd27b971, 0xb6bee14f, 0x17f088ad, 0x66c920ac, 0xb47dce3a, 0x1863df4a, 0x82e51a31, 0x60975133, 0x4562537f, 0xe0b16477, 0x84bb6bae, 0x1cfe81a0, 0x94f9082b, 0x58704868, 0x198f45fd, 0x8794de6c, 0xb7527bf8, 0x23ab73d3, 0xe2724b02, 0x57e31f8f, 0x2a6655ab, 0x07b2eb28, 0x032fb5c2, 0x9a86c57b, 0xa5d33708, 0xf2302887, 0xb223bfa5, 0xba02036a, 0x5ced1682, 0x2b8acf1c, 0x92a779b4, 0xf0f307f2, 0xa14e69e2, 0xcd65daf4, 0xd50605be, 0x1fd13462, 0x8ac4a6fe, 0x9d342e53, 0xa0a2f355, 0x32058ae1, 0x75a4f6eb, 0x390b83ec, 0xaa4060ef, 0x065e719f, 0x51bd6e10, 0xf93e218a, 0x3d96dd06, 0xaedd3e05, 0x464de6bd, 0xb591548d, 0x0571c45d, 0x6f0406d4, 0xff605015, 0x241998fb, 0x97d6bde9, 0xcc894043, 0x7767d99e, 0xbdb0e842, 0x8807898b, 0x38e7195b, 0xdb79c8ee, 0x47a17c0a, 0xe97c420f, 0xc9f8841e, 0x00000000, 0x83098086, 0x48322bed, 0xac1e1170, 0x4e6c5a72, 0xfbfd0eff, 0x560f8538, 0x1e3daed5, 0x27362d39, 0x640a0fd9, 0x21685ca6, 0xd19b5b54, 0x3a24362e, 0xb10c0a67, 0x0f9357e7, 0xd2b4ee96, 0x9e1b9b91, 0x4f80c0c5, 0xa261dc20, 0x695a774b, 0x161c121a, 0x0ae293ba, 0xe5c0a02a, 0x433c22e0, 0x1d121b17, 0x0b0e090d, 0xadf28bc7, 0xb92db6a8, 0xc8141ea9, 0x8557f119, 0x4caf7507, 0xbbee99dd, 0xfda37f60, 0x9ff70126, 0xbc5c72f5, 0xc544663b, 0x345bfb7e, 0x768b4329, 0xdccb23c6, 0x68b6edfc, 0x63b8e4f1, 0xcad731dc, 0x10426385, 0x40139722, 0x2084c611, 0x7d854a24, 0xf8d2bb3d, 0x11aef932, 0x6dc729a1, 0x4b1d9e2f, 0xf3dcb230, 0xec0d8652, 0xd077c1e3, 0x6c2bb316, 0x99a970b9, 0xfa119448, 0x2247e964, 0xc4a8fc8c, 0x1aa0f03f, 0xd8567d2c, 0xef223390, 0xc787494e, 0xc1d938d1, 0xfe8ccaa2, 0x3698d40b, 0xcfa6f581, 0x28a57ade, 0x26dab78e, 0xa43fadbf, 0xe42c3a9d, 0x0d507892, 0x9b6a5fcc, 0x62547e46, 0xc2f68d13, 0xe890d8b8, 0x5e2e39f7, 0xf582c3af, 0xbe9f5d80, 0x7c69d093, 0xa96fd52d, 0xb3cf2512, 0x3bc8ac99, 0xa710187d, 0x6ee89c63, 0x7bdb3bbb, 0x09cd2678, 0xf46e5918, 0x01ec9ab7, 0xa8834f9a, 0x65e6956e, 0x7eaaffe6, 0x0821bccf, 0xe6ef15e8, 0xd9bae79b, 0xce4a6f36, 0xd4ea9f09, 0xd629b07c, 0xaf31a4b2, 0x312a3f23, 0x30c6a594, 0xc035a266, 0x37744ebc, 0xa6fc82ca, 0xb0e090d0, 0x1533a7d8, 0x4af10498, 0xf741ecda, 0x0e7fcd50, 0x2f1791f6, 0x8d764dd6, 0x4d43efb0, 0x54ccaa4d, 0xdfe49604, 0xe39ed1b5, 0x1b4c6a88, 0xb8c12c1f, 0x7f466551, 0x049d5eea, 0x5d018c35, 0x73fa8774, 0x2efb0b41, 0x5ab3671d, 0x5292dbd2, 0x33e91056, 0x136dd647, 0x8c9ad761, 0x7a37a10c, 0x8e59f814, 0x89eb133c, 0xeecea927, 0x35b761c9, 0xede11ce5, 0x3c7a47b1, 0x599cd2df, 0x3f55f273, 0x791814ce, 0xbf73c737, 0xea53f7cd, 0x5b5ffdaa, 0x14df3d6f, 0x867844db, 0x81caaff3, 0x3eb968c4, 0x2c382434, 0x5fc2a340, 0x72161dc3, 0x0cbce225, 0x8b283c49, 0x41ff0d95, 0x7139a801, 0xde080cb3, 0x9cd8b4e4, 0x906456c1, 0x617bcb84, 0x70d532b6, 0x74486c5c, 0x42d0b857 ]
123 T7 = [ 0xa75051f4, 0x65537e41, 0xa4c31a17, 0x5e963a27, 0x6bcb3bab, 0x45f11f9d, 0x58abacfa, 0x03934be3, 0xfa552030, 0x6df6ad76, 0x769188cc, 0x4c25f502, 0xd7fc4fe5, 0xcbd7c52a, 0x44802635, 0xa38fb562, 0x5a49deb1, 0x1b6725ba, 0x0e9845ea, 0xc0e15dfe, 0x7502c32f, 0xf012814c, 0x97a38d46, 0xf9c66bd3, 0x5fe7038f, 0x9c951592, 0x7aebbf6d, 0x59da9552, 0x832dd4be, 0x21d35874, 0x692949e0, 0xc8448ec9, 0x896a75c2, 0x7978f48e, 0x3e6b9958, 0x71dd27b9, 0x4fb6bee1, 0xad17f088, 0xac66c920, 0x3ab47dce, 0x4a1863df, 0x3182e51a, 0x33609751, 0x7f456253, 0x77e0b164, 0xae84bb6b, 0xa01cfe81, 0x2b94f908, 0x68587048, 0xfd198f45, 0x6c8794de, 0xf8b7527b, 0xd323ab73, 0x02e2724b, 0x8f57e31f, 0xab2a6655, 0x2807b2eb, 0xc2032fb5, 0x7b9a86c5, 0x08a5d337, 0x87f23028, 0xa5b223bf, 0x6aba0203, 0x825ced16, 0x1c2b8acf, 0xb492a779, 0xf2f0f307, 0xe2a14e69, 0xf4cd65da, 0xbed50605, 0x621fd134, 0xfe8ac4a6, 0x539d342e, 0x55a0a2f3, 0xe132058a, 0xeb75a4f6, 0xec390b83, 0xefaa4060, 0x9f065e71, 0x1051bd6e, 0x8af93e21, 0x063d96dd, 0x05aedd3e, 0xbd464de6, 0x8db59154, 0x5d0571c4, 0xd46f0406, 0x15ff6050, 0xfb241998, 0xe997d6bd, 0x43cc8940, 0x9e7767d9, 0x42bdb0e8, 0x8b880789, 0x5b38e719, 0xeedb79c8, 0x0a47a17c, 0x0fe97c42, 0x1ec9f884, 0x00000000, 0x86830980, 0xed48322b, 0x70ac1e11, 0x724e6c5a, 0xfffbfd0e, 0x38560f85, 0xd51e3dae, 0x3927362d, 0xd9640a0f, 0xa621685c, 0x54d19b5b, 0x2e3a2436, 0x67b10c0a, 0xe70f9357, 0x96d2b4ee, 0x919e1b9b, 0xc54f80c0, 0x20a261dc, 0x4b695a77, 0x1a161c12, 0xba0ae293, 0x2ae5c0a0, 0xe0433c22, 0x171d121b, 0x0d0b0e09, 0xc7adf28b, 0xa8b92db6, 0xa9c8141e, 0x198557f1, 0x074caf75, 0xddbbee99, 0x60fda37f, 0x269ff701, 0xf5bc5c72, 0x3bc54466, 0x7e345bfb, 0x29768b43, 0xc6dccb23, 0xfc68b6ed, 0xf163b8e4, 0xdccad731, 0x85104263, 0x22401397, 0x112084c6, 0x247d854a, 0x3df8d2bb, 0x3211aef9, 0xa16dc729, 0x2f4b1d9e, 0x30f3dcb2, 0x52ec0d86, 0xe3d077c1, 0x166c2bb3, 0xb999a970, 0x48fa1194, 0x642247e9, 0x8cc4a8fc, 0x3f1aa0f0, 0x2cd8567d, 0x90ef2233, 0x4ec78749, 0xd1c1d938, 0xa2fe8cca, 0x0b3698d4, 0x81cfa6f5, 0xde28a57a, 0x8e26dab7, 0xbfa43fad, 0x9de42c3a, 0x920d5078, 0xcc9b6a5f, 0x4662547e, 0x13c2f68d, 0xb8e890d8, 0xf75e2e39, 0xaff582c3, 0x80be9f5d, 0x937c69d0, 0x2da96fd5, 0x12b3cf25, 0x993bc8ac, 0x7da71018, 0x636ee89c, 0xbb7bdb3b, 0x7809cd26, 0x18f46e59, 0xb701ec9a, 0x9aa8834f, 0x6e65e695, 0xe67eaaff, 0xcf0821bc, 0xe8e6ef15, 0x9bd9bae7, 0x36ce4a6f, 0x09d4ea9f, 0x7cd629b0, 0xb2af31a4, 0x23312a3f, 0x9430c6a5, 0x66c035a2, 0xbc37744e, 0xcaa6fc82, 0xd0b0e090, 0xd81533a7, 0x984af104, 0xdaf741ec, 0x500e7fcd, 0xf62f1791, 0xd68d764d, 0xb04d43ef, 0x4d54ccaa, 0x04dfe496, 0xb5e39ed1, 0x881b4c6a, 0x1fb8c12c, 0x517f4665, 0xea049d5e, 0x355d018c, 0x7473fa87, 0x412efb0b, 0x1d5ab367, 0xd25292db, 0x5633e910, 0x47136dd6, 0x618c9ad7, 0x0c7a37a1, 0x148e59f8, 0x3c89eb13, 0x27eecea9, 0xc935b761, 0xe5ede11c, 0xb13c7a47, 0xdf599cd2, 0x733f55f2, 0xce791814, 0x37bf73c7, 0xcdea53f7, 0xaa5b5ffd, 0x6f14df3d, 0xdb867844, 0xf381caaf, 0xc43eb968, 0x342c3824, 0x405fc2a3, 0xc372161d, 0x250cbce2, 0x498b283c, 0x9541ff0d, 0x017139a8, 0xb3de080c, 0xe49cd8b4, 0xc1906456, 0x84617bcb, 0xb670d532, 0x5c74486c, 0x5742d0b8 ]
124 T8 = [ 0xf4a75051, 0x4165537e, 0x17a4c31a, 0x275e963a, 0xab6bcb3b, 0x9d45f11f, 0xfa58abac, 0xe303934b, 0x30fa5520, 0x766df6ad, 0xcc769188, 0x024c25f5, 0xe5d7fc4f, 0x2acbd7c5, 0x35448026, 0x62a38fb5, 0xb15a49de, 0xba1b6725, 0xea0e9845, 0xfec0e15d, 0x2f7502c3, 0x4cf01281, 0x4697a38d, 0xd3f9c66b, 0x8f5fe703, 0x929c9515, 0x6d7aebbf, 0x5259da95, 0xbe832dd4, 0x7421d358, 0xe0692949, 0xc9c8448e, 0xc2896a75, 0x8e7978f4, 0x583e6b99, 0xb971dd27, 0xe14fb6be, 0x88ad17f0, 0x20ac66c9, 0xce3ab47d, 0xdf4a1863, 0x1a3182e5, 0x51336097, 0x537f4562, 0x6477e0b1, 0x6bae84bb, 0x81a01cfe, 0x082b94f9, 0x48685870, 0x45fd198f, 0xde6c8794, 0x7bf8b752, 0x73d323ab, 0x4b02e272, 0x1f8f57e3, 0x55ab2a66, 0xeb2807b2, 0xb5c2032f, 0xc57b9a86, 0x3708a5d3, 0x2887f230, 0xbfa5b223, 0x036aba02, 0x16825ced, 0xcf1c2b8a, 0x79b492a7, 0x07f2f0f3, 0x69e2a14e, 0xdaf4cd65, 0x05bed506, 0x34621fd1, 0xa6fe8ac4, 0x2e539d34, 0xf355a0a2, 0x8ae13205, 0xf6eb75a4, 0x83ec390b, 0x60efaa40, 0x719f065e, 0x6e1051bd, 0x218af93e, 0xdd063d96, 0x3e05aedd, 0xe6bd464d, 0x548db591, 0xc45d0571, 0x06d46f04, 0x5015ff60, 0x98fb2419, 0xbde997d6, 0x4043cc89, 0xd99e7767, 0xe842bdb0, 0x898b8807, 0x195b38e7, 0xc8eedb79, 0x7c0a47a1, 0x420fe97c, 0x841ec9f8, 0x00000000, 0x80868309, 0x2bed4832, 0x1170ac1e, 0x5a724e6c, 0x0efffbfd, 0x8538560f, 0xaed51e3d, 0x2d392736, 0x0fd9640a, 0x5ca62168, 0x5b54d19b, 0x362e3a24, 0x0a67b10c, 0x57e70f93, 0xee96d2b4, 0x9b919e1b, 0xc0c54f80, 0xdc20a261, 0x774b695a, 0x121a161c, 0x93ba0ae2, 0xa02ae5c0, 0x22e0433c, 0x1b171d12, 0x090d0b0e, 0x8bc7adf2, 0xb6a8b92d, 0x1ea9c814, 0xf1198557, 0x75074caf, 0x99ddbbee, 0x7f60fda3, 0x01269ff7, 0x72f5bc5c, 0x663bc544, 0xfb7e345b, 0x4329768b, 0x23c6dccb, 0xedfc68b6, 0xe4f163b8, 0x31dccad7, 0x63851042, 0x97224013, 0xc6112084, 0x4a247d85, 0xbb3df8d2, 0xf93211ae, 0x29a16dc7, 0x9e2f4b1d, 0xb230f3dc, 0x8652ec0d, 0xc1e3d077, 0xb3166c2b, 0x70b999a9, 0x9448fa11, 0xe9642247, 0xfc8cc4a8, 0xf03f1aa0, 0x7d2cd856, 0x3390ef22, 0x494ec787, 0x38d1c1d9, 0xcaa2fe8c, 0xd40b3698, 0xf581cfa6, 0x7ade28a5, 0xb78e26da, 0xadbfa43f, 0x3a9de42c, 0x78920d50, 0x5fcc9b6a, 0x7e466254, 0x8d13c2f6, 0xd8b8e890, 0x39f75e2e, 0xc3aff582, 0x5d80be9f, 0xd0937c69, 0xd52da96f, 0x2512b3cf, 0xac993bc8, 0x187da710, 0x9c636ee8, 0x3bbb7bdb, 0x267809cd, 0x5918f46e, 0x9ab701ec, 0x4f9aa883, 0x956e65e6, 0xffe67eaa, 0xbccf0821, 0x15e8e6ef, 0xe79bd9ba, 0x6f36ce4a, 0x9f09d4ea, 0xb07cd629, 0xa4b2af31, 0x3f23312a, 0xa59430c6, 0xa266c035, 0x4ebc3774, 0x82caa6fc, 0x90d0b0e0, 0xa7d81533, 0x04984af1, 0xecdaf741, 0xcd500e7f, 0x91f62f17, 0x4dd68d76, 0xefb04d43, 0xaa4d54cc, 0x9604dfe4, 0xd1b5e39e, 0x6a881b4c, 0x2c1fb8c1, 0x65517f46, 0x5eea049d, 0x8c355d01, 0x877473fa, 0x0b412efb, 0x671d5ab3, 0xdbd25292, 0x105633e9, 0xd647136d, 0xd7618c9a, 0xa10c7a37, 0xf8148e59, 0x133c89eb, 0xa927eece, 0x61c935b7, 0x1ce5ede1, 0x47b13c7a, 0xd2df599c, 0xf2733f55, 0x14ce7918, 0xc737bf73, 0xf7cdea53, 0xfdaa5b5f, 0x3d6f14df, 0x44db8678, 0xaff381ca, 0x68c43eb9, 0x24342c38, 0xa3405fc2, 0x1dc37216, 0xe2250cbc, 0x3c498b28, 0x0d9541ff, 0xa8017139, 0x0cb3de08, 0xb4e49cd8, 0x56c19064, 0xcb84617b, 0x32b670d5, 0x6c5c7448, 0xb85742d0 ]
125
126 # Transformations for decryption key expansion
127 U1 = [ 0x00000000, 0x0e090d0b, 0x1c121a16, 0x121b171d, 0x3824342c, 0x362d3927, 0x24362e3a, 0x2a3f2331, 0x70486858, 0x7e416553, 0x6c5a724e, 0x62537f45, 0x486c5c74, 0x4665517f, 0x547e4662, 0x5a774b69, 0xe090d0b0, 0xee99ddbb, 0xfc82caa6, 0xf28bc7ad, 0xd8b4e49c, 0xd6bde997, 0xc4a6fe8a, 0xcaaff381, 0x90d8b8e8, 0x9ed1b5e3, 0x8ccaa2fe, 0x82c3aff5, 0xa8fc8cc4, 0xa6f581cf, 0xb4ee96d2, 0xbae79bd9, 0xdb3bbb7b, 0xd532b670, 0xc729a16d, 0xc920ac66, 0xe31f8f57, 0xed16825c, 0xff0d9541, 0xf104984a, 0xab73d323, 0xa57ade28, 0xb761c935, 0xb968c43e, 0x9357e70f, 0x9d5eea04, 0x8f45fd19, 0x814cf012, 0x3bab6bcb, 0x35a266c0, 0x27b971dd, 0x29b07cd6, 0x038f5fe7, 0x0d8652ec, 0x1f9d45f1, 0x119448fa, 0x4be30393, 0x45ea0e98, 0x57f11985, 0x59f8148e, 0x73c737bf, 0x7dce3ab4, 0x6fd52da9, 0x61dc20a2, 0xad766df6, 0xa37f60fd, 0xb16477e0, 0xbf6d7aeb, 0x955259da, 0x9b5b54d1, 0x894043cc, 0x87494ec7, 0xdd3e05ae, 0xd33708a5, 0xc12c1fb8, 0xcf2512b3, 0xe51a3182, 0xeb133c89, 0xf9082b94, 0xf701269f, 0x4de6bd46, 0x43efb04d, 0x51f4a750, 0x5ffdaa5b, 0x75c2896a, 0x7bcb8461, 0x69d0937c, 0x67d99e77, 0x3daed51e, 0x33a7d815, 0x21bccf08, 0x2fb5c203, 0x058ae132, 0x0b83ec39, 0x1998fb24, 0x1791f62f, 0x764dd68d, 0x7844db86, 0x6a5fcc9b, 0x6456c190, 0x4e69e2a1, 0x4060efaa, 0x527bf8b7, 0x5c72f5bc, 0x0605bed5, 0x080cb3de, 0x1a17a4c3, 0x141ea9c8, 0x3e218af9, 0x302887f2, 0x223390ef, 0x2c3a9de4, 0x96dd063d, 0x98d40b36, 0x8acf1c2b, 0x84c61120, 0xaef93211, 0xa0f03f1a, 0xb2eb2807, 0xbce2250c, 0xe6956e65, 0xe89c636e, 0xfa877473, 0xf48e7978, 0xdeb15a49, 0xd0b85742, 0xc2a3405f, 0xccaa4d54, 0x41ecdaf7, 0x4fe5d7fc, 0x5dfec0e1, 0x53f7cdea, 0x79c8eedb, 0x77c1e3d0, 0x65daf4cd, 0x6bd3f9c6, 0x31a4b2af, 0x3fadbfa4, 0x2db6a8b9, 0x23bfa5b2, 0x09808683, 0x07898b88, 0x15929c95, 0x1b9b919e, 0xa17c0a47, 0xaf75074c, 0xbd6e1051, 0xb3671d5a, 0x99583e6b, 0x97513360, 0x854a247d, 0x8b432976, 0xd134621f, 0xdf3d6f14, 0xcd267809, 0xc32f7502, 0xe9105633, 0xe7195b38, 0xf5024c25, 0xfb0b412e, 0x9ad7618c, 0x94de6c87, 0x86c57b9a, 0x88cc7691, 0xa2f355a0, 0xacfa58ab, 0xbee14fb6, 0xb0e842bd, 0xea9f09d4, 0xe49604df, 0xf68d13c2, 0xf8841ec9, 0xd2bb3df8, 0xdcb230f3, 0xcea927ee, 0xc0a02ae5, 0x7a47b13c, 0x744ebc37, 0x6655ab2a, 0x685ca621, 0x42638510, 0x4c6a881b, 0x5e719f06, 0x5078920d, 0x0a0fd964, 0x0406d46f, 0x161dc372, 0x1814ce79, 0x322bed48, 0x3c22e043, 0x2e39f75e, 0x2030fa55, 0xec9ab701, 0xe293ba0a, 0xf088ad17, 0xfe81a01c, 0xd4be832d, 0xdab78e26, 0xc8ac993b, 0xc6a59430, 0x9cd2df59, 0x92dbd252, 0x80c0c54f, 0x8ec9c844, 0xa4f6eb75, 0xaaffe67e, 0xb8e4f163, 0xb6edfc68, 0x0c0a67b1, 0x02036aba, 0x10187da7, 0x1e1170ac, 0x342e539d, 0x3a275e96, 0x283c498b, 0x26354480, 0x7c420fe9, 0x724b02e2, 0x605015ff, 0x6e5918f4, 0x44663bc5, 0x4a6f36ce, 0x587421d3, 0x567d2cd8, 0x37a10c7a, 0x39a80171, 0x2bb3166c, 0x25ba1b67, 0x0f853856, 0x018c355d, 0x13972240, 0x1d9e2f4b, 0x47e96422, 0x49e06929, 0x5bfb7e34, 0x55f2733f, 0x7fcd500e, 0x71c45d05, 0x63df4a18, 0x6dd64713, 0xd731dcca, 0xd938d1c1, 0xcb23c6dc, 0xc52acbd7, 0xef15e8e6, 0xe11ce5ed, 0xf307f2f0, 0xfd0efffb, 0xa779b492, 0xa970b999, 0xbb6bae84, 0xb562a38f, 0x9f5d80be, 0x91548db5, 0x834f9aa8, 0x8d4697a3 ]
128 U2 = [ 0x00000000, 0x0b0e090d, 0x161c121a, 0x1d121b17, 0x2c382434, 0x27362d39, 0x3a24362e, 0x312a3f23, 0x58704868, 0x537e4165, 0x4e6c5a72, 0x4562537f, 0x74486c5c, 0x7f466551, 0x62547e46, 0x695a774b, 0xb0e090d0, 0xbbee99dd, 0xa6fc82ca, 0xadf28bc7, 0x9cd8b4e4, 0x97d6bde9, 0x8ac4a6fe, 0x81caaff3, 0xe890d8b8, 0xe39ed1b5, 0xfe8ccaa2, 0xf582c3af, 0xc4a8fc8c, 0xcfa6f581, 0xd2b4ee96, 0xd9bae79b, 0x7bdb3bbb, 0x70d532b6, 0x6dc729a1, 0x66c920ac, 0x57e31f8f, 0x5ced1682, 0x41ff0d95, 0x4af10498, 0x23ab73d3, 0x28a57ade, 0x35b761c9, 0x3eb968c4, 0x0f9357e7, 0x049d5eea, 0x198f45fd, 0x12814cf0, 0xcb3bab6b, 0xc035a266, 0xdd27b971, 0xd629b07c, 0xe7038f5f, 0xec0d8652, 0xf11f9d45, 0xfa119448, 0x934be303, 0x9845ea0e, 0x8557f119, 0x8e59f814, 0xbf73c737, 0xb47dce3a, 0xa96fd52d, 0xa261dc20, 0xf6ad766d, 0xfda37f60, 0xe0b16477, 0xebbf6d7a, 0xda955259, 0xd19b5b54, 0xcc894043, 0xc787494e, 0xaedd3e05, 0xa5d33708, 0xb8c12c1f, 0xb3cf2512, 0x82e51a31, 0x89eb133c, 0x94f9082b, 0x9ff70126, 0x464de6bd, 0x4d43efb0, 0x5051f4a7, 0x5b5ffdaa, 0x6a75c289, 0x617bcb84, 0x7c69d093, 0x7767d99e, 0x1e3daed5, 0x1533a7d8, 0x0821bccf, 0x032fb5c2, 0x32058ae1, 0x390b83ec, 0x241998fb, 0x2f1791f6, 0x8d764dd6, 0x867844db, 0x9b6a5fcc, 0x906456c1, 0xa14e69e2, 0xaa4060ef, 0xb7527bf8, 0xbc5c72f5, 0xd50605be, 0xde080cb3, 0xc31a17a4, 0xc8141ea9, 0xf93e218a, 0xf2302887, 0xef223390, 0xe42c3a9d, 0x3d96dd06, 0x3698d40b, 0x2b8acf1c, 0x2084c611, 0x11aef932, 0x1aa0f03f, 0x07b2eb28, 0x0cbce225, 0x65e6956e, 0x6ee89c63, 0x73fa8774, 0x78f48e79, 0x49deb15a, 0x42d0b857, 0x5fc2a340, 0x54ccaa4d, 0xf741ecda, 0xfc4fe5d7, 0xe15dfec0, 0xea53f7cd, 0xdb79c8ee, 0xd077c1e3, 0xcd65daf4, 0xc66bd3f9, 0xaf31a4b2, 0xa43fadbf, 0xb92db6a8, 0xb223bfa5, 0x83098086, 0x8807898b, 0x9515929c, 0x9e1b9b91, 0x47a17c0a, 0x4caf7507, 0x51bd6e10, 0x5ab3671d, 0x6b99583e, 0x60975133, 0x7d854a24, 0x768b4329, 0x1fd13462, 0x14df3d6f, 0x09cd2678, 0x02c32f75, 0x33e91056, 0x38e7195b, 0x25f5024c, 0x2efb0b41, 0x8c9ad761, 0x8794de6c, 0x9a86c57b, 0x9188cc76, 0xa0a2f355, 0xabacfa58, 0xb6bee14f, 0xbdb0e842, 0xd4ea9f09, 0xdfe49604, 0xc2f68d13, 0xc9f8841e, 0xf8d2bb3d, 0xf3dcb230, 0xeecea927, 0xe5c0a02a, 0x3c7a47b1, 0x37744ebc, 0x2a6655ab, 0x21685ca6, 0x10426385, 0x1b4c6a88, 0x065e719f, 0x0d507892, 0x640a0fd9, 0x6f0406d4, 0x72161dc3, 0x791814ce, 0x48322bed, 0x433c22e0, 0x5e2e39f7, 0x552030fa, 0x01ec9ab7, 0x0ae293ba, 0x17f088ad, 0x1cfe81a0, 0x2dd4be83, 0x26dab78e, 0x3bc8ac99, 0x30c6a594, 0x599cd2df, 0x5292dbd2, 0x4f80c0c5, 0x448ec9c8, 0x75a4f6eb, 0x7eaaffe6, 0x63b8e4f1, 0x68b6edfc, 0xb10c0a67, 0xba02036a, 0xa710187d, 0xac1e1170, 0x9d342e53, 0x963a275e, 0x8b283c49, 0x80263544, 0xe97c420f, 0xe2724b02, 0xff605015, 0xf46e5918, 0xc544663b, 0xce4a6f36, 0xd3587421, 0xd8567d2c, 0x7a37a10c, 0x7139a801, 0x6c2bb316, 0x6725ba1b, 0x560f8538, 0x5d018c35, 0x40139722, 0x4b1d9e2f, 0x2247e964, 0x2949e069, 0x345bfb7e, 0x3f55f273, 0x0e7fcd50, 0x0571c45d, 0x1863df4a, 0x136dd647, 0xcad731dc, 0xc1d938d1, 0xdccb23c6, 0xd7c52acb, 0xe6ef15e8, 0xede11ce5, 0xf0f307f2, 0xfbfd0eff, 0x92a779b4, 0x99a970b9, 0x84bb6bae, 0x8fb562a3, 0xbe9f5d80, 0xb591548d, 0xa8834f9a, 0xa38d4697 ]
129 U3 = [ 0x00000000, 0x0d0b0e09, 0x1a161c12, 0x171d121b, 0x342c3824, 0x3927362d, 0x2e3a2436, 0x23312a3f, 0x68587048, 0x65537e41, 0x724e6c5a, 0x7f456253, 0x5c74486c, 0x517f4665, 0x4662547e, 0x4b695a77, 0xd0b0e090, 0xddbbee99, 0xcaa6fc82, 0xc7adf28b, 0xe49cd8b4, 0xe997d6bd, 0xfe8ac4a6, 0xf381caaf, 0xb8e890d8, 0xb5e39ed1, 0xa2fe8cca, 0xaff582c3, 0x8cc4a8fc, 0x81cfa6f5, 0x96d2b4ee, 0x9bd9bae7, 0xbb7bdb3b, 0xb670d532, 0xa16dc729, 0xac66c920, 0x8f57e31f, 0x825ced16, 0x9541ff0d, 0x984af104, 0xd323ab73, 0xde28a57a, 0xc935b761, 0xc43eb968, 0xe70f9357, 0xea049d5e, 0xfd198f45, 0xf012814c, 0x6bcb3bab, 0x66c035a2, 0x71dd27b9, 0x7cd629b0, 0x5fe7038f, 0x52ec0d86, 0x45f11f9d, 0x48fa1194, 0x03934be3, 0x0e9845ea, 0x198557f1, 0x148e59f8, 0x37bf73c7, 0x3ab47dce, 0x2da96fd5, 0x20a261dc, 0x6df6ad76, 0x60fda37f, 0x77e0b164, 0x7aebbf6d, 0x59da9552, 0x54d19b5b, 0x43cc8940, 0x4ec78749, 0x05aedd3e, 0x08a5d337, 0x1fb8c12c, 0x12b3cf25, 0x3182e51a, 0x3c89eb13, 0x2b94f908, 0x269ff701, 0xbd464de6, 0xb04d43ef, 0xa75051f4, 0xaa5b5ffd, 0x896a75c2, 0x84617bcb, 0x937c69d0, 0x9e7767d9, 0xd51e3dae, 0xd81533a7, 0xcf0821bc, 0xc2032fb5, 0xe132058a, 0xec390b83, 0xfb241998, 0xf62f1791, 0xd68d764d, 0xdb867844, 0xcc9b6a5f, 0xc1906456, 0xe2a14e69, 0xefaa4060, 0xf8b7527b, 0xf5bc5c72, 0xbed50605, 0xb3de080c, 0xa4c31a17, 0xa9c8141e, 0x8af93e21, 0x87f23028, 0x90ef2233, 0x9de42c3a, 0x063d96dd, 0x0b3698d4, 0x1c2b8acf, 0x112084c6, 0x3211aef9, 0x3f1aa0f0, 0x2807b2eb, 0x250cbce2, 0x6e65e695, 0x636ee89c, 0x7473fa87, 0x7978f48e, 0x5a49deb1, 0x5742d0b8, 0x405fc2a3, 0x4d54ccaa, 0xdaf741ec, 0xd7fc4fe5, 0xc0e15dfe, 0xcdea53f7, 0xeedb79c8, 0xe3d077c1, 0xf4cd65da, 0xf9c66bd3, 0xb2af31a4, 0xbfa43fad, 0xa8b92db6, 0xa5b223bf, 0x86830980, 0x8b880789, 0x9c951592, 0x919e1b9b, 0x0a47a17c, 0x074caf75, 0x1051bd6e, 0x1d5ab367, 0x3e6b9958, 0x33609751, 0x247d854a, 0x29768b43, 0x621fd134, 0x6f14df3d, 0x7809cd26, 0x7502c32f, 0x5633e910, 0x5b38e719, 0x4c25f502, 0x412efb0b, 0x618c9ad7, 0x6c8794de, 0x7b9a86c5, 0x769188cc, 0x55a0a2f3, 0x58abacfa, 0x4fb6bee1, 0x42bdb0e8, 0x09d4ea9f, 0x04dfe496, 0x13c2f68d, 0x1ec9f884, 0x3df8d2bb, 0x30f3dcb2, 0x27eecea9, 0x2ae5c0a0, 0xb13c7a47, 0xbc37744e, 0xab2a6655, 0xa621685c, 0x85104263, 0x881b4c6a, 0x9f065e71, 0x920d5078, 0xd9640a0f, 0xd46f0406, 0xc372161d, 0xce791814, 0xed48322b, 0xe0433c22, 0xf75e2e39, 0xfa552030, 0xb701ec9a, 0xba0ae293, 0xad17f088, 0xa01cfe81, 0x832dd4be, 0x8e26dab7, 0x993bc8ac, 0x9430c6a5, 0xdf599cd2, 0xd25292db, 0xc54f80c0, 0xc8448ec9, 0xeb75a4f6, 0xe67eaaff, 0xf163b8e4, 0xfc68b6ed, 0x67b10c0a, 0x6aba0203, 0x7da71018, 0x70ac1e11, 0x539d342e, 0x5e963a27, 0x498b283c, 0x44802635, 0x0fe97c42, 0x02e2724b, 0x15ff6050, 0x18f46e59, 0x3bc54466, 0x36ce4a6f, 0x21d35874, 0x2cd8567d, 0x0c7a37a1, 0x017139a8, 0x166c2bb3, 0x1b6725ba, 0x38560f85, 0x355d018c, 0x22401397, 0x2f4b1d9e, 0x642247e9, 0x692949e0, 0x7e345bfb, 0x733f55f2, 0x500e7fcd, 0x5d0571c4, 0x4a1863df, 0x47136dd6, 0xdccad731, 0xd1c1d938, 0xc6dccb23, 0xcbd7c52a, 0xe8e6ef15, 0xe5ede11c, 0xf2f0f307, 0xfffbfd0e, 0xb492a779, 0xb999a970, 0xae84bb6b, 0xa38fb562, 0x80be9f5d, 0x8db59154, 0x9aa8834f, 0x97a38d46 ]
130 U4 = [ 0x00000000, 0x090d0b0e, 0x121a161c, 0x1b171d12, 0x24342c38, 0x2d392736, 0x362e3a24, 0x3f23312a, 0x48685870, 0x4165537e, 0x5a724e6c, 0x537f4562, 0x6c5c7448, 0x65517f46, 0x7e466254, 0x774b695a, 0x90d0b0e0, 0x99ddbbee, 0x82caa6fc, 0x8bc7adf2, 0xb4e49cd8, 0xbde997d6, 0xa6fe8ac4, 0xaff381ca, 0xd8b8e890, 0xd1b5e39e, 0xcaa2fe8c, 0xc3aff582, 0xfc8cc4a8, 0xf581cfa6, 0xee96d2b4, 0xe79bd9ba, 0x3bbb7bdb, 0x32b670d5, 0x29a16dc7, 0x20ac66c9, 0x1f8f57e3, 0x16825ced, 0x0d9541ff, 0x04984af1, 0x73d323ab, 0x7ade28a5, 0x61c935b7, 0x68c43eb9, 0x57e70f93, 0x5eea049d, 0x45fd198f, 0x4cf01281, 0xab6bcb3b, 0xa266c035, 0xb971dd27, 0xb07cd629, 0x8f5fe703, 0x8652ec0d, 0x9d45f11f, 0x9448fa11, 0xe303934b, 0xea0e9845, 0xf1198557, 0xf8148e59, 0xc737bf73, 0xce3ab47d, 0xd52da96f, 0xdc20a261, 0x766df6ad, 0x7f60fda3, 0x6477e0b1, 0x6d7aebbf, 0x5259da95, 0x5b54d19b, 0x4043cc89, 0x494ec787, 0x3e05aedd, 0x3708a5d3, 0x2c1fb8c1, 0x2512b3cf, 0x1a3182e5, 0x133c89eb, 0x082b94f9, 0x01269ff7, 0xe6bd464d, 0xefb04d43, 0xf4a75051, 0xfdaa5b5f, 0xc2896a75, 0xcb84617b, 0xd0937c69, 0xd99e7767, 0xaed51e3d, 0xa7d81533, 0xbccf0821, 0xb5c2032f, 0x8ae13205, 0x83ec390b, 0x98fb2419, 0x91f62f17, 0x4dd68d76, 0x44db8678, 0x5fcc9b6a, 0x56c19064, 0x69e2a14e, 0x60efaa40, 0x7bf8b752, 0x72f5bc5c, 0x05bed506, 0x0cb3de08, 0x17a4c31a, 0x1ea9c814, 0x218af93e, 0x2887f230, 0x3390ef22, 0x3a9de42c, 0xdd063d96, 0xd40b3698, 0xcf1c2b8a, 0xc6112084, 0xf93211ae, 0xf03f1aa0, 0xeb2807b2, 0xe2250cbc, 0x956e65e6, 0x9c636ee8, 0x877473fa, 0x8e7978f4, 0xb15a49de, 0xb85742d0, 0xa3405fc2, 0xaa4d54cc, 0xecdaf741, 0xe5d7fc4f, 0xfec0e15d, 0xf7cdea53, 0xc8eedb79, 0xc1e3d077, 0xdaf4cd65, 0xd3f9c66b, 0xa4b2af31, 0xadbfa43f, 0xb6a8b92d, 0xbfa5b223, 0x80868309, 0x898b8807, 0x929c9515, 0x9b919e1b, 0x7c0a47a1, 0x75074caf, 0x6e1051bd, 0x671d5ab3, 0x583e6b99, 0x51336097, 0x4a247d85, 0x4329768b, 0x34621fd1, 0x3d6f14df, 0x267809cd, 0x2f7502c3, 0x105633e9, 0x195b38e7, 0x024c25f5, 0x0b412efb, 0xd7618c9a, 0xde6c8794, 0xc57b9a86, 0xcc769188, 0xf355a0a2, 0xfa58abac, 0xe14fb6be, 0xe842bdb0, 0x9f09d4ea, 0x9604dfe4, 0x8d13c2f6, 0x841ec9f8, 0xbb3df8d2, 0xb230f3dc, 0xa927eece, 0xa02ae5c0, 0x47b13c7a, 0x4ebc3774, 0x55ab2a66, 0x5ca62168, 0x63851042, 0x6a881b4c, 0x719f065e, 0x78920d50, 0x0fd9640a, 0x06d46f04, 0x1dc37216, 0x14ce7918, 0x2bed4832, 0x22e0433c, 0x39f75e2e, 0x30fa5520, 0x9ab701ec, 0x93ba0ae2, 0x88ad17f0, 0x81a01cfe, 0xbe832dd4, 0xb78e26da, 0xac993bc8, 0xa59430c6, 0xd2df599c, 0xdbd25292, 0xc0c54f80, 0xc9c8448e, 0xf6eb75a4, 0xffe67eaa, 0xe4f163b8, 0xedfc68b6, 0x0a67b10c, 0x036aba02, 0x187da710, 0x1170ac1e, 0x2e539d34, 0x275e963a, 0x3c498b28, 0x35448026, 0x420fe97c, 0x4b02e272, 0x5015ff60, 0x5918f46e, 0x663bc544, 0x6f36ce4a, 0x7421d358, 0x7d2cd856, 0xa10c7a37, 0xa8017139, 0xb3166c2b, 0xba1b6725, 0x8538560f, 0x8c355d01, 0x97224013, 0x9e2f4b1d, 0xe9642247, 0xe0692949, 0xfb7e345b, 0xf2733f55, 0xcd500e7f, 0xc45d0571, 0xdf4a1863, 0xd647136d, 0x31dccad7, 0x38d1c1d9, 0x23c6dccb, 0x2acbd7c5, 0x15e8e6ef, 0x1ce5ede1, 0x07f2f0f3, 0x0efffbfd, 0x79b492a7, 0x70b999a9, 0x6bae84bb, 0x62a38fb5, 0x5d80be9f, 0x548db591, 0x4f9aa883, 0x4697a38d ]
131
132 def __init__(self, key):
133
134 if len(key) not in (16, 24, 32):
135 raise ValueError('Invalid key size')
136
137 rounds = self.number_of_rounds[len(key)]
138
139 # Encryption round keys
140 self._Ke = [[0] * 4 for i in xrange(rounds + 1)]
141
142 # Decryption round keys
143 self._Kd = [[0] * 4 for i in xrange(rounds + 1)]
144
145 round_key_count = (rounds + 1) * 4
146 KC = len(key) // 4
147
148 # Convert the key into ints
149 tk = [ struct.unpack('>i', key[i:i + 4])[0] for i in xrange(0, len(key), 4) ]
150
151 # Copy values into round key arrays
152 for i in xrange(0, KC):
153 self._Ke[i // 4][i % 4] = tk[i]
154 self._Kd[rounds - (i // 4)][i % 4] = tk[i]
155
156 # Key expansion (fips-197 section 5.2)
157 rconpointer = 0
158 t = KC
159 while t < round_key_count:
160
161 tt = tk[KC - 1]
162 tk[0] ^= ((self.S[(tt >> 16) & 0xFF] << 24) ^
163 (self.S[(tt >> 8) & 0xFF] << 16) ^
164 (self.S[ tt & 0xFF] << 8) ^
165 self.S[(tt >> 24) & 0xFF] ^
166 (self.rcon[rconpointer] << 24))
167 rconpointer += 1
168
169 if KC != 8:
170 for i in xrange(1, KC):
171 tk[i] ^= tk[i - 1]
172
173 # Key expansion for 256-bit keys is "slightly different" (fips-197)
174 else:
175 for i in xrange(1, KC // 2):
176 tk[i] ^= tk[i - 1]
177 tt = tk[KC // 2 - 1]
178
179 tk[KC // 2] ^= (self.S[ tt & 0xFF] ^
180 (self.S[(tt >> 8) & 0xFF] << 8) ^
181 (self.S[(tt >> 16) & 0xFF] << 16) ^
182 (self.S[(tt >> 24) & 0xFF] << 24))
183
184 for i in xrange(KC // 2 + 1, KC):
185 tk[i] ^= tk[i - 1]
186
187 # Copy values into round key arrays
188 j = 0
189 while j < KC and t < round_key_count:
190 self._Ke[t // 4][t % 4] = tk[j]
191 self._Kd[rounds - (t // 4)][t % 4] = tk[j]
192 j += 1
193 t += 1
194
195 # Inverse-Cipher-ify the decryption round key (fips-197 section 5.3)
196 for r in xrange(1, rounds):
197 for j in xrange(0, 4):
198 tt = self._Kd[r][j]
199 self._Kd[r][j] = (self.U1[(tt >> 24) & 0xFF] ^
200 self.U2[(tt >> 16) & 0xFF] ^
201 self.U3[(tt >> 8) & 0xFF] ^
202 self.U4[ tt & 0xFF])
203
204 def encrypt(self, plaintext):
205 'Encrypt a block of plain text using the AES block cipher.'
206
207 if len(plaintext) != 16:
208 raise ValueError('wrong block length')
209
210 rounds = len(self._Ke) - 1
211 (s1, s2, s3) = [1, 2, 3]
212 a = [0, 0, 0, 0]
213
214 # Convert plaintext to (ints ^ key)
215 t = [(_compact_word(plaintext[4 * i:4 * i + 4]) ^ self._Ke[0][i]) for i in xrange(0, 4)]
216
217 # Apply round transforms
218 for r in xrange(1, rounds):
219 for i in xrange(0, 4):
220 a[i] = (self.T1[(t[ i ] >> 24) & 0xFF] ^
221 self.T2[(t[(i + s1) % 4] >> 16) & 0xFF] ^
222 self.T3[(t[(i + s2) % 4] >> 8) & 0xFF] ^
223 self.T4[ t[(i + s3) % 4] & 0xFF] ^
224 self._Ke[r][i])
225 t = copy.copy(a)
226
227 # The last round is special
228 result = [ ]
229 for i in xrange(0, 4):
230 tt = self._Ke[rounds][i]
231 result.append((self.S[(t[ i ] >> 24) & 0xFF] ^ (tt >> 24)) & 0xFF)
232 result.append((self.S[(t[(i + s1) % 4] >> 16) & 0xFF] ^ (tt >> 16)) & 0xFF)
233 result.append((self.S[(t[(i + s2) % 4] >> 8) & 0xFF] ^ (tt >> 8)) & 0xFF)
234 result.append((self.S[ t[(i + s3) % 4] & 0xFF] ^ tt ) & 0xFF)
235
236 return result
237
238 def decrypt(self, ciphertext):
239 'Decrypt a block of cipher text using the AES block cipher.'
240
241 if len(ciphertext) != 16:
242 raise ValueError('wrong block length')
243
244 rounds = len(self._Kd) - 1
245 (s1, s2, s3) = [3, 2, 1]
246 a = [0, 0, 0, 0]
247
248 # Convert ciphertext to (ints ^ key)
249 t = [(_compact_word(ciphertext[4 * i:4 * i + 4]) ^ self._Kd[0][i]) for i in xrange(0, 4)]
250
251 # Apply round transforms
252 for r in xrange(1, rounds):
253 for i in xrange(0, 4):
254 a[i] = (self.T5[(t[ i ] >> 24) & 0xFF] ^
255 self.T6[(t[(i + s1) % 4] >> 16) & 0xFF] ^
256 self.T7[(t[(i + s2) % 4] >> 8) & 0xFF] ^
257 self.T8[ t[(i + s3) % 4] & 0xFF] ^
258 self._Kd[r][i])
259 t = copy.copy(a)
260
261 # The last round is special
262 result = [ ]
263 for i in xrange(0, 4):
264 tt = self._Kd[rounds][i]
265 result.append((self.Si[(t[ i ] >> 24) & 0xFF] ^ (tt >> 24)) & 0xFF)
266 result.append((self.Si[(t[(i + s1) % 4] >> 16) & 0xFF] ^ (tt >> 16)) & 0xFF)
267 result.append((self.Si[(t[(i + s2) % 4] >> 8) & 0xFF] ^ (tt >> 8)) & 0xFF)
268 result.append((self.Si[ t[(i + s3) % 4] & 0xFF] ^ tt ) & 0xFF)
269
270 return result
271
272
273 class Counter(object):
274 '''A counter object for the Counter (CTR) mode of operation.
275
276 To create a custom counter, you can usually just override the
277 increment method.'''
278
279 def __init__(self, initial_value = 1):
280
281 # Convert the value into an array of bytes long
282 self._counter = [ ((initial_value >> i) % 256) for i in xrange(128 - 8, -1, -8) ]
283
284 value = property(lambda s: s._counter)
285
286 def increment(self):
287 '''Increment the counter (overflow rolls back to 0).'''
288
289 for i in xrange(len(self._counter) - 1, -1, -1):
290 self._counter[i] += 1
291
292 if self._counter[i] < 256: break
293
294 # Carry the one
295 self._counter[i] = 0
296
297 # Overflow
298 else:
299 self._counter = [ 0 ] * len(self._counter)
300
301
302 class AESBlockModeOfOperation(object):
303 '''Super-class for AES modes of operation that require blocks.'''
304 def __init__(self, key):
305 self._aes = AES(key)
306
307 def decrypt(self, ciphertext):
308 raise Exception('not implemented')
309
310 def encrypt(self, plaintext):
311 raise Exception('not implemented')
312
313
314 class AESStreamModeOfOperation(AESBlockModeOfOperation):
315 '''Super-class for AES modes of operation that are stream-ciphers.'''
316
317 class AESSegmentModeOfOperation(AESStreamModeOfOperation):
318 '''Super-class for AES modes of operation that segment data.'''
319
320 segment_bytes = 16
321
322
323
324 class AESModeOfOperationECB(AESBlockModeOfOperation):
325 '''AES Electronic Codebook Mode of Operation.
326
327 o Block-cipher, so data must be padded to 16 byte boundaries
328
329 Security Notes:
330 o This mode is not recommended
331 o Any two identical blocks produce identical encrypted values,
332 exposing data patterns. (See the image of Tux on wikipedia)
333
334 Also see:
335 o https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Electronic_codebook_.28ECB.29
336 o See NIST SP800-38A (http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf); section 6.1'''
337
338
339 name = "Electronic Codebook (ECB)"
340
341 def encrypt(self, plaintext):
342 if len(plaintext) != 16:
343 raise ValueError('plaintext block must be 16 bytes')
344
345 plaintext = _string_to_bytes(plaintext)
346 return _bytes_to_string(self._aes.encrypt(plaintext))
347
348 def decrypt(self, ciphertext):
349 if len(ciphertext) != 16:
350 raise ValueError('ciphertext block must be 16 bytes')
351
352 ciphertext = _string_to_bytes(ciphertext)
353 return _bytes_to_string(self._aes.decrypt(ciphertext))
354
355
356
357 class AESModeOfOperationCBC(AESBlockModeOfOperation):
358 '''AES Cipher-Block Chaining Mode of Operation.
359
360 o The Initialization Vector (IV)
361 o Block-cipher, so data must be padded to 16 byte boundaries
362 o An incorrect initialization vector will only cause the first
363 block to be corrupt; all other blocks will be intact
364 o A corrupt bit in the cipher text will cause a block to be
365 corrupted, and the next block to be inverted, but all other
366 blocks will be intact.
367
368 Security Notes:
369 o This method (and CTR) ARE recommended.
370
371 Also see:
372 o https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher-block_chaining_.28CBC.29
373 o See NIST SP800-38A (http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf); section 6.2'''
374
375
376 name = "Cipher-Block Chaining (CBC)"
377
378 def __init__(self, key, iv = None):
379 if iv is None:
380 self._last_cipherblock = [ 0 ] * 16
381 elif len(iv) != 16:
382 raise ValueError('initialization vector must be 16 bytes')
383 else:
384 self._last_cipherblock = _string_to_bytes(iv)
385
386 AESBlockModeOfOperation.__init__(self, key)
387
388 def encrypt(self, plaintext):
389 if len(plaintext) != 16:
390 raise ValueError('plaintext block must be 16 bytes')
391
392 plaintext = _string_to_bytes(plaintext)
393 precipherblock = [ (p ^ l) for (p, l) in zip(plaintext, self._last_cipherblock) ]
394 self._last_cipherblock = self._aes.encrypt(precipherblock)
395
396 return _bytes_to_string(self._last_cipherblock)
397
398 def decrypt(self, ciphertext):
399 if len(ciphertext) != 16:
400 raise ValueError('ciphertext block must be 16 bytes')
401
402 cipherblock = _string_to_bytes(ciphertext)
403 plaintext = [ (p ^ l) for (p, l) in zip(self._aes.decrypt(cipherblock), self._last_cipherblock) ]
404 self._last_cipherblock = cipherblock
405
406 return _bytes_to_string(plaintext)
407
408
409
410 class AESModeOfOperationCFB(AESSegmentModeOfOperation):
411 '''AES Cipher Feedback Mode of Operation.
412
413 o A stream-cipher, so input does not need to be padded to blocks,
414 but does need to be padded to segment_size
415
416 Also see:
417 o https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher_feedback_.28CFB.29
418 o See NIST SP800-38A (http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf); section 6.3'''
419
420
421 name = "Cipher Feedback (CFB)"
422
423 def __init__(self, key, iv, segment_size = 1):
424 if segment_size == 0: segment_size = 1
425
426 if iv is None:
427 self._shift_register = [ 0 ] * 16
428 elif len(iv) != 16:
429 raise ValueError('initialization vector must be 16 bytes')
430 else:
431 self._shift_register = _string_to_bytes(iv)
432
433 self._segment_bytes = segment_size
434
435 AESBlockModeOfOperation.__init__(self, key)
436
437 segment_bytes = property(lambda s: s._segment_bytes)
438
439 def encrypt(self, plaintext):
440 if len(plaintext) % self._segment_bytes != 0:
441 raise ValueError('plaintext block must be a multiple of segment_size')
442
443 plaintext = _string_to_bytes(plaintext)
444
445 # Break block into segments
446 encrypted = [ ]
447 for i in xrange(0, len(plaintext), self._segment_bytes):
448 plaintext_segment = plaintext[i: i + self._segment_bytes]
449 xor_segment = self._aes.encrypt(self._shift_register)[:len(plaintext_segment)]
450 cipher_segment = [ (p ^ x) for (p, x) in zip(plaintext_segment, xor_segment) ]
451
452 # Shift the top bits out and the ciphertext in
453 self._shift_register = _concat_list(self._shift_register[len(cipher_segment):], cipher_segment)
454
455 encrypted.extend(cipher_segment)
456
457 return _bytes_to_string(encrypted)
458
459 def decrypt(self, ciphertext):
460 if len(ciphertext) % self._segment_bytes != 0:
461 raise ValueError('ciphertext block must be a multiple of segment_size')
462
463 ciphertext = _string_to_bytes(ciphertext)
464
465 # Break block into segments
466 decrypted = [ ]
467 for i in xrange(0, len(ciphertext), self._segment_bytes):
468 cipher_segment = ciphertext[i: i + self._segment_bytes]
469 xor_segment = self._aes.encrypt(self._shift_register)[:len(cipher_segment)]
470 plaintext_segment = [ (p ^ x) for (p, x) in zip(cipher_segment, xor_segment) ]
471
472 # Shift the top bits out and the ciphertext in
473 self._shift_register = _concat_list(self._shift_register[len(cipher_segment):], cipher_segment)
474
475 decrypted.extend(plaintext_segment)
476
477 return _bytes_to_string(decrypted)
478
479
480
481 class AESModeOfOperationOFB(AESStreamModeOfOperation):
482 '''AES Output Feedback Mode of Operation.
483
484 o A stream-cipher, so input does not need to be padded to blocks,
485 allowing arbitrary length data.
486 o A bit twiddled in the cipher text, twiddles the same bit in the
487 same bit in the plain text, which can be useful for error
488 correction techniques.
489
490 Also see:
491 o https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Output_feedback_.28OFB.29
492 o See NIST SP800-38A (http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf); section 6.4'''
493
494
495 name = "Output Feedback (OFB)"
496
497 def __init__(self, key, iv = None):
498 if iv is None:
499 self._last_precipherblock = [ 0 ] * 16
500 elif len(iv) != 16:
501 raise ValueError('initialization vector must be 16 bytes')
502 else:
503 self._last_precipherblock = _string_to_bytes(iv)
504
505 self._remaining_block = [ ]
506
507 AESBlockModeOfOperation.__init__(self, key)
508
509 def encrypt(self, plaintext):
510 encrypted = [ ]
511 for p in _string_to_bytes(plaintext):
512 if len(self._remaining_block) == 0:
513 self._remaining_block = self._aes.encrypt(self._last_precipherblock)
514 self._last_precipherblock = [ ]
515 precipherbyte = self._remaining_block.pop(0)
516 self._last_precipherblock.append(precipherbyte)
517 cipherbyte = p ^ precipherbyte
518 encrypted.append(cipherbyte)
519
520 return _bytes_to_string(encrypted)
521
522 def decrypt(self, ciphertext):
523 # AES-OFB is symetric
524 return self.encrypt(ciphertext)
525
526
527
528 class AESModeOfOperationCTR(AESStreamModeOfOperation):
529 '''AES Counter Mode of Operation.
530
531 o A stream-cipher, so input does not need to be padded to blocks,
532 allowing arbitrary length data.
533 o The counter must be the same size as the key size (ie. len(key))
534 o Each block independant of the other, so a corrupt byte will not
535 damage future blocks.
536 o Each block has a uniue counter value associated with it, which
537 contributes to the encrypted value, so no data patterns are
538 leaked.
539 o Also known as: Counter Mode (CM), Integer Counter Mode (ICM) and
540 Segmented Integer Counter (SIC
541
542 Security Notes:
543 o This method (and CBC) ARE recommended.
544 o Each message block is associated with a counter value which must be
545 unique for ALL messages with the same key. Otherwise security may be
546 compromised.
547
548 Also see:
549
550 o https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Counter_.28CTR.29
551 o See NIST SP800-38A (http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf); section 6.5
552 and Appendix B for managing the initial counter'''
553
554
555 name = "Counter (CTR)"
556
557 def __init__(self, key, counter = None):
558 AESBlockModeOfOperation.__init__(self, key)
559
560 if counter is None:
561 counter = Counter()
562
563 self._counter = counter
564 self._remaining_counter = [ ]
565
566 def encrypt(self, plaintext):
567 while len(self._remaining_counter) < len(plaintext):
568 self._remaining_counter += self._aes.encrypt(self._counter.value)
569 self._counter.increment()
570
571 plaintext = _string_to_bytes(plaintext)
572
573 encrypted = [ (p ^ c) for (p, c) in zip(plaintext, self._remaining_counter) ]
574 self._remaining_counter = self._remaining_counter[len(encrypted):]
575
576 return _bytes_to_string(encrypted)
577
578 def decrypt(self, crypttext):
579 # AES-CTR is symetric
580 return self.encrypt(crypttext)
581
582
583 # Simple lookup table for each mode
584 AESModesOfOperation = dict(
585 ctr = AESModeOfOperationCTR,
586 cbc = AESModeOfOperationCBC,
587 cfb = AESModeOfOperationCFB,
588 ecb = AESModeOfOperationECB,
589 ofb = AESModeOfOperationOFB,
590 )
+0
-54
msldap/crypto/pure/AES/__init__.py less more
0 #https://raw.githubusercontent.com/ricmoo/pyaes/master/pyaes/__init__.py
1 # The MIT License (MIT)
2 #
3 # Copyright (c) 2014 Richard Moore
4 #
5 # Permission is hereby granted, free of charge, to any person obtaining a copy
6 # of this software and associated documentation files (the "Software"), to deal
7 # in the Software without restriction, including without limitation the rights
8 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 # copies of the Software, and to permit persons to whom the Software is
10 # furnished to do so, subject to the following conditions:
11 #
12 # The above copyright notice and this permission notice shall be included in
13 # all copies or substantial portions of the Software.
14 #
15 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 # THE SOFTWARE.
22
23 # This is a pure-Python implementation of the AES algorithm and AES common
24 # modes of operation.
25
26 # See: https://en.wikipedia.org/wiki/Advanced_Encryption_Standard
27 # See: https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation
28
29
30 # Supported key sizes:
31 # 128-bit
32 # 192-bit
33 # 256-bit
34
35
36 # Supported modes of operation:
37 # ECB - Electronic Codebook
38 # CBC - Cipher-Block Chaining
39 # CFB - Cipher Feedback
40 # OFB - Output Feedback
41 # CTR - Counter
42
43 # See the README.md for API details and general information.
44
45 # Also useful, PyCrypto, a crypto library implemented in C with Python bindings:
46 # https://www.dlitz.net/software/pycrypto/
47
48
49 VERSION = [1, 3, 0]
50
51 from .AES import AES, AESModeOfOperationCTR, AESModeOfOperationCBC, AESModeOfOperationCFB, AESModeOfOperationECB, AESModeOfOperationOFB, AESModesOfOperation, Counter
52 from .blockfeeder import decrypt_stream, Decrypter, encrypt_stream, Encrypter
53 from .blockfeeder import PADDING_NONE, PADDING_DEFAULT
+0
-229
msldap/crypto/pure/AES/blockfeeder.py less more
0
1 #https://github.com/ricmoo/pyaes/blob/master/pyaes/blockfeeder.py
2 # The MIT License (MIT)
3 #
4 # Copyright (c) 2014 Richard Moore
5 #
6 # Permission is hereby granted, free of charge, to any person obtaining a copy
7 # of this software and associated documentation files (the "Software"), to deal
8 # in the Software without restriction, including without limitation the rights
9 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 # copies of the Software, and to permit persons to whom the Software is
11 # furnished to do so, subject to the following conditions:
12 #
13 # The above copyright notice and this permission notice shall be included in
14 # all copies or substantial portions of the Software.
15 #
16 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 # THE SOFTWARE.
23
24
25 from .AES import AESBlockModeOfOperation, AESSegmentModeOfOperation, AESStreamModeOfOperation
26 from .util import append_PKCS7_padding, strip_PKCS7_padding, to_bufferable
27
28
29 # First we inject three functions to each of the modes of operations
30 #
31 # _can_consume(size)
32 # - Given a size, determine how many bytes could be consumed in
33 # a single call to either the decrypt or encrypt method
34 #
35 # _final_encrypt(data, padding = PADDING_DEFAULT)
36 # - call and return encrypt on this (last) chunk of data,
37 # padding as necessary; this will always be at least 16
38 # bytes unless the total incoming input was less than 16
39 # bytes
40 #
41 # _final_decrypt(data, padding = PADDING_DEFAULT)
42 # - same as _final_encrypt except for decrypt, for
43 # stripping off padding
44 #
45
46 PADDING_NONE = 'none'
47 PADDING_DEFAULT = 'default'
48
49 # @TODO: Ciphertext stealing and explicit PKCS#7
50 # PADDING_CIPHERTEXT_STEALING
51 # PADDING_PKCS7
52
53 # ECB and CBC are block-only ciphers
54
55 def _block_can_consume(self, size):
56 if size >= 16: return 16
57 return 0
58
59 # After padding, we may have more than one block
60 def _block_final_encrypt(self, data, padding = PADDING_DEFAULT):
61 if padding == PADDING_DEFAULT:
62 data = append_PKCS7_padding(data)
63
64 elif padding == PADDING_NONE:
65 if len(data) != 16:
66 raise Exception('invalid data length for final block')
67 else:
68 raise Exception('invalid padding option')
69
70 if len(data) == 32:
71 return self.encrypt(data[:16]) + self.encrypt(data[16:])
72
73 return self.encrypt(data)
74
75
76 def _block_final_decrypt(self, data, padding = PADDING_DEFAULT):
77 if padding == PADDING_DEFAULT:
78 return strip_PKCS7_padding(self.decrypt(data))
79
80 if padding == PADDING_NONE:
81 if len(data) != 16:
82 raise Exception('invalid data length for final block')
83 return self.decrypt(data)
84
85 raise Exception('invalid padding option')
86
87 AESBlockModeOfOperation._can_consume = _block_can_consume
88 AESBlockModeOfOperation._final_encrypt = _block_final_encrypt
89 AESBlockModeOfOperation._final_decrypt = _block_final_decrypt
90
91
92
93 # CFB is a segment cipher
94
95 def _segment_can_consume(self, size):
96 return self.segment_bytes * int(size // self.segment_bytes)
97
98 # CFB can handle a non-segment-sized block at the end using the remaining cipherblock
99 def _segment_final_encrypt(self, data, padding = PADDING_DEFAULT):
100 if padding != PADDING_DEFAULT:
101 raise Exception('invalid padding option')
102
103 faux_padding = (chr(0) * (self.segment_bytes - (len(data) % self.segment_bytes)))
104 padded = data + to_bufferable(faux_padding)
105 return self.encrypt(padded)[:len(data)]
106
107 # CFB can handle a non-segment-sized block at the end using the remaining cipherblock
108 def _segment_final_decrypt(self, data, padding = PADDING_DEFAULT):
109 if padding != PADDING_DEFAULT:
110 raise Exception('invalid padding option')
111
112 faux_padding = (chr(0) * (self.segment_bytes - (len(data) % self.segment_bytes)))
113 padded = data + to_bufferable(faux_padding)
114 return self.decrypt(padded)[:len(data)]
115
116 AESSegmentModeOfOperation._can_consume = _segment_can_consume
117 AESSegmentModeOfOperation._final_encrypt = _segment_final_encrypt
118 AESSegmentModeOfOperation._final_decrypt = _segment_final_decrypt
119
120
121
122 # OFB and CTR are stream ciphers
123
124 def _stream_can_consume(self, size):
125 return size
126
127 def _stream_final_encrypt(self, data, padding = PADDING_DEFAULT):
128 if padding not in [PADDING_NONE, PADDING_DEFAULT]:
129 raise Exception('invalid padding option')
130
131 return self.encrypt(data)
132
133 def _stream_final_decrypt(self, data, padding = PADDING_DEFAULT):
134 if padding not in [PADDING_NONE, PADDING_DEFAULT]:
135 raise Exception('invalid padding option')
136
137 return self.decrypt(data)
138
139 AESStreamModeOfOperation._can_consume = _stream_can_consume
140 AESStreamModeOfOperation._final_encrypt = _stream_final_encrypt
141 AESStreamModeOfOperation._final_decrypt = _stream_final_decrypt
142
143
144
145 class BlockFeeder(object):
146 '''The super-class for objects to handle chunking a stream of bytes
147 into the appropriate block size for the underlying mode of operation
148 and applying (or stripping) padding, as necessary.'''
149
150 def __init__(self, mode, feed, final, padding = PADDING_DEFAULT):
151 self._mode = mode
152 self._feed = feed
153 self._final = final
154 self._buffer = to_bufferable("")
155 self._padding = padding
156
157 def feed(self, data = None):
158 '''Provide bytes to encrypt (or decrypt), returning any bytes
159 possible from this or any previous calls to feed.
160
161 Call with None or an empty string to flush the mode of
162 operation and return any final bytes; no further calls to
163 feed may be made.'''
164
165 if self._buffer is None:
166 raise ValueError('already finished feeder')
167
168 # Finalize; process the spare bytes we were keeping
169 if data is None:
170 result = self._final(self._buffer, self._padding)
171 self._buffer = None
172 return result
173
174 self._buffer += to_bufferable(data)
175
176 # We keep 16 bytes around so we can determine padding
177 result = to_bufferable('')
178 while len(self._buffer) > 16:
179 can_consume = self._mode._can_consume(len(self._buffer) - 16)
180 if can_consume == 0: break
181 result += self._feed(self._buffer[:can_consume])
182 self._buffer = self._buffer[can_consume:]
183
184 return result
185
186
187 class Encrypter(BlockFeeder):
188 'Accepts bytes of plaintext and returns encrypted ciphertext.'
189
190 def __init__(self, mode, padding = PADDING_DEFAULT):
191 BlockFeeder.__init__(self, mode, mode.encrypt, mode._final_encrypt, padding)
192
193
194 class Decrypter(BlockFeeder):
195 'Accepts bytes of ciphertext and returns decrypted plaintext.'
196
197 def __init__(self, mode, padding = PADDING_DEFAULT):
198 BlockFeeder.__init__(self, mode, mode.decrypt, mode._final_decrypt, padding)
199
200
201 # 8kb blocks
202 BLOCK_SIZE = (1 << 13)
203
204 def _feed_stream(feeder, in_stream, out_stream, block_size = BLOCK_SIZE):
205 'Uses feeder to read and convert from in_stream and write to out_stream.'
206
207 while True:
208 chunk = in_stream.read(block_size)
209 if not chunk:
210 break
211 converted = feeder.feed(chunk)
212 out_stream.write(converted)
213 converted = feeder.feed()
214 out_stream.write(converted)
215
216
217 def encrypt_stream(mode, in_stream, out_stream, block_size = BLOCK_SIZE, padding = PADDING_DEFAULT):
218 'Encrypts a stream of bytes from in_stream to out_stream using mode.'
219
220 encrypter = Encrypter(mode, padding = padding)
221 _feed_stream(encrypter, in_stream, out_stream, block_size)
222
223
224 def decrypt_stream(mode, in_stream, out_stream, block_size = BLOCK_SIZE, padding = PADDING_DEFAULT):
225 'Decrypts a stream of bytes from in_stream to out_stream using mode.'
226
227 decrypter = Decrypter(mode, padding = padding)
228 _feed_stream(decrypter, in_stream, out_stream, block_size)
+0
-62
msldap/crypto/pure/AES/util.py less more
0
1 #https://github.com/ricmoo/pyaes/blob/master/pyaes/util.py
2 # The MIT License (MIT)
3 #
4 # Copyright (c) 2014 Richard Moore
5 #
6 # Permission is hereby granted, free of charge, to any person obtaining a copy
7 # of this software and associated documentation files (the "Software"), to deal
8 # in the Software without restriction, including without limitation the rights
9 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 # copies of the Software, and to permit persons to whom the Software is
11 # furnished to do so, subject to the following conditions:
12 #
13 # The above copyright notice and this permission notice shall be included in
14 # all copies or substantial portions of the Software.
15 #
16 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 # THE SOFTWARE.
23
24 # Why to_bufferable?
25 # Python 3 is very different from Python 2.x when it comes to strings of text
26 # and strings of bytes; in Python 3, strings of bytes do not exist, instead to
27 # represent arbitrary binary data, we must use the "bytes" object. This method
28 # ensures the object behaves as we need it to.
29
30 def to_bufferable(binary):
31 return binary
32
33 def _get_byte(c):
34 return ord(c)
35
36 try:
37 xrange
38 except:
39
40 def to_bufferable(binary):
41 if isinstance(binary, bytes):
42 return binary
43 return bytes(ord(b) for b in binary)
44
45 def _get_byte(c):
46 return c
47
48 def append_PKCS7_padding(data):
49 pad = 16 - (len(data) % 16)
50 return data + to_bufferable(chr(pad) * pad)
51
52 def strip_PKCS7_padding(data):
53 if len(data) % 16 != 0:
54 raise ValueError("invalid length")
55
56 pad = _get_byte(data[-1])
57
58 if pad > 16:
59 raise ValueError("invalid padding byte")
60
61 return data[:-pad]
+0
-852
msldap/crypto/pure/DES/DES.py less more
0 #############################################################################
1 # Documentation #
2 #############################################################################
3
4 # Author: Todd Whiteman
5 # Date: 28th April, 2010
6 # Version: 2.0.1
7 # License: MIT
8 # Homepage: http://twhiteman.netfirms.com/des.html
9 #
10 # This is a pure python implementation of the DES encryption algorithm.
11 # It's pure python to avoid portability issues, since most DES
12 # implementations are programmed in C (for performance reasons).
13 #
14 # Triple DES class is also implemented, utilizing the DES base. Triple DES
15 # is either DES-EDE3 with a 24 byte key, or DES-EDE2 with a 16 byte key.
16 #
17 # See the README.txt that should come with this python module for the
18 # implementation methods used.
19 #
20 # Thanks to:
21 # * David Broadwell for ideas, comments and suggestions.
22 # * Mario Wolff for pointing out and debugging some triple des CBC errors.
23 # * Santiago Palladino for providing the PKCS5 padding technique.
24 # * Shaya for correcting the PAD_PKCS5 triple des CBC errors.
25 #
26 """A pure python implementation of the DES and TRIPLE DES encryption algorithms.
27
28 Class initialization
29 --------------------
30 pyDes.des(key, [mode], [IV], [pad], [padmode])
31 pyDes.triple_des(key, [mode], [IV], [pad], [padmode])
32
33 key -> Bytes containing the encryption key. 8 bytes for DES, 16 or 24 bytes
34 for Triple DES
35 mode -> Optional argument for encryption type, can be either
36 pyDes.ECB (Electronic Code Book) or pyDes.CBC (Cypher Block Chaining)
37 IV -> Optional Initial Value bytes, must be supplied if using CBC mode.
38 Length must be 8 bytes.
39 pad -> Optional argument, set the pad character (PAD_NORMAL) to use during
40 all encrypt/decrypt operations done with this instance.
41 padmode -> Optional argument, set the padding mode (PAD_NORMAL or PAD_PKCS5)
42 to use during all encrypt/decrypt operations done with this instance.
43
44 I recommend to use PAD_PKCS5 padding, as then you never need to worry about any
45 padding issues, as the padding can be removed unambiguously upon decrypting
46 data that was encrypted using PAD_PKCS5 padmode.
47
48 Common methods
49 --------------
50 encrypt(data, [pad], [padmode])
51 decrypt(data, [pad], [padmode])
52
53 data -> Bytes to be encrypted/decrypted
54 pad -> Optional argument. Only when using padmode of PAD_NORMAL. For
55 encryption, adds this characters to the end of the data block when
56 data is not a multiple of 8 bytes. For decryption, will remove the
57 trailing characters that match this pad character from the last 8
58 bytes of the unencrypted data block.
59 padmode -> Optional argument, set the padding mode, must be one of PAD_NORMAL
60 or PAD_PKCS5). Defaults to PAD_NORMAL.
61
62
63 Example
64 -------
65 from pyDes import *
66
67 data = "Please encrypt my data"
68 k = des("DESCRYPT", CBC, "\0\0\0\0\0\0\0\0", pad=None, padmode=PAD_PKCS5)
69 # For Python3, you'll need to use bytes, i.e.:
70 # data = b"Please encrypt my data"
71 # k = des(b"DESCRYPT", CBC, b"\0\0\0\0\0\0\0\0", pad=None, padmode=PAD_PKCS5)
72 d = k.encrypt(data)
73 print "Encrypted: %r" % d
74 print "Decrypted: %r" % k.decrypt(d)
75 assert k.decrypt(d, padmode=PAD_PKCS5) == data
76
77
78 See the module source (pyDes.py) for more examples of use.
79 You can also run the pyDes.py file without and arguments to see a simple test.
80
81 Note: This code was not written for high-end systems needing a fast
82 implementation, but rather a handy portable solution with small usage.
83
84 """
85
86 import sys
87
88 # _pythonMajorVersion is used to handle Python2 and Python3 differences.
89 _pythonMajorVersion = sys.version_info[0]
90
91 # Modes of crypting / cyphering
92 ECB = 0
93 CBC = 1
94
95 # Modes of padding
96 PAD_NORMAL = 1
97 PAD_PKCS5 = 2
98
99 # PAD_PKCS5: is a method that will unambiguously remove all padding
100 # characters after decryption, when originally encrypted with
101 # this padding mode.
102 # For a good description of the PKCS5 padding technique, see:
103 # http://www.faqs.org/rfcs/rfc1423.html
104
105 # The base class shared by des and triple des.
106 class _baseDes(object):
107 def __init__(self, mode=ECB, IV=None, pad=None, padmode=PAD_NORMAL):
108 if IV:
109 IV = self._guardAgainstUnicode(IV)
110 if pad:
111 pad = self._guardAgainstUnicode(pad)
112 self.block_size = 8
113 # Sanity checking of arguments.
114 if pad and padmode == PAD_PKCS5:
115 raise ValueError("Cannot use a pad character with PAD_PKCS5")
116 if IV and len(IV) != self.block_size:
117 raise ValueError("Invalid Initial Value (IV), must be a multiple of " + str(self.block_size) + " bytes")
118
119 # Set the passed in variables
120 self._mode = mode
121 self._iv = IV
122 self._padding = pad
123 self._padmode = padmode
124
125 def getKey(self):
126 """getKey() -> bytes"""
127 return self.__key
128
129 def setKey(self, key):
130 """Will set the crypting key for this object."""
131 key = self._guardAgainstUnicode(key)
132 self.__key = key
133
134 def getMode(self):
135 """getMode() -> pyDes.ECB or pyDes.CBC"""
136 return self._mode
137
138 def setMode(self, mode):
139 """Sets the type of crypting mode, pyDes.ECB or pyDes.CBC"""
140 self._mode = mode
141
142 def getPadding(self):
143 """getPadding() -> bytes of length 1. Padding character."""
144 return self._padding
145
146 def setPadding(self, pad):
147 """setPadding() -> bytes of length 1. Padding character."""
148 if pad is not None:
149 pad = self._guardAgainstUnicode(pad)
150 self._padding = pad
151
152 def getPadMode(self):
153 """getPadMode() -> pyDes.PAD_NORMAL or pyDes.PAD_PKCS5"""
154 return self._padmode
155
156 def setPadMode(self, mode):
157 """Sets the type of padding mode, pyDes.PAD_NORMAL or pyDes.PAD_PKCS5"""
158 self._padmode = mode
159
160 def getIV(self):
161 """getIV() -> bytes"""
162 return self._iv
163
164 def setIV(self, IV):
165 """Will set the Initial Value, used in conjunction with CBC mode"""
166 if not IV or len(IV) != self.block_size:
167 raise ValueError("Invalid Initial Value (IV), must be a multiple of " + str(self.block_size) + " bytes")
168 IV = self._guardAgainstUnicode(IV)
169 self._iv = IV
170
171 def _padData(self, data, pad, padmode):
172 # Pad data depending on the mode
173 if padmode is None:
174 # Get the default padding mode.
175 padmode = self.getPadMode()
176 if pad and padmode == PAD_PKCS5:
177 raise ValueError("Cannot use a pad character with PAD_PKCS5")
178
179 if padmode == PAD_NORMAL:
180 if len(data) % self.block_size == 0:
181 # No padding required.
182 return data
183
184 if not pad:
185 # Get the default padding.
186 pad = self.getPadding()
187 if not pad:
188 raise ValueError("Data must be a multiple of " + str(self.block_size) + " bytes in length. Use padmode=PAD_PKCS5 or set the pad character.")
189 data += (self.block_size - (len(data) % self.block_size)) * pad
190
191 elif padmode == PAD_PKCS5:
192 pad_len = 8 - (len(data) % self.block_size)
193 if _pythonMajorVersion < 3:
194 data += pad_len * chr(pad_len)
195 else:
196 data += bytes([pad_len] * pad_len)
197
198 return data
199
200 def _unpadData(self, data, pad, padmode):
201 # Unpad data depending on the mode.
202 if not data:
203 return data
204 if pad and padmode == PAD_PKCS5:
205 raise ValueError("Cannot use a pad character with PAD_PKCS5")
206 if padmode is None:
207 # Get the default padding mode.
208 padmode = self.getPadMode()
209
210 if padmode == PAD_NORMAL:
211 if not pad:
212 # Get the default padding.
213 pad = self.getPadding()
214 if pad:
215 data = data[:-self.block_size] + \
216 data[-self.block_size:].rstrip(pad)
217
218 elif padmode == PAD_PKCS5:
219 if _pythonMajorVersion < 3:
220 pad_len = ord(data[-1])
221 else:
222 pad_len = data[-1]
223 data = data[:-pad_len]
224
225 return data
226
227 def _guardAgainstUnicode(self, data):
228 # Only accept byte strings or ascii unicode values, otherwise
229 # there is no way to correctly decode the data into bytes.
230 if _pythonMajorVersion < 3:
231 if isinstance(data, unicode):
232 raise ValueError("pyDes can only work with bytes, not Unicode strings.")
233 else:
234 if isinstance(data, str):
235 # Only accept ascii unicode values.
236 try:
237 return data.encode('ascii')
238 except UnicodeEncodeError:
239 pass
240 raise ValueError("pyDes can only work with encoded strings, not Unicode.")
241 return data
242
243 #############################################################################
244 # DES #
245 #############################################################################
246 class des(_baseDes):
247 """DES encryption/decrytpion class
248
249 Supports ECB (Electronic Code Book) and CBC (Cypher Block Chaining) modes.
250
251 pyDes.des(key,[mode], [IV])
252
253 key -> Bytes containing the encryption key, must be exactly 8 bytes
254 mode -> Optional argument for encryption type, can be either pyDes.ECB
255 (Electronic Code Book), pyDes.CBC (Cypher Block Chaining)
256 IV -> Optional Initial Value bytes, must be supplied if using CBC mode.
257 Must be 8 bytes in length.
258 pad -> Optional argument, set the pad character (PAD_NORMAL) to use
259 during all encrypt/decrypt operations done with this instance.
260 padmode -> Optional argument, set the padding mode (PAD_NORMAL or
261 PAD_PKCS5) to use during all encrypt/decrypt operations done
262 with this instance.
263 """
264
265
266 # Permutation and translation tables for DES
267 __pc1 = [56, 48, 40, 32, 24, 16, 8,
268 0, 57, 49, 41, 33, 25, 17,
269 9, 1, 58, 50, 42, 34, 26,
270 18, 10, 2, 59, 51, 43, 35,
271 62, 54, 46, 38, 30, 22, 14,
272 6, 61, 53, 45, 37, 29, 21,
273 13, 5, 60, 52, 44, 36, 28,
274 20, 12, 4, 27, 19, 11, 3
275 ]
276
277 # number left rotations of pc1
278 __left_rotations = [
279 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1
280 ]
281
282 # permuted choice key (table 2)
283 __pc2 = [
284 13, 16, 10, 23, 0, 4,
285 2, 27, 14, 5, 20, 9,
286 22, 18, 11, 3, 25, 7,
287 15, 6, 26, 19, 12, 1,
288 40, 51, 30, 36, 46, 54,
289 29, 39, 50, 44, 32, 47,
290 43, 48, 38, 55, 33, 52,
291 45, 41, 49, 35, 28, 31
292 ]
293
294 # initial permutation IP
295 __ip = [57, 49, 41, 33, 25, 17, 9, 1,
296 59, 51, 43, 35, 27, 19, 11, 3,
297 61, 53, 45, 37, 29, 21, 13, 5,
298 63, 55, 47, 39, 31, 23, 15, 7,
299 56, 48, 40, 32, 24, 16, 8, 0,
300 58, 50, 42, 34, 26, 18, 10, 2,
301 60, 52, 44, 36, 28, 20, 12, 4,
302 62, 54, 46, 38, 30, 22, 14, 6
303 ]
304
305 # Expansion table for turning 32 bit blocks into 48 bits
306 __expansion_table = [
307 31, 0, 1, 2, 3, 4,
308 3, 4, 5, 6, 7, 8,
309 7, 8, 9, 10, 11, 12,
310 11, 12, 13, 14, 15, 16,
311 15, 16, 17, 18, 19, 20,
312 19, 20, 21, 22, 23, 24,
313 23, 24, 25, 26, 27, 28,
314 27, 28, 29, 30, 31, 0
315 ]
316
317 # The (in)famous S-boxes
318 __sbox = [
319 # S1
320 [14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7,
321 0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8,
322 4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0,
323 15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13],
324
325 # S2
326 [15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10,
327 3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5,
328 0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15,
329 13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9],
330
331 # S3
332 [10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8,
333 13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1,
334 13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7,
335 1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12],
336
337 # S4
338 [7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15,
339 13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9,
340 10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4,
341 3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14],
342
343 # S5
344 [2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9,
345 14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6,
346 4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14,
347 11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3],
348
349 # S6
350 [12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11,
351 10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8,
352 9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6,
353 4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13],
354
355 # S7
356 [4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1,
357 13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6,
358 1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2,
359 6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12],
360
361 # S8
362 [13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7,
363 1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2,
364 7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8,
365 2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11],
366 ]
367
368
369 # 32-bit permutation function P used on the output of the S-boxes
370 __p = [
371 15, 6, 19, 20, 28, 11,
372 27, 16, 0, 14, 22, 25,
373 4, 17, 30, 9, 1, 7,
374 23,13, 31, 26, 2, 8,
375 18, 12, 29, 5, 21, 10,
376 3, 24
377 ]
378
379 # final permutation IP^-1
380 __fp = [
381 39, 7, 47, 15, 55, 23, 63, 31,
382 38, 6, 46, 14, 54, 22, 62, 30,
383 37, 5, 45, 13, 53, 21, 61, 29,
384 36, 4, 44, 12, 52, 20, 60, 28,
385 35, 3, 43, 11, 51, 19, 59, 27,
386 34, 2, 42, 10, 50, 18, 58, 26,
387 33, 1, 41, 9, 49, 17, 57, 25,
388 32, 0, 40, 8, 48, 16, 56, 24
389 ]
390
391 # Type of crypting being done
392 ENCRYPT = 0x00
393 DECRYPT = 0x01
394
395 # Initialisation
396 def __init__(self, key, mode=ECB, IV=None, pad=None, padmode=PAD_NORMAL):
397 # Sanity checking of arguments.
398 if len(key) != 8:
399 raise ValueError("Invalid DES key size. Key must be exactly 8 bytes long.")
400 _baseDes.__init__(self, mode, IV, pad, padmode)
401 self.key_size = 8
402
403 self.L = []
404 self.R = []
405 self.Kn = [ [0] * 48 ] * 16 # 16 48-bit keys (K1 - K16)
406 self.final = []
407
408 self.setKey(key)
409
410 def setKey(self, key):
411 """Will set the crypting key for this object. Must be 8 bytes."""
412 _baseDes.setKey(self, key)
413 self.__create_sub_keys()
414
415 def __String_to_BitList(self, data):
416 """Turn the string data, into a list of bits (1, 0)'s"""
417 if _pythonMajorVersion < 3:
418 # Turn the strings into integers. Python 3 uses a bytes
419 # class, which already has this behaviour.
420 data = [ord(c) for c in data]
421 l = len(data) * 8
422 result = [0] * l
423 pos = 0
424 for ch in data:
425 i = 7
426 while i >= 0:
427 if ch & (1 << i) != 0:
428 result[pos] = 1
429 else:
430 result[pos] = 0
431 pos += 1
432 i -= 1
433
434 return result
435
436 def __BitList_to_String(self, data):
437 """Turn the list of bits -> data, into a string"""
438 result = []
439 pos = 0
440 c = 0
441 while pos < len(data):
442 c += data[pos] << (7 - (pos % 8))
443 if (pos % 8) == 7:
444 result.append(c)
445 c = 0
446 pos += 1
447
448 if _pythonMajorVersion < 3:
449 return ''.join([ chr(c) for c in result ])
450 else:
451 return bytes(result)
452
453 def __permutate(self, table, block):
454 """Permutate this block with the specified table"""
455 return list(map(lambda x: block[x], table))
456
457 # Transform the secret key, so that it is ready for data processing
458 # Create the 16 subkeys, K[1] - K[16]
459 def __create_sub_keys(self):
460 """Create the 16 subkeys K[1] to K[16] from the given key"""
461 key = self.__permutate(des.__pc1, self.__String_to_BitList(self.getKey()))
462 i = 0
463 # Split into Left and Right sections
464 self.L = key[:28]
465 self.R = key[28:]
466 while i < 16:
467 j = 0
468 # Perform circular left shifts
469 while j < des.__left_rotations[i]:
470 self.L.append(self.L[0])
471 del self.L[0]
472
473 self.R.append(self.R[0])
474 del self.R[0]
475
476 j += 1
477
478 # Create one of the 16 subkeys through pc2 permutation
479 self.Kn[i] = self.__permutate(des.__pc2, self.L + self.R)
480
481 i += 1
482
483 # Main part of the encryption algorithm, the number cruncher :)
484 def __des_crypt(self, block, crypt_type):
485 """Crypt the block of data through DES bit-manipulation"""
486 block = self.__permutate(des.__ip, block)
487 self.L = block[:32]
488 self.R = block[32:]
489
490 # Encryption starts from Kn[1] through to Kn[16]
491 if crypt_type == des.ENCRYPT:
492 iteration = 0
493 iteration_adjustment = 1
494 # Decryption starts from Kn[16] down to Kn[1]
495 else:
496 iteration = 15
497 iteration_adjustment = -1
498
499 i = 0
500 while i < 16:
501 # Make a copy of R[i-1], this will later become L[i]
502 tempR = self.R[:]
503
504 # Permutate R[i - 1] to start creating R[i]
505 self.R = self.__permutate(des.__expansion_table, self.R)
506
507 # Exclusive or R[i - 1] with K[i], create B[1] to B[8] whilst here
508 self.R = list(map(lambda x, y: x ^ y, self.R, self.Kn[iteration]))
509 B = [self.R[:6], self.R[6:12], self.R[12:18], self.R[18:24], self.R[24:30], self.R[30:36], self.R[36:42], self.R[42:]]
510 # Optimization: Replaced below commented code with above
511 #j = 0
512 #B = []
513 #while j < len(self.R):
514 # self.R[j] = self.R[j] ^ self.Kn[iteration][j]
515 # j += 1
516 # if j % 6 == 0:
517 # B.append(self.R[j-6:j])
518
519 # Permutate B[1] to B[8] using the S-Boxes
520 j = 0
521 Bn = [0] * 32
522 pos = 0
523 while j < 8:
524 # Work out the offsets
525 m = (B[j][0] << 1) + B[j][5]
526 n = (B[j][1] << 3) + (B[j][2] << 2) + (B[j][3] << 1) + B[j][4]
527
528 # Find the permutation value
529 v = des.__sbox[j][(m << 4) + n]
530
531 # Turn value into bits, add it to result: Bn
532 Bn[pos] = (v & 8) >> 3
533 Bn[pos + 1] = (v & 4) >> 2
534 Bn[pos + 2] = (v & 2) >> 1
535 Bn[pos + 3] = v & 1
536
537 pos += 4
538 j += 1
539
540 # Permutate the concatination of B[1] to B[8] (Bn)
541 self.R = self.__permutate(des.__p, Bn)
542
543 # Xor with L[i - 1]
544 self.R = list(map(lambda x, y: x ^ y, self.R, self.L))
545 # Optimization: This now replaces the below commented code
546 #j = 0
547 #while j < len(self.R):
548 # self.R[j] = self.R[j] ^ self.L[j]
549 # j += 1
550
551 # L[i] becomes R[i - 1]
552 self.L = tempR
553
554 i += 1
555 iteration += iteration_adjustment
556
557 # Final permutation of R[16]L[16]
558 self.final = self.__permutate(des.__fp, self.R + self.L)
559 return self.final
560
561
562 # Data to be encrypted/decrypted
563 def crypt(self, data, crypt_type):
564 """Crypt the data in blocks, running it through des_crypt()"""
565
566 # Error check the data
567 if not data:
568 return ''
569 if len(data) % self.block_size != 0:
570 if crypt_type == des.DECRYPT: # Decryption must work on 8 byte blocks
571 raise ValueError("Invalid data length, data must be a multiple of " + str(self.block_size) + " bytes\n.")
572 if not self.getPadding():
573 raise ValueError("Invalid data length, data must be a multiple of " + str(self.block_size) + " bytes\n. Try setting the optional padding character")
574 else:
575 data += (self.block_size - (len(data) % self.block_size)) * self.getPadding()
576 # print "Len of data: %f" % (len(data) / self.block_size)
577
578 if self.getMode() == CBC:
579 if self.getIV():
580 iv = self.__String_to_BitList(self.getIV())
581 else:
582 raise ValueError("For CBC mode, you must supply the Initial Value (IV) for ciphering")
583
584 # Split the data into blocks, crypting each one seperately
585 i = 0
586 dict = {}
587 result = []
588 #cached = 0
589 #lines = 0
590 while i < len(data):
591 # Test code for caching encryption results
592 #lines += 1
593 #if dict.has_key(data[i:i+8]):
594 #print "Cached result for: %s" % data[i:i+8]
595 # cached += 1
596 # result.append(dict[data[i:i+8]])
597 # i += 8
598 # continue
599
600 block = self.__String_to_BitList(data[i:i+8])
601
602 # Xor with IV if using CBC mode
603 if self.getMode() == CBC:
604 if crypt_type == des.ENCRYPT:
605 block = list(map(lambda x, y: x ^ y, block, iv))
606 #j = 0
607 #while j < len(block):
608 # block[j] = block[j] ^ iv[j]
609 # j += 1
610
611 processed_block = self.__des_crypt(block, crypt_type)
612
613 if crypt_type == des.DECRYPT:
614 processed_block = list(map(lambda x, y: x ^ y, processed_block, iv))
615 #j = 0
616 #while j < len(processed_block):
617 # processed_block[j] = processed_block[j] ^ iv[j]
618 # j += 1
619 iv = block
620 else:
621 iv = processed_block
622 else:
623 processed_block = self.__des_crypt(block, crypt_type)
624
625
626 # Add the resulting crypted block to our list
627 #d = self.__BitList_to_String(processed_block)
628 #result.append(d)
629 result.append(self.__BitList_to_String(processed_block))
630 #dict[data[i:i+8]] = d
631 i += 8
632
633 # print "Lines: %d, cached: %d" % (lines, cached)
634
635 # Return the full crypted string
636 if _pythonMajorVersion < 3:
637 return ''.join(result)
638 else:
639 return bytes.fromhex('').join(result)
640
641 def encrypt(self, data, pad=None, padmode=None):
642 """encrypt(data, [pad], [padmode]) -> bytes
643
644 data : Bytes to be encrypted
645 pad : Optional argument for encryption padding. Must only be one byte
646 padmode : Optional argument for overriding the padding mode.
647
648 The data must be a multiple of 8 bytes and will be encrypted
649 with the already specified key. Data does not have to be a
650 multiple of 8 bytes if the padding character is supplied, or
651 the padmode is set to PAD_PKCS5, as bytes will then added to
652 ensure the be padded data is a multiple of 8 bytes.
653 """
654 data = self._guardAgainstUnicode(data)
655 if pad is not None:
656 pad = self._guardAgainstUnicode(pad)
657 data = self._padData(data, pad, padmode)
658 return self.crypt(data, des.ENCRYPT)
659
660 def decrypt(self, data, pad=None, padmode=None):
661 """decrypt(data, [pad], [padmode]) -> bytes
662
663 data : Bytes to be decrypted
664 pad : Optional argument for decryption padding. Must only be one byte
665 padmode : Optional argument for overriding the padding mode.
666
667 The data must be a multiple of 8 bytes and will be decrypted
668 with the already specified key. In PAD_NORMAL mode, if the
669 optional padding character is supplied, then the un-encrypted
670 data will have the padding characters removed from the end of
671 the bytes. This pad removal only occurs on the last 8 bytes of
672 the data (last data block). In PAD_PKCS5 mode, the special
673 padding end markers will be removed from the data after decrypting.
674 """
675 data = self._guardAgainstUnicode(data)
676 if pad is not None:
677 pad = self._guardAgainstUnicode(pad)
678 data = self.crypt(data, des.DECRYPT)
679 return self._unpadData(data, pad, padmode)
680
681
682
683 #############################################################################
684 # Triple DES #
685 #############################################################################
686 class triple_des(_baseDes):
687 """Triple DES encryption/decrytpion class
688
689 This algorithm uses the DES-EDE3 (when a 24 byte key is supplied) or
690 the DES-EDE2 (when a 16 byte key is supplied) encryption methods.
691 Supports ECB (Electronic Code Book) and CBC (Cypher Block Chaining) modes.
692
693 pyDes.des(key, [mode], [IV])
694
695 key -> Bytes containing the encryption key, must be either 16 or
696 24 bytes long
697 mode -> Optional argument for encryption type, can be either pyDes.ECB
698 (Electronic Code Book), pyDes.CBC (Cypher Block Chaining)
699 IV -> Optional Initial Value bytes, must be supplied if using CBC mode.
700 Must be 8 bytes in length.
701 pad -> Optional argument, set the pad character (PAD_NORMAL) to use
702 during all encrypt/decrypt operations done with this instance.
703 padmode -> Optional argument, set the padding mode (PAD_NORMAL or
704 PAD_PKCS5) to use during all encrypt/decrypt operations done
705 with this instance.
706 """
707 def __init__(self, key, mode=ECB, IV=None, pad=None, padmode=PAD_NORMAL):
708 _baseDes.__init__(self, mode, IV, pad, padmode)
709 self.setKey(key)
710
711 def setKey(self, key):
712 """Will set the crypting key for this object. Either 16 or 24 bytes long."""
713 self.key_size = 24 # Use DES-EDE3 mode
714 if len(key) != self.key_size:
715 if len(key) == 16: # Use DES-EDE2 mode
716 self.key_size = 16
717 else:
718 raise ValueError("Invalid triple DES key size. Key must be either 16 or 24 bytes long")
719 if self.getMode() == CBC:
720 if not self.getIV():
721 # Use the first 8 bytes of the key
722 self._iv = key[:self.block_size]
723 if len(self.getIV()) != self.block_size:
724 raise ValueError("Invalid IV, must be 8 bytes in length")
725 self.__key1 = des(key[:8], self._mode, self._iv,
726 self._padding, self._padmode)
727 self.__key2 = des(key[8:16], self._mode, self._iv,
728 self._padding, self._padmode)
729 if self.key_size == 16:
730 self.__key3 = self.__key1
731 else:
732 self.__key3 = des(key[16:], self._mode, self._iv,
733 self._padding, self._padmode)
734 _baseDes.setKey(self, key)
735
736 # Override setter methods to work on all 3 keys.
737
738 def setMode(self, mode):
739 """Sets the type of crypting mode, pyDes.ECB or pyDes.CBC"""
740 _baseDes.setMode(self, mode)
741 for key in (self.__key1, self.__key2, self.__key3):
742 key.setMode(mode)
743
744 def setPadding(self, pad):
745 """setPadding() -> bytes of length 1. Padding character."""
746 _baseDes.setPadding(self, pad)
747 for key in (self.__key1, self.__key2, self.__key3):
748 key.setPadding(pad)
749
750 def setPadMode(self, mode):
751 """Sets the type of padding mode, pyDes.PAD_NORMAL or pyDes.PAD_PKCS5"""
752 _baseDes.setPadMode(self, mode)
753 for key in (self.__key1, self.__key2, self.__key3):
754 key.setPadMode(mode)
755
756 def setIV(self, IV):
757 """Will set the Initial Value, used in conjunction with CBC mode"""
758 _baseDes.setIV(self, IV)
759 for key in (self.__key1, self.__key2, self.__key3):
760 key.setIV(IV)
761
762 def encrypt(self, data, pad=None, padmode=None):
763 """encrypt(data, [pad], [padmode]) -> bytes
764
765 data : bytes to be encrypted
766 pad : Optional argument for encryption padding. Must only be one byte
767 padmode : Optional argument for overriding the padding mode.
768
769 The data must be a multiple of 8 bytes and will be encrypted
770 with the already specified key. Data does not have to be a
771 multiple of 8 bytes if the padding character is supplied, or
772 the padmode is set to PAD_PKCS5, as bytes will then added to
773 ensure the be padded data is a multiple of 8 bytes.
774 """
775 ENCRYPT = des.ENCRYPT
776 DECRYPT = des.DECRYPT
777 data = self._guardAgainstUnicode(data)
778 if pad is not None:
779 pad = self._guardAgainstUnicode(pad)
780 # Pad the data accordingly.
781 data = self._padData(data, pad, padmode)
782 if self.getMode() == CBC:
783 self.__key1.setIV(self.getIV())
784 self.__key2.setIV(self.getIV())
785 self.__key3.setIV(self.getIV())
786 i = 0
787 result = []
788 while i < len(data):
789 block = self.__key1.crypt(data[i:i+8], ENCRYPT)
790 block = self.__key2.crypt(block, DECRYPT)
791 block = self.__key3.crypt(block, ENCRYPT)
792 self.__key1.setIV(block)
793 self.__key2.setIV(block)
794 self.__key3.setIV(block)
795 result.append(block)
796 i += 8
797 if _pythonMajorVersion < 3:
798 return ''.join(result)
799 else:
800 return bytes.fromhex('').join(result)
801 else:
802 data = self.__key1.crypt(data, ENCRYPT)
803 data = self.__key2.crypt(data, DECRYPT)
804 return self.__key3.crypt(data, ENCRYPT)
805
806 def decrypt(self, data, pad=None, padmode=None):
807 """decrypt(data, [pad], [padmode]) -> bytes
808
809 data : bytes to be encrypted
810 pad : Optional argument for decryption padding. Must only be one byte
811 padmode : Optional argument for overriding the padding mode.
812
813 The data must be a multiple of 8 bytes and will be decrypted
814 with the already specified key. In PAD_NORMAL mode, if the
815 optional padding character is supplied, then the un-encrypted
816 data will have the padding characters removed from the end of
817 the bytes. This pad removal only occurs on the last 8 bytes of
818 the data (last data block). In PAD_PKCS5 mode, the special
819 padding end markers will be removed from the data after
820 decrypting, no pad character is required for PAD_PKCS5.
821 """
822 ENCRYPT = des.ENCRYPT
823 DECRYPT = des.DECRYPT
824 data = self._guardAgainstUnicode(data)
825 if pad is not None:
826 pad = self._guardAgainstUnicode(pad)
827 if self.getMode() == CBC:
828 self.__key1.setIV(self.getIV())
829 self.__key2.setIV(self.getIV())
830 self.__key3.setIV(self.getIV())
831 i = 0
832 result = []
833 while i < len(data):
834 iv = data[i:i+8]
835 block = self.__key3.crypt(iv, DECRYPT)
836 block = self.__key2.crypt(block, ENCRYPT)
837 block = self.__key1.crypt(block, DECRYPT)
838 self.__key1.setIV(iv)
839 self.__key2.setIV(iv)
840 self.__key3.setIV(iv)
841 result.append(block)
842 i += 8
843 if _pythonMajorVersion < 3:
844 data = ''.join(result)
845 else:
846 data = bytes.fromhex('').join(result)
847 else:
848 data = self.__key3.crypt(data, DECRYPT)
849 data = self.__key2.crypt(data, ENCRYPT)
850 data = self.__key1.crypt(data, DECRYPT)
851 return self._unpadData(data, pad, padmode)
+0
-0
msldap/crypto/pure/DES/__init__.py less more
(Empty file)
+0
-64
msldap/crypto/pure/RC4/RC4.py less more
0 #!/usr/bin/env python
1
2
3 """
4 https://raw.githubusercontent.com/bozhu/RC4-Python/master/rc4.py
5
6 Copyright (C) 2012 Bo Zhu http://about.bozhu.me
7
8 Permission is hereby granted, free of charge, to any person obtaining a
9 copy of this software and associated documentation files (the "Software"),
10 to deal in the Software without restriction, including without limitation
11 the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 and/or sell copies of the Software, and to permit persons to whom the
13 Software is furnished to do so, subject to the following conditions:
14
15 The above copyright notice and this permission notice shall be included in
16 all copies or substantial portions of the Software.
17
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24 DEALINGS IN THE SOFTWARE.
25 """
26 class RC4():
27 def __init__(self, key):
28 self.key = key
29 self.S = self.KSA()
30 self.keystream = self.PRGA()
31
32 def KSA(self):
33 keylength = len(self.key)
34
35 S = list(range(256))
36
37 j = 0
38 for i in range(256):
39 j = (j + S[i] + self.key[i % keylength]) % 256
40 S[i], S[j] = S[j], S[i] # swap
41
42 return S
43
44 def PRGA(self):
45 i = 0
46 j = 0
47 while True:
48 i = (i + 1) % 256
49 j = (j + self.S[i]) % 256
50 self.S[i], self.S[j] = self.S[j], self.S[i] # swap
51
52 K = self.S[(self.S[i] + self.S[j]) % 256]
53 yield K
54
55
56 def encrypt(self, data):
57 res = b''
58 for b in data:
59 res += (b ^ next(self.keystream)).to_bytes(1, byteorder = 'big', signed = False)
60 return res
61
62 def decrypt(self, data):
63 return self.encrypt(data)
+0
-0
msldap/crypto/pure/RC4/__init__.py less more
(Empty file)
+0
-0
msldap/crypto/pure/__init__.py less more
(Empty file)
+0
-67
msldap/crypto/symmetric.py less more
0 import importlib
1 import importlib.util
2
3 #
4 ##key = name of the cipher, value=list of module names, in order of preference
5 #preftable = {
6 # 'DES' : ['pyCrypto','pure'],
7 # 'TDES': ['pyCrypto','pure'],
8 # 'AES' : ['cryptography','pyCrypto','pure'],
9 # 'RC4' : ['cryptography','pyCrypto','pure'],
10 #
11 #}
12 #
13 #available_modules = ['pure']
14 #
15 #if importlib.util.find_spec("cryptography") is not None:
16 # #print('Found cryptography package!')
17 # available_modules.append("cryptography")
18 #
19 #elif importlib.util.find_spec("pyCrypto") is not None:
20 # #print('Found cryptography package!')
21 # available_modules.append("pyCrypto")
22 #
23 #
24 ##https://stackoverflow.com/questions/8790003/dynamically-import-a-method-in-a-file-from-a-string
25 #def import_from(module, name):
26 # module = __import__(module, fromlist=[name])
27 # return getattr(module, name)
28 #
29 #
30 #def getPreferredCipher(cipherName):
31 # if cipherName not in preftable:
32 # raise Exception('Cipher %s doesnt have any preferences set!' % cipherName)
33 # possible_prefmodule = list(set(preftable[cipherName]).intersection(set(available_modules)))
34 # selected_module = None
35 # for moduleName in preftable[cipherName]:
36 # if moduleName in possible_prefmodule:
37 # selected_module = moduleName
38 #
39 # if selected_module is None:
40 # raise Exception('Could not find any modules to load cipher %s' % cipherName)
41 #
42 #
43 # #print('Preferred module selected for cipher %s is %s' % (cipherName, selected_module))
44 # moduleName = 'aiosmb.crypto.%s' % cipherName
45 # objectName = selected_module + cipherName
46 # return import_from(moduleName , objectName)
47 #
48 #def getSpecificCipher(cipherName, moduleBaseName):
49 # moduleName = 'aiosmb.crypto.%s' % cipherName
50 # objectName = '%s%s' % (moduleBaseName, cipherName)
51 # return import_from(moduleName , objectName)
52
53
54 #import ciphers
55 # TODO: fix the dynamic imports, currently only supporting pure-python ciphers for two reasons:
56 # 1. dynamic import messes up some scripts like pyinstaller/nuitka/py2exe
57 # 2. additional effort needed to support more crypto libs anyhow
58
59 from msldap.crypto.AES import pureAES
60 from msldap.crypto.RC4 import pureRC4
61 from msldap.crypto.DES import pureDES
62
63 DES = pureDES #getPreferredCipher('DES')
64 AES = pureAES #getPreferredCipher('AES')
65 RC4 = pureRC4 #getPreferredCipher('RC4')
66 #TDES = getPreferredCipher('TDES')
44 #
55
66 import asyncio
7 from os import terminal_size
78 import traceback
89 import logging
910 import csv
1011 import shlex
1112 import datetime
1213 import copy
14 import typing
1315
1416 from msldap.external.aiocmd.aiocmd import aiocmd
1517 from msldap.external.asciitree.asciitree import LeftAligned
2224 from msldap.ldap_objects import MSADUser, MSADMachine, MSADUser_TSV_ATTRS
2325
2426 from winacl.dtyp.security_descriptor import SECURITY_DESCRIPTOR
25 from winacl.dtyp.ace import ACCESS_ALLOWED_OBJECT_ACE, ADS_ACCESS_MASK
27 from winacl.dtyp.ace import ACCESS_ALLOWED_OBJECT_ACE, ADS_ACCESS_MASK, AceFlags, ACE_OBJECT_PRESENCE
2628 from winacl.dtyp.sid import SID
2729 from winacl.dtyp.guid import GUID
30
31 from msldap.ldap_objects.adcertificatetemplate import MSADCertificateTemplate, EX_RIGHT_CERTIFICATE_ENROLLMENT, CertificateNameFlag
32 from msldap.wintypes.asn1.sdflagsrequest import SDFlagsRequest
2833
2934
3035 class MSLDAPClientConsole(aiocmd.PromptToolkitCmd):
211216 traceback.print_exc()
212217 return False
213218
214 async def do_user(self, samaccountname):
219 async def do_user(self, samaccountname, to_print=True):
215220 """Feteches a user object based on the sAMAccountName of the user"""
216221 try:
217222 await self.do_ldapinfo(False)
219224 user, err = await self.connection.get_user(samaccountname)
220225 if err is not None:
221226 raise err
222 if user is None:
223 print('User not found!')
224 else:
225 print(user)
226
227 return True
227
228 if to_print is True:
229 if user is None:
230 print('User not found!')
231 else:
232 print(user)
233
234 return user
228235 except:
229236 traceback.print_exc()
230237 return False
604611 except:
605612 traceback.print_exc()
606613 return False
607
614
615 async def do_rootcas(self, to_print = True):
616 """Lists Root CA certificates"""
617 try:
618 cas = []
619 async for ca, err in self.connection.list_root_cas():
620 if err is not None:
621 raise err
622 cas.append(ca)
623 if to_print is True:
624 print(ca)
625 return cas
626 except:
627 traceback.print_exc()
628 return False
629
630 async def do_ntcas(self, to_print = True):
631 """Lists NT CA certificates"""
632 try:
633 cas = []
634 async for ca, err in self.connection.list_ntcas():
635 if err is not None:
636 raise err
637 cas.append(ca)
638 if to_print is True:
639 print(ca)
640 return cas
641 except:
642 traceback.print_exc()
643 return False
644
645 async def do_aiacas(self, to_print = True):
646 """Lists AIA CA certificates"""
647 try:
648 cas = []
649 async for ca, err in self.connection.list_aiacas():
650 if err is not None:
651 raise err
652 cas.append(ca)
653 if to_print is True:
654 print(ca)
655 return cas
656 except:
657 traceback.print_exc()
658 return False
659
660 async def do_enrollmentservices(self, to_print=True):
661 """Lists AIA CA certificates"""
662 try:
663 services = []
664 async for srv, err in self.connection.list_enrollment_services():
665 if err is not None:
666 raise err
667 services.append(srv)
668 if to_print is True:
669 print(srv)
670 return services
671 except:
672 traceback.print_exc()
673 return False
674
675 async def do_addcerttemplatenameflagaltname(self, certtemplatename, flags = None):
676 """Modifyies the msPKI-Certificate-Name-Flag value of the specified certificate template and enables ENROLLEE_SUPPLIES_SUBJECT_ALT_NAME bit. If 'flags' is present then it will assign that value."""
677 try:
678 template = None
679 async for template, err in self.connection.list_certificate_templates(certtemplatename):
680 if err is not None:
681 raise err
682 break
683
684 if template is None:
685 raise Exception("Template could not be found!")
686
687 template = typing.cast(MSADCertificateTemplate, template)
688 if flags is not None:
689 flags = int(flags)
690 else:
691 flags = int(CertificateNameFlag(template.Certificate_Name_Flag) | CertificateNameFlag.ENROLLEE_SUPPLIES_SUBJECT_ALT_NAME)
692
693 changes = {
694 'msPKI-Certificate-Name-Flag' : [('replace', [flags])]
695 }
696
697 _, err = await self.connection.modify(template.distinguishedName, changes)
698 if err is not None:
699 raise err
700
701 print('Modify OK!')
702 return True
703
704
705 except:
706 traceback.print_exc()
707 return False
708
709 async def do_addenrollmentright(self, certtemplatename, user_dn):
710 """Grants enrollment rights to a user (by DN) for the specified certificate template."""
711 try:
712 user_sid, err = await self.connection.get_objectsid_for_dn(user_dn)
713 if err is not None:
714 raise err
715
716 template = None
717 async for template, err in self.connection.list_certificate_templates(certtemplatename):
718 if err is not None:
719 raise err
720 break
721
722 if template is None:
723 raise Exception("Template could not be found!")
724 template = typing.cast(MSADCertificateTemplate, template)
725 new_sd = copy.deepcopy(template.nTSecurityDescriptor)
726 ace = ACCESS_ALLOWED_OBJECT_ACE()
727 ace.Sid = SID.from_string(user_sid)
728 ace.ObjectType = GUID.from_string(EX_RIGHT_CERTIFICATE_ENROLLMENT)
729 ace.AceFlags = AceFlags(0)
730 ace.Mask = ADS_ACCESS_MASK.READ_PROP | ADS_ACCESS_MASK.WRITE_PROP | ADS_ACCESS_MASK.CONTROL_ACCESS
731 ace.Flags = ACE_OBJECT_PRESENCE.ACE_OBJECT_TYPE_PRESENT
732 new_sd.Dacl.aces.append(ace)
733 _, err = await self.connection.set_objectacl_by_dn(template.distinguishedName, new_sd.to_bytes(), flags=SDFlagsRequest.DACL_SECURITY_INFORMATION)
734 if err is not None:
735 raise err
736 print('SD set sucessfully')
737 return True
738 except:
739 traceback.print_exc()
740 return False
741
742 async def do_certtemplates(self, name = None, to_print = True):
743 """Lists certificate templates"""
744 try:
745 services = await self.do_enrollmentservices(to_print=False)
746 templates = []
747 async for template, err in self.connection.list_certificate_templates(name):
748 if err is not None:
749 raise err
750
751 lt = None
752 if template.nTSecurityDescriptor is not None:
753 lt, err = await self.connection.resolv_sd(template.nTSecurityDescriptor)
754 if err is not None:
755 raise err
756 template.sid_lookup_table = lt
757 for srv in services:
758 if template.name in srv.certificateTemplates:
759 template.enroll_services.append('%s\\%s' % (srv.dNSHostName, srv.name))
760
761 templates.append(template)
762 if to_print is True:
763 print(template.prettyprint())
764
765 return templates
766 except:
767 traceback.print_exc()
768 return False
769
770 async def do_sidresolv(self, sid, to_print = True):
771 """Returns the domain and username for SID"""
772 try:
773 domain, username, err = await self.connection.resolv_sid(sid)
774 if err is not None:
775 raise err
776 res = '%s\\%s' % (domain, username)
777 if to_print is True:
778 print(res)
779 return res
780 except:
781 traceback.print_exc()
782 return False
783
784 async def do_certify(self, cmd = None, username = None):
785 """ADCA security test"""
786 try:
787 es = await self.do_enrollmentservices(to_print=False)
788 if es is False:
789 raise Exception('Listing enrollment Services error! %s' % es)
790 if es is None:
791 raise Exception('No Enrollment Services present, stopping!')
792
793 templates = await self.do_certtemplates(to_print=False)
794 if templates is False:
795 raise Exception('Listing templates error! %s' % es)
796
797 if templates is None:
798 raise Exception('No templates exists!')
799
800 for enrollment in es:
801 print(enrollment)
802
803 if cmd is not None:
804 if cmd.lower().startswith('vuln') is True:
805 tokengroups = None
806 if username is not None:
807 tokengroups, err = await self.connection.get_tokengroups_user(username)
808 if err is not None:
809 raise err
810
811 for template in templates:
812 isvuln, reason = template.is_vulnerable(tokengroups)
813 if isvuln is True:
814 print(reason)
815 print(template)
816 else:
817 for template in templates:
818 print(template)
819
820 return True
821 except:
822 traceback.print_exc()
823 return False
824
825 async def do_whoamiraw(self):
826 """Simple whoami"""
827 try:
828 res, err = await self.connection.whoami()
829 if err is not None:
830 raise err
831 print(res)
832 except:
833 traceback.print_exc()
834 return False
835
836 async def do_whoami(self):
837 """Full whoami"""
838 try:
839 res, err = await self.connection.whoamifull()
840 if err is not None:
841 raise err
842
843 for x in res:
844 if isinstance(res[x], str) is True:
845 print('%s: %s' % (x, res[x]))
846 elif isinstance(res[x], dict) is True:
847 for k in res[x]:
848 print('Group: %s (%s)' % (k,'\\'.join(res[x][k])))
849 return True
850 except:
851 traceback.print_exc()
852 return False, None
853
608854 async def do_test(self):
609855 """testing, dontuse"""
610856 try:
1313 from msldap.ldap_objects.adgpo import MSADGPO, MSADGPO_ATTRS
1414 from msldap.ldap_objects.adtrust import MSADDomainTrust, MSADDomainTrust_ATTRS
1515 from msldap.ldap_objects.adschemaentry import MSADSCHEMAENTRY_ATTRS, MSADSchemaEntry
16 from msldap.ldap_objects.adca import MSADCA, MSADCA_ATTRS
17 from msldap.ldap_objects.adenrollmentservice import MSADEnrollmentService_ATTRS, MSADEnrollmentService
18 from msldap.ldap_objects.adcertificatetemplate import MSADCertificateTemplate, MSADCertificateTemplate_ATTRS
1619
1720 __all__ = [
1821 'MSADUser',
3639 'MSADOU_ATTRS',
3740 'MSADSCHEMAENTRY_ATTRS',
3841 'MSADSchemaEntry',
42 'MSADCA',
43 'MSADCA_ATTRS',
44 'MSADEnrollmentService_ATTRS',
45 'MSADEnrollmentService',
46 'MSADCertificateTemplate',
47 'MSADCertificateTemplate_ATTRS',
48
3949 ]
0
1 from asn1crypto.x509 import Certificate
2
3 MSADCA_ATTRS = ['cACertificate', 'cn', 'sn', 'distinguishedName', 'whenChanged', 'whenCreated', 'name']
4
5 class MSADCA:
6 def __init__(self):
7 self.location = None
8 self.sn = None #str
9 self.cn = None #str
10 self.distinguishedName = None #dn
11 self.whenChanged = None
12 self.whenCreated = None
13 self.cACertificate = None
14 self.name = None
15
16 @staticmethod
17 def from_ldap(entry, location):
18 adi = MSADCA()
19 adi.location = location
20 adi.sn = entry['attributes'].get('sn')
21 adi.cn = entry['attributes'].get('cn')
22 adi.distinguishedName = entry['attributes'].get('distinguishedName')
23 adi.whenChanged = entry['attributes'].get('whenChanged')
24 adi.whenCreated = entry['attributes'].get('whenCreated')
25 adi.cACertificate = entry['attributes'].get('cACertificate')
26 if adi.cACertificate is not None:
27 adi.cACertificate = Certificate.load(adi.cACertificate)
28 adi.name = entry['attributes'].get('name')
29
30 return adi
31
32 def __str__(self):
33 t = '== MSADCA ==\r\n'
34 for k in self.__dict__:
35 t += '%s: %s\r\n' % (k, self.__dict__[k])
36
37 return t
0 import enum
1 from winacl.dtyp.security_descriptor import SECURITY_DESCRIPTOR
2 from winacl.dtyp.ace import ACEType, ACE_OBJECT_PRESENCE, ACCESS_MASK, ADS_ACCESS_MASK
3
4
5 EX_RIGHT_CERTIFICATE_ENROLLMENT = "0e10c968-78fb-11d2-90d4-00c04f79dc55"
6 EX_RIGHT_CERTIFICATE_AUTOENROLLMENT = "a05b8cc2-17bc-4802-a710-e7c15ab866a2"
7
8
9 class CertificateNameFlag(enum.IntFlag):
10 ENROLLEE_SUPPLIES_SUBJECT = 0x00000001
11 ENROLLEE_SUPPLIES_SUBJECT_ALT_NAME = 0x00010000
12 SUBJECT_ALT_REQUIRE_DOMAIN_DNS = 0x00400000
13 SUBJECT_ALT_REQUIRE_SPN = 0x00800000
14 SUBJECT_ALT_REQUIRE_DIRECTORY_GUID = 0x01000000
15 SUBJECT_ALT_REQUIRE_UPN = 0x02000000
16 SUBJECT_ALT_REQUIRE_EMAIL = 0x04000000
17 SUBJECT_ALT_REQUIRE_DNS = 0x08000000
18 SUBJECT_REQUIRE_DNS_AS_CN = 0x10000000
19 SUBJECT_REQUIRE_EMAIL = 0x20000000
20 SUBJECT_REQUIRE_COMMON_NAME = 0x40000000
21 SUBJECT_REQUIRE_DIRECTORY_PATH = 0x80000000
22 OLD_CERT_SUPPLIES_SUBJECT_AND_ALT_NAME = 0x00000008
23
24 class EnrollmentFlag(enum.IntFlag):
25 INCLUDE_SYMMETRIC_ALGORITHMS = 0x00000001
26 PEND_ALL_REQUESTS = 0x00000002
27 PUBLISH_TO_KRA_CONTAINER = 0x00000004
28 PUBLISH_TO_DS = 0x00000008
29 AUTO_ENROLLMENT_CHECK_USER_DS_CERTIFICATE = 0x00000010
30 AUTO_ENROLLMENT = 0x00000020
31 PREVIOUS_APPROVAL_VALIDATE_REENROLLMENT = 0x00000040
32 USER_INTERACTION_REQUIRED = 0x00000100
33 REMOVE_INVALID_CERTIFICATE_FROM_PERSONAL_STORE = 0x00000400
34 ALLOW_ENROLL_ON_BEHALF_OF = 0x00000800
35 ADD_OCSP_NOCHECK = 0x00001000
36 ENABLE_KEY_REUSE_ON_NT_TOKEN_KEYSET_STORAGE_FULL = 0x00002000
37 NOREVOCATIONINFOINISSUEDCERTS = 0x00004000
38 INCLUDE_BASIC_CONSTRAINTS_FOR_EE_CERTS = 0x00008000
39 ALLOW_PREVIOUS_APPROVAL_KEYBASEDRENEWAL_VALIDATE_REENROLLMENT = 0x00010000
40 ISSUANCE_POLICIES_FROM_REQUEST = 0x00020000
41 SKIP_AUTO_RENEWAL = 0x00040000
42
43 class PrivateKeyFlag(enum.IntFlag):
44 REQUIRE_PRIVATE_KEY_ARCHIVAL = 0x00000001
45 EXPORTABLE_KEY = 0x00000010
46 STRONG_KEY_PROTECTION_REQUIRED = 0x00000020
47 REQUIRE_ALTERNATE_SIGNATURE_ALGORITHM = 0x00000040
48 REQUIRE_SAME_KEY_RENEWAL = 0x00000080
49 USE_LEGACY_PROVIDER = 0x00000100
50 ATTEST_REQUIRED = 0x000002000
51 ATTEST_PREFERRED = 0x000001000
52 HELLO_LOGON_KEY = 0x00200000
53
54 EKU_CLIENT_AUTHENTICATION_OID = "1.3.6.1.5.5.7.3.2"
55 EKU_PKINIT_CLIENT_AUTHENTICATION_OID = "1.3.6.1.5.2.3.4"
56 EKU_SMART_CARD_LOGON_OID = "1.3.6.1.4.1.311.20.2.2"
57 EKU_ANY_PURPOSE_OID = "2.5.29.37.0"
58 EKU_CERTIFICATE_REQUEST_AGENT_OID = "1.3.6.1.4.1.311.20.2.1"
59
60 EKUS_NAMES = {
61 "1.3.6.1.4.1.311.2.6.1": "SpcRelaxedPEMarkerCheck",
62 "1.3.6.1.4.1.311.2.6.2": "SpcEncryptedDigestRetryCount",
63 "1.3.6.1.4.1.311.10.3.6": "Windows System Component Verification",
64 "1.3.6.1.4.1.311.10.3.22": "Protected Process Light Verification",
65 "1.3.6.1.4.1.311.10.3.27": "Preview Build Signing",
66 "1.3.6.1.4.1.311.10.3.1": "Microsoft Trust List Signing",
67 "1.3.6.1.4.1.311.10.3.2": "Microsoft Time Stamping",
68 "1.3.6.1.4.1.311.10.3.7": "OEM Windows System Component Verification",
69 "1.3.6.1.4.1.311.10.3.13": "Lifetime Signing",
70 "1.3.6.1.4.1.311.10.3.11": "Key Recovery",
71 "1.3.6.1.4.1.311.10.3.23": "Windows TCB Component",
72 "1.3.6.1.4.1.311.10.3.25": "Windows Third Party Application Component",
73 "1.3.6.1.4.1.311.10.3.26": "Windows Software Extension Verification",
74 "1.3.6.1.4.1.311.10.3.8": "Embedded Windows System Component Verification",
75 "1.3.6.1.4.1.311.10.3.20": "Windows Kits Component",
76 "1.3.6.1.4.1.311.10.3.5": "Windows Hardware Driver Verification",
77 "1.3.6.1.4.1.311.10.3.39": "Windows Hardware Driver Extended Verification",
78 "1.3.6.1.4.1.311.10.3.5.1": "Windows Hardware Driver Attested Verification",
79 "1.3.6.1.4.1.311.10.3.4.1": "File Recovery",
80 "1.3.6.1.4.1.311.10.3.30": "Disallowed List",
81 "1.3.6.1.4.1.311.10.3.19": "Revoked List Signer",
82 "1.3.6.1.4.1.311.10.3.21": "Windows RT Verification",
83 "1.3.6.1.4.1.311.10.3.10": "Qualified Subordination",
84 "1.3.6.1.4.1.311.10.3.12": "Document Signing",
85 "1.3.6.1.4.1.311.10.3.24": "Protected Process Verification",
86 "1.3.6.1.4.1.311.10.3.4": "Encrypting File System",
87 "1.3.6.1.4.1.311.10.3.9": "Root List Signer",
88 "1.3.6.1.4.1.311.10.5.1": "Digital Rights",
89 "1.3.6.1.4.1.311.10.6.2": "License Server Verification",
90 "1.3.6.1.4.1.311.10.6.1": "Key Pack Licenses",
91 EKU_SMART_CARD_LOGON_OID: "Smart Card Logon",
92 EKU_CERTIFICATE_REQUEST_AGENT_OID: "Certificate Request Agent",
93 "1.3.6.1.4.1.311.20.1": "CTL Usage",
94 "1.3.6.1.4.1.311.21.6": "Key Recovery Agent",
95 "1.3.6.1.4.1.311.21.19": "Directory Service Email Replication",
96 "1.3.6.1.4.1.311.21.5": "Private Key Archival",
97 "1.3.6.1.4.1.311.61.1.1": "Kernel Mode Code Signing",
98 "1.3.6.1.4.1.311.61.4.1": "Early Launch Antimalware Driver",
99 "1.3.6.1.4.1.311.61.5.1": "HAL Extension",
100 "1.3.6.1.4.1.311.64.1.1": "Domain Name System (DNS) Server Trust",
101 "1.3.6.1.4.1.311.76.6.1": "Windows Update",
102 "1.3.6.1.4.1.311.76.3.1": "Windows Store",
103 "1.3.6.1.4.1.311.76.5.1": "Dynamic Code Generator",
104 "1.3.6.1.4.1.311.76.8.1": "Microsoft Publisher",
105 "1.3.6.1.4.1.311.80.1": "Document Encryption",
106 EKU_PKINIT_CLIENT_AUTHENTICATION_OID: "PKINIT Client Authentication",
107 "1.3.6.1.5.2.3.5": "KDC Authentication",
108 "1.3.6.1.5.5.7.3.7": "IP security user",
109 EKU_CLIENT_AUTHENTICATION_OID: "Client Authentication",
110 "1.3.6.1.5.5.7.3.9": "OCSP Signing",
111 "1.3.6.1.5.5.7.3.3": "Code Signing",
112 "1.3.6.1.5.5.7.3.4": "Secure Email",
113 "1.3.6.1.5.5.7.3.5": "IP security end system",
114 "1.3.6.1.5.5.7.3.6": "IP security tunnel termination",
115 "1.3.6.1.5.5.8.2.2": "IP security IKE intermediate",
116 "1.3.6.1.5.5.7.3.8": "Time Stamping",
117 "1.3.6.1.5.5.7.3.1": "Server Authentication",
118 EKU_ANY_PURPOSE_OID: "Any Purpose",
119 "2.23.133.8.1": "Endorsement Key Certificate",
120 "2.23.133.8.2": "Platform Certificate",
121 "2.23.133.8.3": "Attestation Identity Key Certificate",
122 }
123
124 ENROLLMENT_FLAGS_NAMES = {
125 EnrollmentFlag.INCLUDE_SYMMETRIC_ALGORITHMS: "INCLUDE_SYMMETRIC_ALGORITHMS",
126 EnrollmentFlag.PEND_ALL_REQUESTS: "PEND_ALL_REQUESTS",
127 EnrollmentFlag.PUBLISH_TO_KRA_CONTAINER: "PUBLISH_TO_KRA_CONTAINER",
128 EnrollmentFlag.PUBLISH_TO_DS: "PUBLISH_TO_DS",
129 EnrollmentFlag.AUTO_ENROLLMENT_CHECK_USER_DS_CERTIFICATE: "AUTO_ENROLLMENT_CHECK_USER_DS_CERTIFICATE",
130 EnrollmentFlag.AUTO_ENROLLMENT: "AUTO_ENROLLMENT",
131 EnrollmentFlag.PREVIOUS_APPROVAL_VALIDATE_REENROLLMENT: "PREVIOUS_APPROVAL_VALIDATE_REENROLLMENT",
132 EnrollmentFlag.USER_INTERACTION_REQUIRED: "USER_INTERACTION_REQUIRED",
133 EnrollmentFlag.REMOVE_INVALID_CERTIFICATE_FROM_PERSONAL_STORE: "REMOVE_INVALID_CERTIFICATE_FROM_PERSONAL_STORE",
134 EnrollmentFlag.ALLOW_ENROLL_ON_BEHALF_OF: "ALLOW_ENROLL_ON_BEHALF_OF",
135 EnrollmentFlag.ADD_OCSP_NOCHECK: "ADD_OCSP_NOCHECK",
136 EnrollmentFlag.ENABLE_KEY_REUSE_ON_NT_TOKEN_KEYSET_STORAGE_FULL: "ENABLE_KEY_REUSE_ON_NT_TOKEN_KEYSET_STORAGE_FULL",
137 EnrollmentFlag.NOREVOCATIONINFOINISSUEDCERTS: "NOREVOCATIONINFOINISSUEDCERTS",
138 EnrollmentFlag.INCLUDE_BASIC_CONSTRAINTS_FOR_EE_CERTS: "INCLUDE_BASIC_CONSTRAINTS_FOR_EE_CERTS",
139 EnrollmentFlag.ALLOW_PREVIOUS_APPROVAL_KEYBASEDRENEWAL_VALIDATE_REENROLLMENT: "ALLOW_PREVIOUS_APPROVAL_KEYBASEDRENEWAL_VALIDATE_REENROLLMENT",
140 EnrollmentFlag.ISSUANCE_POLICIES_FROM_REQUEST: "ISSUANCE_POLICIES_FROM_REQUEST",
141 EnrollmentFlag.SKIP_AUTO_RENEWAL: "SKIP_AUTO_RENEWAL",
142 }
143
144 MSADCertificateTemplate_ATTRS = [
145 'cn', 'sn', 'distinguishedName', 'name', 'msPKI-RA-Application-Policies', 'msPKI-Certificate-Application-Policy',
146 'msPKI-Template-Schema-Version', 'msPKI-Certificate-Name-Flag', 'msPKI-Enrollment-Flag', 'msPKI-RA-Signature',
147 'msPKI-Private-Key-Flag', 'pKIExtendedKeyUsage', 'nTSecurityDescriptor'
148 ]
149
150 class MSADCertificateTemplate:
151 def __init__(self):
152 self.sn = None #str
153 self.cn = None #str
154 self.distinguishedName = None #dn
155 self.name = None
156 self.RA_Application_Policies = None
157 self.Certificate_Application_Policy = None
158 self.Template_Schema_Version = None
159 self.Certificate_Name_Flag = None
160 self.Enrollment_Flag = None
161 self.RA_Signature = None
162 self.Private_Key_Flag = None
163 self.pKIExtendedKeyUsage = None
164 self.nTSecurityDescriptor:SECURITY_DESCRIPTOR = None
165
166 self.vulns = []
167 self.enroll_sids = set()
168 self.autoenroll_sids = set()
169 self.write_owner_sids = set()
170 self.write_dacl_sids = set()
171 self.write_property_sids = set()
172 self.fullcontrol_sids = set()
173 self.allextendedrights_sids = set()
174 self.sid_lookup_table = None
175 self.enroll_services = []
176
177 @staticmethod
178 def from_ldap(entry):
179 adi = MSADCertificateTemplate()
180 adi.sn = entry['attributes'].get('sn')
181 adi.cn = entry['attributes'].get('cn')
182 adi.distinguishedName = entry['attributes'].get('distinguishedName')
183 adi.name = entry['attributes'].get('name')
184 adi.RA_Application_Policies = entry['attributes'].get('msPKI-RA-Application-Policies')
185 adi.Certificate_Application_Policy = entry['attributes'].get('msPKI-Certificate-Application-Policy')
186 adi.Template_Schema_Version = entry['attributes'].get('msPKI-Template-Schema-Version')
187 adi.Certificate_Name_Flag = entry['attributes'].get('msPKI-Certificate-Name-Flag')
188 adi.Enrollment_Flag = entry['attributes'].get('msPKI-Enrollment-Flag')
189 adi.RA_Signature = entry['attributes'].get('msPKI-RA-Signature')
190 adi.Private_Key_Flag = entry['attributes'].get('msPKI-Private-Key-Flag')
191 adi.pKIExtendedKeyUsage = entry['attributes'].get('pKIExtendedKeyUsage', [])
192 adi.nTSecurityDescriptor = entry['attributes'].get('nTSecurityDescriptor')
193 if adi.nTSecurityDescriptor is not None:
194 adi.nTSecurityDescriptor = SECURITY_DESCRIPTOR.from_bytes(adi.nTSecurityDescriptor)
195
196 adi.calc_aces()
197 return adi
198
199 def allows_authentication(self):
200 return self.can_be_used_for_any_purpose() or len(set([EKU_CLIENT_AUTHENTICATION_OID, EKU_SMART_CARD_LOGON_OID, EKU_PKINIT_CLIENT_AUTHENTICATION_OID]).intersection(set(self.pKIExtendedKeyUsage))) > 0
201
202 def can_be_used_for_any_purpose(self):
203 return len(self.pKIExtendedKeyUsage) == 0 or EKU_ANY_PURPOSE_OID in self.pKIExtendedKeyUsage
204
205 def requires_manager_approval(self):
206 return EnrollmentFlag.PEND_ALL_REQUESTS in EnrollmentFlag(self.Enrollment_Flag)
207
208 def requires_authorized_signatures(self):
209 return self.RA_Signature != None and self.RA_Signature > 0
210
211 def allows_to_specify_san(self):
212 return CertificateNameFlag(self.Certificate_Name_Flag) & CertificateNameFlag.ENROLLEE_SUPPLIES_SUBJECT > 0
213
214 def allows_to_request_agent_certificate(self):
215 return EKU_CERTIFICATE_REQUEST_AGENT_OID in self.pKIExtendedKeyUsage
216
217 def allows_to_use_agent_certificate(self):
218 return self.Template_Schema_Version == 1 \
219 or (
220 self.Template_Schema_Version > 1 \
221 and self.RA_Signature == 1 \
222 and EKU_CERTIFICATE_REQUEST_AGENT_OID in self.RA_Application_Policies
223 )
224
225 def is_vulnerable(self, tokengroups = None):
226 def isLowPrivSid(sid):
227 sid = str(sid)
228 if sid in ['S-1-1-0', 'S-1-5-11']:
229 return True
230 if sid.startswith('S-1-5-21-') is True and sid.rsplit('-',1)[1] in ['513','515','545']:
231 return True
232 return False
233
234 if tokengroups is None:
235 if isLowPrivSid(str(self.nTSecurityDescriptor.Owner)) is True:
236 return True, 'Owner is low priv user'
237
238 else:
239 if str(self.nTSecurityDescriptor.Owner) in tokengroups:
240 return True, 'Owner can be controlled by current user'
241
242 lowprivcanenroll = False
243 if tokengroups is None:
244 if any(isLowPrivSid(str(sid)) for sid in self.fullcontrol_sids) is True:
245 return True, 'Lowpriv SID has full control'
246
247 if any(isLowPrivSid(str(sid)) for sid in self.write_dacl_sids) is True:
248 return True, 'Lowpriv SID can write DACLs'
249
250 if any(isLowPrivSid(str(sid)) for sid in self.write_owner_sids) is True:
251 return True, 'Lowpriv SID can change Owner'
252
253 if any(isLowPrivSid(str(sid)) for sid in self.write_property_sids) is True:
254 return True, 'Lowpriv SID can write property'
255
256 if any(isLowPrivSid(str(sid)) for sid in self.enroll_sids) is True:
257 lowprivcanenroll = True
258
259 if any(isLowPrivSid(str(sid)) for sid in self.allextendedrights_sids) is True:
260 lowprivcanenroll = True
261
262 else:
263 if len(self.enroll_sids.intersection(set(tokengroups))) > 0 or len(self.allextendedrights_sids.intersection(set(tokengroups))) > 0:
264 lowprivcanenroll = True
265
266 if len(self.write_dacl_sids.intersection(set(tokengroups))) > 0:
267 return True, 'Current user can write DACLs'
268
269 if len(self.write_owner_sids.intersection(set(tokengroups))) > 0:
270 return True, 'Current user can change Owner'
271
272 if len(self.write_property_sids.intersection(set(tokengroups))) > 0:
273 return True, 'Current user can write property'
274
275 if len(self.fullcontrol_sids.intersection(set(tokengroups))) > 0:
276 return True, 'Current user has full control'
277
278 if self.requires_manager_approval() is True:
279 return False, 'Needs manager approval'
280
281 if self.requires_authorized_signatures() is True:
282 return False, 'Needs authorized signature'
283
284 if self.allows_authentication() and lowprivcanenroll and self.allows_to_specify_san():
285 return True, 'Enrollee supplies subject'
286
287 if lowprivcanenroll and self.allows_to_use_agent_certificate() and self.allows_to_request_agent_certificate():
288 return True, 'Certificate request agent'
289
290 return False, 'No match found'
291
292 def calc_aces(self):
293 if self.nTSecurityDescriptor is None:
294 return
295 for ace in self.nTSecurityDescriptor.Dacl.aces:
296 if ace.AceType != ACEType.ACCESS_ALLOWED_OBJECT_ACE_TYPE and ace.AceType != ACEType.ACCESS_ALLOWED_ACE_TYPE:
297 continue
298
299 if ace.AceType == ACEType.ACCESS_ALLOWED_OBJECT_ACE_TYPE:
300 if str(ace.ObjectType) == EX_RIGHT_CERTIFICATE_ENROLLMENT:
301 self.enroll_sids.add(str(ace.Sid))
302 elif str(ace.ObjectType) == EX_RIGHT_CERTIFICATE_AUTOENROLLMENT:
303 self.autoenroll_sids.add(str(ace.Sid))
304 elif ADS_ACCESS_MASK.CONTROL_ACCESS in ADS_ACCESS_MASK(ace.Mask) and ace.ObjectType is None:
305 self.allextendedrights_sids.add(str(ace.Sid))
306 continue
307
308 if ADS_ACCESS_MASK.GENERIC_ALL in ADS_ACCESS_MASK(ace.Mask):
309 self.fullcontrol_sids.add(str(ace.Sid))
310
311 if ADS_ACCESS_MASK.WRITE_DACL in ADS_ACCESS_MASK(ace.Mask):
312 self.write_dacl_sids.add(str(ace.Sid))
313
314 if ADS_ACCESS_MASK.WRITE_OWNER in ADS_ACCESS_MASK(ace.Mask):
315 self.write_owner_sids.add(str(ace.Sid))
316
317 if ADS_ACCESS_MASK.WRITE_PROP in ADS_ACCESS_MASK(ace.Mask):
318 self.write_property_sids.add(str(ace.Sid))
319
320 if ADS_ACCESS_MASK.CONTROL_ACCESS in ADS_ACCESS_MASK(ace.Mask):
321 self.allextendedrights_sids.add(str(ace.Sid))
322
323 @property
324 def is_enabled(self):
325 return len(self.enroll_services) > 0
326
327 def __str__(self):
328 t = '== MSADCertificateTemplate ==\r\n'
329 for k in self.__dict__:
330 t += '%s: %s\r\n' % (k, self.__dict__[k])
331
332 return t
333
334 def prettyprint(self):
335 def print_sids(buffer, sidlist, offset = 6):
336 for sid in sidlist:
337 if self.sid_lookup_table is not None and sid in self.sid_lookup_table:
338 buffer += '%s%s\\%s [%s]\r\n' % (offset*' ', self.sid_lookup_table[sid][0], self.sid_lookup_table[sid][1], sid)
339 else:
340 buffer += '%s%s\r\n' % (offset*' ', sid)
341 return buffer
342
343 t = '== MSADCertificateTemplate ==\r\n'
344 t += "Name: %s\r\n" % self.name
345 t += 'distinguishedName: %s\r\n' % self.distinguishedName
346 t += "Schema Version: %s\r\n" % self.Template_Schema_Version
347
348 if self.enroll_services:
349 t += "Enroll Services: %s\r\n" % ", ".join(self.enroll_services)
350
351 if len(self.vulns) > 0:
352 t += "Vulnerabilities: %s\r\n" % ", ".join(self.vulns)
353
354 if self.Certificate_Name_Flag is not None:
355 t += "msPKI-Certificate-Name-Flag: %s\r\n" % str(CertificateNameFlag(self.Certificate_Name_Flag)).split('.',1)[1].replace('|',', ')
356 if self.Enrollment_Flag is not None:
357 t += "msPKI-Enrollment-Flag: %s\r\n" % str(EnrollmentFlag(self.Enrollment_Flag)).split('.',1)[1].replace('|',', ')
358 if self.RA_Signature is not None:
359 t += "msPKI-RA-Signature: %s\r\n" % self.RA_Signature
360 if self.pKIExtendedKeyUsage is not None:
361 t += "pKIExtendedKeyUsage: %s\r\n" % ", ".join([EKUS_NAMES.get(oid, oid) for oid in self.pKIExtendedKeyUsage])
362 if self.Certificate_Application_Policy is not None:
363 t += "msPKI-Certificate-Application-Policy: %s\r\n" % ", ".join([EKUS_NAMES.get(oid, oid) for oid in self.Certificate_Application_Policy])
364 if self.RA_Application_Policies is not None:
365 t += "msPKI-RA-Application-Policy: %s\r\n" % ", ".join([EKUS_NAMES.get(oid, oid) for oid in self.RA_Application_Policies])
366
367 t += "Permissions\r\n"
368 t += " Enrollment Permissions\r\n"
369 if len(self.enroll_sids) > 0:
370 t += " Enrollment Rights\r\n"
371 t = print_sids(t, self.enroll_sids)
372
373 if len(self.autoenroll_sids) > 0:
374 t += " AutoEnrollment Rights\r\n"
375 t = print_sids(t, self.autoenroll_sids)
376
377 if len(self.allextendedrights_sids) > 0:
378 t += " All Extended Rights\r\n"
379 t = print_sids(t, self.allextendedrights_sids)
380
381 t+= " Object Control Permissions\r\n"
382 t+= ' Owner\r\n'
383 sid = str(self.nTSecurityDescriptor.Owner)
384 if self.sid_lookup_table is not None and sid in self.sid_lookup_table:
385 t += ' %s\\%s [%s]\r\n' % (self.sid_lookup_table[sid][0], self.sid_lookup_table[sid][1], sid)
386 else:
387 t += " %s\r\n" % sid
388
389 if len(self.fullcontrol_sids) > 0:
390 t+= " Full Control\r\n"
391 t = print_sids(t, self.fullcontrol_sids)
392
393 t += " Write Owner\r\n"
394 t = print_sids(t, self.write_owner_sids)
395
396 t += " Write DACL\r\n"
397 t = print_sids(t, self.write_dacl_sids)
398
399 t += " Write Property\r\n"
400 t = print_sids(t, self.write_property_sids)
401
402 t += " SDDL\r\n"
403 t += self.nTSecurityDescriptor.to_sddl()
404 t += '\r\n'
405 return t
406
407 def __str__(self):
408 return self.prettyprint()
0
1
2 from msldap.commons.utils import print_cert
3 from asn1crypto.x509 import Certificate
4
5 MSADEnrollmentService_ATTRS = ['cACertificate', 'msPKI-Enrollment-Servers', 'dNSHostName', 'cn', 'sn', 'distinguishedName', 'whenChanged', 'whenCreated', 'name', 'displayName', 'cACertificateDN', 'certificateTemplates']
6
7 class MSADEnrollmentService:
8 def __init__(self):
9 self.sn = None #str
10 self.cn = None #str
11 self.distinguishedName = None #dn
12 self.name = None
13 self.displayName = None
14 self.cACertificate = None
15 self.cACertificateDN = None
16 self.dNSHostName = None
17 self.certificateTemplates = []
18 self.enrollmentServers = []
19
20 @staticmethod
21 def from_ldap(entry):
22 adi = MSADEnrollmentService()
23 adi.sn = entry['attributes'].get('sn')
24 adi.cn = entry['attributes'].get('cn')
25 adi.distinguishedName = entry['attributes'].get('distinguishedName')
26 adi.cACertificate = entry['attributes'].get('cACertificate')
27 if adi.cACertificate is not None:
28 adi.cACertificate = Certificate.load(adi.cACertificate)
29 adi.name = entry['attributes'].get('name')
30 adi.displayName = entry['attributes'].get('displayName')
31 adi.dNSHostName = entry['attributes'].get('dNSHostName')
32 adi.cACertificateDN = entry['attributes'].get('cACertificateDN')
33 adi.certificateTemplates = entry['attributes'].get('certificateTemplates')
34 for serverdef in entry['attributes'].get('msPKI-Enrollment-Servers', []):
35 adi.enrollmentServers.append(serverdef.split('\n')[3])
36 return adi
37
38 def __str__(self):
39 t = '== MSADEnrollmentService ==\r\n'
40 t += "Name: %s\r\n" % self.name
41 t += "DNS name: %s\r\n" % self.dNSHostName
42 t += "Templates: %s\r\n" % ', '.join(self.certificateTemplates)
43 if len(self.enrollmentServers) > 0:
44 t += "Web services: %s\r\n" % ", ".join(self.enrollmentServers)
45 t += "Certificate: \r\n%s\r\n" % print_cert(self.cACertificate.native, 2)
46
47 return t
11 import enum
22 import asyncio
33 import ipaddress
4 import traceback
45
56 from msldap import logger
67
78 from asysocks.client import SOCKSClient
89 from asysocks.common.comms import SocksQueueComms
910 from msldap.protocol.utils import calcualte_length
11 from msldap.commons.target import LDAPProtocol
1012
1113
1214 class SocksProxyConnection:
4345 await self.disconnect()
4446
4547 def get_peer_certificate(self):
46 raise Exception('Not yet implemented! SSL implementation on socks is missing!')
47 return self.writer.get_extra_info('socket').getpeercert(True)
48 return self.client.get_peercert()
4849
4950 def get_one_message(self,data):
5051 if len(data) < 6:
101102
102103 """
103104 try:
105 wrap_ssl = False
106 if self.target.proto == LDAPProtocol.SSL:
107 wrap_ssl = True
104108 self.out_queue = asyncio.Queue()
105109 self.in_queue = asyncio.Queue()
106110
107111 self.proxy_in_queue = asyncio.Queue()
108 comms = SocksQueueComms(self.out_queue, self.proxy_in_queue)
112 comms = SocksQueueComms(self.out_queue, self.proxy_in_queue, wrap_ssl=wrap_ssl)
109113
110114 self.target.proxy.target[-1].endpoint_ip = self.target.host if self.target.serverip is None else self.target.serverip
111115 self.target.proxy.target[-1].endpoint_port = int(self.target.port)
112116 self.target.proxy.target[-1].endpoint_timeout = None #TODO: maybe implement endpoint timeout?
113117 self.target.proxy.target[-1].timeout = self.target.timeout
114118 self.client = SOCKSClient(comms, self.target.proxy.target)
115 self.proxy_task = asyncio.create_task(self.client.run())
119 proxy_coro = await self.client.run(True)
120 self.proxy_task = asyncio.create_task(proxy_coro)
121 await self.client.proxy_running_evt.wait()
116122 self.handle_in_task = asyncio.create_task(self.handle_in_q())
117123 return True, None
118124 except Exception as e:
125 traceback.print_exc()
119126 return False, e
120127
1313 from msldap import logger
1414 from msldap.protocol.utils import calcualte_length
1515
16 from pyodidewsnet.client import WSNetworkTCP
16 from wsnet.pyodide.client import WSNetworkTCP
1717
1818
1919
2020 elif value == '*':
2121 return Filter({
2222 'present' : AttributeDescription(attr.encode())
23 })
24
25 elif value.startswith('*') and value.endswith('*'):
26 return Filter({
27 'substrings' : SubstringFilter({
28 'type' : attr.encode(),
29 'substrings' : Substrings([
30 Substring({
31 'any' : value[1:-1].encode()
32 })
33 ])
34 })
2335 })
2436
2537 elif value.startswith('*') is True:
9292 def list_bytes_one_enc(x):
9393 return x
9494
95 def bytes2timedelta(x):
96 return int2timedelta([int.from_bytes(x[0], byteorder='little', signed=True)])
97
9598 def int2timedelta(x):
9699 x = int(x[0])
97100 if x == '-9223372036854775808':
165168 t.append(ts2dt((a, None)))
166169 return t
167170
171 def list_ts2dt_one(x):
172 return ts2dt(x[0])
168173
169174 LDAP_ATTRIBUTE_TYPES = {
170175 'supportedCapabilities' : list_str,
274279 'unicodePwd' : list_str_one,
275280 'ms-Mcs-AdmPwd' : list_str_one,
276281 'msDS-AllowedToActOnBehalfOfOtherIdentity' : list_bytes_one,
282 'cACertificate': list_bytes_one,
283 'certificateTemplates': list_str,
284 'cACertificateDN': list_str_one,
285 'msPKI-Enrollment-Servers': list_str, # it's actually a 5-part multi string split by '\n'
286 'revision' : list_int_one,
287 'pKIKeyUsage' : list_bytes_one,
288 'pKIDefaultKeySpec' : list_str_one,
289 'pKIMaxIssuingDepth' : list_int_one,
290 'pKICriticalExtensions' : list_str_one,
291 'pKIExpirationPeriod' : bytes2timedelta,
292 'pKIOverlapPeriod' : bytes2timedelta,
293 'pKIExtendedKeyUsage' : list_str,
294 'msPKI-RA-Signature' : list_int_one,
295 'msPKI-Enrollment-Flag' : list_int_one,
296 'msPKI-Private-Key-Flag' : list_int_one,
297 'msPKI-Certificate-Name-Flag' : list_int_one,
298 'msPKI-Minimal-Key-Size' : list_int_one,
299 'msPKI-Template-Schema-Version': list_int_one,
300 'msPKI-Template-Minor-Revision': list_int_one,
301 'msPKI-Cert-Template-OID' : list_str_one,
302 'msPKI-Certificate-Application-Policy' : list_str,
303 'msPKI-RA-Application-Policies' : list_str, #I'm guessing here
277304 }
278305
279306 LDAP_ATTRIBUTE_TYPES_ENC = {
294321 'member' : list_str_enc,
295322 'msDS-AllowedToActOnBehalfOfOtherIdentity' : list_bytes_one_enc,
296323 'nTSecurityDescriptor' : list_bytes_one_enc,
324 'msPKI-Certificate-Name-Flag' : list_int_one_enc
297325 }
298326
299327 def encode_attributes(x):
00 Metadata-Version: 1.2
11 Name: msldap
2 Version: 0.3.30
2 Version: 0.3.38
33 Summary: Python library to play with MS LDAP
44 Home-page: https://github.com/skelsec/msldap
55 Author: Tamas Jos
5656 msldap/commons/target.py
5757 msldap/commons/url.py
5858 msldap/commons/utils.py
59 msldap/crypto/AES.py
60 msldap/crypto/BASE.py
61 msldap/crypto/DES.py
62 msldap/crypto/MD4.py
63 msldap/crypto/RC4.py
64 msldap/crypto/TDES.py
65 msldap/crypto/__init__.py
66 msldap/crypto/hashing.py
67 msldap/crypto/symmetric.py
68 msldap/crypto/pure/__init__.py
69 msldap/crypto/pure/AES/AES.py
70 msldap/crypto/pure/AES/__init__.py
71 msldap/crypto/pure/AES/blockfeeder.py
72 msldap/crypto/pure/AES/util.py
73 msldap/crypto/pure/DES/DES.py
74 msldap/crypto/pure/DES/__init__.py
75 msldap/crypto/pure/RC4/RC4.py
76 msldap/crypto/pure/RC4/__init__.py
7759 msldap/examples/__init__.py
7860 msldap/examples/msldapclient.py
7961 msldap/examples/msldapcompdnslist.py
9072 msldap/external/asciitree/asciitree/traversal.py
9173 msldap/external/asciitree/asciitree/util.py
9274 msldap/ldap_objects/__init__.py
75 msldap/ldap_objects/adca.py
76 msldap/ldap_objects/adcertificatetemplate.py
9377 msldap/ldap_objects/adcomp.py
78 msldap/ldap_objects/adenrollmentservice.py
9479 msldap/ldap_objects/adgpo.py
9580 msldap/ldap_objects/adgroup.py
9681 msldap/ldap_objects/adinfo.py
0 asn1crypto
1 asysocks>=0.1.1
2 minikerberos>=0.2.14
0 asn1crypto>=1.3.0
1 asysocks>=0.1.7
2 minikerberos>=0.2.20
33 prompt-toolkit>=3.0.2
44 tqdm
5 winacl>=0.1.1
5 unicrypto>=0.0.5
6 wcwidth
7 winacl>=0.1.2
68
79 [:platform_system == "Windows"]
810 winsspi>=0.0.9
4646 "Operating System :: OS Independent",
4747 ),
4848 install_requires=[
49 'asn1crypto',
49 'unicrypto>=0.0.5',
50 'asn1crypto>=1.3.0',
51 'asysocks>=0.1.7',
52 'minikerberos>=0.2.20',
5053 'winsspi>=0.0.9;platform_system=="Windows"',
51 'minikerberos>=0.2.14',
52 'asysocks>=0.1.1',
53 'winacl>=0.1.1',
54 'winacl>=0.1.2',
5455 'prompt-toolkit>=3.0.2',
5556 'tqdm',
57 'wcwidth',
5658 ],
5759 entry_points={
5860 'console_scripts': [