青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

隨筆-80  評論-22  文章-0  trackbacks-0

[摘要]本文介紹了如何在VC中通過PC/SC接口實現對智能卡讀寫器的操作,并給出了詳細的例子代碼。
[關鍵詞] 智能卡、PC/SC、智能卡讀寫器

1 引言
完整的智能卡應用系統由后臺服務程序、主機或終端應用程序和智能卡等組成,如圖1所示。其中,后臺服務程序提供了支持智能卡的服務。例如,在一個電子付款系統中,后臺服務程序可以提供到信用卡和帳戶信息的訪問;主機或終端應用程序一般存在于臺式機或者終端、電子付款終端、手機或者一個安全子系統中,終端應用程序要處理用戶、智能卡和后臺服務程序之間的通訊;智能卡則存儲用戶的一些信息。
 
終端應用程序需要通過讀卡器來訪問智能卡,在一個系統中,通常存在多家廠商提供的讀卡器,因此需要一個統一的讀卡器設備驅動接口。
隨著智能卡的廣泛應用,為解決計算機與各種讀卡器之間的互操作性問題,人們提出了PC/SC(Personal Computer/Smart Card)規范,PC/SC規范作為讀卡器和卡與計算機之間有一個標準接口,實現不同生產商的卡和讀卡器之間的互操作性,其獨立于設備的 API使得應用程序開發人員不必考慮當前實現形式和將來實現形式之間的差異,并避免了由于基本硬件改變而引起的應用程序變更,從而降低了軟件開發成本。
Microsoft在其Platform SDK中實現了PC/SC,作為連接智能卡讀卡器與計算機的一個標準模型,提供了獨立于設備的 API,并與Windows平臺集成。因此,我們可以用PC/SC接口來訪問智能卡。

2 PC/SC概述
PC/SC接口包含30多個以Scard為前綴的函數,所有函數的原型都在winscard.h中聲明,應用程序需要包含winscard.lib,所有函數的正常返回值都是SCARD_S_SUCCESS。在這30多個函數中,常用的函數只有幾個,與智能卡的訪問流程(圖2)對應,下面將詳細介紹這些常用函數。

3 PC/SC的使用

3.1建立資源管理器的上下文
函數ScardEstablishContext()用于建立將在其中進行設備數據庫操作的資源管理器上下文(范圍)。
函數原型:LONG SCardEstablishContext(DWORD dwScope,  LPCVOID pvReserved1,  LPCVOID pvReserved2,  LPSCARDCONTEXT phContext);
各個參數的含義:(1)dwScope:輸入類型;表示資源管理器上下文范圍,取值為:SCARD_SCOPE_USER(在用戶域中完成設備數據庫操作)、SCARD_SCOPE_SYSTEM(在系統域中完成設備數據庫操作)。要求應用程序具有相應的操作權限。(2)pvReserved1:輸入類型;保留,必須為NULL。(3)pvReserved2:輸入類型;保留,必須為NULL。(4)phContext:輸出類型;建立的資源管理器上下文的句柄。
 
 
下面是建立資源管理器上下文的代碼:
SCARDCONTEXT        hSC;
LONG                lReturn;
lReturn = SCardEstablishContext(SCARD_SCOPE_USER, NULL, NULL, &hSC);
if ( lReturn!=SCARD_S_SUCCESS )
printf("Failed SCardEstablishContext\n");

3.2 獲得系統中安裝的讀卡器列表
函數ScardListReaders()可以列出系統中安裝的讀卡器的名字。
函數原型:LONG SCardListReaders(SCARDCONTEXT hContext,  LPCTSTR mszGroups,  LPTSTR mszReaders,  LPDWORD pcchReaders);
各個參數的含義:(1)hContext:輸入類型;ScardEstablishContext()建立的資源管理器上下文的句柄,不能為NULL。(2)mszGroups:輸入類型;讀卡器組名,為NULL時,表示列出所有讀卡器。(3)mszReaders:輸出類型;系統中安裝的讀卡器的名字,各個名字之間用’\0’分隔,最后一個名字后面為兩個連續的’\0’。(4)pcchReaders:輸入輸出類型;mszReaders的長度。
系統中可能安裝多個讀卡器,因此,需要保存各個讀卡器的名字,以便以后與需要的讀卡器建立連接。
下面是獲得系統中安裝的讀卡器列表的代碼:
char            mszReaders[1024];
LPTSTR          pReader, pReaderName[2];
DWORD           dwLen=sizeof(mzsReaders);
int             nReaders=0;
lReturn = SCardListReaders(hSC, NULL, (LPTSTR)mszReaders, &dwLen);
if ( lReturn==SCARD_S_SUCCESS )
{
pReader = (LPTSTR)pmszReaders;
while (*pReader !='\0'  )
{
if ( nReaders<2 ) //使用系統中前2個讀卡器
                pReaderName[nReaders++]=pReader;
printf("Reader: %S\n", pReader );
//下一個讀卡器名
pReader = pReader + strlen(pReader) + 1;
}
}

