예제 #1
0
 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')
예제 #2
0
def validate_9F4B(icc_pub_key,icc_exp,sig_data,tag9F4B):
    '''
    校验tag9F4B的正确性
    '''
    recovery_data = gen_recovery_data(icc_pub_key,icc_exp,tag9F4B)
    if not recovery_data:
        Log.error('can not require recovery data through public cert tag90')
        return False
    Log.info('tag9F4B recovery data: %s',recovery_data)
    if recovery_data[0:4] not in ('6A05','6A95') or recovery_data[-2:] != 'BC':
        Log.error('recovery data format incorrect, it should start with 6A05/6A95 and end with BC')
        return False
    hash_input = recovery_data[2:-42] + sig_data
    hash_9F4B = recovery_data[-42:-2]
    hash_output = algorithm.gen_hash(hash_input)
    if hash_9F4B != hash_output:
        Log.error('hash in tag9F4B: %s',hash_9F4B)
        Log.error('hash input: %s',hash_input)
        Log.error('hash calc: %s',hash_output)
        Log.error('hash compared failed whereby tag9F4B is not correct ')
        return False
    icc_dynamic_data_len = int(recovery_data[8:10],16) * 2
    tag9F4C = recovery_data[10:10 + icc_dynamic_data_len]
    terminal.set_terminal('9F4C',tag9F4C)
    return True
예제 #3
0
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
예제 #4
0
 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)
예제 #5
0
 def do_cda(self):
     tag8C = self.get_tag(PROCESS_STEP.READ_RECORD,'8C')
     tag9F47 = self.get_tag(PROCESS_STEP.READ_RECORD,'9F47')
     tag9F4B = self.get_tag(PROCESS_STEP.FIRST_GAC,'9F4B')
     if not tag8C:
         Log.error('tag8C: %s',tag8C)
         Log.error('require tag8C failed whereby dda failed')
         return False
     if not tag9F47:
         Log.error('tag9F47: %s',tag9F47)
         Log.error('require tag9F47 failed whereby dda failed')
         return False
     if not tag9F4B:
         Log.error('tag9F4B: %s',tag9F4B)
         Log.error('require tag9F4B failed whereby dda failed')
         return False
     issuer_pub_key = self._get_issuer_pub_key()
     if not issuer_pub_key:
         Log.error('get issuer public key failed where by cda failed.')
         return False
     icc_pub_key = self._get_icc_pub_key(issuer_pub_key)
     if not icc_pub_key:
         Log.error('get icc public key failed where by cda failed.')
         return False
     sig_data = self.unpredicatble_number
     if not auth.validate_9F4B(icc_pub_key,tag9F47,sig_data,tag9F4B):
         Log.error('icc public key: %s',icc_pub_key)
         Log.error('tag9F47: %s',tag9F47)
         Log.error('tag9F4B: %s',tag9F4B)
         Log.error('validate tag9F4B failed whereby cda failed')
         return False
     Log.info('cda authentication sucess.')
     return True
예제 #6
0
 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
예제 #7
0
 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.')
