blob: 5821a4fcd97f92b3eb6ccb3e581303dcaa07f3bf [file] [log] [blame]
# -*- coding: utf-8 -*-
'''
Created on 2011-9-29
读卡库程序
@author: cheng.tang
'''
from ctypes import *
import codecs
import traceback
def _b(v):
if isinstance(v, unicode):
return v.encode('latin_1')
else:
return v
class CardOperatorError(Exception):
def __init__(self, msg):
Exception.__init__(self, msg)
self.msg = msg
class py_decard(object):
# M1 卡密钥
KEY_A = 1
KEY_B = 2
# 寻卡模式
MODE_ALL = 1
MODE_IDLE = 0
#
ERROR_RET_NONE = 0
ERROR_RAISE_EXP = 1
dll_handle = None
dll_name = 'dcrf32.dll'
device_handle = None
error_method = ERROR_RET_NONE
@staticmethod
def _do_load_dll():
if py_decard.dll_handle != None:
return
py_decard.dll_handle = windll.LoadLibrary(py_decard.dll_name)
@staticmethod
def setup(**kwdargs):
if 'error_method' in kwdargs:
py_decard.error_method = kwdargs["error_method"]
####################################################################
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
if self.card_mode != 'contactless':
self.ic_port = icport
def setsamport(self, port):
self.sam_port = self._get_sam_port(port)
ats_buffer = create_string_buffer('\000' * 256)
ats_len = c_char('\000')
py_decard.dll_handle.dc_setcpu(py_decard.device_handle, self.sam_port)
ret = py_decard.dll_handle.dc_cpureset(py_decard.device_handle,
byref(ats_len), ats_buffer)
if ret != 0:
return self.error('CPUCard ats error')
l = ord(ats_len.value)
r = ats_buffer.raw[:l]
#print codecs.encode(r,'hex')
return r
def error(self, error):
if py_decard.error_method == py_decard.ERROR_RET_NONE:
return None
raise CardOperatorError(error)
def open_port(self, port, baud):
if py_decard.dll_handle == None:
raise RuntimeError(py_decard.dll_name + ' not load ')
if py_decard.device_handle != None:
return True
dev_handle = py_decard.dll_handle.dc_init(port, baud)
if dev_handle <= 0:
return False
py_decard.device_handle = dev_handle
return True
def close_port(self):
if py_decard.device_handle == None:
return
py_decard.dll_handle.dc_exit(py_decard.device_handle)
py_decard.device_handle = None
def request_card(self):
if self.card_mode == 'contactless':
py_decard.dll_handle.dc_reset(py_decard.device_handle, 1)
cardphyno = create_string_buffer('\000' * 64)
ret = py_decard.dll_handle.dc_card_hex(py_decard.device_handle,
py_decard.MODE_ALL,
cardphyno)
if ret == 0:
return cardphyno.value
return self.error('Request Card Error')
else:
return ''
def cpucard_ats(self):
ats_buffer = create_string_buffer('\000' * 256)
ats_len = c_char('\000')
if self.card_mode == 'contactless':
py_decard.dll_handle.dc_pro_reset.restype = c_short
ret = py_decard.dll_handle.dc_pro_reset(py_decard.device_handle,
byref(ats_len), ats_buffer)
if ret != 0:
return self.error('CPUCard ats error')
l = ord(ats_len.value)
r = ats_buffer.raw[:l]
#print codecs.encode(r,'hex')
return r
else:
py_decard.dll_handle.dc_setcpu(py_decard.device_handle,
self._get_sam_port(self.ic_port))
ret = py_decard.dll_handle.dc_cpureset(py_decard.device_handle,
byref(ats_len), ats_buffer)
if ret != 0:
return self.error('CPUCard ats error')
l = ord(ats_len.value)
r = ats_buffer.raw[:l]
#print codecs.encode(r,'hex')
return r
def _get_sam_port(self, port):
if port == 1:
return 0x0c
elif port == 2:
return 0x0d
elif port == 3:
return 0x0e
elif port == 4:
return 0x0f
else:
self.error('samport error')
def _do_apdu(self, command):
response = create_string_buffer('\000' * 256)
resplen = c_char('\000')
if self.card_mode == 'contactless':
py_decard.dll_handle.dc_pro_commandlink.restype = c_short
ret = py_decard.dll_handle.dc_pro_commandlink(py_decard.device_handle, len(command),
command, byref(resplen), response, 7, 56)
else:
ret = py_decard.dll_handle.dc_cpuapdu(py_decard.device_handle, len(command),
command, byref(resplen), response)
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)]
def cpucard_apdu(self, command):
current_resp = self._do_apdu(command)
if ord(current_resp[-2]) == 0x61 and ord(current_resp[-1]) > 0x00:
cmd = '\x00\xC0\x00\x00' + current_resp[-1]
#print "get response : %s" % codecs.encode(cmd,'hex')
return self._do_apdu(cmd)
else:
return current_resp
def cpucard_apdu_hex(self, command):
cmd_result = command.replace(' ', '')
resp = self.cpucard_apdu(codecs.decode(cmd_result, 'hex'))
if resp == None:
return None
return codecs.encode(resp, 'hex').upper()
def _do_sam_apdu(self, command):
response = create_string_buffer('\000' * 256)
resplen = c_char('\000')
ret = py_decard.dll_handle.dc_cpuapdu(py_decard.device_handle, len(command),
command, byref(resplen), response)
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)]
def sam_apdu(self, command):
current_resp = self._do_sam_apdu(command)
if ord(current_resp[-2]) == 0x61 and ord(current_resp[-1]) > 0x00:
cmd = '\x00\xC0\x00\x00' + current_resp[-1]
#print "get response : %s" % codecs.encode(cmd,'hex')
return self._do_sam_apdu(cmd)
else:
return current_resp
def sam_apdu_hex(self, command):
cmd_result = command.replace(' ', '')
resp = self.sam_apdu(codecs.decode(cmd_result, 'hex'))
if resp == None:
return None
return codecs.encode(resp, 'hex').upper()
def beep(self):
py_decard.dll_handle.dc_beep(py_decard.device_handle, 10)
def auth_card(self, sectno, key, key_type):
assert key_type in (py_decard.KEY_A, py_decard.KEY_B), u"密钥类型错误"
if key_type == py_decard.KEY_A:
key_type = 0
else:
key_type = 4
r = py_decard.dll_handle.dc_authentication_pass(py_decard.device_handle,
key_type, sectno, key)
if r != 0:
return False
return True
def read_block(self, block_no):
data = create_string_buffer('\000' * 16)
r = py_decard.dll_handle.dc_read(py_decard.device_handle,
block_no, data)
if r != 0:
return None
return data.raw[:16]
def write_block(self, block_no, data):
data = _b(data)
r = py_decard.dll_handle.dc_write(py_decard.device_handle,
block_no, data)
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