智能卡CSP 的設(shè)計(jì)與實(shí)現(xiàn)方法
隨著智能卡功能的不斷完善,卡片運(yùn)算速度和存貯功能的不斷加強(qiáng),在對(duì)安全性要求較高的領(lǐng)域,智能卡的應(yīng)用開(kāi)始越來(lái)越廣泛。其中作為硬件數(shù)字證書使用,也是智能卡的一項(xiàng)重要功能。智能卡作為硬件級(jí)的加密設(shè)備,如何同當(dāng)前使用最為廣泛的windows操作系統(tǒng)進(jìn)行無(wú)縫連接,需要開(kāi)發(fā)智能卡讀卡器硬件、讀卡器驅(qū)動(dòng)程序、智能卡CSP 等一系列軟硬件設(shè)施,本文將主要針對(duì)其中的智能卡CSP 開(kāi)發(fā)。
1 CSP 簡(jiǎn)介
加密服務(wù)提供者Cryptographic Service Provider(簡(jiǎn)稱CSP)是Windows 操作系統(tǒng)加密體系的重要組成部分,它提供了一組標(biāo)準(zhǔn)API 函數(shù)(CryptoAPI)供應(yīng)用程序調(diào)用,如IE 使用SSL 訪問(wèn)網(wǎng)站、Outlook 發(fā)送加密郵件等,均會(huì)調(diào)用到CryptoAPI 函數(shù)。智能卡作為一種硬件級(jí)的加密設(shè)備,要實(shí)現(xiàn)和windows 操作系統(tǒng)的無(wú)縫連接,使應(yīng)用程序能夠通過(guò)CryptoAPI 這套標(biāo)準(zhǔn)函數(shù)使用智能卡設(shè)備, 就必定要針對(duì)該種設(shè)備開(kāi)發(fā)CSP 服務(wù)程序。智能卡設(shè)備CSP 在系統(tǒng)中的位置如圖1 所示。
2 CSP 中的容器
CSP 使用容器來(lái)管理密鑰,以RSA 密鑰為例,一個(gè)容器中可以存在一對(duì)RSA 交換密鑰和一對(duì)RSA 簽名密鑰。一個(gè)智能卡中可以有多個(gè)容器。結(jié)構(gòu)如圖2 所示。Windows 系統(tǒng)中一般會(huì)存在多個(gè)CSP,既有微軟自己的純軟件型CSP,也可能有數(shù)個(gè)不同廠商的軟硬件加密設(shè)備的CSP。應(yīng)用程序可以通過(guò)CryptoAPI 函數(shù)的來(lái)指定使用哪個(gè)CSP 以及該CSP 中的哪個(gè)容器。
3 CSP 在智能卡中的密鑰存貯結(jié)構(gòu)
3.1 智能卡中私鑰的特點(diǎn)
在CSP 中私鑰的作用主要是用來(lái)做解密或簽名。智能卡這種設(shè)備的一個(gè)重要特點(diǎn)是私鑰可以設(shè)定為讀禁止,私鑰不能被從智能卡中讀出。當(dāng)需要用私鑰進(jìn)行解密或者簽名時(shí),被解密或簽名的數(shù)據(jù)必須先送入智能卡,由智能卡中的處理器對(duì)數(shù)據(jù)做解密或簽名,解密或簽名后的數(shù)據(jù)再出智能卡返回計(jì)算機(jī)中。整個(gè)過(guò)程中私鑰不能被計(jì)算機(jī)讀出,解密或簽名的過(guò)程是在智能卡中進(jìn)行的,保證了私鑰的不可復(fù)制特性,避免了黑客攻入計(jì)算機(jī),將私鑰遠(yuǎn)程拷貝走的可能。
3.2 私鑰、公鑰和證書的不同保護(hù)級(jí)別
使用私鑰時(shí),智能卡需要驗(yàn)證保護(hù)該私鑰的PIN 碼,只有PIN 碼驗(yàn)證正確的情況下才能使用私鑰。但智能卡中的證書和公鑰則一般不需要PIN 碼保護(hù),以保證使用過(guò)程中的靈活性。在CryptoAPI 的SILENT 模式中,公鑰可以隨時(shí)被讀出。另外當(dāng)智能卡插入到連接計(jì)算機(jī)的讀卡器中時(shí),一般都需要將智能卡中的證書導(dǎo)入到windows 系統(tǒng)的證書庫(kù)中,因IE 瀏覽器不能直接識(shí)別智能卡中的證書,它需要從windows 系統(tǒng)的證書庫(kù)中去讀證書。這些情況下均需要讓智能卡不經(jīng)過(guò)PIN 碼驗(yàn)證,就能使智能卡中的公鑰和證書被讀出。
3.3 CSP 密鑰容器的存貯結(jié)構(gòu)設(shè)計(jì)
3.3.1 CSP 密鑰容器存貯結(jié)構(gòu)圖
圖3 為CSP 密鑰容器存貯結(jié)構(gòu)圖。
.3.2 公開(kāi)目錄(DDF):如圖3 所示,公開(kāi)目錄(DDF)下的ADF 子目錄下存放RSA 加密公鑰及相應(yīng)證書、RSA 簽名公鑰及相應(yīng)證書,容器名稱為ADF 目錄的名稱,可以同時(shí)存在多個(gè)容器。公開(kāi)目錄(DDF)、容器目錄(ADF)、公鑰、證書都不設(shè)置PIN 碼保護(hù),公鑰和證書可以隨時(shí)可以被從智能卡中讀出。
3.3.3 私鑰目錄(DDF):如圖3 所示,私鑰目錄(DDF)下的ADF 子目錄下存放RSA 加密密鑰對(duì)中的私鑰和RSA 簽名密鑰對(duì)中的私鑰,ADF 目錄名稱與對(duì)應(yīng)公鑰所在的ADF 目錄名稱相同。私鑰目錄(DDF)設(shè)置PIN 碼保護(hù),要使用該目錄的子目錄下的私鑰,必須首先通過(guò)私鑰目錄(DDF)的PIN 碼驗(yàn)證。
3.3.4 容器名稱:圖3 中的私鑰目錄(DDF)下的容器目錄(ADF)名稱必須和公開(kāi)目錄(DDF)下的容器目錄(ADF)名稱對(duì)應(yīng),比如私鑰目錄(DDF)下的
容器目錄1 和公開(kāi)目錄(DDF)下的容器目錄1 的名稱必須相同,因?yàn)樗鼈儗?shí)際上是代表著同一個(gè)容器名。
3.3.5 容器索引文件:容器索引文件存放著智能卡中的所有容器名稱, 并且指明容器名稱和容器目錄(ADF) 之間的關(guān)系。每次調(diào)用CSP 的CPAcquireContext函數(shù)時(shí),該函數(shù)都需要從這個(gè)文件中獲取智能卡中已有的所有容器名稱。容器索引文件的結(jié)構(gòu)可以用如下方式表示:
## 容器名稱1# 容器目錄1(ADF)## 容器名稱2# 容器目錄2(ADF)##......#......##
4 CSP 軟件架構(gòu)的設(shè)計(jì)與實(shí)現(xiàn)
4.1 CSP 軟件架構(gòu)的種類
CSP 從整體上看主要有上下文環(huán)境對(duì)象、密鑰對(duì)象、哈希對(duì)象三種數(shù)據(jù)結(jié)構(gòu)。在開(kāi)發(fā)CSP 的過(guò)程有幾種方法來(lái)實(shí)現(xiàn)對(duì)這三種數(shù)據(jù)結(jié)構(gòu)對(duì)象的管理,具體如下:
結(jié)構(gòu)對(duì)象的管理,具體如下:
1) 上下文環(huán)境對(duì)象在CSP 中實(shí)現(xiàn),密鑰對(duì)象和哈希對(duì)象交給微軟的純軟件型CSP 來(lái)管理。
2) 上下文環(huán)境對(duì)象和密鑰對(duì)象在CSP 中實(shí)現(xiàn),哈希對(duì)象交給微軟的純軟件型CSP 來(lái)管理。
3) 上下文環(huán)境對(duì)象、密鑰對(duì)象和哈希對(duì)象都在CSP 中實(shí)現(xiàn)。
其中第3 種方法實(shí)現(xiàn)CSP 的復(fù)雜性最高,但也最為靈活,本文主要探討這種方法。由于在CSP 開(kāi)發(fā)中一般都用C 語(yǔ)言或C++語(yǔ)言來(lái)實(shí)現(xiàn),因此約定以下用到的數(shù)據(jù)結(jié)構(gòu)定義均使用C++語(yǔ)言來(lái)表述。
4.2 CSP 中幾個(gè)基本的對(duì)象類型分析
通過(guò)分析微軟定義的CSP 25 個(gè)基本函數(shù),可以發(fā)現(xiàn)CSP 的上下文環(huán)境對(duì)象、密鑰對(duì)象、哈希對(duì)象是以HCRYPTPROV、HCRYPTKEY和HCRYPTHASH 三種類型存在的。
HCRYPTPROV 對(duì)象類型的作用是串聯(lián)起整個(gè)CSP 的上下文環(huán)境。該對(duì)象一般由CPAcquireContext 函數(shù)產(chǎn)生,由CPReleaseContext函數(shù)終止。
HCRYPTKEY 對(duì)象類型起到密鑰句柄的作用。其存在周期一般是從密鑰的產(chǎn)生或者密鑰導(dǎo)入開(kāi)始,經(jīng)歷密鑰的使用,最后到密鑰句柄被釋放的過(guò)程。
HCRYPTHASH 對(duì)象類型起到哈希句柄的作用。其存在周期一般是從哈希的產(chǎn)生,到哈希的使用,最后是哈希句柄被釋放的過(guò)程。
{$page$}
4.3 三種對(duì)象類型的設(shè)計(jì)與實(shí)現(xiàn)
在CSP 的具體設(shè)計(jì)與實(shí)現(xiàn)中,HCRYPTPROV 對(duì)象類型、HCRYPTKEY對(duì)象類型和HCRYPTHASH 對(duì)象類型之間的相互關(guān)系如圖4 所示。
ProvQueue 鏈表為CSP 上下文環(huán)境句柄鏈表,KeyQueue 鏈表為密鑰句柄鏈表,HashQueue 鏈表為哈希句柄鏈表。
CProvContext 為CSP 上下文環(huán)境類、CCryptKey 為密鑰句柄類、CCryptHash 為哈希句柄類,這幾個(gè)類的具體設(shè)計(jì)見(jiàn)下文。
4.3.1 CSP 上下文環(huán)境對(duì)象的實(shí)現(xiàn)
CSP 的上下文環(huán)境由HCRYPTPROV 對(duì)象類型實(shí)現(xiàn),在實(shí)現(xiàn)過(guò)程中可以定義一個(gè)CProvContext 的類,具體定義如下:
該類包含有在當(dāng)前上下文環(huán)境中使用的容器名ContainerName,通過(guò)SetProvParam 成員函數(shù)可以對(duì)當(dāng)前上下文環(huán)境屬性進(jìn)行設(shè)置,通過(guò)GetProvParam 成員函數(shù)可以得到當(dāng)前上下文環(huán)境的屬性。將該類強(qiáng)制轉(zhuǎn)換成HCRYPTPROV 類型,即可實(shí)現(xiàn)CSP 上下文環(huán)境的數(shù)據(jù)類型。
如果在同一個(gè)進(jìn)程中通過(guò)CryptoAPI 的CryptAcquireContext 函數(shù)同時(shí)打開(kāi)多個(gè)不同的容器,此時(shí)就會(huì)有多個(gè)CProvContext 類實(shí)例,因此需要通過(guò)鏈表來(lái)管理多個(gè)實(shí)例。這里定義一個(gè)ProvQueue 的鏈表,在同一個(gè)進(jìn)程中每當(dāng)打開(kāi)一個(gè)容器或新建一個(gè)容器時(shí),就產(chǎn)生一個(gè)CProvContext 類的實(shí)例,將該實(shí)例加入到ProvQueue 鏈表中,通過(guò)prevContext 指針指向前一個(gè)實(shí)例, 通過(guò)nextContext 指針指向后一個(gè)實(shí)例。
CSP 25 個(gè)函數(shù)中都有CSP 的上下文環(huán)境句柄,25 個(gè)函數(shù)之間的關(guān)系可以通過(guò)這個(gè)句柄得到聯(lián)系。比如調(diào)用CPEncryt 函數(shù)時(shí),首先檢查CPEncryt 傳入HCRYPTPROV 句柄是否在ProvQueue 中存在,如果存在,則ProvQueue 鏈表中對(duì)應(yīng)的該條記錄即為當(dāng)前的上下文環(huán)境句柄,該記錄中包含有當(dāng)前的容器名、相關(guān)的密鑰隊(duì)列(KeyQueue)和哈希隊(duì)列(HashQueue),從密鑰隊(duì)列(KeyQueue)中可以獲取CPEncryt 函數(shù)需要使用的密鑰對(duì)象。對(duì)象之間的關(guān)系可參見(jiàn)圖4。
4.3.2 HCRYPTKEY 密鑰對(duì)象類型
HCRYPTKEY 密鑰對(duì)象類型可以定義一個(gè)CCryptKey 的類,在使用過(guò)程中將該類強(qiáng)制轉(zhuǎn)換成HCRYPTKEY 類型,該類具體定義如下:
該類包含有當(dāng)前密鑰所對(duì)應(yīng)的算法(KeyAlgid)、dwFlags 參數(shù)以及當(dāng)前密鑰隸屬于的CSP 上下文環(huán)境對(duì)象(pProContext)。通過(guò)SetKeyParam 成員函數(shù)可以對(duì)當(dāng)前密鑰屬性進(jìn)行設(shè)置,通過(guò)GetKeyParam 成員函數(shù)可以得到當(dāng)前密鑰的屬性。
在同一個(gè)CSP 上下文環(huán)境對(duì)象中可以同時(shí)產(chǎn)生多個(gè)不同的密鑰句柄,因此需要通過(guò)密鑰句柄鏈表來(lái)管理這些密鑰句柄。定義一個(gè)KeyQueue 的鏈表,在同一個(gè)CSP 上下文環(huán)境對(duì)象中每當(dāng)產(chǎn)生一個(gè)新的密鑰或?qū)胍粋€(gè)新的密鑰時(shí),就會(huì)產(chǎn)生一個(gè)CCryptKey類的實(shí)例,將該實(shí)例加入到KeyQueue 鏈表中,通過(guò)prevCryptKey 指針指向前一個(gè)實(shí)例, 通過(guò)nextCryptKey 指針指向后一個(gè)實(shí)例。
通過(guò)圖4,可以看到密鑰與密鑰鏈表之間的關(guān)系,具體使用某個(gè)密鑰時(shí)需要先從KeyQueue 鏈表中找到對(duì)應(yīng)的密鑰句柄。比如調(diào)用CPEncryt 函數(shù)時(shí),先檢查CPEncryt 函數(shù)傳入的HCRYPTKEY 句柄是否在KeyQueue 鏈表中已經(jīng)存在,如果存在,則KeyQueue 鏈表中對(duì)應(yīng)的該條記錄即為當(dāng)前的密鑰句柄,該記錄中包含有當(dāng)前密鑰的算法(KeyAlgid)、dwFlags 等參數(shù)。
4.3.3 HCRYPTHASH 哈希對(duì)象類型
HCRYPTHASH 哈希對(duì)象類型的定義和HCRYPTKEY 密鑰對(duì)象類型的定義相似,定義一個(gè)CCryptHash 的類,在使用過(guò)程中將該類強(qiáng)制轉(zhuǎn)換成HCRYPTHASH 類型,該類具體定義如下:
該類中包含有當(dāng)前哈希所對(duì)應(yīng)的算法(HashAlgid)、dwFlags 參數(shù)以及當(dāng)前哈希隸屬于的CSP 上下文環(huán)境對(duì)象(pProContext)。通過(guò)SetHashParam 成員函數(shù)可以對(duì)當(dāng)前哈希屬性進(jìn)行設(shè)置,通過(guò)GetHashParam 成員函數(shù)可以得到當(dāng)前哈希的屬性。
在同一個(gè)CSP 上下文環(huán)境對(duì)象中可以同時(shí)產(chǎn)生多個(gè)不同的哈希句柄,因此需要通過(guò)哈希句柄鏈表來(lái)管理這些哈希句柄。定義一個(gè)HashQueue 的鏈表,在同一CSP 上下文環(huán)境中每當(dāng)產(chǎn)生一個(gè)新的哈希時(shí),就會(huì)產(chǎn)生一個(gè)CCryptHash 類的實(shí)例,將該實(shí)例加入到HashQueue 鏈表中,通過(guò)prevCryptHash 指針指向前一個(gè)實(shí)例, 通過(guò)nextCryptHash 指針指向后一個(gè)實(shí)例。
通過(guò)圖4,可以看到哈希與哈希鏈表之間的關(guān)系,具體使用某個(gè)哈希時(shí)需要先從HashQueue 鏈表中找到對(duì)應(yīng)的哈希句柄。比如調(diào)用CPHashData 函數(shù)時(shí), 先檢查CPHashData 函數(shù)傳入的HCRYPTHASH 句柄是否在HashQueue 鏈表中已經(jīng)存在, 如果存在,則HashQueue 鏈表中對(duì)應(yīng)的該條記錄即為當(dāng)前的哈希句柄,該記錄中包含有當(dāng)前哈希的算法(HashAlgid)、dwFlags 等參數(shù)。
5 綜述
綜上所述,由于微軟對(duì)于CSP 只是定義了基本的函數(shù)接口,具體在CSP 的設(shè)計(jì)與實(shí)現(xiàn)過(guò)程中有很強(qiáng)的靈活性,除了本文提到的幾種CSP 的設(shè)計(jì)和實(shí)現(xiàn)方法外,可能還會(huì)有其它的CSP 設(shè)計(jì)和實(shí)現(xiàn)方法,CSP 中密鑰存貯結(jié)構(gòu)的設(shè)計(jì)方法也有很多。隨著智能卡技術(shù)的不斷發(fā)展,以及智能卡在各行各業(yè)中應(yīng)用的普及,各行各業(yè)對(duì)智能卡CSP 功能上的要求可能會(huì)有不同,安全性方面的要求可能也會(huì)有差異,因此CSP 軟件架構(gòu)如何設(shè)計(jì),對(duì)應(yīng)的密鑰存貯結(jié)構(gòu)如何設(shè)計(jì),主要還是看CSP 的具體用途 。