예제 #8
0
 def do_dda(self,fDDA=False):
     tag9F47 = self.get_tag(PROCESS_STEP.READ_RECORD,'9F47')
     if not tag9F47:
         Log.error('tag9F47: %s',tag9F47)
         Log.error('require tag9F47 failed whereby dda failed')
         return False
     tag9F4B = ''
     ddol = ''
     if fDDA:
         tag9F4B = self.get_tag(PROCESS_STEP.GPO,'9F4B')
         tag9F69 = self.get_tag(PROCESS_STEP.READ_RECORD,'9F69')
         if not tag9F69:
             Log.error('tag9F69: %s',tag9F69)
             Log.error('require tag9F69 failed whereby dda failed')
             return False
         # 这里无需再判断终端数据是否存在,在GPO阶段已经验证过
         tag9F37 = terminal.get_terminal('9F37')
         tag9F02 = terminal.get_terminal('9F02')
         tag5F2A = terminal.get_terminal('5F2A')
         # 这里默认使用ddol代替fDDA的签名数据
         # 签名使用的tag9F36自动包含在了tag9F4B恢复数据中,这里无需重复包含
         ddol = tag9F37 + tag9F02 + tag5F2A + tag9F69 
     else:
         tag9F49 = self.get_tag(PROCESS_STEP.READ_RECORD,'9F49')
         if not tag9F49:
             Log.error('tag9F49: %s',tag9F49)
             Log.error('require tag9F49 failed whereby dda failed')
             return False
         ddol = tools.assemble_dol(tag9F49)
         if not ddol:
             Log.error('tag9F49: %s',tag9F49)
             Log.error('can not get terminal ddol data whereby dda failed')
             return False
         tag9F4B = self.gen_9F4B(ddol)
     if not tag9F4B:
         Log.error('can not get tag9F4B data whereby dda failed')
         return False
     issuer_pub_key = self._get_issuer_pub_key()
     if not issuer_pub_key:
         Log.error('get issuer public key failed where by dda failed.')
         return False
     icc_pub_key = self._get_icc_pub_key(issuer_pub_key)
     if not icc_pub_key:
         Log.error('get icc public key failed where by dda failed.')
         return False
     if not auth.validate_9F4B(icc_pub_key,tag9F47,ddol,tag9F4B):
         Log.error('icc public key: %s',icc_pub_key)
         Log.error('tag9F47: %s',tag9F47)
         Log.error('sig data: %s',ddol)
         Log.error('tag9F4B: %s',tag9F4B)
         Log.error('validate tag9F4B failed whereby dda failed')
         return False
     Log.info('dda authentication sucess.')
     return True
예제 #9
0
 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
예제 #10
0
 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
예제 #11
0
 def _get_icc_pub_key(self,issuer_pub_key):
     icc_pub_key = ''
     tag9F32 = self.get_tag(PROCESS_STEP.READ_RECORD,'9F32')
     tag9F46 = self.get_tag(PROCESS_STEP.READ_RECORD,'9F46')
     tag9F48 = self.get_tag(PROCESS_STEP.READ_RECORD,'9F48')
     tag9F47 = self.get_tag(PROCESS_STEP.READ_RECORD,'9F47')
     tag5A = self.get_tag(PROCESS_STEP.READ_RECORD,'5A')
     tag5F24 = self.get_tag(PROCESS_STEP.READ_RECORD,'5F24')
     
     if not tag9F46:
         Log.error('tag9F46: %s',tag9F46)
         Log.error('require tag9F46 failed whereby dda failed')
         return icc_pub_key
     if not tag9F47:
         Log.error('tag9F47: %s',tag9F47)
         Log.error('require tag9F47 failed whereby dda failed')
         return icc_pub_key
     if not tag5A:
         Log.error('tag5A: %s',tag5A)
         Log.error('require tag5A failed whereby dda failed')
         return icc_pub_key
     if not tag5F24:
         Log.error('tag5F24: %s',tag5F24)
         Log.error('require tag5F24 failed whereby dda failed')
         return icc_pub_key
     if not tag9F32:
         Log.error('tag9F32: %s',tag9F32)
         Log.info('require tag9F32 failed whereby dda failed')
         return issuer_pub_key
     tag9F4A = self.get_tag(PROCESS_STEP.READ_RECORD,'9F4A')
     if tag9F4A:
         tag82 = self.get_tag(PROCESS_STEP.GPO,'82')
         if not tag82:
             Log.error('require tag82 failed whereby dda failed')
             return icc_pub_key
         self.sig_data += tag82
     icc_pub_key = auth.get_icc_pub_key(issuer_pub_key,tag9F32,tag9F46,tag9F48,tag9F47,self.sig_data,tag5A,tag5F24)
     if not icc_pub_key:
         Log.error('issuer public key: %s',issuer_pub_key)
         Log.error('tag9F32: %s',tag9F32)
         Log.error('tag9F46: %s',tag9F46)
         Log.error('tag9F47: %s',tag9F47)
         Log.error('sig data: %s',self.sig_data)
         Log.error('tag5A: %s',tag5A)
         Log.error('tag5F24: %s',tag5F24)
         Log.error('can not get icc public key whereby dda failed')
         return ''
     return icc_pub_key
