def _display_key_info(self, cps): keys = ['8000', 'A006', '8401', '9000'] dgis = cps.get_all_dgis() Log.info( '===================== First Application Key Info =====================' ) for dgi in dgis: kcv = '' for tag, value in dgi.get_all_tags().items(): if tag in keys: if tag != '9000': kcv = algorithm.gen_kcv(value) Log.info('tag%-5s: value:%s kcv:%s', tag, value, kcv) second_keys = ['8000_2', '9000_2'] Log.info( '\n===================== Second Application Key Info =====================' ) for dgi in dgis: kcv = '' for tag, value in dgi.get_all_tags().items(): if dgi.name in second_keys: Log.info('tag%-5s: value:%s kcv:%s', tag, value, kcv) Log.info('\n')
def check_fci_9102(buffer): tlvs = utils.parse_tlv(buffer) sub_tlvs = [] sub_fci_9102 = [] for tlv in tlvs: for fci_item in fci_9102: if tlv.tag == fci_item[0]: sub_fci_9102.append(fci_item) sub_tlvs.append(tlv) # 判断集合中的顺序是否一致 has_ordered = True for index in range(len(sub_fci_9102)): if sub_fci_9102[index][0] != sub_tlvs[index].tag or sub_fci_9102[index][1] != sub_tlvs[index].level: Log.warn('tag%s is not ordered.',sub_tlvs[index].tag) has_ordered = False if not has_ordered: order_tags = [item[0] for item in sub_fci_9102] Log.warn('the minium order list should be %s',str(order_tags)) # 判断是否缺少必须的tag for item in fci_9102: if item not in sub_fci_9102: if item[2] == TagCondition.M: Log.error('FCI 9102 should contains tag%s',item[0]) elif item[2] == TagCondition.C: Log.warn('FCI 9102 recommand that tag%s should be existed.',item[0]) # 判断是否包含多余的tag for item in tlvs: if item not in sub_tlvs: Log.warn('FCI 9102 should not contains tag%s',item.tag)
def read_log(self): Log.info('get trans log') tag9F4D = self.get_tag(PROCESS_STEP.SELECT, '9F4D') if not tag9F4D: Log.info('no tag9F4D,do not support record log') else: record_count = int(tag9F4D[2:4], 16) log_sfi = int(tag9F4D[0:2], 16) buffer = [] for i in range(record_count + 1): resp = apdu.read_record(log_sfi, i + 1, (0x9000, 0x6A83)) if resp.sw == 0x9000: Log.info(resp.response) buffer.append(resp.response) else: break Log.info('%-10s%-15s%-10s%-10s%-8s%-15s%-10s%-10s%-10s', 'result', 'money', 'currency', 'date', 'atc', 'cvr', 'interface', 'time', 'merchant') for resp in buffer: result = resp[0:2] money = resp[2:14] currency = resp[14:18] date = resp[18:24] atc = resp[24:28] cvr = resp[28:40] interface = resp[40:42] trans_time = resp[42:48] merchant = utils.bcd_to_str(resp[48:]) Log.info('%-10s%-15s%-10s%-10s%-8s%-15s%-10s%-10s%-10s', result, money, currency, date, atc, cvr, interface, trans_time, merchant)
def get_dgi_list(fh): dgi_list_len = fh.read_int(fh.current_offset) dgi_list_str = fh.read_binary(fh.current_offset, dgi_list_len) dgi_list = [] for i in range(0, dgi_list_len * 2, 4): dgi_list.append(dgi_list_str[i:i + 4]) des_encrypt_dgi_list_len = fh.read_int(fh.current_offset) des_encrypt_dgi_list_str = fh.read_binary(fh.current_offset, des_encrypt_dgi_list_len) des_encrypt_dgi_list = [] for i in range(0, des_encrypt_dgi_list_len * 2, 4): des_encrypt_dgi_list.append(des_encrypt_dgi_list_str[i:i + 4]) sm_encrypt_dgi_list_len = fh.read_int(fh.current_offset) sm_encrypt_dgi_list_str = fh.read_binary(fh.current_offset, sm_encrypt_dgi_list_len) sm_encrypt_dgi_list = [] for i in range(0, sm_encrypt_dgi_list_len * 2, 4): sm_encrypt_dgi_list.append(sm_encrypt_dgi_list_str[i:i + 4]) Log.info('sm encrypt dgi list: ', end=' ') Log.info(sm_encrypt_dgi_list) des_encrypt_dgi_list.extend(sm_encrypt_dgi_list) log_dgi_list_len = fh.read_int(fh.current_offset) fh.read_binary(fh.current_offset, log_dgi_list_len) #暂时不需要log DGI记录 return dgi_list, des_encrypt_dgi_list
def second_gac(self): tag8D = self.get_tag(PROCESS_STEP.READ_RECORD, '8D') data = tools.assemble_dol(tag8D) resp = super().gac(Crypto_Type.TC, data) if resp.sw != 0x9000: Log.info('send gac1 failed.') return return resp
def create_check_aid_case(self, check_aid_list): case_node = self.smart_qc.create_case_node('AID检测-非接', 'SSQCaseEx3.dll') # <DeviceList> device_list_node = self.smart_qc.create_node(case_node, 'DeviceList') self.smart_qc.create_device_node(device_list_node, 'PC Twin2') # <SpecialInput> special_input_node = self.smart_qc.create_node(case_node, 'SpecialInput') # <CardStruct> card_struct_node = self.smart_qc.create_node(special_input_node, 'CardSturct') # <MF> self.smart_qc.create_node(card_struct_node, 'MF', fid='3F00') # <ApduList> app_nodes = self.dp_xml_handle.get_child_nodes( self.dp_xml_handle.root_element, 'App') cur_aids = [] for app_node in app_nodes: aid = self.dp_xml_handle.get_attribute(app_node, 'aid') if not aid: Log.error( 'can not get aid from dp xml, check wether the dp xml is correct.' ) return cur_aids.append(aid) need_check_aids = [] for aid in check_aid_list: if aid not in cur_aids: need_check_aids.append(aid) apdu_list_node = self.smart_qc.create_node(card_struct_node, 'ApduList') for aid in need_check_aids: apdu = '00A40400' + utils.get_strlen(aid) + aid self.smart_qc.create_node(apdu_list_node, 'Apdu ', value=apdu, sw12="6A82") test_process_list_node = self.smart_qc.create_node( case_node, 'TestProcessList') self.smart_qc.create_node(test_process_list_node, 'Card_sturct_test', enable='false') self.smart_qc.create_node(test_process_list_node, 'Compare_IC_info', enable='false') self.smart_qc.create_node(test_process_list_node, 'Special_file_test', enable='false') self.smart_qc.create_node(test_process_list_node, 'Transaction_test', enable='false') self.smart_qc.create_node(test_process_list_node, 'Check_atr', enable='false') self.smart_qc.create_node(test_process_list_node, 'ApduList_test', enable='true')
def check_startswith_70(apdu_resps): ''' 检测读记录响应数据是否以70模板开头 ''' for resp in apdu_resps: if helper.case_startswith('70', resp.response) != CR.OK: Log.error('read record response not start with template 70') return CR.ERROR return CR.OK
def store_tag(self,step,tag,value): ''' 存储交易中的tag信息 ''' if not value: Log.warn('tag:%s is empty') if tag == '9F10': self.dki = value[2:4] self.cvn = value[4:6] self.tags_info.append(TransTag(step,tag,value))
def check_empty_tag(trans_obj): ''' 检测读记录之前的数据是否有空值的现象 ''' has_empty_tag = False for tag_info in trans_obj.tags_info: if not tag_info.value: Log.error('tag%s is empty', tag_info.tag) has_empty_tag = True if has_empty_tag: return CR.ERROR return CR.OK
def store_tag_group(self,step,tlvs): ''' 存储交易中的一组tag信息 ''' for tlv in tlvs: if not tlv.is_template: if not tlv.value: Log.warn('tag:%s is empty',tlv.tag) if tlv.tag == '9F10': self.dki = tlv.value[2:4] self.cvn = tlv.value[4:6] self.tags_info.append(TransTag(step,tlv.tag,tlv.value))
def second_gac(self): tag8D = self.get_tag(PROCESS_STEP.READ_RECORD, '8D') data = tools.assemble_dol(tag8D) resp = super().gac(Crypto_Type.TC, data) if resp.sw != 0x9000: Log.info('send gac1 failed.') return tlvs = utils.parse_tlv(resp.response) tools.output_apdu_info(resp) self.store_tag_group(PROCESS_STEP.SECOND_GAC, utils.parse_tlv(resp.response)) return resp
def _filter(self, data): if data and data.startswith('APDU'): start_index = data.find('[') end_index = data.find(']', start_index) resp_start_index = data.find('[', end_index) resp_end_index = data.find(']', resp_start_index) req = data[start_index + 1:end_index] #取[]中间的APDU指令 resp = data[resp_start_index + 1:resp_end_index] if req[0:4] in ('00A4', '80E2', '80E6', '80D8', '80F0'): if not req.endswith('00'): Log.error('data error: %s not end with 00' % data) return req[0:-2], resp return '', ''
def first_gac(self): tag8C = self.get_tag(PROCESS_STEP.READ_RECORD, '8C') data = tools.assemble_dol(tag8C) resp = super().gac(Crypto_Type.ARQC, data) if resp.sw != 0x9000: Log.info('send gac1 failed.') return tlvs = utils.parse_tlv(resp.response) tools.output_apdu_info(resp) self.store_tag_group(PROCESS_STEP.FIRST_GAC, utils.parse_tlv(resp.response)) self.run_case('case_first_gac', 'run_mc', resp) return resp
def _comapre_dgi_list(self, mock_cps, prod_cps): Log.info('===================== Check DGI List =====================') mock_cps_dgis = [item.name for item in mock_cps.dgi_list] prod_cps_dgis = [item.name for item in prod_cps.dgi_list] for mock_cps_dgi_name in mock_cps_dgis: if mock_cps_dgi_name not in prod_cps_dgis: Log.error('should perso DGI %s in product environment', mock_cps_dgi_name) for prod_cps_dgi_name in prod_cps_dgis: if prod_cps_dgi_name not in mock_cps_dgis: Log.error('should NOT perso DGI %s in product environment', prod_cps_dgi_name) Log.info("\nmock dgi list:%s\n", mock_cps_dgis) Log.info('prod dgi list:%s\n', str(prod_cps_dgis))
def process_card_data(fh, rule_file): cps = Cps() flag = fh.read_str(fh.current_offset, 6) if flag != '000EMV': return False, cps card_data_len = fh.read_int64(fh.current_offset) app_count = utils.hex_str_to_int(fh.read_binary(fh.current_offset, 1)) for app in range(app_count): aid_len = utils.hex_str_to_int(fh.read_binary(fh.current_offset, 1)) aid = fh.read_binary(fh.current_offset, aid_len) app_data_len = fh.read_int64(fh.current_offset) dgi_list, encrypt_dgi_list = get_dgi_list(fh) Log.info('encrypt dgi list :', encrypt_dgi_list) for item in dgi_list: card_dgi = Dgi() dgi = fh.read_binary(fh.current_offset, 2) dgi_len = utils.hex_str_to_int(fh.read_binary( fh.current_offset, 1)) dgi_data = fh.read_binary(fh.current_offset, dgi_len) n_dgi = utils.hex_str_to_int(dgi) card_dgi.dgi = dgi if dgi == '0098' or dgi == '0099': dgi = process_pse(dgi, dgi_data) elif dgi == '0100': dgi = process_ppse(dgi, dgi_data) else: if n_dgi < 0x0B01: if dgi_data[0:2] != '70': return False, cps if dgi_data[2:4] == '81': dgi_data = dgi_data[6:] else: dgi_data = dgi_data[4:] if utils.is_rsa(dgi) is False and utils.is_tlv(dgi_data): tlvs = utils.parse_tlv(dgi_data) if len(tlvs) > 0 and tlvs[0].is_template is True: value = utils.assemble_tlv(tlvs[0].tag, tlvs[0].value) card_dgi.add_tag_value(dgi, value) else: for tlv in tlvs: value = process_tag_decrypt( rule_file, tlv.tag, tlv.value) value = utils.assemble_tlv(tlv.tag, value) card_dgi.add_tag_value(tlv.tag, value) else: card_dgi.add_tag_value(dgi, dgi_data) cps.add_dgi(card_dgi) return True, cps
def first_gac(self): tag8C = self.get_tag(PROCESS_STEP.READ_RECORD, '8C') data = tools.assemble_dol(tag8C) resp = super().gac(Crypto_Type.ARQC, data) if resp.sw != 0x9000: Log.info('send gac1 failed.') return tlvs = utils.parse_tlv(resp.response) if len(tlvs) != 1 and tlvs[0].tag != '80': Log.info('gac1 response data error') data = tlvs[0].value self.store_tag(PROCESS_STEP.FIRST_GAC, '9F27', data[0:2]) self.store_tag(PROCESS_STEP.FIRST_GAC, '9F36', data[2:6]) self.store_tag(PROCESS_STEP.FIRST_GAC, '9F26', data[6:22]) self.store_tag(PROCESS_STEP.FIRST_GAC, '9F10', data[22:]) return resp
def _display_dki(self, cps): dgis = cps.get_all_dgis() Log.info( '===================== First Application DKI Info =====================' ) for dgi in dgis: for tag, value in dgi.get_all_tags().items(): if tag in ('9F10') and '_2' not in dgi.name: Log.info('tag9F10:%s DKI:%s', value[6:], value[8:10]) Log.info( '\n===================== Second Application DKI Info =====================' ) for dgi in dgis: for tag, value in dgi.get_all_tags().items(): if tag in ('9F10') and '_2' in dgi.name: Log.info('tag9F10:%s DKI:%s', value[6:], value[8:10]) Log.info('\n')
def read_record(self,tag94): ''' 读记录数据 ''' resps = [] afls = utils.parse_afl(tag94) for afl in afls: Log.info('read record: %02X%02X',afl.sfi,afl.record_no) resp = apdu.read_record(afl.sfi,afl.record_no) if resp.sw != 0x9000: Log.error('read record wrong') return resps tools.output_apdu_info(resp) resps.append(resp) if afl.is_static_sign_data: self.sig_data += utils.remove_template70(resp.response) return resps
def _parse_set_status_cmd(self, req, resp): if req[0:6] == '80F080': if req[6:8] == '07': Log.info('current card lifecycle: OP_INITIALIZE') elif req[6:8] == '0F': Log.info('current card lifecycle: SECURED') else: Log.error('Unknown card lifecycle') if resp != '9000': Log.error('set current lifecyle Failed.')
def check_duplicate_tag(trans_obj): ''' 检测GPO和读记录数据中是否有重复tag出现 ''' tags = [] has_duplicate = False for tag_info in trans_obj.tags_info: if tag_info.step in (PROCESS_STEP.GPO, PROCESS_STEP.READ_RECORD): tags.append(tag_info.tag) tag_counts = len(tags) for current in range(tag_counts): for index in range(current + 1, tag_counts): if tags[current] == tags[index]: Log.error('tag%s has duplicated', tags[current]) has_duplicate = True if has_duplicate: return CR.ERROR return CR.OK
def send_raw(cmd, resp_sw_list=None): ''' 在连接读卡器后,发送APDU指令。 cmd 表示要发送的APDU命令,包括命令头,数据长度,数据。 resp_sw_list 表示期望的响应返回码列表,若返回不是期望的响应码,则自动退出APDU的交互 ''' apdu_response = ApduResponse() bytes_cmd = str.encode(cmd) resp_len = c_int(2048) resp_data = create_string_buffer(resp_len.value) Log.info('APDU: %s', cmd) apdu_response.sw = _pcsc_lib.SendApdu(bytes_cmd, resp_data, resp_len) apdu_response.response = bytes.decode(resp_data.value) apdu_response.request = cmd Log.info('RESP: %X', apdu_response.sw) if resp_sw_list and apdu_response.sw not in resp_sw_list: sys.exit(1) return apdu_response
def create_tag_node(self, app_name, dp_dgi_node, compare_node, aid, super_tag_list=[]): comment = app_name comment += '_' + self.dp_xml_handle.get_attribute(dp_dgi_node, 'name') + ' tag ' tag_nodes = self.dp_xml_handle.get_nodes(dp_dgi_node, 'Tag') for tag_node in tag_nodes: name = self.dp_xml_handle.get_attribute(tag_node, 'name') if name != '--': comment += name + '/' # comment node self.smart_qc.create_comment_node(compare_node, comment) # tag node for tag_node in tag_nodes: name = self.dp_xml_handle.get_attribute(tag_node, 'name') value = self.dp_xml_handle.get_attribute(tag_node, 'value') source = self.dp_xml_handle.get_attribute(tag_node, 'type') if source == 'kms': continue if super_tag_list: existed = False for item in super_tag_list: if item[0] == name: existed = True item[1] = True break if not existed: Log.warn( 'tag %s not be checked in smartQC xml, maybe you need config this tag in your "get_data_list" configration', name) continue if source == 'fixed': self.smart_qc.create_tag_node( compare_node, name, value, settings.get_mappings_info(aid, name).desc, 'BCD', 'error') elif source == 'file': _, value = self.mock_cps._parse_tag_value(tag_node) self.smart_qc.create_tag_node( compare_node, name, value, settings.get_mappings_info(aid, name).desc, 'BCD', 'warn')
def check_tag_len(trans_obj): has_error = False for tag_info in trans_obj.tags_info: tag_len = len(tag_info.value) // 2 len_type, lens = get_tag_len(tag_info.tag, trans_obj.aid) if len_type == LenType.Range: if tag_len < lens[0] or tag_len > lens[1]: Log.error( 'tag%s length is not correct, should be in range%d-%d. current len: %d', tag_info.tag, lens[0], lens[1], tag_len) has_error = True elif len_type == LenType.Fixed: if tag_len not in lens: Log.error( 'tag%s length is not correct, should be any of %s. current len: %d', tag_info.tag, str(lens), tag_len) has_error = True if has_error: return CR.ERROR return CR.OK
def first_gac_cda(self): tag8C = self.get_tag(PROCESS_STEP.READ_RECORD, '8C') if not tag8C: Log.error('first gac cda faild since tag8C is tempty') return False tls = utils.parse_tl(tag8C) data = '' self.unpredicatble_number = '' for tl in tls: data += terminal.get_terminal(tl.tag, tl.len) if tl.tag == '9F37': self.unpredicatble_number = terminal.get_terminal( tl.tag, tl.len) resp = super().gac(Crypto_Type.TC_CDA, data) if resp.sw != 0x9000: Log.error('send first gac command failed. SW:%04X', resp.sw) return tlvs = utils.parse_tlv(resp.response) tools.output_apdu_info(resp) self.store_tag_group(PROCESS_STEP.FIRST_GAC, tlvs)
def get_pse_and_ppse_dgi_list(sddf_dgi_list): global _aid_list_info pse_dgi_list = [] ppse_dgi_list = [] pse_index, _ = _aid_list_info.get( '315041592E5359532E4444463031', ('F', '')) #_aid_list_info['315041592E5359532E4444463031'] ppse_index, _ = _aid_list_info.get( '325041592E5359532E4444463031', ('F', '')) #_aid_list_info['325041592E5359532E4444463031'] if pse_index == 'F': Log.error('无法获取PSE DGI相关列表') if ppse_index == 'F': Log.error('无法获取PPSE DGI相关列表') for dgi in sddf_dgi_list: if dgi[4] == pse_index: pse_dgi_list.append(dgi) elif dgi[4] == ppse_index: ppse_dgi_list.append(dgi) return pse_dgi_list, ppse_dgi_list
def _parse_tlv(dgi_name, data): dgi = Dgi() data = utils.remove_dgi(data, dgi_name) int_dgi = utils.str_to_int(dgi_name) if int_dgi < 0x0B01: if data[0:2] != '70': Log.error('数据有误,小于0B01的DGI应包含70模板') return None data = utils.remove_template70(data) if not utils.is_rsa(dgi_name) and utils.is_tlv(data): tlvs = utils.parse_tlv(data) if len(tlvs) > 0 and tlvs[0].is_template is True: value = utils.assemble_tlv(tlvs[0].tag, tlvs[0].value) dgi.add_tag_value(dgi_name, value) else: for tlv in tlvs: value = utils.assemble_tlv(tlv.tag, tlv.value) dgi.add_tag_value(tlv.tag, value) else: dgi.add_tag_value(dgi_name, data) return dgi
def issuer_auth(self): tag9F26 = self.get_tag(PROCESS_STEP.FIRST_GAC, '9F26') if not self.cvn: Log.error('can not get CVN, check tag9F10 wether existed.') return if self.cvn == '0A': # CVN10处理流程 arc = '3030' key = self.key_ac if self.key_flag == App_Master_Key.MDK: tag5A = self.get_tag(PROCESS_STEP.READ_RECORD, '5A') tag5F34 = self.get_tag(PROCESS_STEP.READ_RECORD, '5F34') key = auth.gen_udk(key, tag5A, tag5F34) arpc = auth.gen_arpc_by_des3(key, tag9F26, arc) resp = apdu.external_auth(arpc, arc) if resp.sw == 0x9000: return True elif self.cvn == '12': # CVN18处理流程 csu = '00820000' self.divert_key() #需要使用AC session key arpc = auth.gen_arpc_by_mac(self.session_key_ac, tag9F26, csu) terminal.set_terminal('91', arpc + csu) return True return False
def process_mag_data(fh,rule_file_name): rule_file = RuleXml(rule_file_name) mag_node = rule_file.get_first_node(rule_file.root_element,'Magstrip') mag_flag = fh.read_str(fh.current_offset,6) if mag_flag != '000MAG': return False mag_data_len = fh.read_int64(fh.current_offset) track_flag_list = [] track_flag_list.append(fh.read(fh.current_offset,1)) track_flag_list.append(fh.read(fh.current_offset + 1,1)) track_flag_list.append(fh.read(fh.current_offset + 1,1)) mag_data = fh.read_binary(fh.current_offset,mag_data_len - 5) mag_data_list = [x for x in mag_data.split('7C') if len(x) > 0] Log.info('decrypt mag data: ',end='') Log.info(mag_data_list) dgi = Dgi() dgi.name = 'Magstrip' if mag_node is not None: mag_key = rule_file.get_attribute(mag_node,'key') decrypt_mag_list = [] for data in mag_data_list: data = utils.bcd_to_str(data) data = algorithm.des3_ecb_decrypt(mag_key,data) data = utils.bcd_to_str(data) data_len = int(data[0:4]) data = data[4:data_len + 4].rstrip() decrypt_mag_list.append(data) pos = 1 for mag in decrypt_mag_list: for index in range(pos,4): pos += 1 option = 'mag' + str(pos) if track_flag_list[index - 1] == '0': dgi.add_tag_value(option,'') continue dgi.add_tag_value(option,mag) break Log.info('decrypt mag data: ',end='') Log.info(decrypt_mag_list) return dgi
def split_rsa(xml, goldpac_dgi_list, is_second_app): rule_file_handle = RuleXml(xml.file_name) _, key = rule_file_handle.get_decrypted_attribute('RSA') sddf_tag = '' _, sddf_tag, _ = rule_file_handle.get_tag_link_attribute( 'EMVDataName', 'Icc_KeyPair') if is_second_app: sddf_tag = sddf_tag[0:4] + get_second_app_index() + sddf_tag[5:8] else: sddf_tag = sddf_tag[0:4] + get_first_app_index() + sddf_tag[5:8] encrypted_data = get_goldpac_data(goldpac_dgi_list, sddf_tag, is_second_app) if encrypted_data is None: Log.error('无法获取RSA数据[tag' + sddf_tag + ']缺少数据') decrypted_data = algorithm.des3_ecb_decrypt(key, encrypted_data) if len(decrypted_data) <= 2 or decrypted_data[0:2] != '30': Log.error('RSA解密失败') return None decrypted_data = decrypted_data[2:] _, decrypted_data = get_rsa_dgi_len(decrypted_data) dgi_list = [] for i in range(9): decrypted_data = decrypted_data[2:] #remove flag '02' dgi_len, decrypted_data = get_rsa_dgi_len(decrypted_data) dgi_data = get_rsa_dgi_value(decrypted_data, dgi_len) decrypted_data = decrypted_data[dgi_len:] dgi = Dgi() if is_second_app: dgi.name = '_2' if i == 4: dgi.name = '8205' + dgi.name elif i == 5: dgi.name = '8204' + dgi.name elif i == 6: dgi.name = '8203' + dgi.name elif i == 7: dgi.name = '8202' + dgi.name elif i == 8: dgi.name = '8201' + dgi.name else: continue dgi.add_tag_value(dgi.name[0:4], dgi_data) dgi_list.append(dgi) Log.info(dgi.name[0:4] + '=' + dgi_data) return dgi_list
def get_terminal(tag, length=None, default=None): value = terminal_cfg.get(tag) if not value: if length: value = '0' * length * 2 Log.warn('can not require terminal settings for tag %s', tag) if value: Log.warn('set tag%s value:%s', tag, value) return value return default else: if length and len(value) != length * 2: if len(value) >= length * 2: value = value[0:length * 2] else: value += '0' * (length * 2 - len(value)) Log.warn('padding 0 at tag %s', tag) return value