任務詳情
密碼引擎API的主要標準和規范包括:
1 微軟的Crypto API
2 RAS公司的PKCS#11標準
3 中國商用密碼標準:GMT 0016-2012 智能密碼鑰匙密碼應用接口規范,GMT 0018-2012密碼設備應用接口規范等
研究以上API接口,總結他們的異同,并以龍脈GM3000Key為例,寫出調用不同接口的代碼,提交博客鏈接和代碼鏈接。
內容:
0 查找各種標準的原始文檔,研究學習(至少包含Crypto API,PKCS#11,GMT 0016-2012,GMT 0018-2012)(5分)
1 總結這些API在編程中的使用方式(5分)
2 列出這些API包含的函數,進行分類,并總結它們的異同(10分)
3 以龍脈GM3000Key為例,寫出調用不同接口的代碼(Crypto API,PKCS#11,SKF接口),把運行截圖加入博客,并提供代碼鏈接(10分)
查找各種標準的原始文檔,研究學習
CryptoAPI
- Cryptography
- CryptoAPI System Architecture
- Cryptographic Provider Types
- Microsoft Cryptographic Service Providers
- Cryptography API: Next Generation
- wincrypt.h header
PKCS#11
GM/T 0016-2012 智能密碼鑰匙密碼應用接口規范
GM/T 0018-2012 密碼設備應用接口規范
總結這些API在編程中的使用方式
CryptoAPI
微軟的CryptoAPI是PKI推薦使用的加密 API。其功能是為應用程序開發者提供在Win32環境下使用加密、驗證等安全服務時的標準加密接口。CryptoAPI處于應用程序和CSP(cryptographic service provider)之間。

CryptoAPI的編程模型同Windows系統的圖形設備接口 GDI比較類似,其中加密服務提供者CSP等同于圖形設備驅動程序 ,加密硬件(可選)等同于圖形硬件,其上層的應用程序也類似,都不需要同設備驅動程序和硬件直接打交道。
CryptoAPI共有五部分組成:簡單消息函數(Simplified Message Functions)、低層消息函數(Low-level Message Functions)、基本加密函數(Base Cryptographic Functions)、證書編解碼函數(Certificate Encode/Decode Functions)和證書庫管理函數(Certificate Store Functions)。其中前三者可用于對敏感信息進行加密或簽名處理,可保證網絡傳輸信心的私有性;后兩者通過對證書的使用,可保證網絡信息交流中的認證性。
密鑰管理
- 在CryptoAPI中,支持兩種類型的密鑰:會話密鑰、公私鑰對。會話密鑰也稱為對稱密鑰,用于對稱密鑰算法。為了保證密鑰的安全性,在CryptoAPI中,這些密鑰都保存在CSP內部,用戶可以通過CryptExportKey以加密密鑰形式導出。公私鑰用于非對稱加密算法。非對稱加密算法主要用于加解密會話密鑰和數字簽名。在CryptoAPI中,一般來說,大多數CSP產生的密鑰容器包含兩對密鑰對,一對用于加密會話密鑰,稱為交換密鑰對,一對用于產生數字簽名,稱為簽名密鑰對。在CryptoAPI中所有的密鑰都存儲在CSP中,CSP負責密鑰的創建,銷毀,導入導出等操作。
數據編解碼
- CryptoAPI采用的編碼方式為ASN.1,編碼規則為DER,表示發送數據時先把數據抽象為ASN.1對象,然后使用DER編碼規則把ASN.1對象轉化為可傳輸的0,1串;接收方接收到數據后,利用DER解碼規則把0,1串轉化為ASN.1對象,然后把ASN.1對象轉化為具體應用支持的數據對象。
數據加解密
- 在CryptoAPI中約定加密較大數據塊時,采用對稱密鑰算法。通過其封裝好的加解密函數來實現數據加解密操作。
哈希和數字簽名
- 哈希和數字簽名一般用于數據的完整性校驗和身份鑒別。CryptoAPI中,通過其封裝好的哈希與數字簽名函數來實現相關操作。微軟公司提供的CSP產生的數字簽名遵循RSA標準(PKCS#6)
數字證書管理
- 數字證書主要用于安全通信中的身份鑒別。CryptoAPI中,對數字證書的使用管理函數分為證書與證書庫函數、證書驗證函數兩大部分。
PKCS#11
我們把Cryptoki 確定為應用程序與各種各樣的便攜式密碼設備(基于智能卡、PCMCIA卡以及智能軟盤)間的一種接口。
Cryptoki 的主要目標是一個低級程序接口,該接口將設備的細節抽象化,并把密碼設備的通用模型—密碼令牌,或簡稱令牌—提供給應用程序。
Cryptoki的通用模型如下圖所示。模型從一個或多個必須執行某些密碼操作的應用程序開始,以一個或多個密碼設備結束(在密碼設備上執行某些或全部操作)。一個用戶可涉及也可不涉及一個程序。

Cryptoki 為一個或多個密碼設備提供一個接口,這些設備通過大量的槽在系統中運行。每個對應于一個物理閱讀器或另一個設備接口的槽可包含一個令牌。當一臺密碼設備存在于閱讀器中,一個令牌就存在于該槽中。當然,由于Cryptoki提供槽和令牌的邏輯視圖,所以可能有其它的物理譯碼。多個槽可能共享一個閱讀器。問題在于一個系統有相當多的槽,應用程序能連接到這些槽的其中任何一個或全部槽的令牌上。
Cryptoki的令牌邏輯視圖是一個能存儲對象和能執行密碼函數的設備。Cryptoki定義如下三個對象:數據、證書和密鑰。數據對象由應用程序定義。一個證書對象存儲一個證書。一個密鑰對象存儲一個密碼密鑰。密鑰可以是一個公共密鑰、一個私鑰或是一個保密密鑰,每個種類的密鑰在專用機制中使用其的輔助型。令牌的這種邏輯視圖如下圖所示:

SKF
針對支持國密算法USB KEY設備的應用,我國頒布一個行業標準《智能密碼鑰匙應用接口規范》(GM/T0016-2012),市面上銷售的國密算法的USB KEY設備必須支持這個接口規范。因此,只要根據這個規范開發的應用程序,就可以兼容使用不同廠家及品牌的USB KEY產品。由于此規范中函數名稱都以SKF開頭,所以我們一般把按照此規范提供的設備開發接口庫叫做SKF庫或SKF接口。
智能密碼鑰匙密碼應用接口位于智能密碼鑰匙應用程序與設備之間,如下圖所示

一個設備中存在設備認證密鑰和多個應用,應用之間相互獨立。設備的邏輯結構如下圖所示

應用由管理員PIN,用戶PIN、文件和容器組成,可以存在多個文件和多個容器。每個應用維護各自的與管理員PIN和用戶PIN相關的權限狀態。
一個應用的邏輯結構如下圖所示

容器中存放加密密鑰對、簽名密鑰對和會話密鑰。其中加密密鑰對用于保護會話密鑰,簽名密鑰對用于數字簽名和驗證,會話密鑰用于數據加解密和MAC運算。容器中也可以存放與加密密鑰對對應的加密數字證書和與簽名密鑰對對應的簽名數字證書。其中,簽名密鑰對由內部產生,加密密鑰對由外部產生并安全導入,會話密鑰可由內部產生或者由外部產生并安全導入。
列出這些API包含的函數,進行分類,并總結它們的異同
CryptoAPI
密碼服務提供者CSP函數
CryptoAPI的密碼服務提供者函數主要包括6個函數。連接或斷開CSP函數CryptAcquireContext、CryptReleaseContext,枚舉CSP函數CryptEnumProviders,獲得或設置默認CSP函數CryptGetDefaultProvider、CryptSetProvider,獲取或設置CSP參數函數CryptGetProvParam、CryptSetProvParam。
連接CSP函數 CryptAcquireContext
- 函數功能:連接CSP,獲得指定CSP的密鑰容器的句柄。
枚舉CSP函數 CryptEnumProviders
- 函數功能:枚舉計算機上的所有CSP。此函數可以得到第一個或下一個可用的CSP。如果循環調用可以得到計算機上所有可用的CSP。
獲得默認CSP函數 CryptGetDefaultProvider
- 函數功能:獲得系統默認的CSP。
設置默認CSP函數 CryptSetProvider
- 函數功能:設置系統默認的CSP。
獲得CSP參數屬性函數 CryptGetProvParam
- 函數功能:獲得CSP各種參數屬性。
設置CSP參數函數 CryptSetProvParam
- 函數功能:設置CSP各種參數屬性。
斷開CSP函數 CryptReleaseContext
- 函數功能:斷開CSP,釋放CSP句柄,和 CryptAcquireContext相對應。
示例枚舉CSP并獲得默認CSP的參數處理過程如下圖所示

密鑰的產生與交換函數
CryptoAPI密鑰產生和交換函數主要有生成密鑰函數 CryptGenKey、派生密鑰函數CryptDeriveKey、銷毀密鑰函數CryptDestoryKey、復制密鑰函數CryptDuplicateKey、導出密鑰函數CryptExportKey、導入密鑰函數CryptImportKey、獲得密鑰參數函數CryptGetKeyParam、設置密鑰參數函數CryptSetKeyParam、產生隨機函數 CryptGenRandom。
生成函數 CryptGenKey
- 函數功能:產生一個隨機的對稱或非對稱算法的密鑰。
派生密鑰函數 CryptDeriveKey
- 函數功能:根據基礎數據派生一對稱密鑰(會話密鑰)。
銷毀密鑰函數 CryptDestroyKey
- 函數功能:銷毀密鑰。
復制密鑰函數 CryptDuplicateKey
- 函數功能:復制一個密鑰。產生一個密鑰的拷貝,包括其狀態。
導出密鑰函數 CryptExportKey
- 函數功能:從CSP導出密鑰或密鑰對。
導入密鑰函數 CryptlmportKey
- 函數功能:把BLOB數據導入的CSP。該函數可以導入會話密鑰、公鑰、或者公/私鑰對。
獲得密鑰參數函數 CryptGetKeyParam
- 函數功能:獲得key句柄的各項參數。
獲得密鑰參數函數 CryptSetKeyParam
- 函數功能:設置key句柄的各項參數。
獲得密鑰參數函數 CryptGenRandom
- 函數功能:生成隨機數。
示例密鑰產生和交換實例處理過程如下圖所示

數據的加密與解密函數
CryptoAPI利用CryptEncrypt函數實現數據加密,利用CryptDecrypt實現數據解密。調用這2個函數前必須指定一個密鑰,這個密鑰可以由CryptGenKey、CryptDeriveKey或CryptImportKey產生。也可用CryptSetKeyParam函數指定額外的加密參數。
數據加密函數 CryptEncrypt
- 函數功能:使用hKey指定的密鑰和算法加密數據。
數據解密函數 CryptDecrypt
- 函數功能:使用hKey指定的密鑰和算法對加密數據解密。
示例數據加密處理過程如下圖所示

示例數據解密處理過程如下圖所示

哈希和數字簽名函數
CryptoAPI提供的哈希和數字簽名函數包括創建哈希函數CryptCreateHash、銷毀哈希CryptDestroyHash、復制哈希函數CryptDuplicateHash、獲得哈希參數函數CryptGetHashParam,設置哈希參數函數CryptSetHashParam、哈希會話密鑰函數 CryptHashSessionKey、哈希數據函數CryptHashData、對哈希簽名函數CryptSignHash和對哈希驗證簽名函數CryptVerifySignature。
創建哈希函數 CryptCreateHash
- 函數功能:創建哈希。
銷毀哈希 CryptDestroyHash
- 函數功能:銷毀哈希對象。
復制哈希函數 CryptDuplicateHash
- 函數功能:復制一個哈希對象。
獲得哈希參數函數 CryptGetHashParam
- 函數功能:獲得哈希對象的參數。
設置哈希參數函數 CryptSetHashParam
- 函數功能:設置哈希對象的參數。
哈希會話密鑰函數 CryptHashSessionKey
- 函數功能:對一個會話密鑰進行哈希,把它加到指定的哈希對象中。
哈希數據函數 CryptHashData
- 函數功能:對數據進行哈希操作,此函數可以反復調用。
對哈希簽名函數 CryptSignHash
- 函數功能:對哈希對象進行簽名。
對哈希驗證簽名函數 CryptVerifySignature
- 函數功能:驗證哈希簽名。
示例對數據簽名和驗證的流程如下圖所示

證書和證書庫函數
CryptoAPI證書和證書庫函數主要包括打開證書庫函數CertOpenStore、關閉證書庫函數CertCloseStore、從證書庫枚舉證書函數CertEnumCertificatesInStore、從證書庫查找證書函數CertFindCertificateInStore、創建證書句柄函數 CertCreateCertificateContext、釋放證書句柄函數CertFreeCertificateContext、獲得證書句柄屬性函數CertGetCertificateContextProperty、設置證書句柄屬性函數CertSetCertificateContextProperty和獲得證書主題名稱函數CertGetNameString。
打開證書庫函數 CertOpenStore
- 函數功能:根據證書庫類型,打開證書庫。
關閉證書庫函數 CertCloseStore
- 函數功能:關閉證書庫。
從證書庫枚舉證書函數 CertEnumCertificateslnStore
- 函數功能:枚舉證書庫中的證書。該函數通過循環調用,可以枚舉證書庫內的全部證書,上一次的返回,是下一次的pPrevCertContext,直到返回值為NULL。
從證書庫查找證書函數 CertFindCertificatelnStore
- 函數功能:從證書庫中查找指定的證書。
創建證書句柄函數 CertCreateCertificateContext
- 函數功能:由證書數據創建證書句柄。
釋放證書句柄函數 CertFreeCertificateContext
- 函數功能:釋放證書句柄。
獲得證書句柄屬性函數 CertGetCertificateContextProperty
- 函數功能:獲得證書句柄屬性。
設置證書句柄屬性函數 CertSetCertificateContextProperty
- 函數功能:設置證書句柄屬性。
獲得證書主題名稱函數 CertGetNameString
- 函數功能:從證書中獲得主題或頒發者的名稱。
示例枚舉證書庫并輸出其屬性的處理流程如下圖所示

SKF
設備管理函數

訪問控制函數

應用管理函數

文件管理函數

容器管理函數

密碼服務函數


得到國密證書
根據國密標準,一種設備類型可以有多個設備(Device),每一個設備內可以有多個應用(Application),每一個應用里可以有多個容器(Container),每個容器里可以有一對證書(Certificate):簽名證書和加密證書。
因此,應按照下列順序依次調用相關接口:
- SKF_EnumDev(BOOL bPresent, LPSTR szNameList, ULONG *pulSize);
調用這個方法用來遍歷當前電腦上的設備,這個方法的第一個參數一般傳TRUE,表示遍歷的是插上的設備;第二個參數就是返回的設備名稱列表;第三個參數是設備名稱列表緩沖區長度。按照慣例,這個方法應該被調用兩次:第一次szNameList傳NULL,pulSize返回長度;第二次給szNameList分配pulSize長度,返回設備列表,每個設備的名稱以單個’\0’結束,以雙’\0’表示列表的結束。 - SKF_ConnectDev(LPSTR szName, DEVHANDLE *phDev);
通過循環調用這個方法用來連接每一個具體的設備,szName為設備名,即上面方法得到的列表中的設備名;返回phDev為設備句柄。 - SKF_EnumApplication(DEVHANDLE hDev, LPSTR szAppNameList,ULONG *pulSize);
得到設備句柄后,再通過此方法枚舉得到設備里的應用列表。hDev為連接設備時返回的設備句柄;szAppNameList返回應用名稱列表;pulSize是列表緩沖區長度。這個方法也是照例要調用兩次,不再贅述。同樣,每個應用的名稱以單個’\0’結束,以雙’\0’表示列表的結束。 - SKF_OpenApplication(DEVHANDLE hDev, LPSTR szAppName, HAPPLICATION phApplication);
通過循環調用此方法打開應用列表里的每一個應用,hDev為連接設備時返回的設備句柄;szAppName是要打開的應用名稱;phApplication為返回的應用句柄。 - SKF_EnumContainer(IN HAPPLICATIONhApplication, OUT LPSTRszContainerNameList, OUT ULONGpulSize)
拿到應用句柄后,我們就可以用此方法遍歷應用中的所有容器了。hApplication是應用句柄;szContainerNameList是返回的容器名稱列表;pulSize是列表長度;后面的就不用了多說了。 - SKF_OpenContainer(HAPPLICATION hApplication,LPSTR szContainerName,HCONTAINER phContainer);
循環調用此方法打開每一個容器。hApplication是應用句柄;szContainerName是要打開的容器名稱;phContainer是返回的容器句柄。 - SKF_ExportCertificate(HCONTAINER hContainer, BOOL bSignFlag, BYTE pbCert, ULONG *pulCertLen);
最后就可以通過這個方法取得每個容器里的證書。hContainer是容器句柄;bSignFlag為導出的證書類型; TRUE表示導出的是簽名證書;FALSE表示導出加密證書。pbCert為返回的證書數據,pulCertLen是證書數據的長度。同樣需兩次調用。
數字簽名
在數字簽名時,要指定簽名所使用的證書。通過遍歷本機上的證書,與簽名用的證書進行對比,定位到簽名證書在USBKEY中的位置,得到設備、應用和容器的句柄,然后使用證書的私鑰進行簽名。遍歷對比的過程可參見上一節的內容。另外,由于數字簽名會用到私鑰,因此這里需要驗證口令。
- SKF_VerifyPIN(HAPPLICATION hApplication, ULONG ulPINType, LPSTR szPIN, ULONG pulRetryCount);
此方法用來驗證證書所在應用的PIN碼,及上面說的口令,為后面的簽名取得權限。hApplication是應用句柄;ulPINType是PIN類型,可以為0是管理員賬戶,1為普通用戶,這個參數一般選擇1。szPIN值是PIN碼,pulRetryCount為出錯后返回的重試次數。 - SKF_ExportPublicKey(HCONTAINER hContainer, BOOL bSignFlag, BYTE pbBlob, ULONG* pulBlobLen);
這個方法用來導出容器中的簽名公鑰,hContainer為證書所在容器句柄;bSignFlag 為導出密鑰類型,TRUE表示導出簽名公鑰,FALSE表示導出加密公鑰,這里選擇TRUE;pbBlob為返回公鑰的數據;pulBlobLen為數據的長度。這里這個方法可以不用調用兩次,因為公鑰結構是已知的,其長度也是固定的,因此可以直接為pbBlob分配固定長度的數據,以返回公鑰。 - SKF_DigestInit(DEVHANDLE hDev, ULONG ulAlgID, ECCPUBLICKEYBLOB *pPubKey, unsigned char *pucID, ULONG ulIDLen, HANDLE *phHash);
此方法進行雜湊(國密標準里把摘要稱之為雜湊)運算初始化,并指定計算消息雜湊的算法。hDev為設備句柄;ulAlgID是雜湊算法標識,這里選擇SGD_SM3(0x00000001),表明使用SM3算法;pPubKey為簽名用證書公鑰數據;pucID為簽名者的ID值;ulIDLen是簽名者的ID值的長度;phHash為返回的雜湊對象句柄。加入簽名者ID值是SM2數字簽名的一個重要特征,默認使用"1234567812345678"這個字符串值。 - SKF_Digest(HANDLE hHash, BYTE *pbData, ULONG ulDataLen, BYTE *pbHashData, ULONG *pulHashLen);
初始化后,調用此方法進行數據雜湊運算。hHash是SKF_DigestInit方法返回的雜湊對象句柄; pbData為產生簽名的原文,ulDataLen是原文數據的長度,pbHashData返回雜湊數據; pulHashLen返回雜湊結果的長度。同樣,因為雜湊數據的長度都是固定的,這里同樣可以為pbHashData事先分配固定長度,而不用再調用兩遍。
注意,如果進行雜湊的數據是分組的,那就得使用下面兩個方法:
SKF_DigestUpdate(HANDLE hHash, BYTE *pbData, ULONG ulDataLen);
SKF_DigestFinal(HANDLE hHash, BYTE *pHashData, ULONG *pulHashLen);
對每一組數據都使用SKF_DigestUpdate,最后調用SKF_DigestFinal返回雜湊值。當然,在數字簽名運算中不存在分塊計算簽名的情況,所以這里也不會把數據分塊雜湊。 - SKF_ECCSignData(HCONTAINER hContainer, BYTE *pbData, ULONG ulDataLen, PECCSIGNATUREBLOB pSignature);
最后調用此方法進行數字簽名。hContainer用來簽名的私鑰所在容器句柄,也就是遍歷對比證書得到的容器句柄;pbData是被簽名的數據;ulDataLen是被簽名數據長度,必須小于密鑰模長; pbSignature為返回的簽名值。
驗證簽名
- SKF_CreateContainer(HAPPLICATION hApplication, LPSTR szContainerName, HCONTAINER phContainer)
調用此方法創建一個臨時容器。hApplication為容器所在的應用句柄;szContainerName是ASCII字符串,表示所建立容器的名稱,最大長度不能超過64字節;phContainer是返回所建立容器的容器句柄。 - SKF_ImportCertificate(HCONTAINER hContainer, BOOL bSignFlag, BYTE pbCert, ULONG ulCertLen);
將簽名用的證書導入到容器中。hContainer為容器句柄,即用上一方法創建的臨時容器;bSignFlag為證書類型,TRUE表示簽名證書,FALSE表示加密證書,這里選TRUE;pbCert,是證書數據;ulCertLen為證書數據長度; - SKF_ExportPublicKey(HCONTAINER hContainer, BOOL bSignFlag, BYTE* pbBlob, ULONG* pulBlobLen);
導出公鑰。 - SKF_DigestInit(DEVHANDLE hDev, ULONG ulAlgID, ECCPUBLICKEYBLOB *pPubKey, unsigned char *pucID, ULONG ulIDLen, HANDLE *phHash);
雜湊初始化。 - SKF_Digest(HANDLE hHash, BYTE *pbData, ULONG ulDataLen, BYTE *pbHashData, ULONG pulHashLen);
雜湊運算。 - SKF_ECCVerify(DEVHANDLE hDev , ECCPUBLICKEYBLOB pECCPubKeyBlob, BYTE *pbData, ULONG ulDataLen, PECCSIGNATUREBLOB pSignature);
進行簽名驗證。hDev是設備句柄;pECCPubKeyBlob是公鑰數據結構,即第3步得到的公鑰; pbData為待驗證簽名的數據;ulDataLen是待驗證簽名數據長度;pbSignature待驗證的簽名值。 - SKF_DeleteContainer(HAPPLICATION hApplication, LPSTR szContainerName);
刪除臨時容器。hApplication為容器所在的應用句柄;szContainerName為容器名稱。
3.以龍脈GM3000Key為例,寫出調用不同接口的代碼(Crypto API,PKCS#11,SKF接口),把運行截圖加入博客,并提供代碼鏈接
SKF接口
- 龍脈密碼鑰匙驅動實例工具等\mToken-GM3000\skf\samples\windows\EncryptData\EncryptData.sln
![]()
Crypto API
- 龍脈密碼鑰匙驅動實例工具等\mToken-GM3000\csp\samples\CryptAPI\VC\EncryptDecryptFile\EncryptFile.sln
![]()
![]()
PKCS#11
- 龍脈密碼鑰匙驅動實例工具等\mToken-GM3000\pkcs11\windows\samples\PKCStest\PKCStest.sln
- DES
![]()
- DES3
![]()
- RC2
![]()
- RC4
![]()
- RSA
![]()
- AES
![]()
- DES









浙公網安備 33010602011771號