Tang Cheng | 396e825 | 2012-07-03 13:21:11 +0800 | [diff] [blame] | 1 | # -*- coding: utf-8 -*-
|
| 2 | '''
|
| 3 | Created on 2011-9-29
|
Tang Cheng | e90e9bb | 2012-07-03 13:38:01 +0800 | [diff] [blame] | 4 | 读卡库程序
|
Tang Cheng | 396e825 | 2012-07-03 13:21:11 +0800 | [diff] [blame] | 5 | @author: cheng.tang
|
| 6 | '''
|
| 7 | from ctypes import *
|
| 8 | import codecs
|
| 9 |
|
Tang Cheng | 1aa15ee | 2012-09-06 10:12:23 +0800 | [diff] [blame^] | 10 |
|
| 11 | def _b(v):
|
| 12 | if isinstance(v, unicode):
|
| 13 | return v.encode('latin_1')
|
| 14 | else:
|
| 15 | return v
|
| 16 |
|
| 17 |
|
Tang Cheng | 396e825 | 2012-07-03 13:21:11 +0800 | [diff] [blame] | 18 | class CardOperatorError(Exception):
|
Tang Cheng | 1aa15ee | 2012-09-06 10:12:23 +0800 | [diff] [blame^] | 19 | def __init__(self, msg):
|
| 20 | Exception.__init__(self, msg)
|
| 21 | self.msg = msg
|
| 22 |
|
| 23 |
|
| 24 | class py_decard(object):
|
| 25 | # M1 卡密钥
|
| 26 | KEY_A = 1
|
| 27 | KEY_B = 2
|
| 28 | # 寻卡模式
|
Tang Cheng | 396e825 | 2012-07-03 13:21:11 +0800 | [diff] [blame] | 29 | MODE_ALL = 1
|
| 30 | MODE_IDLE = 0
|
Tang Cheng | 1aa15ee | 2012-09-06 10:12:23 +0800 | [diff] [blame^] | 31 | #
|
Tang Cheng | 396e825 | 2012-07-03 13:21:11 +0800 | [diff] [blame] | 32 | ERROR_RET_NONE = 0
|
| 33 | ERROR_RAISE_EXP = 1
|
| 34 | dll_handle = None
|
| 35 | dll_name = 'dcrf32.dll'
|
| 36 | device_handle = None
|
| 37 | error_method = ERROR_RET_NONE
|
| 38 |
|
| 39 | @staticmethod
|
| 40 | def _do_load_dll():
|
Tang Cheng | 1aa15ee | 2012-09-06 10:12:23 +0800 | [diff] [blame^] | 41 | if py_decard.dll_handle != None:
|
Tang Cheng | 396e825 | 2012-07-03 13:21:11 +0800 | [diff] [blame] | 42 | return
|
| 43 | py_decard.dll_handle = windll.LoadLibrary(py_decard.dll_name)
|
| 44 |
|
| 45 | @staticmethod
|
| 46 | def setup(**kwdargs):
|
Tang Cheng | 1aa15ee | 2012-09-06 10:12:23 +0800 | [diff] [blame^] | 47 | if 'error_method' in kwdargs:
|
Tang Cheng | 396e825 | 2012-07-03 13:21:11 +0800 | [diff] [blame] | 48 | py_decard.error_method = kwdargs["error_method"]
|
| 49 |
|
Tang Cheng | 1aa15ee | 2012-09-06 10:12:23 +0800 | [diff] [blame^] | 50 | ####################################################################
|
Tang Cheng | 396e825 | 2012-07-03 13:21:11 +0800 | [diff] [blame] | 51 | def __init__(self):
|
| 52 | py_decard._do_load_dll()
|
| 53 | self.card_mode = 'contactless'
|
| 54 | self.ic_port = 0
|
Tang Cheng | 1aa15ee | 2012-09-06 10:12:23 +0800 | [diff] [blame^] | 55 |
|
| 56 | def set_card_mode(self, mode='cotactless', icport=-1):
|
Tang Cheng | 396e825 | 2012-07-03 13:21:11 +0800 | [diff] [blame] | 57 | self.card_mode = mode
|
Tang Cheng | 1aa15ee | 2012-09-06 10:12:23 +0800 | [diff] [blame^] | 58 | if self.card_mode != 'contactless':
|
Tang Cheng | 396e825 | 2012-07-03 13:21:11 +0800 | [diff] [blame] | 59 | self.ic_port = icport
|
Tang Cheng | 1aa15ee | 2012-09-06 10:12:23 +0800 | [diff] [blame^] | 60 |
|
| 61 | def setsamport(self, port):
|
Tang Cheng | 396e825 | 2012-07-03 13:21:11 +0800 | [diff] [blame] | 62 | self.sam_port = self._get_sam_port(port)
|
| 63 | ats_buffer = create_string_buffer('\000' * 256)
|
| 64 | ats_len = c_char('\000')
|
Tang Cheng | 1aa15ee | 2012-09-06 10:12:23 +0800 | [diff] [blame^] | 65 |
|
| 66 | py_decard.dll_handle.dc_setcpu(py_decard.device_handle, self.sam_port)
|
| 67 | ret = py_decard.dll_handle.dc_cpureset(py_decard.device_handle,
|
| 68 | byref(ats_len), ats_buffer)
|
| 69 | if ret != 0:
|
Tang Cheng | 396e825 | 2012-07-03 13:21:11 +0800 | [diff] [blame] | 70 | return self.error('CPUCard ats error')
|
| 71 | l = ord(ats_len.value)
|
| 72 | r = ats_buffer.raw[:l]
|
| 73 | #print codecs.encode(r,'hex')
|
| 74 | return r
|
Tang Cheng | 1aa15ee | 2012-09-06 10:12:23 +0800 | [diff] [blame^] | 75 |
|
| 76 | def error(self, error):
|
Tang Cheng | 396e825 | 2012-07-03 13:21:11 +0800 | [diff] [blame] | 77 | if py_decard.error_method == py_decard.ERROR_RET_NONE:
|
| 78 | return None
|
| 79 | raise CardOperatorError(error)
|
Tang Cheng | 1aa15ee | 2012-09-06 10:12:23 +0800 | [diff] [blame^] | 80 |
|
| 81 | def open_port(self, port, baud):
|
Tang Cheng | 396e825 | 2012-07-03 13:21:11 +0800 | [diff] [blame] | 82 | if py_decard.dll_handle == None:
|
Tang Cheng | 1aa15ee | 2012-09-06 10:12:23 +0800 | [diff] [blame^] | 83 | raise RuntimeError(py_decard.dll_name + ' not load ')
|
| 84 | if py_decard.device_handle != None:
|
Tang Cheng | 396e825 | 2012-07-03 13:21:11 +0800 | [diff] [blame] | 85 | return True
|
Tang Cheng | 1aa15ee | 2012-09-06 10:12:23 +0800 | [diff] [blame^] | 86 |
|
| 87 | dev_handle = py_decard.dll_handle.dc_init(port, baud)
|
Tang Cheng | 396e825 | 2012-07-03 13:21:11 +0800 | [diff] [blame] | 88 | if dev_handle <= 0:
|
| 89 | return False
|
| 90 | py_decard.device_handle = dev_handle
|
| 91 | return True
|
Tang Cheng | 1aa15ee | 2012-09-06 10:12:23 +0800 | [diff] [blame^] | 92 |
|
Tang Cheng | 396e825 | 2012-07-03 13:21:11 +0800 | [diff] [blame] | 93 | def close_port(self):
|
| 94 | if py_decard.device_handle == None:
|
| 95 | return
|
| 96 | py_decard.dll_handle.dc_exit(py_decard.device_handle)
|
| 97 | py_decard.device_handle = None
|
Tang Cheng | 1aa15ee | 2012-09-06 10:12:23 +0800 | [diff] [blame^] | 98 |
|
Tang Cheng | 396e825 | 2012-07-03 13:21:11 +0800 | [diff] [blame] | 99 | def request_card(self):
|
| 100 | if self.card_mode == 'contactless':
|
Tang Cheng | 1aa15ee | 2012-09-06 10:12:23 +0800 | [diff] [blame^] | 101 | py_decard.dll_handle.dc_reset(py_decard.device_handle, 1)
|
Tang Cheng | 396e825 | 2012-07-03 13:21:11 +0800 | [diff] [blame] | 102 | cardphyno = create_string_buffer('\000' * 64)
|
| 103 | ret = py_decard.dll_handle.dc_card_hex(py_decard.device_handle,
|
| 104 | py_decard.MODE_ALL,
|
| 105 | cardphyno)
|
| 106 | if ret == 0:
|
| 107 | return cardphyno.value
|
| 108 | return self.error('Request Card Error')
|
| 109 | else:
|
| 110 | return ''
|
Tang Cheng | 1aa15ee | 2012-09-06 10:12:23 +0800 | [diff] [blame^] | 111 |
|
Tang Cheng | 396e825 | 2012-07-03 13:21:11 +0800 | [diff] [blame] | 112 | def cpucard_ats(self):
|
| 113 | ats_buffer = create_string_buffer('\000' * 256)
|
| 114 | ats_len = c_char('\000')
|
| 115 | if self.card_mode == 'contactless':
|
| 116 | py_decard.dll_handle.dc_pro_reset.restype = c_short
|
Tang Cheng | 1aa15ee | 2012-09-06 10:12:23 +0800 | [diff] [blame^] | 117 | ret = py_decard.dll_handle.dc_pro_reset(py_decard.device_handle,
|
| 118 | byref(ats_len), ats_buffer)
|
| 119 | if ret != 0:
|
Tang Cheng | 396e825 | 2012-07-03 13:21:11 +0800 | [diff] [blame] | 120 | return self.error('CPUCard ats error')
|
| 121 | l = ord(ats_len.value)
|
| 122 | r = ats_buffer.raw[:l]
|
| 123 | #print codecs.encode(r,'hex')
|
| 124 | return r
|
| 125 | else:
|
Tang Cheng | 1aa15ee | 2012-09-06 10:12:23 +0800 | [diff] [blame^] | 126 | py_decard.dll_handle.dc_setcpu(py_decard.device_handle,
|
| 127 | self._get_sam_port(self.ic_port))
|
| 128 | ret = py_decard.dll_handle.dc_cpureset(py_decard.device_handle,
|
| 129 | byref(ats_len), ats_buffer)
|
| 130 | if ret != 0:
|
Tang Cheng | 396e825 | 2012-07-03 13:21:11 +0800 | [diff] [blame] | 131 | return self.error('CPUCard ats error')
|
| 132 | l = ord(ats_len.value)
|
| 133 | r = ats_buffer.raw[:l]
|
| 134 | #print codecs.encode(r,'hex')
|
Tang Cheng | 1aa15ee | 2012-09-06 10:12:23 +0800 | [diff] [blame^] | 135 | return r
|
| 136 |
|
| 137 | def _get_sam_port(self, port):
|
Tang Cheng | 396e825 | 2012-07-03 13:21:11 +0800 | [diff] [blame] | 138 | if port == 1:
|
| 139 | return 0x0c
|
| 140 | elif port == 2:
|
| 141 | return 0x0d
|
| 142 | elif port == 3:
|
| 143 | return 0x0e
|
| 144 | elif port == 4:
|
| 145 | return 0x0f
|
| 146 | else:
|
| 147 | self.error('samport error')
|
Tang Cheng | 1aa15ee | 2012-09-06 10:12:23 +0800 | [diff] [blame^] | 148 |
|
| 149 | def _do_apdu(self, command):
|
Tang Cheng | 396e825 | 2012-07-03 13:21:11 +0800 | [diff] [blame] | 150 | response = create_string_buffer('\000' * 256)
|
| 151 | resplen = c_char('\000')
|
| 152 | if self.card_mode == 'contactless':
|
| 153 | py_decard.dll_handle.dc_pro_commandlink.restype = c_short
|
Tang Cheng | 1aa15ee | 2012-09-06 10:12:23 +0800 | [diff] [blame^] | 154 | ret = py_decard.dll_handle.dc_pro_commandlink(py_decard.device_handle, len(command),
|
| 155 | command, byref(resplen), response, 7, 56)
|
Tang Cheng | 396e825 | 2012-07-03 13:21:11 +0800 | [diff] [blame] | 156 | else:
|
Tang Cheng | 1aa15ee | 2012-09-06 10:12:23 +0800 | [diff] [blame^] | 157 | ret = py_decard.dll_handle.dc_cpuapdu(py_decard.device_handle, len(command),
|
| 158 | command, byref(resplen), response)
|
| 159 |
|
| 160 | if ret != 0:
|
| 161 | command_header = codecs.encode(command, 'hex')
|
| 162 | return self.error('CPUCard apdu command : %s ,ret=%d' % (command_header, ret))
|
Tang Cheng | 396e825 | 2012-07-03 13:21:11 +0800 | [diff] [blame] | 163 | return response.raw[:ord(resplen.value)]
|
| 164 |
|
Tang Cheng | 1aa15ee | 2012-09-06 10:12:23 +0800 | [diff] [blame^] | 165 | def cpucard_apdu(self, command):
|
Tang Cheng | 396e825 | 2012-07-03 13:21:11 +0800 | [diff] [blame] | 166 | current_resp = self._do_apdu(command)
|
| 167 | if ord(current_resp[-2]) == 0x61 and ord(current_resp[-1]) > 0x00:
|
| 168 | cmd = '\x00\xC0\x00\x00' + current_resp[-1]
|
| 169 | #print "get response : %s" % codecs.encode(cmd,'hex')
|
| 170 | return self._do_apdu(cmd)
|
| 171 | else:
|
| 172 | return current_resp
|
Tang Cheng | 1aa15ee | 2012-09-06 10:12:23 +0800 | [diff] [blame^] | 173 |
|
| 174 | def cpucard_apdu_hex(self, command):
|
| 175 | cmd_result = command.replace(' ', '')
|
| 176 | resp = self.cpucard_apdu(codecs.decode(cmd_result, 'hex'))
|
Tang Cheng | 396e825 | 2012-07-03 13:21:11 +0800 | [diff] [blame] | 177 | if resp == None:
|
| 178 | return None
|
Tang Cheng | 1aa15ee | 2012-09-06 10:12:23 +0800 | [diff] [blame^] | 179 | return codecs.encode(resp, 'hex').upper()
|
| 180 |
|
| 181 | def _do_sam_apdu(self, command):
|
Tang Cheng | 396e825 | 2012-07-03 13:21:11 +0800 | [diff] [blame] | 182 | response = create_string_buffer('\000' * 256)
|
| 183 | resplen = c_char('\000')
|
Tang Cheng | 1aa15ee | 2012-09-06 10:12:23 +0800 | [diff] [blame^] | 184 | ret = py_decard.dll_handle.dc_cpuapdu(py_decard.device_handle, len(command),
|
| 185 | command, byref(resplen), response)
|
| 186 |
|
| 187 | if ret != 0:
|
| 188 | command_header = codecs.encode(command, 'hex')
|
| 189 | return self.error('CPUCard apdu command : %s ,ret=%d' % (command_header, ret))
|
Tang Cheng | 396e825 | 2012-07-03 13:21:11 +0800 | [diff] [blame] | 190 | return response.raw[:ord(resplen.value)]
|
Tang Cheng | 1aa15ee | 2012-09-06 10:12:23 +0800 | [diff] [blame^] | 191 |
|
| 192 | def sam_apdu(self, command):
|
Tang Cheng | 396e825 | 2012-07-03 13:21:11 +0800 | [diff] [blame] | 193 | current_resp = self._do_sam_apdu(command)
|
| 194 | if ord(current_resp[-2]) == 0x61 and ord(current_resp[-1]) > 0x00:
|
| 195 | cmd = '\x00\xC0\x00\x00' + current_resp[-1]
|
| 196 | #print "get response : %s" % codecs.encode(cmd,'hex')
|
| 197 | return self._do_sam_apdu(cmd)
|
| 198 | else:
|
| 199 | return current_resp
|
Tang Cheng | 1aa15ee | 2012-09-06 10:12:23 +0800 | [diff] [blame^] | 200 |
|
| 201 | def sam_apdu_hex(self, command):
|
| 202 | cmd_result = command.replace(' ', '')
|
| 203 | resp = self.sam_apdu(codecs.decode(cmd_result, 'hex'))
|
Tang Cheng | 396e825 | 2012-07-03 13:21:11 +0800 | [diff] [blame] | 204 | if resp == None:
|
| 205 | return None
|
Tang Cheng | 1aa15ee | 2012-09-06 10:12:23 +0800 | [diff] [blame^] | 206 | return codecs.encode(resp, 'hex').upper()
|
| 207 |
|
Tang Cheng | 396e825 | 2012-07-03 13:21:11 +0800 | [diff] [blame] | 208 | def beep(self):
|
Tang Cheng | 1aa15ee | 2012-09-06 10:12:23 +0800 | [diff] [blame^] | 209 | py_decard.dll_handle.dc_beep(py_decard.device_handle, 10)
|
| 210 |
|
| 211 | def auth_card(self, sectno, key, key_type):
|
| 212 | assert key_type in (py_decard.KEY_A, py_decard.KEY_B), u"密钥类型错误"
|
| 213 | if key_type == py_decard.KEY_A:
|
| 214 | key_type = 0
|
| 215 | else:
|
| 216 | key_type = 4
|
| 217 |
|
| 218 | r = py_decard.dll_handle.dc_authentication_pass(py_decard.device_handle,
|
| 219 | key_type, sectno, key)
|
| 220 | if r != 0:
|
| 221 | return False
|
| 222 | return True
|
| 223 |
|
| 224 | def read_block(self, block_no):
|
| 225 | data = create_string_buffer('\000' * 16)
|
| 226 | r = py_decard.dll_handle.dc_read(py_decard.device_handle,
|
| 227 | block_no, data)
|
| 228 | if r != 0:
|
| 229 | return None
|
| 230 | return data.raw[:16]
|
| 231 |
|
| 232 | def write_block(self, block_no, data):
|
| 233 | data = _b(data)
|
| 234 | r = py_decard.dll_handle.dc_write(py_decard.device_handle,
|
| 235 | block_no, data)
|
| 236 | if r != 0:
|
| 237 | return False
|
| 238 | return True
|