3.3 與讀卡器(智能卡)連接
函數ScardConnect()在應用程序與讀卡器上的智能卡之間建立一個連接。
函數原型:LONG SCardConnect(SCARDCONTEXT hContext,  LPCTSTR szReader,  DWORD dwShareMode,  DWORD dwPreferredProtocols,  LPSCARDHANDLE phCard,  LPDWORD pdwActiveProtocol);
各個參數的含義:(1)hContext:輸入類型;ScardEstablishContext()建立的資源管理器上下文的句柄。(2)szReader:輸入類型;包含智能卡的讀卡器名稱(讀卡器名稱由ScardListReaders()給出)。(3)dwShareMode:輸入類型;應用程序對智能卡的操作方式,SCARD_SHARE_SHARED(多個應用共享同一個智能卡)、SCARD_SHARE_EXCLUSIVE(應用獨占智能卡)、SCARD_SHARE_DIRECT(應用將智能卡作為私有用途,直接操縱智能卡,不允許其它應用訪問智能卡)。(4)dwPreferredProtocols:輸入類型;連接使用的協議,SCARD_PROTOCOL_T0(使用T=0協議)、SCARD_PROTOCOL_T1(使用T=1協議)。(5)phCard:輸出類型;與智能卡連接的句柄。(6)PdwActiveProtocol:輸出類型;實際使用的協議。
下面是與智能卡建立連接的代碼:
SCARDHANDLE     hCardHandle[2];
DWORD           dwAP;
lReturn = SCardConnect( hContext, pReaderName[0],    SCARD_SHARE_SHARED,
SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &hCardHandle[0], &dwAP );
if ( lReturn!=SCARD_S_SUCCESS )
{
printf("Failed SCardConnect\n");
exit(1);
}
與智能卡建立連接后,就可以向智能卡發送指令,與其交換數據了。

3.4 向智能卡發送指令
函數ScardTransmit()向智能卡發送指令,并接受返回的數據。
函數原型:LONG SCardTransmit(SCARDHANDLE hCard, LPCSCARD_I0_REQUEST pioSendPci, LPCBYTE pbSendBuffer, DWORD cbSendLength, LPSCARD_IO_REQUEST pioRecvPci, LPBYTE pbRecvBuffer, LPDWORD pcbRecvLength);
各個參數的含義:(1)hCard:輸入類型;與智能卡連接的句柄。(2)pioSendPci:輸入類型;指令的協議頭結構的指針,由SCARD_IO_REQUEST結構定義。后面是使用的協議的協議控制信息。一般使用系統定義的結構,SCARD_PCI_T0(T=0協議)、 SCARD_PCI_T1(T=1協議)、SCARD_PCI_RAW(原始協議)。(3)pbSendBuffer:輸入類型;要發送到智能卡的數據的指針。(4)cbSendLength:輸入類型;pbSendBuffer的字節數目。(5)pioRecvPci:輸入輸出類型;指令協議頭結構的指針,后面是使用的協議的協議控制信息,如果不返回協議控制信息,可以為NULL。(6)pbRecvBuffer:輸入輸出類型;從智能卡返回的數據的指針。(7)pcbRecvLength:輸入輸出類型;pbRecvBuffer的大小和實際大小。

對于T=0協議,收發緩沖的用法如下:
(a)向智能卡發送數據:要向智能卡發送n>0字節數據時,pbSendBuffer 前4字節分別為T=0的CLA、INS、P1、P2,第5字節是n,隨后是n字節的數據;cbSendLength值為n+5(4字節頭+1字節Lc+n字節數據)。PbRecvBuffer將接收SW1、SW2狀態碼;pcbRecvLength值在調用時至少為2,返回后為2。
BYTE        recvBuffer[260];
int         sendSize, recvSize;
BTYE        sw1, sw2;
BYTE    select_mf[]={0xC0, 0xA4, 0x00, 0x00, 0x02, 0x3F, 0x00};
sendSize=7;
recvSize=sizeof(recvBuffer);
lReturn = SCardTransmit(hCardHandle[0], SCARD_PCI_T0, select_mf, sendSize,
NULL, recvBuffer, &recvSize);
if ( lReturn != SCARD_S_SUCCESS )
{
printf("Failed SCardTransmit\n");
exit(1);
}
//返回的數據,recvSize=2
sw1=recvBuffer[recvSize-2];
sw2=recvBuffer[recvSize-1];

