def upload(pathtocap, aid, blocksize=250, clains='80E8'): ''' Upload a cap file. will send INSTALL for load & LOAD Command ''' caps = a2b(api_cap.CAPFile(pathtocap).readAllCap(GP_List)) lgth = len(caps) c4 = a2b('C4' + getBERTLVlengthfield(lgth)) + caps lgth = len(c4) blocks = [c4[i:i + blocksize] for i in range(0, lgth, blocksize)] assert len(''.join(blocks)) == lgth assert len(blocks) <= 0x100 apdus = [ ''.join([clains, '00%.2X' % i, '%.2X' % len(b), b2a(b)]) for i, b in enumerate(blocks) ] lastblock = apdus[-1] apdus[-1] = '80E880' + lastblock[6:] installforload(aid) for apdu in apdus[:-1]: api_pcsc.send(apdu, expectData='', expectSW='9000', name='LOAD') api_pcsc.send(apdus[-1], expectData='00', expectSW='9000', name='LOAD')
def installforinstall(loadfileaid, moduleaid, appletaid, privileges='00', param='', token='', header='80E60400'): ''' 9.5.2.3.2 Data Field for INSTALL [for install] Mandatory 1 Length of Executable Load File AID Mandatory 5-16 Executable Load File AID Mandatory 1 Length of Executable Module AID Mandatory 5-16 Executable Module AID Mandatory 1 Length of Application AID Mandatory 5-16 Application AID Mandatory 1 Length of Application Privileges Mandatory 1 Application Privileges Mandatory 1 Length of install parameters field Mandatory 2-n Install parameters field Mandatory 1 Length of Install Token Conditional 0-n Install Token ''' lst = (loadfileaid, moduleaid, appletaid, privileges, ('C9' + lv(param)), token) data = ''.join(map(lv, lst)) apdu = header + lv(data) return api_pcsc.send(apdu, expectSW='9000', info='', name='INSTALL for install')
def installforload(aid, securitydomainaid=CardManagerAID, datablockhash='', param='', token='', header='80E60200'): ''' 9.5.2.3.1 Data Field for INSTALL [for load] Mandatory 1 Length of Load File AID Mandatory 5-16 Load File AID Mandatory 1 Length of Security Domain AID Conditional 0-16 Security Domain AID Mandatory 1 Length of Load File Data Block Hash Conditional 0-n Load File Data Block Hash Mandatory 1 Length of load parameters field Conditional 0-n Load parameters field Mandatory 1 Length of Load Token Conditional 0-n Load Token ''' lst = (aid, securitydomainaid, datablockhash, param, token) data = ''.join(map(lv, lst)) apdu = header + lv(data) return api_pcsc.send(apdu, expectData='00', expectSW='9000', info='', name='INSTALL for load')
def extauth(s_enc, s_mac, seq, cardchallenge, hostchallenge, level='00', expectSW='9000', info='', name='GP, EXTERNAL AUTHENTICATE'): ''' See <E.5.2 EXTERNAL AUTHENTICATE Command> of [1]. ''' sk_enc = getEncryptSkey(s_enc, seq) sk_cmac = getCMACSkey(s_mac, seq) hostcryptogram = computeHostCryptogram(sk_enc, seq, hostchallenge, cardchallenge) header = '8482%s0010' % level pt = header + hostcryptogram cmac = generateCMAC(pt, sk_cmac) apdu = pt + cmac return api_pcsc.send(apdu, expectSW=expectSW, info=info, name=name)
def erasepage(self, start, end, erasevector=False): if not erasevector: if start == 0: raise ValueError(u'请注意!请谨慎擦除CIU98428F的首页') return api_pcsc.send('BFEE00FF04%.4X%.4X' % (start & 0xFFFF, end & 0xFFFF), info='Erase Page')
def setseed(self, seed): ''' seed should be hexdigits string ''' lgth = len(seed) / 2 r, sw = api_pcsc.send('00010000%.2X%s' % (lgth & 0xFF, seed.upper()), expectSW='9000', name='set SEED') return self # return self to enable chain-operation
def exchange_raw(self, rawdata, expected_length): ''' 6.3.5.7. CONTACT_EXCHANGE_RAW ''' lgth = len(rawdata) / 2 msb1, lsb1 = '%.2X'%((lgth>>8)&0xFF), '%.2X'%(lgth&0xFF) msb2, lsb2 = '%.2X'%((expected_length>>8)&0xFF), '%.2X'%(expected_length&0xFF) apdu = '10' +lsb1+msb1 +lsb2+msb2 + rawdata return api_pcsc.send(self.ESCAPE + '%.2X'%(len(apdu)/2) + apdu, expectSW='9000', name='CONTACT_EXCHANGE_RAW')
def plaindownload(self, start, data): lgth = len(data) if lgth > 256 * 2: raise ValueError(u'写入数据太长 %d/2,一条APDU最多允许256字节' % lgth) else: apdu = 'B' + data[-2] + '7' + data[-1] + '%.4X' % ( start & 0xFFFF) + '%.2X' % (lgth / 2 - 1) + data[:-2] return api_pcsc.send(apdu, info='Plain Download, %d bytes' % (lgth / 2))
def enable_class(self, a, b, c): ''' 6.3.5.1. CONTACT_GET_SET_PWR_UP_SEQUENCE ''' bitmap = 0 bitmap = bitmap|0x01 if a else bitmap&0xFE bitmap = bitmap|0x02 if b else bitmap&0xFD bitmap = bitmap|0x04 if c else bitmap&0xFB apdu = '04' + '09' + '%.2X'%(bitmap&0xFF) return api_pcsc.send(self.ESCAPE + '03' + apdu, expectSW='9000', name='CONTACT_GET_SET_PWR_UP_SEQUENCE')
def deleteaid(aid, related=False, expectSW='9000'): ''' The DELETE command is used to delete a uniquely identifiable object such as an Executable Load File, an Application, optionally an Executable Load File and its related Applications. Deletion of Key is not yet supported. ''' header = '80E40080' if related else '80E40000' data = '4F' + lv(aid) apdu = header + lv(data) return api_pcsc.send(apdu, expectSW=expectSW, info='', name='Delete AID')
def select(aid, expectData='', expectSW='9000', info='', name='GP, Select AID', header='00A40400'): ''' Select File (INS : 'A4') ''' return api_pcsc.send(header + lv(aid), expectData=expectData, expectSW=expectSW, info=info, name=name)
def set_clock_divison(self, divison): ''' 6.3.5.8. CONTACT_GET_SET_CLK_FREQUENCY DIVISOR VALUE SCCLK Frequency 12 4 MHz 10 4.8 MHz 8 6 MHz 7 6.8 MHz 6 8 MHz 5 9.6 MHz 4 12 MHz 3 16 MHz ''' apdu = '1F' + '%.2X' % (divison&0xFF) return api_pcsc.send(self.ESCAPE + '02' + apdu, expectSW='9000', name='CONTACT_SET_CLK_FREQUENCY')
def initupdate(key_version_number='00', host_challenge='', s_enc='', apduheader='8050000008', expectData='', expectSW='9000', info='', name='GP, INITIALIZE-UPDATE'): ''' key_version_number: the Key Version Number within the Security Domain to be used to initiate the Secure Channel Session. If this value is zero, the first available key chosen by the Security Domain will be used. Returns a tuple of 2 element: ((kdiv, kver, scpid, seq, cardchallenge, cardcryptogram, hostchallenge), sw). Key diversification data 10 bytes Key version number 1 bytes Secure Channel Protocol identifier 1 bytes Sequence Counter 2 bytes Card challenge 6 bytes Card cryptogram 8 bytes Host challenge 8 bytes See <E.5.1 INITIALIZE UPDATE Command> of [1]. ''' if host_challenge: r = host_challenge[:] else: r = api_general.randhex(8) apdu = apduheader + r response_data, sw = api_pcsc.send(apdu, expectSW=expectSW, info=info, name=name) ret = a2b(response_data) kdiv, kver, scpid, seq, cardchallenge, cardcryptogram = [ b2a(ret[a:b]) for a, b in ((0, 10), (10, 11), (11, 12), (12, 14), (14, 20), (20, 28)) ] if s_enc: sk_enc = getEncryptSkey(s_enc, seq) verifyCardCryptogram(r, seq, cardchallenge, cardcryptogram, sk_enc) t = (kdiv, kver, scpid, seq, cardchallenge, cardcryptogram, r) LogMessage( 'Init-update, (kdiv, kver, scpid, seq, cardchallenge, cardcryptogram, hostchallenge): %s' % str(t).upper()) return t, sw
def cipherdownload(self, start, data, key=KEY): lgth = len(data) lgth1 = (lgth / 2 + 7) % 8 # 填充后长度 if lgth > 256 * 2 or lgth1 > 256: raise ValueError(u'写入数据太长 %d/2,一条APDU最多允许256字节' % lgth) else: data1 = a2b(data) if len(data1) % 8: padding = '\xFF' * (8 - len(data1) % 8) data1 = data1 + padding des = DES.new(a2b(key), DES.MODE_ECB, None) cipher = b2a(des.encrypt(a2b(data1))) apdu = 'B' + cipher[-2] + 'B' + cipher[-1] + '%.4X' % ( start & 0xFFFF) + '%.2X' % (len(cipher) - 1) + cipher[:-2] return api_pcsc.send(apdu, info='Write Flash, %d bytes, %s' % (lgth / 2, data))
def setKey(self, mode, val): #0 : des_64 1:des_128 2:des_192 return api_pcsc.send('0000%.2X00%.2X%s' % (mode, len(val) / 2, val), name='setkey')
def seticv(self, icv): return api_pcsc.send('0001000008%s' % icv, name='seticv')
def initDec(self, mode, paddingMode): return api_pcsc.send('0004%.2X%.2X00' % (mode, paddingMode), name='initDec')
def buildCipher(self, cipher, mode): return api_pcsc.send('000A%.2X%.2X00' % (cipher, mode), name='buildcipher')
def clearKey(self, nkey): #0 : des_64 1:des_128 2:des_192 return api_pcsc.send('0008%.2X0000' % nkey, name='clearKey')
def update(self): return api_pcsc.send('0006000000', name='update')
def chooseKey(self, nkey): #0 : des_64 1:des_128 2:des_192 return api_pcsc.send('0002%.2X0000' % nkey, name='chooseKey')
def checkdata(self, start, end, crc, expectSW='9000'): return api_pcsc.send('BF42000006%.4X%.4X%s' % (start & 0xFFFF, end & 0xFFFF, crc), expectSW=expectSW, info='Check Data')
def dofinal(self, data): return api_pcsc.send('00050000%.2X%s' % (len(data) / 2, data), name='dofinal')
def request(self): return api_pcsc.send('BF48020020', info='Read Factory Information')
def getAlgorithm(self, mode): return api_pcsc.send('000700%.2X01' % mode, name='getAlgorithm')
def verifypin(self, pin=PIN, expectSW='9000'): return api_pcsc.send('BF20000108' + pin, expectSW=expectSW, info='Verify PIN')
def buildKey(self, deskey, key_lgth): return api_pcsc.send('0009%.2X%.2X00' % (deskey, key_lgth), name='buildKey')
def changepin(self, old, new): return api_pcsc.send('BF24000010' + old + new, info='Change PIN')
def send(self, apdu, expectData='', expectSW=SW_NO_ERROR): ''' 对pcsc send函数的简单封装,设定期望状态字为9000 ''' return api_pcsc.send(apdu, expectData='', expectSW=expectSW)
def changekey(self, old, new): des = DES.new(a2b(old), DES.MODE_ECB, None) cipher = des.encrypt(a2b(new + '80' + '00' * 7)) return api_pcsc.send('BF24010010' + b2a(cipher), info='Change Key, new key ' + new)