Beispiel #1
0
    def encode(self):
        keys = self.keys_to_blob(self.keys)

        salt3 = drsblobs.package_PrimaryKerberosString()
        salt3.string = self.keys[0]['salt']

        ctr3 = drsblobs.package_PrimaryKerberosCtr3()
        ctr3.salt = salt3
        ctr3.num_keys = len(keys)
        ctr3.keys = keys

        krb_Primary_Kerberos = drsblobs.package_PrimaryKerberosBlob()
        krb_Primary_Kerberos.version = 3
        krb_Primary_Kerberos.ctr = ctr3

        return binascii.hexlify(ndr_pack(krb_Primary_Kerberos)).upper()
Beispiel #2
0
    def encode(self):
        keys = self.keys_to_blob(self.keys)

        salt3 = drsblobs.package_PrimaryKerberosString()
        salt3.string = self.keys[0]['salt']

        ctr3 = drsblobs.package_PrimaryKerberosCtr3()
        ctr3.salt = salt3
        ctr3.num_keys = len(keys)
        ctr3.keys = keys

        krb_Primary_Kerberos = drsblobs.package_PrimaryKerberosBlob()
        krb_Primary_Kerberos.version = 3
        krb_Primary_Kerberos.ctr = ctr3

        return binascii.hexlify(ndr_pack(krb_Primary_Kerberos)).upper()