예제 #12
0
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
예제 #13
0
def get_issuer_pub_key(ca_pub_key,ca_exp,tag90,tag92,tag9F32,tag5A,tag5F24):
    '''
    获取发卡行公钥
    '''
    issuer_pub_key = ''
    recovery_data = gen_recovery_data(ca_pub_key,ca_exp,tag90)
    if not recovery_data:
        Log.error('can not require recovery data through public cert tag90')
        return issuer_pub_key
    Log.info('issuer recovery data: %s',recovery_data)
    if recovery_data[0:4] != '6A02' or recovery_data[-2:] != 'BC':
        Log.error('recovery data format incorrect, it should start with 6A02 and end with BC')
        return issuer_pub_key
    issuer_bin = recovery_data[4:12].replace('F','')
    if len(issuer_bin) < 3 or not tag5A.startswith(issuer_bin):
        Log.error('issuer_bin: %s',issuer_bin)
        Log.error('tag5A: %s',tag5A)
        Log.error('issuer_bin required from recovery data is not accord with tag5A')
        return issuer_pub_key
    expiry_date = int(recovery_data[14:16] + recovery_data[12:14])
    now = int(time.strftime('%y%m'))
    if expiry_date < now:
        Log.warn('expiry date: %s',recovery_data[14:16] + recovery_data[12:14])
        Log.warn('issuer cert has been overdue')
    if expiry_date < int(tag5F24[0:4]):
        Log.warn('expiry date: %s',recovery_data[14:16] + recovery_data[12:14])
        Log.warn('tag5F24: %s',tag5F24)
        Log.warn('issuer cert overdue earlier than application expiry date')
    if recovery_data[22:26] != '0101':
        Log.error('hash algo flag: %s',recovery_data[22:24])
        Log.error('ipk algo flag: %s',recovery_data[24:26])
        return issuer_pub_key
    hash_input = recovery_data[2:-42] + tag92 + tag9F32
    hash_cert = recovery_data[-42:-2]
    hash_output = algorithm.gen_hash(hash_input)
    if hash_cert != hash_output:
        Log.error('hash input: %s',hash_input)
        Log.error('hash: %s',hash_output)
        Log.error('hash cert: %s',hash_cert)
        Log.error('hash compared failed whereby gen issuer recovery data failed ')
        return issuer_pub_key
    issuer_cert_len = int(recovery_data[26:28],16) * 2
    if issuer_cert_len <= len(ca_pub_key) - 72:
        issuer_pub_key = recovery_data[30:30 + issuer_cert_len]
    else:
        issuer_pub_key = recovery_data[30:-42] + tag92
    Log.info('issuer pub key: %s',issuer_pub_key)
    return issuer_pub_key
예제 #14
0
 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
예제 #15
0
def get_icc_pub_key(issuer_pub_key,tag9F32,tag9F46,tag9F48,tag9F47,sig_data,tag5A,tag5F24):
    '''
    获取IC卡公钥
    '''
    icc_pub_key = ''
    recovery_data = gen_recovery_data(issuer_pub_key,tag9F32,tag9F46)
    if not recovery_data:
        Log.error('can not require recovery data through public cert tag90')
        return icc_pub_key
    Log.info('icc recovery data: %s',recovery_data)
    if recovery_data[0:4] != '6A04' or recovery_data[-2:] != 'BC':
        Log.error('recovery data format incorrect, it should start with 6A02 and end with BC')
        return icc_pub_key
    pan = recovery_data[4:24].replace('F','')
    if len(pan) < 16 or tag5A.replace('F','') != pan:
        Log.error('PAN: %s',pan)
        Log.error('tag5A: %s',tag5A)
        Log.error('pan required from recovery data is not accord with tag5A')
        return icc_pub_key
    expiry_date = int(recovery_data[26:28] + recovery_data[24:26])
    now = int(time.strftime('%y%m'))
    if expiry_date < now:
        Log.warn('expiry date: %s',recovery_data[26:28] + recovery_data[24:26])
        Log.warn('icc cert has been overdue')
    if expiry_date < int(tag5F24[0:4]):
        Log.warn('expiry date: %s',recovery_data[26:28] + recovery_data[24:26])
        Log.warn('tag5F24: %s',tag5F24)
        Log.warn('icc cert overdue earlier than application expiry date')
    if recovery_data[34:38] != '0101':
        Log.error('hash algo flag: %s',recovery_data[34:36])
        Log.error('ipk algo flag: %s',recovery_data[36:38])
    hash_input = recovery_data[2:-42] + tag9F48 + tag9F47 + sig_data
    hash_cert = recovery_data[-42:-2]
    hash_output = algorithm.gen_hash(hash_input)
    if hash_cert != hash_output:
        Log.error('hash input: %s',hash_input)
        Log.error('hash: %s',hash_output)
        Log.error('hash cert: %s',hash_cert)
        Log.error('hash compared failed whereby gen icc recovery data failed ')
        return icc_pub_key
    icc_cert_len = int(recovery_data[38:40],16) * 2
    if icc_cert_len <= len(issuer_pub_key) - 84:
        icc_pub_key = recovery_data[42:42 + icc_cert_len]
    else:
        icc_pub_key = recovery_data[42:-42] + tag9F48
    Log.info('icc pub key: %s',icc_pub_key)
    return icc_pub_key
