blob: 5821a4fcd97f92b3eb6ccb3e581303dcaa07f3bf [file] [log] [blame]
Tang Cheng396e8252012-07-03 13:21:11 +08001# -*- coding: utf-8 -*-
2'''
3Created on 2011-9-29
Tang Chenge90e9bb2012-07-03 13:38:01 +08004读卡库程序
Tang Cheng396e8252012-07-03 13:21:11 +08005@author: cheng.tang
6'''
7from ctypes import *
8import codecs
Cheng Tangc1b86be2012-09-24 11:18:36 +08009import traceback
Tang Cheng396e8252012-07-03 13:21:11 +080010
Tang Cheng1aa15ee2012-09-06 10:12:23 +080011
12def _b(v):
13 if isinstance(v, unicode):
14 return v.encode('latin_1')
15 else:
16 return v
17
18
Tang Cheng396e8252012-07-03 13:21:11 +080019class CardOperatorError(Exception):
Tang Cheng1aa15ee2012-09-06 10:12:23 +080020 def __init__(self, msg):
21 Exception.__init__(self, msg)
22 self.msg = msg
23
24
25class py_decard(object):
26 # M1 卡密钥
27 KEY_A = 1
28 KEY_B = 2
29 # 寻卡模式
Tang Cheng396e8252012-07-03 13:21:11 +080030 MODE_ALL = 1
31 MODE_IDLE = 0
Tang Cheng1aa15ee2012-09-06 10:12:23 +080032 #
Tang Cheng396e8252012-07-03 13:21:11 +080033 ERROR_RET_NONE = 0
34 ERROR_RAISE_EXP = 1
35 dll_handle = None
36 dll_name = 'dcrf32.dll'
37 device_handle = None
38 error_method = ERROR_RET_NONE
39
40 @staticmethod
41 def _do_load_dll():
Tang Cheng1aa15ee2012-09-06 10:12:23 +080042 if py_decard.dll_handle != None:
Tang Cheng396e8252012-07-03 13:21:11 +080043 return
44 py_decard.dll_handle = windll.LoadLibrary(py_decard.dll_name)
45
46 @staticmethod
47 def setup(**kwdargs):
Tang Cheng1aa15ee2012-09-06 10:12:23 +080048 if 'error_method' in kwdargs:
Tang Cheng396e8252012-07-03 13:21:11 +080049 py_decard.error_method = kwdargs["error_method"]
50
Tang Cheng1aa15ee2012-09-06 10:12:23 +080051####################################################################
Cheng Tangc1b86be2012-09-24 11:18:36 +080052 def __init__(self, port=None, baud=None):
Tang Cheng396e8252012-07-03 13:21:11 +080053 py_decard._do_load_dll()
54 self.card_mode = 'contactless'
55 self.ic_port = 0
Cheng Tangc1b86be2012-09-24 11:18:36 +080056 if port:
57 if not self.open_port(port, baud):
58 raise RuntimeError(u"不能打开读卡器port=%d,baud=%d" % (port, baud))
59 self.beep()
Tang Cheng1aa15ee2012-09-06 10:12:23 +080060
61 def set_card_mode(self, mode='cotactless', icport=-1):
Tang Cheng396e8252012-07-03 13:21:11 +080062 self.card_mode = mode
Tang Cheng1aa15ee2012-09-06 10:12:23 +080063 if self.card_mode != 'contactless':
Tang Cheng396e8252012-07-03 13:21:11 +080064 self.ic_port = icport
Tang Cheng1aa15ee2012-09-06 10:12:23 +080065
66 def setsamport(self, port):
Tang Cheng396e8252012-07-03 13:21:11 +080067 self.sam_port = self._get_sam_port(port)
68 ats_buffer = create_string_buffer('\000' * 256)
69 ats_len = c_char('\000')
Tang Cheng1aa15ee2012-09-06 10:12:23 +080070
71 py_decard.dll_handle.dc_setcpu(py_decard.device_handle, self.sam_port)
72 ret = py_decard.dll_handle.dc_cpureset(py_decard.device_handle,
73 byref(ats_len), ats_buffer)
74 if ret != 0:
Tang Cheng396e8252012-07-03 13:21:11 +080075 return self.error('CPUCard ats error')
76 l = ord(ats_len.value)
77 r = ats_buffer.raw[:l]
78 #print codecs.encode(r,'hex')
79 return r
Tang Cheng1aa15ee2012-09-06 10:12:23 +080080
81 def error(self, error):
Tang Cheng396e8252012-07-03 13:21:11 +080082 if py_decard.error_method == py_decard.ERROR_RET_NONE:
83 return None
84 raise CardOperatorError(error)
Tang Cheng1aa15ee2012-09-06 10:12:23 +080085
86 def open_port(self, port, baud):
Tang Cheng396e8252012-07-03 13:21:11 +080087 if py_decard.dll_handle == None:
Tang Cheng1aa15ee2012-09-06 10:12:23 +080088 raise RuntimeError(py_decard.dll_name + ' not load ')
89 if py_decard.device_handle != None:
Tang Cheng396e8252012-07-03 13:21:11 +080090 return True
Tang Cheng1aa15ee2012-09-06 10:12:23 +080091
92 dev_handle = py_decard.dll_handle.dc_init(port, baud)
Tang Cheng396e8252012-07-03 13:21:11 +080093 if dev_handle <= 0:
94 return False
95 py_decard.device_handle = dev_handle
96 return True
Tang Cheng1aa15ee2012-09-06 10:12:23 +080097
Tang Cheng396e8252012-07-03 13:21:11 +080098 def close_port(self):
99 if py_decard.device_handle == None:
100 return
101 py_decard.dll_handle.dc_exit(py_decard.device_handle)
102 py_decard.device_handle = None
Tang Cheng1aa15ee2012-09-06 10:12:23 +0800103
Tang Cheng396e8252012-07-03 13:21:11 +0800104 def request_card(self):
105 if self.card_mode == 'contactless':
Tang Cheng1aa15ee2012-09-06 10:12:23 +0800106 py_decard.dll_handle.dc_reset(py_decard.device_handle, 1)
Tang Cheng396e8252012-07-03 13:21:11 +0800107 cardphyno = create_string_buffer('\000' * 64)
108 ret = py_decard.dll_handle.dc_card_hex(py_decard.device_handle,
109 py_decard.MODE_ALL,
110 cardphyno)
111 if ret == 0:
112 return cardphyno.value
113 return self.error('Request Card Error')
114 else:
115 return ''
Tang Cheng1aa15ee2012-09-06 10:12:23 +0800116
Tang Cheng396e8252012-07-03 13:21:11 +0800117 def cpucard_ats(self):
118 ats_buffer = create_string_buffer('\000' * 256)
119 ats_len = c_char('\000')
120 if self.card_mode == 'contactless':
121 py_decard.dll_handle.dc_pro_reset.restype = c_short
Tang Cheng1aa15ee2012-09-06 10:12:23 +0800122 ret = py_decard.dll_handle.dc_pro_reset(py_decard.device_handle,
123 byref(ats_len), ats_buffer)
124 if ret != 0:
Tang Cheng396e8252012-07-03 13:21:11 +0800125 return self.error('CPUCard ats error')
126 l = ord(ats_len.value)
127 r = ats_buffer.raw[:l]
128 #print codecs.encode(r,'hex')
129 return r
130 else:
Tang Cheng1aa15ee2012-09-06 10:12:23 +0800131 py_decard.dll_handle.dc_setcpu(py_decard.device_handle,
132 self._get_sam_port(self.ic_port))
133 ret = py_decard.dll_handle.dc_cpureset(py_decard.device_handle,
134 byref(ats_len), ats_buffer)
135 if ret != 0:
Tang Cheng396e8252012-07-03 13:21:11 +0800136 return self.error('CPUCard ats error')
137 l = ord(ats_len.value)
138 r = ats_buffer.raw[:l]
139 #print codecs.encode(r,'hex')
Tang Cheng1aa15ee2012-09-06 10:12:23 +0800140 return r
141
142 def _get_sam_port(self, port):
Tang Cheng396e8252012-07-03 13:21:11 +0800143 if port == 1:
144 return 0x0c
145 elif port == 2:
146 return 0x0d
147 elif port == 3:
148 return 0x0e
149 elif port == 4:
150 return 0x0f
151 else:
152 self.error('samport error')
Tang Cheng1aa15ee2012-09-06 10:12:23 +0800153
154 def _do_apdu(self, command):
Tang Cheng396e8252012-07-03 13:21:11 +0800155 response = create_string_buffer('\000' * 256)
156 resplen = c_char('\000')
157 if self.card_mode == 'contactless':
158 py_decard.dll_handle.dc_pro_commandlink.restype = c_short
Tang Cheng1aa15ee2012-09-06 10:12:23 +0800159 ret = py_decard.dll_handle.dc_pro_commandlink(py_decard.device_handle, len(command),
160 command, byref(resplen), response, 7, 56)
Tang Cheng396e8252012-07-03 13:21:11 +0800161 else:
Tang Cheng1aa15ee2012-09-06 10:12:23 +0800162 ret = py_decard.dll_handle.dc_cpuapdu(py_decard.device_handle, len(command),
163 command, byref(resplen), response)
164
165 if ret != 0:
166 command_header = codecs.encode(command, 'hex')
167 return self.error('CPUCard apdu command : %s ,ret=%d' % (command_header, ret))
Cheng Tangc1b86be2012-09-24 11:18:36 +0800168 return response.raw[:ord(resplen.value)]
Tang Cheng396e8252012-07-03 13:21:11 +0800169
Tang Cheng1aa15ee2012-09-06 10:12:23 +0800170 def cpucard_apdu(self, command):
Tang Cheng396e8252012-07-03 13:21:11 +0800171 current_resp = self._do_apdu(command)
172 if ord(current_resp[-2]) == 0x61 and ord(current_resp[-1]) > 0x00:
173 cmd = '\x00\xC0\x00\x00' + current_resp[-1]
174 #print "get response : %s" % codecs.encode(cmd,'hex')
175 return self._do_apdu(cmd)
176 else:
177 return current_resp
Tang Cheng1aa15ee2012-09-06 10:12:23 +0800178
179 def cpucard_apdu_hex(self, command):
180 cmd_result = command.replace(' ', '')
181 resp = self.cpucard_apdu(codecs.decode(cmd_result, 'hex'))
Tang Cheng396e8252012-07-03 13:21:11 +0800182 if resp == None:
183 return None
Tang Cheng1aa15ee2012-09-06 10:12:23 +0800184 return codecs.encode(resp, 'hex').upper()
185
186 def _do_sam_apdu(self, command):
Tang Cheng396e8252012-07-03 13:21:11 +0800187 response = create_string_buffer('\000' * 256)
188 resplen = c_char('\000')
Tang Cheng1aa15ee2012-09-06 10:12:23 +0800189 ret = py_decard.dll_handle.dc_cpuapdu(py_decard.device_handle, len(command),
190 command, byref(resplen), response)
191
192 if ret != 0:
193 command_header = codecs.encode(command, 'hex')
194 return self.error('CPUCard apdu command : %s ,ret=%d' % (command_header, ret))
Cheng Tangc1b86be2012-09-24 11:18:36 +0800195 return response.raw[:ord(resplen.value)]
Tang Cheng1aa15ee2012-09-06 10:12:23 +0800196
197 def sam_apdu(self, command):
Tang Cheng396e8252012-07-03 13:21:11 +0800198 current_resp = self._do_sam_apdu(command)
199 if ord(current_resp[-2]) == 0x61 and ord(current_resp[-1]) > 0x00:
200 cmd = '\x00\xC0\x00\x00' + current_resp[-1]
201 #print "get response : %s" % codecs.encode(cmd,'hex')
202 return self._do_sam_apdu(cmd)
203 else:
204 return current_resp
Tang Cheng1aa15ee2012-09-06 10:12:23 +0800205
206 def sam_apdu_hex(self, command):
207 cmd_result = command.replace(' ', '')
208 resp = self.sam_apdu(codecs.decode(cmd_result, 'hex'))
Tang Cheng396e8252012-07-03 13:21:11 +0800209 if resp == None:
210 return None
Tang Cheng1aa15ee2012-09-06 10:12:23 +0800211 return codecs.encode(resp, 'hex').upper()
212
Tang Cheng396e8252012-07-03 13:21:11 +0800213 def beep(self):
Tang Cheng1aa15ee2012-09-06 10:12:23 +0800214 py_decard.dll_handle.dc_beep(py_decard.device_handle, 10)
215
216 def auth_card(self, sectno, key, key_type):
217 assert key_type in (py_decard.KEY_A, py_decard.KEY_B), u"密钥类型错误"
218 if key_type == py_decard.KEY_A:
219 key_type = 0
220 else:
221 key_type = 4
222
223 r = py_decard.dll_handle.dc_authentication_pass(py_decard.device_handle,
224 key_type, sectno, key)
225 if r != 0:
226 return False
227 return True
228
229 def read_block(self, block_no):
230 data = create_string_buffer('\000' * 16)
231 r = py_decard.dll_handle.dc_read(py_decard.device_handle,
232 block_no, data)
233 if r != 0:
234 return None
235 return data.raw[:16]
236
237 def write_block(self, block_no, data):
238 data = _b(data)
239 r = py_decard.dll_handle.dc_write(py_decard.device_handle,
240 block_no, data)
241 if r != 0:
242 return False
243 return True
Cheng Tangc1b86be2012-09-24 11:18:36 +0800244
245 def __enter__(self):
246 if not py_decard.device_handle:
247 raise RuntimeError(u"Device not open")
248 py_decard.setup(error_method=self.ERROR_RAISE_EXP)
249 return self
250
251 def __exit__(self, exc_type, exc_value, tb):
252 try:
253 self.close_port()
254 except:
255 pass
256 if exc_type:
257 traceback.print_exception(exc_type, exc_value, tb)
258 return True