(b)從智能卡接收數據:為從智能卡接收n>0字節數據,pbSendBuffer 前4字節分別為T=0的CLA、INS、P1、P2,第5字節是n(即Le),如果從智能卡接收256字節,則第5字節為0;cbSendLength值為5(4字節頭+1字節Le)。PbRecvBuffer將接收智能卡返回的n字節,隨后是SW1、SW2狀態碼;pcbRecvLength的值在調用時至少為 n+2,返回后為n+2。
BYTE        get_challenge[]={0x00, 0x84, 0x00, 0x00, 0x08};
sendSize=5;
recvSize=sizeof(recvBuffer);
lReturn = SCardTransmit(hCardHandle[0], SCARD_PCI_T0, get_challenge,
sendSize, NULL, recvBuffer, &recvSize);
if ( lReturn != SCARD_S_SUCCESS )
{
printf("Failed SCardTransmit\n");
exit(1);
}
//返回的數據, recvSize=10
sw1=recvBuffer[recvSize-2];
sw2=recvBuffer[recvSize-1];
//data=recvBuffer[0]----recvBuffer[7]

(c)向智能卡發送沒有數據交換的命令:應用程序既不向智能卡發送數據,也不從智能卡接收數據,pbSendBuffer 前4字節分別為T=0的CLA、INS、P1、P2,不發送P3;cbSendLength 值必須為4。PbRecvBuffer從智能卡接收SW1、SW2狀態碼;pcbRecvLength值在調用時至少為2,返回后為2。
BYTE    set_flag[]={0x80, 0xFE, 0x00, 0x00};
sendSize=4;
recvSize=sizeof(recvBuffer);
lReturn = SCardTransmit(hCardHandle[0], SCARD_PCI_T0, set_flag, sendSize,
NULL, recvBuffer, &recvSize);
if ( lReturn != SCARD_S_SUCCESS )
{
printf("Failed SCardTransmit\n");
exit(1);
}
//返回的數據,recvSize=2
sw1=recvBuffer[recvSize-2];
sw2=recvBuffer[recvSize-1];