예제 #16
0
 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
예제 #17
0
 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')
예제 #18
0
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
예제 #19
0
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
예제 #20
0
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
예제 #21
0
 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))
예제 #22
0
 def _display_emboss_data(self, cps, dp_xml):
     Log.info(
         '===================== Show Dynamic Data =====================')
     tags = []
     xml_handle = XmlParser(dp_xml)
     tag_nodes = xml_handle.get_nodes(xml_handle.root_element, 'Tag')
     for tag_node in tag_nodes:
         if xml_handle.get_attribute(tag_node, 'type') == 'file':
             name = xml_handle.get_attribute(tag_node, 'name')
             if name not in tags:
                 tags.append(name)
     dgis = cps.get_all_dgis()
     for dgi in dgis:
         for tag, value in dgi.get_all_tags().items():
             if value:
                 value = value[len(tag) + 2:]  #去掉tag及长度域
             if tag in tags:
                 Log.info('tag%-5s:       value:%s', tag, value)
     Log.info('\n')
예제 #23
0
 def compare_cps(self, product_cps, mock_cps, ignore_list=[]):
     self._comapre_dgi_list(mock_cps, product_cps)
     self._display_dki(product_cps)
     self._display_key_info(product_cps)
     mock_dgis = mock_cps.get_all_dgis()
     if not ignore_list:
         # 涉及KMS相关的值,不比较
         ignore_list = [
             '8F', '90', '92', '9F32', '9F46', '9F48', '93', '8201', '8202',
             '8203', '8204', '8205', '8000', '9000', 'A006', 'A016', '8400',
             '8401', '8001', '9001', 'B010', 'B023'
         ]
     Log.info('===================== Compare Data =====================')
     has_err = False
     for mock_dgi in mock_dgis:
         Log.info(
             '===================== compare dgi %s =====================',
             mock_dgi.name)
         product_dgi = product_cps.get_dgi(mock_dgi.name)
         if not product_dgi:
             Log.error('cannot find DGI %s in product enviromnent' %
                       mock_dgi.name)
             has_err = True
             continue
         if product_dgi.name in ('9115', '9116', '9117'):
             product_value = product_dgi.get_value(product_dgi.name)
             mock_value = ''
             for tag, value in mock_dgi.get_all_tags().items():
                 mock_value += value
             if mock_value != product_value:
                 has_err = True
                 Log.error('compare dgi %s failed.' % product_dgi.name)
                 Log.error('Prod_value: %s' % product_value)
                 Log.error('Mock_value: %s\n' % mock_value)
             else:
                 Log.info('compare dgi %s sucess.' % product_dgi.name)
                 Log.info('Prod_value: %s' % product_value)
                 Log.info('Mock_value: %s\n' % mock_value)
         else:
             for tag, value in mock_dgi.get_all_tags().items():
                 if tag in ignore_list:
                     continue
                 product_value = product_dgi.get_value(tag)
                 if product_value != value:
                     has_err = True
                     Log.error('compare tag %s failed.' % tag)
                     Log.error('Prod_value: %s' % product_value)
                     Log.error('Mock_value: %s\n' % value)
                 else:
                     Log.info('compare tag %s sucess.' % tag)
                     Log.info('Prod_value: %s' % product_value)
                     Log.info('Mock_value: %s\n' % value)
     if has_err:
         Log.error('Comapare data failed.')
     else:
         Log.info('Compared data sucess.')
