def truncate_key(value, keysize): output = b'' currentNum = 0 while len(output) < keysize: currentDigest = hashlib.sha1(bytes([currentNum]) + value).digest() if len(output) + len(currentDigest) > keysize: output += currentDigest[:keysize - len(output)] break output += currentDigest currentNum += 1 return output
def to_kirbi(self): filename = '%s@%s_%s' % ( self.client.to_string(), self.server.to_string(), hashlib.sha1(self.ticket.to_asn1()).hexdigest()[:8]) krbcredinfo = {} krbcredinfo['key'] = EncryptionKey(self.key.to_asn1()) krbcredinfo['prealm'] = self.client.realm.to_string() krbcredinfo['pname'] = self.client.to_asn1()[0] krbcredinfo['flags'] = core.IntegerBitString( self.tktflags).cast(TicketFlags) if self.time.authtime != 0: #this parameter is not mandatory, and most of the time not present krbcredinfo['authtime'] = datetime.datetime.fromtimestamp( self.time.authtime, datetime.timezone.utc) if self.time.starttime != 0: krbcredinfo['starttime'] = datetime.datetime.fromtimestamp( self.time.starttime, datetime.timezone.utc) if self.time.endtime != 0: krbcredinfo['endtime'] = datetime.datetime.fromtimestamp( self.time.endtime, datetime.timezone.utc) if self.time.renew_till != 0: #this parameter is not mandatory, and sometimes it's not present krbcredinfo['renew-till'] = datetime.datetime.fromtimestamp( self.time.authtime, datetime.timezone.utc) krbcredinfo['srealm'] = self.server.realm.to_string() krbcredinfo['sname'] = self.server.to_asn1()[0] enc_krbcred = {} enc_krbcred['ticket-info'] = [KrbCredInfo(krbcredinfo)] krbcred = {} krbcred['pvno'] = krb5_pvno krbcred['msg-type'] = MESSAGE_TYPE.KRB_CRED.value krbcred['tickets'] = [Ticket.load(self.ticket.to_asn1())] krbcred['enc-part'] = EncryptedData({ 'etype': EncryptionType.NULL.value, 'cipher': EncKrbCredPart(enc_krbcred).dump() }) kirbi = KRBCRED(krbcred) return kirbi, filename
def sign_authpack_native(self, data, wrap_signed=False): """ Creating PKCS7 blob which contains the following things: 1. 'data' blob which is an ASN1 encoded "AuthPack" structure 2. the certificate used to sign the data blob 3. the singed 'signed_attrs' structure (ASN1) which points to the "data" structure (in point 1) """ da = {} da['algorithm'] = algos.DigestAlgorithmId('1.3.14.3.2.26') # for sha1 si = {} si['version'] = 'v1' si['sid'] = cms.IssuerAndSerialNumber({ 'issuer': self.certificate.issuer, 'serial_number': self.certificate.serial_number, }) si['digest_algorithm'] = algos.DigestAlgorithm(da) si['signed_attrs'] = [ cms.CMSAttribute( { 'type': 'content_type', 'values': ['1.3.6.1.5.2.3.1'] } ), # indicates that the encap_content_info's authdata struct (marked with OID '1.3.6.1.5.2.3.1' is signed ) cms.CMSAttribute( { 'type': 'message_digest', 'values': [hashlib.sha1(data).digest()] } ), ### hash of the data, the data itself will not be signed, but this block of data will be. ] si['signature_algorithm'] = algos.SignedDigestAlgorithm( {'algorithm': '1.2.840.113549.1.1.1'}) si['signature'] = rsa_pkcs1v15_sign( self.privkey, cms.CMSAttributes(si['signed_attrs']).dump(), "sha1") ec = {} ec['content_type'] = '1.3.6.1.5.2.3.1' ec['content'] = data sd = {} sd['version'] = 'v3' sd['digest_algorithms'] = [algos.DigestAlgorithm(da) ] # must have only one sd['encap_content_info'] = cms.EncapsulatedContentInfo(ec) sd['certificates'] = [self.certificate] sd['signer_infos'] = cms.SignerInfos([cms.SignerInfo(si)]) if wrap_signed is True: ci = {} ci['content_type'] = '1.2.840.113549.1.7.2' # signed data OID ci['content'] = cms.SignedData(sd) return cms.ContentInfo(ci).dump() return cms.SignedData(sd).dump()
def build_asreq( self, target=None, cname=None, kdcopts=['forwardable', 'renewable', 'proxiable', 'canonicalize']): if isinstance(kdcopts, list): kdcopts = set(kdcopts) if cname is not None: if isinstance(cname, str): cname = [cname] else: cname = [self.cname] if target is not None: if isinstance(target, str): target = [target] else: target = ['127.0.0.1'] now = datetime.datetime.now(datetime.timezone.utc) kdc_req_body_data = {} kdc_req_body_data['kdc-options'] = KDCOptions(kdcopts) kdc_req_body_data['cname'] = PrincipalName({ 'name-type': NAME_TYPE.MS_PRINCIPAL.value, 'name-string': cname }) kdc_req_body_data['realm'] = 'WELLKNOWN:PKU2U' kdc_req_body_data['sname'] = PrincipalName({ 'name-type': NAME_TYPE.MS_PRINCIPAL.value, 'name-string': target }) kdc_req_body_data['till'] = (now + datetime.timedelta(days=1)).replace( microsecond=0) kdc_req_body_data['rtime'] = (now + datetime.timedelta(days=1)).replace( microsecond=0) kdc_req_body_data['nonce'] = secrets.randbits(31) kdc_req_body_data['etype'] = [18, 17] # 23 breaks... kdc_req_body_data['addresses'] = [ HostAddress({ 'addr-type': 20, 'address': b'127.0.0.1' }) ] # not sure if this is needed kdc_req_body = KDC_REQ_BODY(kdc_req_body_data) checksum = hashlib.sha1(kdc_req_body.dump()).digest() authenticator = {} authenticator['cusec'] = now.microsecond authenticator['ctime'] = now.replace(microsecond=0) authenticator['nonce'] = secrets.randbits(31) authenticator['paChecksum'] = checksum dp = {} dp['p'] = self.diffie.p dp['g'] = self.diffie.g dp['q'] = 0 # mandatory parameter, but it is not needed pka = {} pka['algorithm'] = '1.2.840.10046.2.1' pka['parameters'] = keys.DomainParameters(dp) spki = {} spki['algorithm'] = keys.PublicKeyAlgorithm(pka) spki['public_key'] = self.diffie.get_public_key() authpack = {} authpack['pkAuthenticator'] = PKAuthenticator(authenticator) authpack['clientPublicValue'] = keys.PublicKeyInfo(spki) authpack['clientDHNonce'] = self.diffie.dh_nonce authpack = AuthPack(authpack) signed_authpack = self.sign_authpack(authpack.dump(), wrap_signed=False) # ??????? This is absolutely nonsense, payload = length_encode(len(signed_authpack)) + signed_authpack payload = b'\x80' + payload signed_authpack = b'\x30' + length_encode(len(payload)) + payload pa_data_1 = {} pa_data_1['padata-type'] = PaDataType.PK_AS_REQ.value pa_data_1['padata-value'] = signed_authpack asreq = {} asreq['pvno'] = 5 asreq['msg-type'] = 10 asreq['padata'] = [pa_data_1] asreq['req-body'] = kdc_req_body return AS_REQ(asreq).dump()
def build_asreq_pkinit( self, supported_encryption_method, kdcopts=['forwardable', 'renewable', 'renewable-ok']): from asn1crypto import keys if supported_encryption_method.value == 23: raise Exception( 'RC4 encryption is not supported for certificate auth!') now = datetime.datetime.now(datetime.timezone.utc) kdc_req_body_data = {} kdc_req_body_data['kdc-options'] = KDCOptions(set(kdcopts)) kdc_req_body_data['cname'] = PrincipalName({ 'name-type': NAME_TYPE.PRINCIPAL.value, 'name-string': [self.usercreds.username] }) kdc_req_body_data['realm'] = self.usercreds.domain.upper() kdc_req_body_data['sname'] = PrincipalName({ 'name-type': NAME_TYPE.SRV_INST.value, 'name-string': ['krbtgt', self.usercreds.domain.upper()] }) kdc_req_body_data['till'] = (now + datetime.timedelta(days=1)).replace( microsecond=0) kdc_req_body_data['rtime'] = (now + datetime.timedelta(days=1)).replace( microsecond=0) kdc_req_body_data['nonce'] = secrets.randbits(31) kdc_req_body_data['etype'] = [supported_encryption_method.value ] #[18,17] # 23 breaks... kdc_req_body = KDC_REQ_BODY(kdc_req_body_data) checksum = hashlib.sha1(kdc_req_body.dump()).digest() authenticator = {} authenticator['cusec'] = now.microsecond authenticator['ctime'] = now.replace(microsecond=0) authenticator['nonce'] = secrets.randbits(31) authenticator['paChecksum'] = checksum dp = {} dp['p'] = self.usercreds.dhparams.p dp['g'] = self.usercreds.dhparams.g dp['q'] = 0 # mandatory parameter, but it is not needed pka = {} pka['algorithm'] = '1.2.840.10046.2.1' pka['parameters'] = keys.DomainParameters(dp) spki = {} spki['algorithm'] = keys.PublicKeyAlgorithm(pka) spki['public_key'] = self.usercreds.dhparams.get_public_key() authpack = {} authpack['pkAuthenticator'] = PKAuthenticator(authenticator) authpack['clientPublicValue'] = keys.PublicKeyInfo(spki) authpack['clientDHNonce'] = self.usercreds.dhparams.dh_nonce authpack = AuthPack(authpack) signed_authpack = self.usercreds.sign_authpack(authpack.dump(), wrap_signed=True) payload = PA_PK_AS_REQ() payload['signedAuthPack'] = signed_authpack pa_data_1 = {} pa_data_1['padata-type'] = PaDataType.PK_AS_REQ.value pa_data_1['padata-value'] = payload.dump() pa_data_0 = {} pa_data_0['padata-type'] = int(PADATA_TYPE('PA-PAC-REQUEST')) pa_data_0['padata-value'] = PA_PAC_REQUEST({ 'include-pac': True }).dump() asreq = {} asreq['pvno'] = 5 asreq['msg-type'] = 10 asreq['padata'] = [pa_data_0, pa_data_1] asreq['req-body'] = kdc_req_body return AS_REQ(asreq)