(d)向智能卡發送具有雙向數據交換的命令:T=0協議中,應用程序不能同時向智能卡發送數據,并從智能卡接收數據,即發送到智能卡的指令中,不能同時有Lc和Le。這只能分兩步實現:向智能卡發送數據,接收智能卡返回的狀態碼,其中,SW2是智能卡將要返回的數據字節數目;從智能卡接收數據(指令為0x00、0xC0、0x00、0x00、Le)。
BYTE    get_response={0x00, 0xc0, 0x00, 0x00, 0x00};
BYTE    internal_auth[]={0x00, 0x88, 0x00, 0x00, 0x08, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
sendSize=13;
recvSize=sizeof(recvBuffer);
lReturn = SCardTransmit(hCardHandle[0], SCARD_PCI_T0, internal_auth,
sendSize, NULL, recvBuffer, &recvSize);
if ( lReturn != SCARD_S_SUCCESS )
{
printf("Failed SCardTransmit\n");
exit(1);
}
//返回的數據,recvSize=2
sw1=recvBuffer[recvSize-2];
sw2=recvBuffer[recvSize-1];
    if ( sw1!=0x61 )
{
printf("Failed Command\n");
exit(1);
}
get_response[4]=sw2;
sendSize=5;
recvSize=sizeof(recvBuffer);
lReturn = SCardTransmit(hCardHandle[0], SCARD_PCI_T0, get_response,
sendSize, NULL, recvBuffer, &recvSize);
if ( lReturn != SCARD_S_SUCCESS )
{
printf("Failed SCardTransmit\n");
exit(1);
}
//返回的數據,recvSize=10
sw1=recvBuffer[recvSize-2];
sw2=recvBuffer[recvSize-1];
//data=recvBuffer[0]----recvBuffer[7]

3.5 斷開與讀卡器(智能卡)的連接
在與智能卡的數據交換完成后,可以使用函數ScardDisconnect()終止應用與智能卡之間的連接。
函數原型:LONG SCardDisconnect(SCARDHANDLE hCard, DWORD dwDisposition);
各個參數的含義:(1)hCard:輸入類型;與智能卡連接的句柄。(2)dwDisposition:輸入類型;斷開連接時,對智能卡的操作,SCARD_LEAVE_CARD(不做任何操作)、SCARD_RESET_CARD(復位智能卡)、SCARD_UNPOWER_CARD(給智能卡掉電)、SCARD_EJECT_CARD(彈出智能卡)。
下面是斷開與智能卡連接的代碼:
lReturn = SCardDisconnect(hCardHandle[0], SCARD_LEAVE_CARD);
if ( lReturn != SCARD_S_SUCCESS )
{
printf("Failed SCardDisconnect\n");
exit(1);
}

3.6 釋放資源管理上下文
    在應用程序終止前時,應該調用函數ScardReleaseContext()釋放資源管理器的上下文。
函數原型:LONG SCardReleaseContext(SCARDCONTEXT hContext);
各個參數含義:(1)hContext:輸入類型;ScardEstablishContext()建立的資源管理器上下文的句柄,不能為NULL。
下面是釋放資源管理上下文的代碼:
lReturn = SCardReleaseContext(hSC);
if ( lReturn!=SCARD_S_SUCCESS )
printf("Failed SCardReleaseContext\n");

4 小結
以上介紹的通過PC/SC來操作智能卡的流程,可以封裝在一個類中。例如,我們可以設計一個類:
class CSmartReader
{
private:
SCARDCONTEXT    hSC;
LONG            lReturn;
char            mszReaders[1024];
LPTSTR          pReader, pReaderName[2];
DWORD           dwLen;
int             nReaders, nCurrentReader;
SCARDHANDLE     hCardHandle[2];
DWORD           dwAP;
public:
    CSmartReader(); //建立上下文、取讀卡器列表
    ~CSmartReader(); //釋放上下文
    void SetCurrentReader(int currentReader);
    int GetReaders(); //獲得讀卡器數目
    int ConnectReader(); //與當前讀卡器建立連接
    int DisConnectReader(); //與當前讀卡器斷開連接
    int SendCommand(BYTE command[], int commandLength, BYTE result[], int *resultLength); //向讀卡器發送命令,并接收返回的數據。返回值為sw
};
    這樣,我們就可以方便地使用PC/SC接口了。

作者:蔣遂平。
聯系方式:jiangsp@couragetech.com.cnjiang_sweeping@263.net

posted on 2009-07-17 12:53 Bluesea 閱讀(1910) 評論(0)  編輯 收藏 引用 所屬分類: SmartCard
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            国内精品模特av私拍在线观看| 亚洲高清在线播放| 国产精品日韩欧美一区| 亚洲观看高清完整版在线观看| av成人动漫| 亚洲日韩中文字幕在线播放| 欧美国产成人精品| 欧美黄色精品| 亚洲精品美女| 亚洲天堂av电影| 欧美伊人久久大香线蕉综合69| 亚洲欧美国产视频| 久久gogo国模啪啪人体图| 久久久久久久久蜜桃| 亚洲福利视频在线| 亚洲美女视频网| 亚洲免费在线观看| 久久中文精品| 欧美日韩一区二区三区在线视频| 亚洲高清资源综合久久精品| 亚洲欧美国产制服动漫| 亚洲无线视频| 久久国产88| 免费人成网站在线观看欧美高清 | 国产亚洲成av人片在线观看桃 | 欧美久久影院| 国产手机视频一区二区| 亚洲激情在线观看视频免费| 一区二区三区日韩| 久久久久一区| 99视频精品在线| 久久婷婷国产综合精品青草 | 亚洲精品自在在线观看| 在线视频一区二区| 久久九九久久九九| 欧美三级日韩三级国产三级| 国产真实久久| 亚洲一级黄色片| 欧美激情中文字幕一区二区| 亚洲一区国产视频| 欧美日韩美女一区二区| 午夜精品久久| 欧美麻豆久久久久久中文| 黄色免费成人| 欧美一级夜夜爽| 99re6热在线精品视频播放速度| 久久久综合香蕉尹人综合网| 亚洲精品精选| 香蕉成人伊视频在线观看| 女女同性女同一区二区三区91| 国产精品午夜av在线| 亚洲国产成人tv| 久久频这里精品99香蕉| 亚洲免费影视| 国产欧美一区二区三区沐欲| 亚洲一二三区精品| 亚洲毛片一区二区| 欧美激情免费在线| 亚洲日本中文字幕| 亚洲高清资源综合久久精品| 裸体素人女欧美日韩| 一区二区三区在线观看视频| 久久riav二区三区| 亚洲影视九九影院在线观看| 欧美日韩综合视频| 一本一本大道香蕉久在线精品| 亚洲激情在线观看| 欧美巨乳波霸| 一本久久综合亚洲鲁鲁五月天| 亚洲日本va午夜在线影院| 欧美精品国产| 一区二区三区欧美在线| 宅男精品导航| 国产精品中文在线| 久久国产毛片| 久久国产精品黑丝| 韩国欧美一区| 欧美大胆成人| 欧美高清不卡| 你懂的视频一区二区| 国产亚洲欧美一区| 久久精品亚洲一区| 一区二区三区国产精品| 欧美视频一区二区三区…| 亚洲精品久久嫩草网站秘色 | 中日韩高清电影网| 一区二区三区鲁丝不卡| 欧美激情小视频| 性高湖久久久久久久久| 欧美激情中文不卡| 欧美视频中文在线看| 日韩视频一区二区三区在线播放免费观看| 99精品免费| 影音先锋中文字幕一区二区| 久久国产黑丝| 久久xxxx| 99pao成人国产永久免费视频| 开元免费观看欧美电视剧网站| 欧美日韩中字| 亚洲专区在线视频| 久久精品综合一区| 亚洲国产精品va在线观看黑人| 亚洲国产精品第一区二区三区| 欧美黄污视频| 久久激情综合网| 久久久久久久综合日本| 99精品国产高清一区二区| 亚洲国产精品久久久久婷婷老年 | 国产精品毛片| 免费视频最近日韩| 女女同性精品视频| 欧美中文在线视频| 久久国产精品色婷婷| avtt综合网| 欧美一级一区| 欧美在线一区二区三区| 亚洲国产精品第一区二区三区| 一区二区三区日韩欧美精品| 国产农村妇女毛片精品久久麻豆 | 欧美成人精品在线视频| 欧美三级视频在线观看| 国内久久精品视频| 亚洲级视频在线观看免费1级| 亚洲视频福利| 亚洲理论在线| 欧美亚洲在线| 中文一区二区在线观看| 久久躁狠狠躁夜夜爽| 亚洲性线免费观看视频成熟| 免费成人黄色av| 欧美一区二区大片| 欧美日韩精品系列| 久久综合狠狠综合久久综合88| 国产精品草草| 欧美成年网站| 亚洲人成77777在线观看网| 制服丝袜激情欧洲亚洲| 99在线精品观看| 久久久xxx| 美国十次成人| 国产乱码精品一区二区三区不卡 | 亚洲国产精品t66y| 麻豆国产精品一区二区三区| 亚洲免费婷婷| 国产婷婷成人久久av免费高清| 亚洲精品美女在线观看播放| 亚洲茄子视频| 噜噜噜在线观看免费视频日韩| 欧美成人免费全部观看天天性色| 国产毛片一区二区| 欧美一区二区三区在线看| 亚洲一区免费在线观看| 国产精品免费网站| 亚洲性视频网站| 国产精品久久久久一区二区| 久久综合导航| 亚洲三级观看| 久久久亚洲精品一区二区三区 | 久久综合狠狠综合久久激情| 亚洲第一福利社区| 久久亚洲欧美| 亚洲黄色免费| 国产亚洲福利一区| 亚欧成人在线| 日韩视频中文字幕| 国产精品理论片| 久久久久久久97| 免费精品视频| 中日韩美女免费视频网址在线观看 | 欧美午夜精品久久久久久久| 亚洲国产精品第一区二区三区| 亚洲一级网站| 国产精品久久久久aaaa九色| 久久成人这里只有精品| 免费亚洲一区二区| 亚洲视频一区二区免费在线观看| 欧美视频第二页| 久久久久久国产精品一区| 免费观看欧美在线视频的网站| 亚洲精品乱码久久久久久黑人| 欧美人与性动交a欧美精品| 亚洲免费网址| 欧美成人国产| 欧美一级播放| 国产精品免费视频xxxx| 欧美高清不卡| 亚洲激情电影在线| 久久精品国产清高在天天线| 亚洲理论在线观看| 国产伦精品一区二区三区免费迷| 亚洲视频在线视频| 久久综合99re88久久爱| 亚洲狼人精品一区二区三区| 欧美午夜精品久久久久久人妖| 午夜精品影院在线观看| 欧美激情按摩| 日韩视频精品在线观看| 国产精品外国| 欧美午夜在线观看| 欧美精品系列|