def process_dp(dp_file, rule_file): fh = FileHandle(dp_file, 'r+') cps_list = [] cps = Cps() cps.dp_file_path = dp_file app_flag = '' while True: card_data = fh.read_line() if card_data == '': #数据处理完毕 break elif card_data == '[01]': app_flag = '01' continue elif card_data == '[02]': app_flag = '02' continue elif card_data == '[03]': app_flag = '03' continue elif card_data == '[04]': #说明这个是双应用数据(Jetco) app_flag = '04' continue dgi = process_data(app_flag, card_data) cps.add_dgi(dgi) if rule_file is not None: cps = process_rule(rule_file, cps) cps_list.append(cps) return cps_list
def process_dp(dp_file, rule_file): cps_list = [] fh = FileHandle(dp_file, 'rb+') dp_flag = fh.read_binary(fh.current_offset, 7) data_len = utils.hex_str_to_int(fh.read_binary(fh.current_offset, 8)) dgi_count = fh.read_int64(fh.current_offset) dgi_list = [] for i in range(dgi_count): dgi_name_len = fh.read_int(fh.current_offset) dgi_name = fh.read_str(fh.current_offset, dgi_name_len) dgi_list.append(dgi_name) card_seq = fh.read_binary(fh.current_offset, 4) card_data_len = fh.read_int(fh.current_offset) while data_len > fh.current_offset: cps = Cps() cps.dp_file_path = dp_file for item in dgi_list: dgi = Dgi() start_flag = fh.read_binary(fh.current_offset, 1) if start_flag != '86': return cps_list dgi_len = get_len(fh) dgi_name = fh.read_binary(fh.current_offset, 2) dgi.name = dgi_name dgi_data_len = utils.hex_str_to_int( fh.read_binary(fh.current_offset, 1)) n_dgi_seq = utils.hex_str_to_int(dgi_name) if n_dgi_seq <= 0x0B00: #认为是记录 template70 = fh.read_binary(fh.current_offset, 1) if template70 != '70': return cps_list dgi_data_len = get_len(fh) dgi_data = fh.read_binary(fh.current_offset, dgi_data_len) if item[0:3] == 'PSE': dgi = process_pse_and_ppse(dgi_name, dgi_data, 'PSE') elif item[0:4] == 'PPSE': dgi = process_pse_and_ppse(dgi_name, dgi_data, 'PPSE') else: if n_dgi_seq <= 0x0B00 or (utils.is_rsa(dgi_name) 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) 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, dgi_data) cps.add_dgi(dgi) if rule_file is not None: process_rule(rule_file, cps) cps_list.append(cps) return cps_list
def get_cps(cps_file): ''' 通过cps文件获取cps数据 ''' cps = Cps() ini = IniParser(cps_file) sections = ini.get_sections() for section in sections: if section == 'AID_LIST': value = ini.get_value(section,section) aid_list = value.split(';') cps.pse_aid = aid_list[0] cps.ppse_aid = aid_list[1] cps.first_app_aid = aid_list[2] cps.second_app_aid = aid_list[3] elif section in ('DGI_LIST','DGI_LIST_2'): continue else: dgi = Dgi() dgi.name = section options = ini.get_options(section) for option in options: value = ini.get_value(section,option) dgi.add_tag_value(option,value) cps.add_dgi(dgi) return cps
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 process_dp(dp_file,rule_file): fh = FileHandle(dp_file,'r+') flag_dc = '[01]' flag_ec = '[02]' flag_q = '[03]' cps_list = [] while True: cps = Cps() cps.dp_file_path = dp_file card_data = fh.read_line() if card_data == '': #数据处理完毕 break index_dc = card_data.find(flag_dc) index_ec = card_data.find(flag_ec) index_q = card_data.find(flag_q) data_dc = card_data[index_dc + len(flag_dc) : index_ec] data_ec = card_data[index_ec + len(flag_ec) : index_q] data_q = card_data[index_q + len(flag_q) :] dgi_dc = process_data(data_dc,'01') dgi_ec = process_data(data_ec,'02') dgi_q = process_data(data_q,'03') cps.add_dgi(dgi_dc) cps.add_dgi(dgi_ec) cps.add_dgi(dgi_q) cps = process_EF02(cps) if rule_file is not None: cps = process_rule(rule_file,cps) cps_list.append(cps) return cps_list
def process_dp(dp_file, rule_file): fh = FileHandle(dp_file, 'rb+') fh.read(fh.current_offset, 8596) #reserved dgi_list = get_dgi_list(fh) file_size = fh.file_size cps_list = [] while fh.current_offset < file_size: card_seq = fh.read_int64_reverse(fh.current_offset) card_data_total_len = fh.read_int_reverse(fh.current_offset) cps = Cps() #存储单个卡片数据 cps.dp_file_path = dp_file pse_and_ppse_dgi = [ 'Store_PSE_1', 'Store_PSE_2', 'Store_PPSE', 'DGIF001' ] for dgi_name in dgi_list: dgi = Dgi() #存储单个DGI数据 if dgi_name in pse_and_ppse_dgi: if dgi_name == 'Store_PSE_1': dgi = process_pse_and_ppse(fh, dgi_name, True) else: dgi = process_pse_and_ppse(fh, dgi_name, False) cps.add_dgi(dgi) continue dgi_mark = fh.read_binary(fh.current_offset, 1) #DGI标识 if dgi_mark != '86': return next_len = get_next_len(fh) dgi_seq = fh.read_binary(fh.current_offset, 2) #读取DGI序号 dgi.name = dgi_seq next_len = get_next_len(fh) n_dgi_seq = utils.hex_str_to_int(dgi_seq) if n_dgi_seq <= 0x0B00: #认为是记录 template70 = fh.read_binary(fh.current_offset, 1) if template70 != '70': return next_len = get_next_len(fh) dgi_data = fh.read_binary(fh.current_offset, next_len) if n_dgi_seq <= 0x0B00 or (dgi_seq not in do_not_parse_tlv_list 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) dgi.add_tag_value(dgi_seq, 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_seq, dgi_data) cps.add_dgi(dgi) if rule_file is not None: process_rule(rule_file, cps) process_rule_A001(rule_file, cps) process_rule_eps(rule_file, cps) cps_list.append(cps) return cps_list
def process_dp(dp_file, rule_file=None): cps_list = [] xml = XmlParser(dp_file) batch_information_header_node = xml.get_first_node( xml.root_element, 'batch_information_header') dgi_name_list_node = xml.get_first_node(batch_information_header_node, 'dgi_name_list') dgi_name_list = xml.get_text(dgi_name_list_node) dgi_name_list = dgi_name_list.split(',') card_data_nodes = xml.get_child_nodes(xml.root_element, 'card_data') for card_data_node in card_data_nodes: cps = Cps() cps.dp_file_path = dp_file # account_node = xml.get_first_node(card_data_node,'PAN') # account = xml.get_text(account_node).replace('F','') for dgi_name in dgi_name_list: dgi_node = xml.get_first_node(card_data_node, dgi_name) dgi_text = xml.get_text(dgi_node) if dgi_name == 'AID': cps.aid = dgi_text[4:] continue if dgi_name == 'B001' or dgi_name == 'PAN': continue elif dgi_name in ('Store_PSE_1', 'Store_PSE_2', 'Store_PPSE'): dgi = _process_pse_and_ppse(dgi_name, dgi_text) else: dgi_name = dgi_name[3:] #默认DGI为DGIXXXX形式 dgi = _parse_tlv(dgi_name, dgi_text) dgi.name = dgi_name cps.add_dgi(dgi) if rule_file: cps = _pre_process_rule(rule_file, cps) cps = _process_rsa(cps) cps = _process_8000_and_8020(cps) cps = _process_8400(cps) cps = _process_rule(rule_file, cps) cps_list.append(cps) return cps_list
def process_dp(dp_file, rule_file, is_mc_app=False): global _is_mc_app _is_mc_app = is_mc_app cps_list = [] fh = FileHandle(dp_file, 'rb+') dp_header = fh.read_binary(fh.current_offset, 26) dgi_count = fh.read_int(fh.current_offset) goldpac_dgi_list = [] for i in range(dgi_count): #获取sddf dgi个数及所包含数据的长度 item = GoldpacDgi() item.goldpac_dgi = fh.read_binary(fh.current_offset, 4) item.data_len = fh.read_int(fh.current_offset) goldpac_dgi_list.append(item) for item in goldpac_dgi_list: #获取sddf dgi所包含的数据 item.data = fh.read_binary(fh.current_offset, item.data_len) Log.info(item.goldpac_dgi + ' = ' + item.data) xml = XmlParser(rule_file) get_aid_list_info(xml) #获取AID应用列表信息 sddf_dgi_list = [] sddf_element_nodes = xml.get_nodes(xml.root_element, 'SDDFElement') constans_second_app = has_second_app() for node in sddf_element_nodes: sddf_tag = xml.get_attribute(node, 'SDDFTag') sddf_value = xml.get_attribute(node, 'Value') sddf_elements = parse_sddf_element(sddf_tag, sddf_value) sddf_dgi_list.extend(sddf_elements) cps = Cps() cps.dp_file_path = dp_file pse_dgi_list, ppse_dgi_list = get_pse_and_ppse_dgi_list(sddf_dgi_list) for sddf_tag in sddf_dgi_list: if sddf_tag not in pse_dgi_list and sddf_tag not in ppse_dgi_list: #解析TagLink节点,并生成cps数据 cps_dgi = parse_sddf_data(xml, sddf_tag, goldpac_dgi_list) if cps_dgi != None: cps.add_dgi(cps_dgi) dgi_8000 = parse_8000(xml, goldpac_dgi_list, False) dgi_9000 = parse_9000(xml, goldpac_dgi_list, False) cps.add_dgi(dgi_8000) cps.add_dgi(dgi_9000) if is_mc_app: dgi_A006 = parse_A006(xml, goldpac_dgi_list) cps.add_dgi(dgi_A006) dgi_A016 = Dgi() dgi_A016.name = 'A016' dgi_A016.add_tag_value('A016', dgi_A006.get_value('A006')) dgi_8001 = Dgi() dgi_8001.name = '8001' dgi_8001.add_tag_value('8001', dgi_8000.get_value('8000')) dgi_9001 = Dgi() dgi_9001.name = '9001' dgi_9001.add_tag_value('9001', dgi_9000.get_value('9000')) cps.add_dgi(dgi_8001) cps.add_dgi(dgi_9001) cps.add_dgi(dgi_A016) rsa_dgi_list = split_rsa(xml, goldpac_dgi_list, False) for rsa_dgi in rsa_dgi_list: cps.add_dgi(rsa_dgi) pse_dgi, ppse_dgi = parse_pse_and_ppse(xml, pse_dgi_list, ppse_dgi_list, goldpac_dgi_list) if pse_dgi.is_empty() is False: cps.add_dgi(pse_dgi) if ppse_dgi.is_empty() is False: cps.add_dgi(ppse_dgi) if constans_second_app: cps = process_jetco_special_dgi(xml, goldpac_dgi_list, cps) cps.add_dgi(parse_8000(xml, goldpac_dgi_list, True)) cps.add_dgi(parse_9000(xml, goldpac_dgi_list, True)) rsa_dgi_list = split_rsa(xml, goldpac_dgi_list, True) for rsa_dgi in rsa_dgi_list: cps.add_dgi(rsa_dgi) cps_list.append(cps) return cps_list
def gen_cps(self, session_key=None, second_session_key=None, delete80_list=[]): cps = Cps() start_perso = False # 个人化起始行 app_type = None # 个人化应用类型 prevous_req = '' #保存上一次的数据,对于一条超长数据,需要使用两条store data指令 prevous_req_len = 0 # is_jetco_app = False #判断是否有jetco应用 parse_perso_complete = False #是否已经完成个人化 has_check_status = False #是否有检测卡片状态 has_check_kmc = False # 是否有检测修改过卡片KMC if not delete80_list: delete80_list = ['8201', '8202', '8203', '8204', '8205'] while not self.log_handle.EOF: is_encrypted = False data = self.log_handle.read_line() #每次读取一行数据进行分析 req, resp = self._filter(data) #过滤非指定的APDU信息,返回请求和响应数据 if req.startswith('80E60C00'): #解析安装参数信息 Log.info( '===================== Check Install Param =====================' ) self._parse_install_cmd(req, resp) if req.startswith('00A40400') and not req.startswith( '00A4040008A000000003000000'): start_perso = True #从此行开始认定个人化开始 if start_perso: if req.startswith('00A404000E315041592E5359532E4444463031'): app_type = 'PSE' #说明接下来是个人化PSE continue elif req.startswith('00A404000E325041592E5359532E4444463031'): app_type = 'PPSE' #接下来个人化PPSE continue elif req.startswith('00A40400'): #应用 app_type = 'APP' if req.startswith('00A4040009A00000047400000001'): app_type = "JETCO" is_jetco_app = True # 这里判断,是因为表示是双应用数据 continue if app_type: if req.startswith('80E2') and req[4:6] in ( '00', '60', '80', 'E0'): #处理store data 数据 if resp != '9000': Log.error('perso error: [APDU: %s][%s]', req, resp) continue #判断是否为加密数据 if req[4:6] in ('60', 'E0'): is_encrypted = True # 判断是否已经解析完个人化数据,接下来要判断卡片安全状态和修改KMC if req[4:6] in ('80', 'E0') and app_type == 'APP': parse_perso_complete = True req = req[10:] # 去掉命令头及长度 # 处理仅一条APDU指令发送store data的情况 if not prevous_req: dgi_name = req[0:4] # DGI名称 if is_jetco_app: #默认Jetco为第二应用 dgi_name += '_2' req = req[4:] # 去掉DGI名称 # 去掉DGI后面跟随的长度 data_len = 0 if req[0:4] == 'FF00': data_len = int(req[4:6], 16) req = req[6:] else: data_len = int(req[0:2], 16) req = req[2:] # 如果长度和后面的数据不一致,则说明分两条APDU发送 if data_len * 2 != len(req): prevous_req = req prevous_req_len = data_len continue else: # 处理需要两条APDU指令发送的情况 req = prevous_req + req if prevous_req_len * 2 != len(req): Log.error("data len error") return None prevous_req = '' prevous_req_len = 0 dgi = None if is_jetco_app: dgi = self.parse_store_data( app_type, dgi_name, req, second_session_key, is_encrypted, delete80_list) else: dgi = self.parse_store_data( app_type, dgi_name, req, session_key, is_encrypted, delete80_list) cps.add_dgi(dgi) if parse_perso_complete: if req.startswith('80F080'): # 检测卡片是否设置为安全状态 Log.info( '===================== Check Card Status =====================' ) has_check_status = True self._parse_set_status_cmd(req, resp) if req.startswith('80D8'): # 检测卡片是否修改KMC Log.info( '===================== Check KMC =====================' ) has_check_kmc = True self._parse_modify_kmc(req, resp) if not has_check_status: Log.info( '===================== Check Card Status =====================' ) Log.error('Not set card status during perso card.\n') if not has_check_kmc: Log.info('===================== Check KMC =====================') Log.error('Not modify kmc during perso card.\n') return cps