Beispiel #3
0
def calculate_supplementalCredentials(ucs_krb5key, old_supplementalCredentials):

	old_krb = {}
	if old_supplementalCredentials:
		sc = ndr_unpack(drsblobs.supplementalCredentialsBlob, old_supplementalCredentials)

		for p in sc.sub.packages:
			ud.debug(ud.LDAP, ud.INFO, "calculate_supplementalCredentials: parsing %s blob" % p.name)
			if p.name == "Primary:Kerberos":
				krb_blob = binascii.unhexlify(p.data)
				try:
					krb = ndr_unpack(drsblobs.package_PrimaryKerberosBlob, krb_blob)
					assert krb.version == 3
					old_krb['ctr3'] = krb.ctr
					for k in krb.ctr.keys:	
						ud.debug(ud.LDAP, ud.INFO, "calculate_supplementalCredentials: ctr3.key.keytype: %s" % k.keytype)
				except:
					ud.debug(ud.LDAP, ud.ERROR, "calculate_supplementalCredentials: ndr_unpack of S4 Primary:Kerberos blob failed. Traceback:")
					traceback.print_exc()
					ud.debug(ud.LDAP, ud.ERROR, "calculate_supplementalCredentials: Continuing anyway, Primary:Kerberos (DES keys) blob will be missing in supplementalCredentials ctr3.old_keys.")
			elif p.name == "Primary:Kerberos-Newer-Keys":
				krb_blob = binascii.unhexlify(p.data)
				try:
					krb = ndr_unpack(drsblobs.package_PrimaryKerberosBlob, krb_blob)
					assert krb.version == 4
					old_krb['ctr4'] = krb.ctr
					for k in krb.ctr.keys:	
						ud.debug(ud.LDAP, ud.INFO, "calculate_supplementalCredentials: ctr4.key.keytype: %s" % k.keytype)
				except:
					ud.debug(ud.LDAP, ud.ERROR, "calculate_supplementalCredentials: ndr_unpack of S4 Primary:Kerberos-Newer-Keys blob failed. Traceback:")
					traceback.print_exc()
					ud.debug(ud.LDAP, ud.ERROR, "calculate_supplementalCredentials: Continuing anyway, Primary:Kerberos-Newer-Keys (AES and DES keys) blob will be missing in supplementalCredentials ctr4.old_keys.")

	krb5_aes256 = ''
	krb5_aes128 = ''
	krb5_des_md5 = ''
	krb5_des_crc = ''
	krb_ctr3_salt = ''
	krb_ctr4_salt = ''
	for k in ucs_krb5key:
		(keyblock, salt, kvno) = heimdal.asn1_decode_key(k)

		key_data = keyblock.keyvalue()
		saltstring = salt.saltvalue()
		enctype = keyblock.keytype()
		enctype_id = enctype.toint()
		ud.debug(ud.LDAP, ud.INFO, "calculate_supplementalCredentials: krb5_keytype: %s (%d)" % (enctype, enctype_id))
		if enctype_id == 18:
			krb5_aes256 = key_data
			if not krb_ctr4_salt:
				krb_ctr4_salt = saltstring
		elif enctype_id == 17:
			krb5_aes128 = key_data
			if not krb_ctr4_salt:
				krb_ctr4_salt = saltstring
		elif enctype_id == 3:
			krb5_des_md5 = key_data
			if not krb_ctr3_salt:
				krb_ctr3_salt = saltstring
		elif enctype_id == 1:
			krb5_des_crc = key_data
			if not krb_ctr3_salt:
				krb_ctr3_salt = saltstring

	## build new drsblobs.supplementalCredentialsBlob

	sc_blob = None
	cred_List = []
	package_names = []
	
	## Primary:Kerberos-Newer-Keys : AES keys
	if krb5_aes256 or krb5_aes128:
		ud.debug(ud.LDAP, ud.INFO, "calculate_supplementalCredentials: building Primary:Kerberos-Newer-Keys blob")
		kerberosKey4list = []
		
		if krb5_aes256:
			assert len(krb5_aes256) == 32
			next_key = drsblobs.package_PrimaryKerberosKey4()
			next_key.keytype = 18
			next_key.value = krb5_aes256
			next_key.value_len = len(krb5_aes256)
			kerberosKey4list.append(next_key)
		if krb5_aes128:
			assert len(krb5_aes128) == 16
			next_key = drsblobs.package_PrimaryKerberosKey4()
			next_key.keytype = 17
			next_key.value = krb5_aes128
			next_key.value_len = len(krb5_aes128)
			kerberosKey4list.append(next_key)
		if krb5_des_md5:
			assert len(krb5_des_md5) == 8
			next_key = drsblobs.package_PrimaryKerberosKey4()
			next_key.keytype = 3
			next_key.value = krb5_des_md5
			next_key.value_len = len(krb5_des_md5)
			kerberosKey4list.append(next_key)
		if krb5_des_crc:
			assert len(krb5_des_crc) == 8
			next_key = drsblobs.package_PrimaryKerberosKey4()
			next_key.keytype = 1
			next_key.value = krb5_des_crc
			next_key.value_len = len(krb5_des_crc)
			kerberosKey4list.append(next_key)

		salt4 = drsblobs.package_PrimaryKerberosString()
		salt4.string = krb_ctr4_salt

		ctr4 = drsblobs.package_PrimaryKerberosCtr4()
		ctr4.salt = salt4
		ctr4.num_keys = len(kerberosKey4list)
		ctr4.keys = kerberosKey4list

		if old_krb.get('ctr4'):
			## Backup old_keys to s4_old_keys
			s4_num_old_keys = old_krb['ctr4'].num_old_keys
			s4_old_keys = []
			for key in old_krb['ctr4'].old_keys:
				s4_old_keys.append(key)

			## keys -> old_keys
			if len(old_krb['ctr4'].keys) != ctr4.num_keys:
				cleaned_old_keys = []
				for key in old_krb['ctr4'].keys:
					if key.keytype == 4294967156:	## in all known cases W2k8 AD uses keytype 4294967156 (=-140L) to include the arc4 hash
						ud.debug(ud.LDAP, ud.INFO, "calculate_supplementalCredentials: Primary:Kerberos-Newer-Keys filtering keytype %s from old_keys" % key.keytype)
						continue
					else:	# TODO: can we do something better at this point to make old_keys == num_keys ?
						cleaned_old_keys.append(key)
					
				ctr4.old_keys = cleaned_old_keys
				ctr4.num_old_keys = len(cleaned_old_keys)
			else:
				ctr4.old_keys = old_krb['ctr4'].keys
				ctr4.num_old_keys = old_krb['ctr4'].num_keys

			## s4_old_keys -> older_keys
			if ctr4.num_old_keys != ctr4.num_older_keys:
				cleaned_older_keys = []
				for key in s4_old_keys:
					if key.keytype == 4294967156:	## in all known cases W2k8 AD uses keytype 4294967156 (=-140L) to include the arc4 hash
						ud.debug(ud.LDAP, ud.INFO, "calculate_supplementalCredentials: Primary:Kerberos-Newer-Keys filtering keytype %s from older_keys" % key.keytype)
						continue
					else:	# TODO: can we do something better at this point to make old_keys == num_keys ?
						cleaned_older_keys.append(key)
					
				ctr4.older_keys = cleaned_older_keys
				ctr4.num_older_keys = len(cleaned_older_keys)
			else:
				ctr4.older_keys = s4_old_keys
				ctr4.num_older_keys = s4_num_old_keys

		if ctr4.num_old_keys != 0 and ctr4.num_old_keys != ctr4.num_keys:
			# TODO: Recommended policy is to fill up old_keys to match num_keys, this will result in a traceback, can we do something better?
			ud.debug(ud.LDAP, ud.WARN, "calculate_supplementalCredentials: Primary:Kerberos-Newer-Keys num_keys = %s" % ctr4.num_keys)
			for k in ctr4.keys:
				ud.debug(ud.LDAP, ud.WARN, "calculate_supplementalCredentials: ctr4.key.keytype: %s" % k.keytype)
			ud.debug(ud.LDAP, ud.WARN, "calculate_supplementalCredentials: Primary:Kerberos-Newer-Keys num_old_keys = %s" % ctr4.num_old_keys)
			for k in ctr4.old_keys:
				ud.debug(ud.LDAP, ud.WARN, "calculate_supplementalCredentials: ctr4.old_key.keytype: %s" % k.keytype)

		if ctr4.num_older_keys != 0 and ctr4.num_older_keys != ctr4.num_old_keys:
			# TODO: Recommended policy is to fill up old_keys to match num_keys, this will result in a traceback, can we do something better?
			ud.debug(ud.LDAP, ud.WARN, "calculate_supplementalCredentials: Primary:Kerberos-Newer-Keys num_old_keys = %s" % ctr4.num_old_keys)
			for k in ctr4.old_keys:
				ud.debug(ud.LDAP, ud.WARN, "calculate_supplementalCredentials: ctr4.old_key.keytype: %s" % k.keytype)
			ud.debug(ud.LDAP, ud.WARN, "calculate_supplementalCredentials: Primary:Kerberos-Newer-Keys num_older_keys = %s" % ctr4.num_older_keys)
			for k in ctr4.older_keys:
				ud.debug(ud.LDAP, ud.WARN, "calculate_supplementalCredentials: ctr4.older_key.keytype: %s" % k.keytype)

		krb_Primary_Kerberos_Newer = drsblobs.package_PrimaryKerberosBlob()
		krb_Primary_Kerberos_Newer.version = 4
		krb_Primary_Kerberos_Newer.ctr = ctr4 

		krb_blob_Primary_Kerberos_Newer = ndr_pack(krb_Primary_Kerberos_Newer)
		creddata_Primary_Kerberos_Newer = binascii.hexlify(krb_blob_Primary_Kerberos_Newer)
		credname_Primary_Kerberos_Newer = "Primary:Kerberos-Newer-Keys"

		cred_Primary_Kerberos_Newer = drsblobs.supplementalCredentialsPackage()
		cred_Primary_Kerberos_Newer.name = credname_Primary_Kerberos_Newer
		cred_Primary_Kerberos_Newer.name_len = len(credname_Primary_Kerberos_Newer)
		cred_Primary_Kerberos_Newer.data = creddata_Primary_Kerberos_Newer
		cred_Primary_Kerberos_Newer.data_len = len(creddata_Primary_Kerberos_Newer)
		cred_Primary_Kerberos_Newer.reserved = 1
		cred_List.append(cred_Primary_Kerberos_Newer)
		package_names.append('Kerberos-Newer-Keys')

	## Primary:Kerberos : MD5 and CRC keys
	if krb5_des_md5 or krb5_des_crc:
		ud.debug(ud.LDAP, ud.INFO, "calculate_supplementalCredentials: building Primary:Kerberos blob")
		kerberosKey3list = []
		
		if krb5_des_md5:
			next_key = drsblobs.package_PrimaryKerberosKey3()
			next_key.keytype = 3
			next_key.value = krb5_des_md5
			next_key.value_len = len(krb5_des_md5)
			kerberosKey3list.append(next_key)
		if krb5_des_crc:
			next_key = drsblobs.package_PrimaryKerberosKey3()
			next_key.keytype = 1
			next_key.value = krb5_des_crc
			next_key.value_len = len(krb5_des_crc)
			kerberosKey3list.append(next_key)

		salt = drsblobs.package_PrimaryKerberosString()
		salt.string = krb_ctr3_salt

		ctr3 = drsblobs.package_PrimaryKerberosCtr3()
		ctr3.salt = salt
		ctr3.num_keys = len(kerberosKey3list)
		ctr3.keys = kerberosKey3list

		if old_krb.get('ctr3'):
			## keys -> old_keys
			if len(old_krb['ctr3'].keys) != ctr3.num_keys:
				cleaned_ctr3_old_keys = []
				for key in old_krb['ctr3'].keys:
					if key.keytype == 4294967156:	## in all known cases W2k8 AD uses keytype 4294967156 (=-140L) to include the arc4 hash
						ud.debug(ud.LDAP, ud.INFO, "calculate_supplementalCredentials: Primary:Kerberos filtering keytype %s from old_keys" % key.keytype)
						continue
					else:	# TODO: can we do something better at this point to make old_keys == num_keys ?
						cleaned_ctr3_old_keys.append(key)
					
				ctr3.old_keys = cleaned_ctr3_old_keys
				ctr3.num_old_keys = len(cleaned_ctr3_old_keys)
			else:
				ctr3.old_keys = old_krb['ctr3'].keys
				ctr3.num_old_keys = old_krb['ctr3'].num_keys

		if ctr3.num_old_keys != 0 and ctr3.num_old_keys != ctr3.num_keys:
			# TODO: Recommended policy is to fill up old_keys to match num_keys, this will result in a traceback, can we do something better?
			ud.debug(ud.LDAP, ud.WARN, "calculate_supplementalCredentials: Primary:Kerberos num_keys = %s" % ctr3.num_keys)
			for k in ctr4.keys:
				ud.debug(ud.LDAP, ud.WARN, "calculate_supplementalCredentials: ctr3.key.keytype: %s" % k.keytype)
			ud.debug(ud.LDAP, ud.WARN, "calculate_supplementalCredentials: Primary:Kerberos num_old_keys = %s" % ctr3.num_old_keys)
			for k in ctr4.old_keys:
				ud.debug(ud.LDAP, ud.WARN, "calculate_supplementalCredentials: ctr3.old_key.keytype: %s" % k.keytype)

		krb = drsblobs.package_PrimaryKerberosBlob()
		krb.version = 3
		krb.ctr = ctr3 
		krb3_blob = ndr_pack(krb)

		creddata_Primary_Kerberos = binascii.hexlify(krb3_blob)
		credname_Primary_Kerberos = "Primary:Kerberos"

		cred_Primary_Kerberos = drsblobs.supplementalCredentialsPackage()
		cred_Primary_Kerberos.name = credname_Primary_Kerberos
		cred_Primary_Kerberos.name_len = len(credname_Primary_Kerberos)
		cred_Primary_Kerberos.data = creddata_Primary_Kerberos
		cred_Primary_Kerberos.data_len = len(creddata_Primary_Kerberos)
		cred_Primary_Kerberos.reserved = 1
		cred_List.append(cred_Primary_Kerberos)
		package_names.append('Kerberos')

	if package_names:
		package_names_carray = (ctypes.c_char_p * len(package_names))(*package_names)
		package_names_PyCObject = _PyCObject_FromVoidPtr(ctypes.cast(package_names_carray, ctypes.POINTER(ctypes.c_char_p)), None) 
		krb_Packages = drsblobs.package_PackagesBlob() 
		krb_Packages.names = package_names_PyCObject
		krb_blob_Packages = ndr_pack(krb_Packages)
		# krb_blob_Packages = '\0'.join(package_names).encode('utf-16le')       # this pretty much simulates it
		cred_PackagesBlob_data = binascii.hexlify(krb_blob_Packages).upper()
		cred_PackagesBlob_name = "Packages"
		cred_PackagesBlob = drsblobs.supplementalCredentialsPackage()
		cred_PackagesBlob.name = cred_PackagesBlob_name
		cred_PackagesBlob.name_len = len(cred_PackagesBlob_name)
		cred_PackagesBlob.data = cred_PackagesBlob_data
		cred_PackagesBlob.data_len = len(cred_PackagesBlob_data)
		cred_PackagesBlob.reserved = 2
		cred_List.insert(-1, cred_PackagesBlob)

		sub = drsblobs.supplementalCredentialsSubBlob()
		sub.num_packages = len(cred_List)
		sub.packages = cred_List
		sub.signature = drsblobs.SUPPLEMENTAL_CREDENTIALS_SIGNATURE
		sub.prefix = drsblobs.SUPPLEMENTAL_CREDENTIALS_PREFIX

		sc = drsblobs.supplementalCredentialsBlob()
		sc.sub = sub
		sc_blob = ndr_pack(sc)

	return sc_blob
