增加pboc 规范中电子现金相关接口
增加 decard 模块 with 支持
diff --git a/tcutils/pbocfunc.py b/tcutils/pbocfunc.py
index c6f6b86..942ea18 100644
--- a/tcutils/pbocfunc.py
+++ b/tcutils/pbocfunc.py
@@ -1,22 +1,26 @@
#! /usr/bin/env python
+# -*- coding: utf-8
# vim: tabstop=4
-import pyDes, codecs
-
+import pyDes
+import codecs
def desencrypt(key, data, m=pyDes.ECB):
k = pyDes.des(key, pad=None, padmode=pyDes.PAD_NORMAL, mode=m)
- return k.encrypt(data)
-
+ return k.encrypt(data)
+
+
def desdecrypt(key, data, m=pyDes.ECB):
k = pyDes.des(key, pad=None, padmode=pyDes.PAD_NORMAL, mode=m)
- return k.decrypt(data)
+ return k.decrypt(data)
+
def tripledesencrypt(key, data, m=pyDes.ECB):
k = pyDes.triple_des(key, pad=None, padmode=pyDes.PAD_NORMAL, mode=m)
return k.encrypt(data)
-
+
+
def tripledesdecrypt(key, data, m=pyDes.ECB):
k = pyDes.triple_des(key, pad=None, padmode=pyDes.PAD_NORMAL, mode=m)
return k.decrypt(data)
@@ -24,20 +28,21 @@
def desencrypthex(key, data):
k = pyDes.des(codecs.decode(key, 'hex'), pad=None, padmode=pyDes.PAD_NORMAL)
- e = k.encrypt(codecs.decode(data, 'hex'))
+ e = k.encrypt(codecs.decode(data, 'hex'))
return codecs.encode(e, 'hex')
+
def tripledesencrypthex(key, data):
k = pyDes.triple_des(codecs.decode(key, 'hex'), pad=None, padmode=pyDes.PAD_NORMAL)
e1 = k.encrypt(codecs.decode(data, 'hex'))
return codecs.encode(e1, 'hex')
+
def DataNot(data):
- r = ''
- for a in data:
- r = r + chr((~ord(a)) & 0xFF)
- return r
-
+ r = [chr((~ord(a)) & 0xFF) for a in data]
+ return "".join(r)
+
+
def PadCardPhyNo(phyno):
r = ''
if len(phyno) < 8:
@@ -49,77 +54,77 @@
else:
r = phyno[:8]
return r
-
+
+
def PadCardPhyNoHex(phyno):
return codecs.encode(PadCardPhyNo(codecs.decode(phyno, 'hex')), 'hex')
-
+
+
def PbocDeliveryKey(factor, key):
cipherdatanot = ''
cipherdata = PadCardPhyNo(factor)
-
print "factor is [%s]" % codecs.encode(cipherdata, 'hex')
- if len(key) == 8: # singledes delivery
+ # singledes delivery
+ if len(key) == 8:
k1 = desencrypt(key, cipherdata)
return k1
elif len(key) == 16:
cipherdatanot = DataNot(cipherdata)
-
k1 = tripledesencrypt(key, cipherdata)
k2 = tripledesencrypt(key, cipherdatanot)
-
return k1 + k2
else:
raise ValueError('key length error')
-
+
+
def PbocDeliveryKeyHex(factor, key):
f = codecs.decode(factor, 'hex')
k = codecs.decode(key, 'hex')
k1 = PbocDeliveryKey(f, k)
return codecs.encode(k1, 'hex')
-
+
def CalcMac3DES(data, initdata, key):
datalen = len(data)
k = pyDes.des(key[:8], pad=None, padmode=pyDes.PAD_NORMAL)
-
for i in range(datalen / 8):
- m = ""
+ m = []
for j in range(len(initdata)):
- m = m + chr(ord(initdata[j]) ^ ord(data[i * 8 + j]))
+ m.append(chr(ord(initdata[j]) ^ ord(data[i * 8 + j])))
- initdata = m
+ initdata = "".join(m)
x = k.encrypt(initdata)
initdata = x
-
k1 = pyDes.des(key[8:], pad=None, padmode=pyDes.PAD_NORMAL)
n = k1.decrypt(initdata)
initdata = k.encrypt(n)
return initdata
-
+
+
def CalcMac3DESHex(data, initdata, key):
d = codecs.decode(data, 'hex')
id = codecs.decode(initdata, 'hex')
k = codecs.decode(key, 'hex')
k1 = CalcMac3DES(d, id, k)
return codecs.encode(k1, 'hex')
-
+
+
def CalcMacDES(data, initdata, key):
datalen = len(data)
k = pyDes.des(key, pad=None, padmode=pyDes.PAD_NORMAL)
-
for i in range(datalen / 8):
- m = ""
+ m = []
for j in range(len(initdata)):
- m = m + chr(ord(initdata[j]) ^ ord(data[i * 8 + j]))
-
- initdata = m
+ m.append(chr(ord(initdata[j]) ^ ord(data[i * 8 + j])))
+ initdata = "".join(m)
x = k.encrypt(initdata)
initdata = x
-
+
return initdata
-
+
+
def CalcMacDESHex(data, initdata, key):
d = codecs.decode(data, 'hex')
id = codecs.decode(initdata, 'hex')
@@ -138,3 +143,154 @@
t = ((~t1) ^ t2) & 0xFF
outkey.append(chr(t))
return codecs.encode(''.join(outkey), 'hex')
+
+
+def tlv_fetch_value(data):
+ datalen = len(data)
+ offset = 0
+ while offset < datalen:
+ t = ord(data[offset])
+ if t & 0x0F == 0x0F:
+ tag = data[offset:offset + 2]
+ offset += 2
+ else:
+ tag = data[offset]
+ offset += 1
+ t = ord(data[offset])
+ if t & 0x80 == 0x80:
+ vl = t & 0x7F
+ vlen = 0
+ for c in data[offset + 1:offset + 1 + vl]:
+ vlen = (vlen << 8) + ord(c)
+ offset += 1 + vl
+ else:
+ vlen = t & 0x7F
+ offset += 1
+
+ if datalen - offset < vlen:
+ raise ValueError(u"data length Error, tag [%s]length[%d]" % (
+ codecs.encode(tag, 'hex'), vlen))
+ value = data[offset:offset + vlen]
+ offset += vlen
+ yield (tag, value,)
+
+
+def tlv_fetch_value_hex(data):
+ for n, v in tlv_fetch_value(codecs.decode(data, 'hex')):
+ yield (codecs.encode(n, 'hex'), codecs.encode(v, 'hex'))
+
+
+def tlv_parse_value(data):
+ """
+ 分析 tlv 格式的数据
+ """
+ result = {}
+ for n, v in tlv_fetch_value(data):
+ result.setdefault(n, v)
+ return result
+
+
+def tlv_parse_value_hex(data):
+ """
+ 分析 tlv 格式的数据, data 是 hex 格式
+ """
+ result = {}
+ for n, v in tlv_fetch_value(codecs.decode(data, 'hex')):
+ result.setdefault(codecs.encode(n, 'hex'), codecs.encode(v, 'hex'))
+ return result
+
+
+def tlv_fetch_define(data):
+ """
+ 分析 tlv 定义(不包括数据)
+ """
+ datalen = len(data)
+ offset = 0
+ while offset < datalen:
+ t = ord(data[offset])
+ if t & 0x0F == 0x0F:
+ tag = data[offset:offset + 2]
+ offset += 2
+ else:
+ tag = data[offset]
+ offset += 1
+ t = ord(data[offset])
+ if t & 0x80 == 0x80:
+ vl = t & 0x7F
+ vlen = 0
+ for c in data[offset + 1:offset + 1 + vl]:
+ vlen = (vlen << 8) + ord(c)
+ offset += 1 + vl
+ else:
+ vlen = t & 0x7F
+ offset += 1
+ yield (tag, vlen,)
+
+
+def tlv_fetch_define_hex(data):
+ """
+ 分析 tlv 定义(不包括数据), data hex 格式
+ """
+ for n, l in tlv_fetch_define(codecs.decode(data, 'hex')):
+ yield (codecs.encode(n, 'hex'), l)
+
+
+def tlv_parse_define(data):
+ """
+ 分析 tlv 定义(不包括数据)
+ """
+ result = {}
+ for n, l in tlv_fetch_define(data):
+ result.setdefault(n, l)
+ return result
+
+
+def tlv_parse_define_hex(data):
+ """
+ 分析 tlv 定义(不包括数据), data hex 格式
+ """
+ result = {}
+ for n, l in tlv_fetch_define(codecs.decode(data, 'hex')):
+ result.setdefault(codecs.encode(n, 'hex'), l)
+ return result
+
+
+def extract_ec_data(data, tags):
+ offset = 0
+ datalen = len(data)
+ for tag in tags:
+ tag_len = len(tag)
+ if offset + tag_len > datalen:
+ break
+ if data[offset:offset + tag_len] != tag:
+ raise KeyError(u"Tag [%s] not found", codecs.encode(tag, 'hex'))
+ offset += tag_len
+ t = ord(data[offset])
+ if t & 0x80 == 0x80:
+ vl = t & 0x7F
+ vlen = 0
+ for c in data[offset + 1:offset + 1 + vl]:
+ vlen = (vlen << 8) + ord(c)
+ offset += 1 + vl
+ else:
+ vlen = t & 0x7F
+ offset += 1
+ if offset + vlen > datalen:
+ raise ValueError(u"data length error!tag[%s]length[%d]" % (
+ codecs.encode(tag, 'hex'), vlen))
+ value = data[offset:offset + vlen]
+ offset += vlen
+ yield (tag, value,)
+
+
+def extract_ec_data_hex(data, tags):
+ t = [codecs.decode(a, 'hex') for a in tags]
+ for t, v in extract_ec_data(codecs.decode(data, 'hex'), t):
+ yield (codecs.encode(t, 'hex'), codecs.encode(v, 'hex'),)
+
+
+def extract_ec_data_dict_hex(data, tags):
+ result = {}
+ for t, v in extract_ec_data_hex(data, tags):
+ result.setdefault(t, v)
+ return result
diff --git a/tcutils/pyDecard.py b/tcutils/pyDecard.py
index 55774e6..5821a4f 100644
--- a/tcutils/pyDecard.py
+++ b/tcutils/pyDecard.py
@@ -6,6 +6,7 @@
'''
from ctypes import *
import codecs
+import traceback
def _b(v):
@@ -48,10 +49,14 @@
py_decard.error_method = kwdargs["error_method"]
####################################################################
- def __init__(self):
+ def __init__(self, port=None, baud=None):
py_decard._do_load_dll()
self.card_mode = 'contactless'
self.ic_port = 0
+ if port:
+ if not self.open_port(port, baud):
+ raise RuntimeError(u"不能打开读卡器port=%d,baud=%d" % (port, baud))
+ self.beep()
def set_card_mode(self, mode='cotactless', icport=-1):
self.card_mode = mode
@@ -160,7 +165,7 @@
if ret != 0:
command_header = codecs.encode(command, 'hex')
return self.error('CPUCard apdu command : %s ,ret=%d' % (command_header, ret))
- return response.raw[:ord(resplen.value)]
+ return response.raw[:ord(resplen.value)]
def cpucard_apdu(self, command):
current_resp = self._do_apdu(command)
@@ -187,7 +192,7 @@
if ret != 0:
command_header = codecs.encode(command, 'hex')
return self.error('CPUCard apdu command : %s ,ret=%d' % (command_header, ret))
- return response.raw[:ord(resplen.value)]
+ return response.raw[:ord(resplen.value)]
def sam_apdu(self, command):
current_resp = self._do_sam_apdu(command)
@@ -236,3 +241,18 @@
if r != 0:
return False
return True
+
+ def __enter__(self):
+ if not py_decard.device_handle:
+ raise RuntimeError(u"Device not open")
+ py_decard.setup(error_method=self.ERROR_RAISE_EXP)
+ return self
+
+ def __exit__(self, exc_type, exc_value, tb):
+ try:
+ self.close_port()
+ except:
+ pass
+ if exc_type:
+ traceback.print_exception(exc_type, exc_value, tb)
+ return True