增加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