Beispiel #4
0
# Store type 1 and 3 hashes in Primary:Kerberos
# https://msdn.microsoft.com/en-us/library/cc245503.aspx
# "ctr3" because this is a revision 3 key container
normal_keys_list = []
for props in hashes:
    if vars(args)[props["arg"]] and props["ctr3"]:
        key = drsblobs.package_PrimaryKerberosKey3()
        key.keytype = props["type"]
        key.value = binascii.unhexlify(vars(args)[props["arg"]])
        key.value_len = props["length"]
        normal_keys_list.append(key)

# It is possible to only specify keys 17, 18
# Then no need to generate the old format entry
if (len(normal_keys_list) > 0):
    normal_keys_ctr = drsblobs.package_PrimaryKerberosCtr3()
    normal_keys_ctr.num_keys = len(normal_keys_list)
    normal_keys_ctr.salt = salt_blob
    normal_keys_ctr.keys = normal_keys_list

    normal_keys_blob_unpacked = drsblobs.package_PrimaryKerberosBlob()
    normal_keys_blob_unpacked.version = 3
    normal_keys_blob_unpacked.ctr = normal_keys_ctr
    normal_keys_blob = ndr_pack(normal_keys_blob_unpacked)

    normal_keys_package = drsblobs.supplementalCredentialsPackage()
    normal_keys_package_hex = binascii.hexlify(normal_keys_blob).upper()
    normal_keys_package.data = normal_keys_package_hex
    normal_keys_package.data_len = len(normal_keys_package.data)
    normal_keys_package.name = "Primary:Kerberos"
    normal_keys_package.name_len = len(normal_keys_package.name)