예제 #24
0
    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
예제 #25
0
 def _parse_install_cmd(self, data, resp):
     if data.startswith('80E60C00'):
         data = data[10:]  # 去掉命令头及长度部分
         data, pkg = self._get_install_param(data)
         data, applet = self._get_install_param(data)
         data, inst = self._get_install_param(data)
         data, priviliage = self._get_install_param(data)
         token, param = self._get_install_param(data)
         if resp != '6101':
             Log.error('Install Instance:%s Failed.', inst)
         else:
             Log.info('Install Instance:%s', inst)
         Log.info('Package:%s', pkg)
         Log.info('Applet:%s', applet)
         Log.info('Priviliage:%s', priviliage)
         Log.info('Install param:%s', param)
         Log.info('Token:%s\n', token)
예제 #26
0
 def _parse_modify_kmc(self, req, resp):
     if req[0:4] == '80D8' and resp == '610A':
         Log.info('Check Modify KMC Sucess.')
     else:
         Log.error('Check Modify KMC Failed.')
예제 #27
0
 def _get_issuer_pub_key(self):
     '''
     恢复发卡行公钥
     '''
     issuer_pub_key = ''
     tag84 = self.get_tag(PROCESS_STEP.SELECT,'84')
     tag8F = self.get_tag(PROCESS_STEP.READ_RECORD,'8F')
     tag90 = self.get_tag(PROCESS_STEP.READ_RECORD,'90')
     tag92 = self.get_tag(PROCESS_STEP.READ_RECORD,'92')
     tag9F32 = self.get_tag(PROCESS_STEP.READ_RECORD,'9F32')
     tag5A = self.get_tag(PROCESS_STEP.READ_RECORD,'5A')
     tag5F24 = self.get_tag(PROCESS_STEP.READ_RECORD,'5F24')
     if not tag84 or len(tag84) < 10:
         Log.error('tag84: %s',tag84)
         Log.error('tag84 is empty or length less than 10 bytes whereby dda failed')
         return issuer_pub_key
     if not tag8F:
         Log.error('tag8F: %s',tag8F)
         Log.info('require tag8F failed whereby dda failed')
         return issuer_pub_key
     if not tag90:
         Log.error('tag90: %s',tag90)
         Log.info('require tag90 failed whereby dda failed')
         return issuer_pub_key
     if not tag9F32:
         Log.error('tag9F32: %s',tag9F32)
         Log.info('require tag9F32 failed whereby dda failed')
         return issuer_pub_key
     if not tag5A:
         Log.error('tag5A: %s',tag5A)
         Log.info('require tag5A failed whereby dda failed')
         return issuer_pub_key
     if not tag5F24:
         Log.error('tag5F24: %s',tag5F24)
         Log.info('require tag5F24 failed whereby dda failed')
         return issuer_pub_key
     # 验证tag90,获取发卡行公钥
     # 获取CA 公钥及CA指数
     ca_pub_key,ca_exp = auth.get_ca_pub_key(tag84[0:10],tag8F)
     if not ca_pub_key or not ca_exp:
         Log.error('rid: %s index: %s ',tag84[0:10],tag8F)
         Log.error('can not get ca public key, make sure this root ca existed, please check pcsc.db file')
         return issuer_pub_key
     issuer_pub_key = auth.get_issuer_pub_key(ca_pub_key,ca_exp,tag90,tag92,tag9F32,tag5A,tag5F24)
     if not issuer_pub_key:
         Log.error('CA public key: %s',ca_pub_key)
         Log.error('CA exp: %s',ca_exp)
         Log.error('tag90: %s',tag90)
         Log.error('tag92: %s',tag92)
         Log.error('tag9F32: %s',tag9F32)
         Log.error('tag5A: %s',tag5A)
         Log.error('tag5F24: %s',tag5F24)
         Log.info('can not get issuer public key whereby dda failed')
         return ''
     return issuer_pub_key
예제 #28
0
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