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
|
Cheng Tang | c1b86be | 2012-09-24 11:18:36 +0800 | [diff] [blame] | 9 | import traceback
|
Tang Cheng | 396e825 | 2012-07-03 13:21:11 +0800 | [diff] [blame] | 10 |
|
Tang Cheng | 1aa15ee | 2012-09-06 10:12:23 +0800 | [diff] [blame] | 11 |
|
| 12 | def _b(v):
|
| 13 | if isinstance(v, unicode):
|
| 14 | return v.encode('latin_1')
|
| 15 | else:
|
| 16 | return v
|
| 17 |
|
| 18 |
|
Tang Cheng | 396e825 | 2012-07-03 13:21:11 +0800 | [diff] [blame] | 19 | class CardOperatorError(Exception):
|
Tang Cheng | 1aa15ee | 2012-09-06 10:12:23 +0800 | [diff] [blame] | 20 | def __init__(self, msg):
|
| 21 | Exception.__init__(self, msg)
|
| 22 | self.msg = msg
|
| 23 |
|
| 24 |
|
| 25 | class py_decard(object):
|
| 26 | # M1 卡密钥
|
| 27 | KEY_A = 1
|
| 28 | KEY_B = 2
|
| 29 | # 寻卡模式
|
Tang Cheng | 396e825 | 2012-07-03 13:21:11 +0800 | [diff] [blame] | 30 | MODE_ALL = 1
|
| 31 | MODE_IDLE = 0
|
Tang Cheng | 1aa15ee | 2012-09-06 10:12:23 +0800 | [diff] [blame] | 32 | #
|
Tang Cheng | 396e825 | 2012-07-03 13:21:11 +0800 | [diff] [blame] | 33 | 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 Cheng | 1aa15ee | 2012-09-06 10:12:23 +0800 | [diff] [blame] | 42 | if py_decard.dll_handle != None:
|
Tang Cheng | 396e825 | 2012-07-03 13:21:11 +0800 | [diff] [blame] | 43 | return
|
| 44 | py_decard.dll_handle = windll.LoadLibrary(py_decard.dll_name)
|
| 45 |
|
| 46 | @staticmethod
|
| 47 | def setup(**kwdargs):
|
Tang Cheng | 1aa15ee | 2012-09-06 10:12:23 +0800 | [diff] [blame] | 48 | if 'error_method' in kwdargs:
|
Tang Cheng | 396e825 | 2012-07-03 13:21:11 +0800 | [diff] [blame] | 49 | py_decard.error_method = kwdargs["error_method"]
|
| 50 |
|
Tang Cheng | 1aa15ee | 2012-09-06 10:12:23 +0800 | [diff] [blame] | 51 | ####################################################################
|
Cheng Tang | c1b86be | 2012-09-24 11:18:36 +0800 | [diff] [blame] | 52 | def __init__(self, port=None, baud=None):
|
Tang Cheng | 396e825 | 2012-07-03 13:21:11 +0800 | [diff] [blame] | 53 | py_decard._do_load_dll()
|
| 54 | self.card_mode = 'contactless'
|
| 55 | self.ic_port = 0
|
Cheng Tang | c1b86be | 2012-09-24 11:18:36 +0800 | [diff] [blame] | 56 | if port:
|
| 57 | if not self.open_port(port, baud):
|
| 58 | raise RuntimeError(u"不能打开读卡器port=%d,baud=%d" % (port, baud))
|
| 59 | self.beep()
|
Tang Cheng | 1aa15ee | 2012-09-06 10:12:23 +0800 | [diff] [blame] | 60 |
|
| 61 | def set_card_mode(self, mode='cotactless', icport=-1):
|
Tang Cheng | 396e825 | 2012-07-03 13:21:11 +0800 | [diff] [blame] | 62 | self.card_mode = mode
|
Tang Cheng | 1aa15ee | 2012-09-06 10:12:23 +0800 | [diff] [blame] | 63 | if self.card_mode != 'contactless':
|
Tang Cheng | 396e825 | 2012-07-03 13:21:11 +0800 | [diff] [blame] | 64 | self.ic_port = icport
|
Tang Cheng | 1aa15ee | 2012-09-06 10:12:23 +0800 | [diff] [blame] | 65 |
|
| 66 | def setsamport(self, port):
|
Tang Cheng | 396e825 | 2012-07-03 13:21:11 +0800 | [diff] [blame] | 67 | self.sam_port = self._get_sam_port(port)
|
| 68 | ats_buffer = create_string_buffer('\000' * 256)
|
| 69 | ats_len = c_char('\000')
|
Tang Cheng | 1aa15ee | 2012-09-06 10:12:23 +0800 | [diff] [blame] | 70 |
|
| 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 Cheng | 396e825 | 2012-07-03 13:21:11 +0800 | [diff] [blame] | 75 | 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 Cheng | 1aa15ee | 2012-09-06 10:12:23 +0800 | [diff] [blame] | 80 |
|
| 81 | def error(self, error):
|
Tang Cheng | 396e825 | 2012-07-03 13:21:11 +0800 | [diff] [blame] | 82 | if py_decard.error_method == py_decard.ERROR_RET_NONE:
|
| 83 | return None
|
| 84 | raise CardOperatorError(error)
|
Tang Cheng | 1aa15ee | 2012-09-06 10:12:23 +0800 | [diff] [blame] | 85 |
|
| 86 | def open_port(self, port, baud):
|
Tang Cheng | 396e825 | 2012-07-03 13:21:11 +0800 | [diff] [blame] | 87 | if py_decard.dll_handle == None:
|
Tang Cheng | 1aa15ee | 2012-09-06 10:12:23 +0800 | [diff] [blame] | 88 | raise RuntimeError(py_decard.dll_name + ' not load ')
|
| 89 | if py_decard.device_handle != None:
|
Tang Cheng | 396e825 | 2012-07-03 13:21:11 +0800 | [diff] [blame] | 90 | return True
|
Tang Cheng | 1aa15ee | 2012-09-06 10:12:23 +0800 | [diff] [blame] | 91 |
|
| 92 | dev_handle = py_decard.dll_handle.dc_init(port, baud)
|
Tang Cheng | 396e825 | 2012-07-03 13:21:11 +0800 | [diff] [blame] | 93 | if dev_handle <= 0:
|
| 94 | return False
|
| 95 | py_decard.device_handle = dev_handle
|
| 96 | return True
|
Tang Cheng | 1aa15ee | 2012-09-06 10:12:23 +0800 | [diff] [blame] | 97 |
|
Tang Cheng | 396e825 | 2012-07-03 13:21:11 +0800 | [diff] [blame] | 98 | 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 Cheng | 1aa15ee | 2012-09-06 10:12:23 +0800 | [diff] [blame] | 103 |
|
Tang Cheng | 396e825 | 2012-07-03 13:21:11 +0800 | [diff] [blame] | 104 | def request_card(self):
|
| 105 | if self.card_mode == 'contactless':
|
Tang Cheng | 1aa15ee | 2012-09-06 10:12:23 +0800 | [diff] [blame] | 106 | py_decard.dll_handle.dc_reset(py_decard.device_handle, 1)
|
Tang Cheng | 396e825 | 2012-07-03 13:21:11 +0800 | [diff] [blame] | 107 | 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 Cheng | 1aa15ee | 2012-09-06 10:12:23 +0800 | [diff] [blame] | 116 |
|
Tang Cheng | 396e825 | 2012-07-03 13:21:11 +0800 | [diff] [blame] | 117 | 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 Cheng | 1aa15ee | 2012-09-06 10:12:23 +0800 | [diff] [blame] | 122 | ret = py_decard.dll_handle.dc_pro_reset(py_decard.device_handle,
|
| 123 | byref(ats_len), ats_buffer)
|
| 124 | if ret != 0:
|
Tang Cheng | 396e825 | 2012-07-03 13:21:11 +0800 | [diff] [blame] | 125 | 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 Cheng | 1aa15ee | 2012-09-06 10:12:23 +0800 | [diff] [blame] | 131 | 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 Cheng | 396e825 | 2012-07-03 13:21:11 +0800 | [diff] [blame] | 136 | 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 Cheng | 1aa15ee | 2012-09-06 10:12:23 +0800 | [diff] [blame] | 140 | return r
|
| 141 |
|
| 142 | def _get_sam_port(self, port):
|
Tang Cheng | 396e825 | 2012-07-03 13:21:11 +0800 | [diff] [blame] | 143 | 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 Cheng | 1aa15ee | 2012-09-06 10:12:23 +0800 | [diff] [blame] | 153 |
|
| 154 | def _do_apdu(self, command):
|
Tang Cheng | 396e825 | 2012-07-03 13:21:11 +0800 | [diff] [blame] | 155 | 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 Cheng | 1aa15ee | 2012-09-06 10:12:23 +0800 | [diff] [blame] | 159 | ret = py_decard.dll_handle.dc_pro_commandlink(py_decard.device_handle, len(command),
|
| 160 | command, byref(resplen), response, 7, 56)
|
Tang Cheng | 396e825 | 2012-07-03 13:21:11 +0800 | [diff] [blame] | 161 | else:
|
Tang Cheng | 1aa15ee | 2012-09-06 10:12:23 +0800 | [diff] [blame] | 162 | 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 Tang | c1b86be | 2012-09-24 11:18:36 +0800 | [diff] [blame] | 168 | return response.raw[:ord(resplen.value)]
|
Tang Cheng | 396e825 | 2012-07-03 13:21:11 +0800 | [diff] [blame] | 169 |
|
Tang Cheng | 1aa15ee | 2012-09-06 10:12:23 +0800 | [diff] [blame] | 170 | def cpucard_apdu(self, command):
|
Tang Cheng | 396e825 | 2012-07-03 13:21:11 +0800 | [diff] [blame] | 171 | 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 Cheng | 1aa15ee | 2012-09-06 10:12:23 +0800 | [diff] [blame] | 178 |
|
| 179 | def cpucard_apdu_hex(self, command):
|
| 180 | cmd_result = command.replace(' ', '')
|
| 181 | resp = self.cpucard_apdu(codecs.decode(cmd_result, 'hex'))
|
Tang Cheng | 396e825 | 2012-07-03 13:21:11 +0800 | [diff] [blame] | 182 | if resp == None:
|
| 183 | return None
|
Tang Cheng | 1aa15ee | 2012-09-06 10:12:23 +0800 | [diff] [blame] | 184 | return codecs.encode(resp, 'hex').upper()
|
| 185 |
|
| 186 | def _do_sam_apdu(self, command):
|
Tang Cheng | 396e825 | 2012-07-03 13:21:11 +0800 | [diff] [blame] | 187 | response = create_string_buffer('\000' * 256)
|
| 188 | resplen = c_char('\000')
|
Tang Cheng | 1aa15ee | 2012-09-06 10:12:23 +0800 | [diff] [blame] | 189 | 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 Tang | c1b86be | 2012-09-24 11:18:36 +0800 | [diff] [blame] | 195 | return response.raw[:ord(resplen.value)]
|
Tang Cheng | 1aa15ee | 2012-09-06 10:12:23 +0800 | [diff] [blame] | 196 |
|
| 197 | def sam_apdu(self, command):
|
Tang Cheng | 396e825 | 2012-07-03 13:21:11 +0800 | [diff] [blame] | 198 | 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 Cheng | 1aa15ee | 2012-09-06 10:12:23 +0800 | [diff] [blame] | 205 |
|
| 206 | def sam_apdu_hex(self, command):
|
| 207 | cmd_result = command.replace(' ', '')
|
| 208 | resp = self.sam_apdu(codecs.decode(cmd_result, 'hex'))
|
Tang Cheng | 396e825 | 2012-07-03 13:21:11 +0800 | [diff] [blame] | 209 | if resp == None:
|
| 210 | return None
|
Tang Cheng | 1aa15ee | 2012-09-06 10:12:23 +0800 | [diff] [blame] | 211 | return codecs.encode(resp, 'hex').upper()
|
| 212 |
|
Tang Cheng | 396e825 | 2012-07-03 13:21:11 +0800 | [diff] [blame] | 213 | def beep(self):
|
Tang Cheng | 1aa15ee | 2012-09-06 10:12:23 +0800 | [diff] [blame] | 214 | 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 Tang | c1b86be | 2012-09-24 11:18:36 +0800 | [diff] [blame] | 244 |
|
| 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
|