def calculate_supplementalCredentials(ucs_krb5key, old_supplementalCredentials):

	old_krb = {}
	if old_supplementalCredentials:
		sc = ndr_unpack(drsblobs.supplementalCredentialsBlob, old_supplementalCredentials)

		for p in sc.sub.packages:
			ud.debug(ud.LDAP, ud.INFO, "calculate_supplementalCredentials: parsing %s blob" % p.name)
			if p.name == "Primary:Kerberos":
				krb_blob = binascii.unhexlify(p.data)
				try:
					krb = ndr_unpack(drsblobs.package_PrimaryKerberosBlob, krb_blob)
					assert krb.version == 3
					old_krb['ctr3'] = krb.ctr
					for k in krb.ctr.keys:
						ud.debug(ud.LDAP, ud.INFO, "calculate_supplementalCredentials: ctr3.key.keytype: %s" % k.keytype)
				except:
					ud.debug(ud.LDAP, ud.ERROR, "calculate_supplementalCredentials: ndr_unpack of S4 Primary:Kerberos blob failed. Traceback:")
					traceback.print_exc()
					ud.debug(ud.LDAP, ud.ERROR, "calculate_supplementalCredentials: Continuing anyway, Primary:Kerberos (DES keys) blob will be missing in supplementalCredentials ctr3.old_keys.")
			elif p.name == "Primary:Kerberos-Newer-Keys":
				krb_blob = binascii.unhexlify(p.data)
				try:
					krb = ndr_unpack(drsblobs.package_PrimaryKerberosBlob, krb_blob)
					assert krb.version == 4
					old_krb['ctr4'] = krb.ctr
					for k in krb.ctr.keys:
						ud.debug(ud.LDAP, ud.INFO, "calculate_supplementalCredentials: ctr4.key.keytype: %s" % k.keytype)
				except:
					ud.debug(ud.LDAP, ud.ERROR, "calculate_supplementalCredentials: ndr_unpack of S4 Primary:Kerberos-Newer-Keys blob failed. Traceback:")
					traceback.print_exc()
					ud.debug(ud.LDAP, ud.ERROR, "calculate_supplementalCredentials: Continuing anyway, Primary:Kerberos-Newer-Keys (AES and DES keys) blob will be missing in supplementalCredentials ctr4.old_keys.")

	krb5_aes256 = ''
	krb5_aes128 = ''
	krb5_des_md5 = ''
	krb5_des_crc = ''
	krb_ctr3_salt = ''
	krb_ctr4_salt = ''
	for k in ucs_krb5key:
		(keyblock, salt, kvno) = heimdal.asn1_decode_key(k)
		key_data = keyblock.keyvalue()
		saltstring = salt.saltvalue()
		enctype = keyblock.keytype()
		enctype_id = enctype.toint()
		if enctype_id not in krb5_context.etype_ids:
			ud.debug(ud.LDAP, ud.WARN, "calculate_supplementalCredentials: ignoring unsupported krb5_keytype: (%d)" % (enctype_id,))
			continue

		ud.debug(ud.LDAP, ud.INFO, "calculate_supplementalCredentials: krb5_keytype: %s (%d)" % (enctype, enctype_id))
		if enctype_id == 18:
			krb5_aes256 = key_data
			if not krb_ctr4_salt:
				krb_ctr4_salt = saltstring
		elif enctype_id == 17:
			krb5_aes128 = key_data
			if not krb_ctr4_salt:
				krb_ctr4_salt = saltstring
		elif enctype_id == 3:
			krb5_des_md5 = key_data
			if not krb_ctr3_salt:
				krb_ctr3_salt = saltstring
		elif enctype_id == 1:
			krb5_des_crc = key_data
			if not krb_ctr3_salt:
				krb_ctr3_salt = saltstring

	# build new drsblobs.supplementalCredentialsBlob

	sc_blob = None
	cred_List = []
	package_names = []

	# Primary:Kerberos-Newer-Keys : AES keys
	if krb5_aes256 or krb5_aes128:
		ud.debug(ud.LDAP, ud.INFO, "calculate_supplementalCredentials: building Primary:Kerberos-Newer-Keys blob")
		kerberosKey4list = []

		if krb5_aes256:
			assert len(krb5_aes256) == 32
			next_key = drsblobs.package_PrimaryKerberosKey4()
			next_key.keytype = 18
			next_key.value = krb5_aes256
			next_key.value_len = len(krb5_aes256)
			kerberosKey4list.append(next_key)
		if krb5_aes128:
			assert len(krb5_aes128) == 16
			next_key = drsblobs.package_PrimaryKerberosKey4()
			next_key.keytype = 17
			next_key.value = krb5_aes128
			next_key.value_len = len(krb5_aes128)
			kerberosKey4list.append(next_key)
		if krb5_des_md5:
			assert len(krb5_des_md5) == 8
			next_key = drsblobs.package_PrimaryKerberosKey4()
			next_key.keytype = 3
			next_key.value = krb5_des_md5
			next_key.value_len = len(krb5_des_md5)
			kerberosKey4list.append(next_key)
		if krb5_des_crc:
			assert len(krb5_des_crc) == 8
			next_key = drsblobs.package_PrimaryKerberosKey4()
			next_key.keytype = 1
			next_key.value = krb5_des_crc
			next_key.value_len = len(krb5_des_crc)
			kerberosKey4list.append(next_key)

		salt4 = drsblobs.package_PrimaryKerberosString()
		salt4.string = krb_ctr4_salt

		ctr4 = drsblobs.package_PrimaryKerberosCtr4()
		ctr4.salt = salt4
		ctr4.num_keys = len(kerberosKey4list)
		ctr4.keys = kerberosKey4list

		if old_krb.get('ctr4'):
			# Backup old_keys to s4_old_keys
			s4_num_old_keys = old_krb['ctr4'].num_old_keys
			s4_old_keys = []
			for key in old_krb['ctr4'].old_keys:
				s4_old_keys.append(key)

			# keys -> old_keys
			if len(old_krb['ctr4'].keys) != ctr4.num_keys:
				cleaned_old_keys = []
				for key in old_krb['ctr4'].keys:
					if key.keytype == 4294967156:  # in all known cases W2k8 AD uses keytype 4294967156 (=-140L) to include the arc4 hash
						ud.debug(ud.LDAP, ud.INFO, "calculate_supplementalCredentials: Primary:Kerberos-Newer-Keys filtering keytype %s from old_keys" % key.keytype)
						continue
					else:  # TODO: can we do something better at this point to make old_keys == num_keys ?
						cleaned_old_keys.append(key)

				ctr4.old_keys = cleaned_old_keys
				ctr4.num_old_keys = len(cleaned_old_keys)
			else:
				ctr4.old_keys = old_krb['ctr4'].keys
				ctr4.num_old_keys = old_krb['ctr4'].num_keys

			# s4_old_keys -> older_keys
			if ctr4.num_old_keys != ctr4.num_older_keys:
				cleaned_older_keys = []
				for key in s4_old_keys:
					if key.keytype == 4294967156:  # in all known cases W2k8 AD uses keytype 4294967156 (=-140L) to include the arc4 hash
						ud.debug(ud.LDAP, ud.INFO, "calculate_supplementalCredentials: Primary:Kerberos-Newer-Keys filtering keytype %s from older_keys" % key.keytype)
						continue
					else:  # TODO: can we do something better at this point to make old_keys == num_keys ?
						cleaned_older_keys.append(key)

				ctr4.older_keys = cleaned_older_keys
				ctr4.num_older_keys = len(cleaned_older_keys)
			else:
				ctr4.older_keys = s4_old_keys
				ctr4.num_older_keys = s4_num_old_keys

		if ctr4.num_old_keys != 0 and ctr4.num_old_keys != ctr4.num_keys:
			# TODO: Recommended policy is to fill up old_keys to match num_keys, this will result in a traceback, can we do something better?
			ud.debug(ud.LDAP, ud.WARN, "calculate_supplementalCredentials: Primary:Kerberos-Newer-Keys num_keys = %s" % ctr4.num_keys)
			for k in ctr4.keys:
				ud.debug(ud.LDAP, ud.WARN, "calculate_supplementalCredentials: ctr4.key.keytype: %s" % k.keytype)
			ud.debug(ud.LDAP, ud.WARN, "calculate_supplementalCredentials: Primary:Kerberos-Newer-Keys num_old_keys = %s" % ctr4.num_old_keys)
			for k in ctr4.old_keys:
				ud.debug(ud.LDAP, ud.WARN, "calculate_supplementalCredentials: ctr4.old_key.keytype: %s" % k.keytype)

		if ctr4.num_older_keys != 0 and ctr4.num_older_keys != ctr4.num_old_keys:
			# TODO: Recommended policy is to fill up old_keys to match num_keys, this will result in a traceback, can we do something better?
			ud.debug(ud.LDAP, ud.WARN, "calculate_supplementalCredentials: Primary:Kerberos-Newer-Keys num_old_keys = %s" % ctr4.num_old_keys)
			for k in ctr4.old_keys:
				ud.debug(ud.LDAP, ud.WARN, "calculate_supplementalCredentials: ctr4.old_key.keytype: %s" % k.keytype)
			ud.debug(ud.LDAP, ud.WARN, "calculate_supplementalCredentials: Primary:Kerberos-Newer-Keys num_older_keys = %s" % ctr4.num_older_keys)
			for k in ctr4.older_keys:
				ud.debug(ud.LDAP, ud.WARN, "calculate_supplementalCredentials: ctr4.older_key.keytype: %s" % k.keytype)

		krb_Primary_Kerberos_Newer = drsblobs.package_PrimaryKerberosBlob()
		krb_Primary_Kerberos_Newer.version = 4
		krb_Primary_Kerberos_Newer.ctr = ctr4

		krb_blob_Primary_Kerberos_Newer = ndr_pack(krb_Primary_Kerberos_Newer)
		creddata_Primary_Kerberos_Newer = binascii.hexlify(krb_blob_Primary_Kerberos_Newer)
		credname_Primary_Kerberos_Newer = "Primary:Kerberos-Newer-Keys"

		cred_Primary_Kerberos_Newer = drsblobs.supplementalCredentialsPackage()
		cred_Primary_Kerberos_Newer.name = credname_Primary_Kerberos_Newer
		cred_Primary_Kerberos_Newer.name_len = len(credname_Primary_Kerberos_Newer)
		cred_Primary_Kerberos_Newer.data = creddata_Primary_Kerberos_Newer
		cred_Primary_Kerberos_Newer.data_len = len(creddata_Primary_Kerberos_Newer)
		cred_Primary_Kerberos_Newer.reserved = 1
		cred_List.append(cred_Primary_Kerberos_Newer)
		package_names.append('Kerberos-Newer-Keys')

	# Primary:Kerberos : MD5 and CRC keys
	if krb5_des_md5 or krb5_des_crc:
		ud.debug(ud.LDAP, ud.INFO, "calculate_supplementalCredentials: building Primary:Kerberos blob")
		kerberosKey3list = []

		if krb5_des_md5:
			next_key = drsblobs.package_PrimaryKerberosKey3()
			next_key.keytype = 3
			next_key.value = krb5_des_md5
			next_key.value_len = len(krb5_des_md5)
			kerberosKey3list.append(next_key)
		if krb5_des_crc:
			next_key = drsblobs.package_PrimaryKerberosKey3()
			next_key.keytype = 1
			next_key.value = krb5_des_crc
			next_key.value_len = len(krb5_des_crc)
			kerberosKey3list.append(next_key)

		salt = drsblobs.package_PrimaryKerberosString()
		salt.string = krb_ctr3_salt

		ctr3 = drsblobs.package_PrimaryKerberosCtr3()
		ctr3.salt = salt
		ctr3.num_keys = len(kerberosKey3list)
		ctr3.keys = kerberosKey3list

		if old_krb.get('ctr3'):
			# keys -> old_keys
			if len(old_krb['ctr3'].keys) != ctr3.num_keys:
				cleaned_ctr3_old_keys = []
				for key in old_krb['ctr3'].keys:
					if key.keytype == 4294967156:  # in all known cases W2k8 AD uses keytype 4294967156 (=-140L) to include the arc4 hash
						ud.debug(ud.LDAP, ud.INFO, "calculate_supplementalCredentials: Primary:Kerberos filtering keytype %s from old_keys" % key.keytype)
						continue
					else:  # TODO: can we do something better at this point to make old_keys == num_keys ?
						cleaned_ctr3_old_keys.append(key)

				ctr3.old_keys = cleaned_ctr3_old_keys
				ctr3.num_old_keys = len(cleaned_ctr3_old_keys)
			else:
				ctr3.old_keys = old_krb['ctr3'].keys
				ctr3.num_old_keys = old_krb['ctr3'].num_keys

		if ctr3.num_old_keys != 0 and ctr3.num_old_keys != ctr3.num_keys:
			# TODO: Recommended policy is to fill up old_keys to match num_keys, this will result in a traceback, can we do something better?
			ud.debug(ud.LDAP, ud.WARN, "calculate_supplementalCredentials: Primary:Kerberos num_keys = %s" % ctr3.num_keys)
			for k in ctr3.keys:
				ud.debug(ud.LDAP, ud.WARN, "calculate_supplementalCredentials: ctr3.key.keytype: %s" % k.keytype)
			ud.debug(ud.LDAP, ud.WARN, "calculate_supplementalCredentials: Primary:Kerberos num_old_keys = %s" % ctr3.num_old_keys)
			for k in ctr3.old_keys:
				ud.debug(ud.LDAP, ud.WARN, "calculate_supplementalCredentials: ctr3.old_key.keytype: %s" % k.keytype)

		krb = drsblobs.package_PrimaryKerberosBlob()
		krb.version = 3
		krb.ctr = ctr3
		krb3_blob = ndr_pack(krb)

		creddata_Primary_Kerberos = binascii.hexlify(krb3_blob)
		credname_Primary_Kerberos = "Primary:Kerberos"

		cred_Primary_Kerberos = drsblobs.supplementalCredentialsPackage()
		cred_Primary_Kerberos.name = credname_Primary_Kerberos
		cred_Primary_Kerberos.name_len = len(credname_Primary_Kerberos)
		cred_Primary_Kerberos.data = creddata_Primary_Kerberos
		cred_Primary_Kerberos.data_len = len(creddata_Primary_Kerberos)
		cred_Primary_Kerberos.reserved = 1
		cred_List.append(cred_Primary_Kerberos)
		package_names.append('Kerberos')

	if package_names:
		krb_blob_Packages = '\0'.join(package_names).encode('utf-16le')
		cred_PackagesBlob_data = binascii.hexlify(krb_blob_Packages).upper()
		cred_PackagesBlob_name = "Packages"
		cred_PackagesBlob = drsblobs.supplementalCredentialsPackage()
		cred_PackagesBlob.name = cred_PackagesBlob_name
		cred_PackagesBlob.name_len = len(cred_PackagesBlob_name)
		cred_PackagesBlob.data = cred_PackagesBlob_data
		cred_PackagesBlob.data_len = len(cred_PackagesBlob_data)
		cred_PackagesBlob.reserved = 2
		cred_List.insert(-1, cred_PackagesBlob)

		sub = drsblobs.supplementalCredentialsSubBlob()
		sub.num_packages = len(cred_List)
		sub.packages = cred_List
		sub.signature = drsblobs.SUPPLEMENTAL_CREDENTIALS_SIGNATURE
		sub.prefix = drsblobs.SUPPLEMENTAL_CREDENTIALS_PREFIX

		sc = drsblobs.supplementalCredentialsBlob()
		sc.sub = sub
		sc_blob = ndr_pack(sc)
		ud.debug(ud.LDAP, ud.ALL, "calculate_supplementalCredentials: sc:\n%s" % ndr_print(sc))

	return sc_blob