1. 程式人生 > >python基於PCSC協議實現讀卡器和卡片通訊

python基於PCSC協議實現讀卡器和卡片通訊

簡介

    PCSC協議是windows平臺下的一套通用API, 所 有 函 數 的 原 型 都 winscard.h中宣告,應用程式需要包含winscard.lib,所有函式的正常返回值都 SCARD_S_SUCCESS。它為讀卡器/卡片和電腦提供了一個標準介面,實現不同生產商的卡片和讀卡器之間的互操作性。之前工作中使用的時候是在VC++環境下之間呼叫的winscard提供的api,學了python之後試著用python來實現。     python由好個模組封裝了PCSC的介面,比如:PySmartCard/pyscard,我是試用了PySmartCard,後面的程式碼也是基於PySmartCard模組編寫的。

PySmartCard模組

下載地址:

https://pypi.org/project/PySmartCard/

需要先pip安裝這個模組,命令如下:

pip install PySmartCard

PySmartCard模組是PCSC/D8/D6/T6都支援的,我只用了PCSC。

實現程式碼

執行程式碼前需要連線上讀卡器,win10下讀卡器驅動貌似是預設安裝的。

#encoding=utf-8

#匯入PcscReader類
from PySmartCard.CpuCard import PcscReader
#匯入time模組
import time

def showLog(data, issend):
      '''列印日誌函式'''
      current = time.strftime('%Y_%m_%d %H:%M:%S', time.localtime())
      if issend:#傳送到卡片的資料
            send = '-->'
      else:#卡片返回的資料
            send = '<--'
      print("{} {} {}".format(current, send, data))
      
def sendApdu(reader, apdu, recv_list, readerType=None):
      '''給卡片傳送指令的函式'''
      #清空
      recv_list[:] = []
      #去掉多餘的空格
      apdu = apdu.replace(' ','')
      showLog(apdu, True)
      respone = reader.send_apdu(apdu,readerType)
      showLog(respone, False)
      #recv_list第1個元素是返回資料
      recv_list.append(respone[:-4])
      #recv_list第2個元素是sw
      recv_list.append(respone[-4:])

def sendApduCommand(reader, apdu, recv_list, readerType=None):
      '''完整的傳送指令函式'''
      sendApdu(reader, apdu, recv_list, readerType)
      #如果是返回的SW是6CXX或者61XX,重新發指令
      apdu = apdu.replace(' ','')
      if recv_list[-1][:2] == '61':
            apdu = '00C00000' + recv_list[-1][2:4]
            sendApdu(reader, apdu, recv_list, readerType)
      elif recv_list[-1][:2].upper() == '6C':
            apdu = apdu[:8] + recv_list[-1][2:4]
            sendApdu(reader, apdu, recv_list, readerType)
      
'''例項化PCSC讀卡器'''
pcsc = PcscReader()

'''獲取所有的讀卡器列表'''
readerName = pcsc.get_pcsc_readerlist()
##print(readerName)#字串型別的讀卡器名稱,按;隔開
#按;切割字串,得到所有的讀卡器名稱
print('當前連線的讀卡器有:')
readerNameList = readerName.split(';')
for  i  in range(len(readerNameList)-1):
      print("{} {} :{}".format('reader',i,readerNameList[i]))

'''連線指定的讀卡器'''
print('*'*40)
#要連線的讀卡器
useReaderName = "SCM Microsystems Inc. SDI010 Contactless Reader 0"
useReaderName = "SCM Microsystems Inc. SDI010 Smart Card Reader 0"

#得到的是字串型別的復位資訊
ATR = pcsc.connect_device(useReaderName)
if ATR:
      print("ConnectDevice Success...")
      print("ATR: ", ATR)
else:
      print("ConnectDevice Failed!")

'''上電'''
print('*'*40)
 #通訊介面型別: 1-contact reader   2-contactless reader
readerType = 1
if 'Contactless'.lower() in useReaderName.lower():
      readerType = 2
if 0== pcsc.power_on(readerType):
      print("Device PowerOn Success...")
else:
      print("Device PowerOn Failed!")

'''傳送APDU'''
print('*'*40)
apdu = '00A4 0400 00'
recv_list = []
sendApduCommand(pcsc,apdu, recv_list, readerType)
if recv_list[1] !="9000":
      print("Send Apdu Failed!")

apdu = '0084 0000 08'
recv_list = []
sendApduCommand(pcsc,apdu, recv_list, readerType)
if recv_list[1] !="9000":
      print("Send Apdu Failed!")

'''斷開讀卡器連線'''
pcsc.disconnect_device()

'''SM4_ECB加密計算'''
print('*'*40)
encrypt = pcsc.sm4_ecb('0123456789ABCDEFFEDCBA9876543210',\
                       '0123456789ABCDEFFEDCBA9876543210',1)
print(encrypt)

執行結果: