Crypto API 学习笔记一
標 題: 【原創】Crypto API 學習筆記一
作 者: jdxyw
時 間: 2006-09-01,16:47
鏈 接: http://bbs.pediy.com/showthread.php?t=31357
Crypto API 學習筆記一
微軟公司在NT4.0以上版本中提供了一套完整的Crypto API的函數,支持密鑰交換,數據加密解密,數字簽名,給程序員帶來了很大方便,用戶在對軟件進行保護的時候可以直接利用Crypto API來完成這些工作,比如計算注冊碼,檢查程序的完整性等。
? 我們在用這些的API進行加密解密的時候,只需要知道如何去應用它們,而不必知道它們的底層實現。如果想知道它們更為詳盡的資料,可以查找相關的資料。
? 對Crypto API只是業余型的感興趣,想通過寫學習筆記,一是讓自己記的更牢固些,二是想把自己的學的跟大家探討一下。寫的不好,大家多多原諒。我主要通過MSDN來學習,例子也是完全取自MSDN。
? 首先,是Crypto API運行的環境。
首先需要Crypt32.lib,將它加到project->setting->link下面,當然你也可以在程序中用#pragma comment (lib, "crypt32.lib")加入。
? 在程序開頭,你要加入兩個頭文件 windows.h 和 Wincrypt.h,和一個#define MY_ENCODING_TYPE? (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING)
? 在正式應用API進行一系列的加密解密的時候,需要有一些準備工作,下面是介紹一些在正式開始時所需要了解和做的工作。
生成密鑰和密鑰容器
? 我們知道,在進行加密解密的時候,我們需要一個密鑰進行加密,和一個密鑰進行解密,加密密鑰和解密密鑰可能相同,也可能不同。于是在我們進行加密解密的開始時,我們首先需要有密鑰。下面這個程序,完成了三個任務,并且介紹了一些函數的用法。
任務一:獲取一個指定的密鑰容器,如果這個容器不存在,創建一個。
任務二:如果容器中不存在一個簽名密鑰對,創建一個
任務三:如果容器中不存在一個交換密鑰對,創建一個
? //-------------------------------------------------------------------
下面這段程序使用到了這幾個函數
CryptAcquireContext??
CryptDestroyKey??
CryptGenKey??
CryptGetUserKey??
//?Copyright?(c)?Microsoft?Corporation.??All?rights?reserved.?
#include?<stdio.h>?
#include?<tchar.h>?
#include?<windows.h>?
#include?<Wincrypt.h>?
//-------------------------------------------------------------------?
void?MyHandleError(LPTSTR?psz)?
{?
????_ftprintf(stderr,?TEXT("An?error?occurred?in?the?program.?\n"));?
????_ftprintf(stderr,?TEXT("%s\n"),?psz);?
????_ftprintf(stderr,?TEXT("Error?number?%x.\n"),?GetLastError());?
????_ftprintf(stderr,?TEXT("Program?terminating.?\n"));?
????exit(1);?
}?//?End?of?MyHandleError.?
上面這個函數是一個異常處理函數,當出現錯誤的時候,出現提示,并推出程序。以后的程序中都有這個函數,以后就會將這個函數的實現省去。現在這個函數的實現在后面。
Codevoid?main(void)??
{??
????????HCRYPTPROV?hCryptProv;???//定義一個CSP模塊的句柄?!癈SP模塊,請查看《加密解密二》222頁,那里有簡單的說明,這里就不說了。??????
????????LPCTSTR?pszContainerName?=?TEXT("My?Sample?Key?Container");//用一個TEXT宏定義一個容器的名字,?
????if(CryptAcquireContext(????????//這個函數是獲取有某個容器的CSP模塊的指針,成功返回TRUE。?
????????&hCryptProv,????????????//指向一個CSP模塊句柄指針,里面用指定的容器?
????????pszContainerName,???????//指定容器的名稱?
?????NULL,????????????????//這個參數這里用的是缺省值,指得是缺省得CSP模塊,你也可以傳入一個LPCTSTR類型的字符串,指定CSP模塊?
????????PROV_RSA_FULL,??????//確定密鑰的類型?
????????0))????????????????????//常設為0,還有些其他的類型,請看MSDN?
????{?
????????_tprintf(?
????????????TEXT("A?crypto?context?with?the?%s?key?container?")?
????????????TEXT("has?been?acquired.\n"),??
????????????pszContainerName);?
????}?
????else?
????{??
????????//不成功的處理段?
????????if(GetLastError()?==?NTE_BAD_KEYSET)?????//?NTE_BAD_KEYSET意味著密鑰?
//容器不存在,下面就去創建一個?
//新的密鑰容器?
????????{?
????????????if(CryptAcquireContext(?
????????????????&hCryptProv,??
????????????????pszContainerName,??
????????????????NULL,??
????????????????PROV_RSA_FULL,??
????????????????CRYPT_NEWKEYSET))???????????//?CRYPT_NEWKEYSET意味著當指定容器不存在的時候,去創建一個容器。?
????????????{?
????????????????_tprintf(TEXT("A?new?key?container?has?been?")?
????????????????????TEXT("created.\n"));?
????????????}?
????????????else?
????????????{?
????????????????MyHandleError(TEXT("Could?not?create?a?new?key?")?
????????????????????TEXT("container.\n"));?
????????????}?
????????}?
????????else?
????????{?
????????????MyHandleError(TEXT("CryptAcquireContext?failed.\n"));?
????????}?
????}?
????HCRYPTKEY?hKey;????????????????????????????//創建一個密鑰句柄?
????if(CryptGetUserKey(???????????????????????????//?CryptGetUserKey是獲取一個密鑰//句柄的函數,成功返回TRUE?
????????hCryptProv,???????????????????????????????//指定容器的CSP模塊句柄?
????????AT_SIGNATURE,?????????????????????????//指定私鑰的類型?
????????&hKey))????????????????????????????????//原來接收獲取的密鑰句柄?
????{?
????????_tprintf(TEXT("A?signature?key?is?available.\n"));?
????}?
????else?
????{?
????????_tprintf(TEXT("No?signature?key?is?available.\n"));?
????????if(GetLastError()?==?NTE_NO_KEY)??????????????//?NTE_NO_KEY意味著密鑰不存在,下面就生成一個密鑰?
????????{?
????????????_tprintf(TEXT("The?signature?key?does?not?exist.\n"));?
????????????_tprintf(TEXT("Create?a?signature?key?pair.\n"));??
????????????if(CryptGenKey(??????????????????????????//?CryptGenKey生成一個密鑰?
????????????????hCryptProv,??????????????????????????//指定CSP模塊的句柄?
????????????????AT_SIGNATURE,????????????????????//對于公鑰密碼系統,生成一個私鑰和一個公鑰,這個參數指定了這個密鑰是公鑰,于是生成了一個密碼對。如果不是公鑰系統,則指定了密碼算法,具體看MSDN。?
????????????????0,?????????????????????????????????//指定了生成密鑰的類型,這個參數的說明挺多的,想獲取更為詳盡的資料請看MSDN。?
????????????????&hKey))??
????????????{?
????????????????_tprintf(TEXT("Created?a?signature?key?pair.\n"));?
????????????}?
????????????else?
????????????{?
????????????????MyHandleError(TEXT("Error?occurred?creating?a?")?
????????????????????TEXT("signature?key.\n"));??
????????????}?
????????}?
????????else?
????????{?
????????????MyHandleError(TEXT("An?error?other?than?NTE_NO_KEY?")?
????????????????TEXT("getting?a?signature?key.\n"));?
????????}?
????}?//?End?if.?
????_tprintf(TEXT("A?signature?key?pair?existed,?or?one?was?")?
????????TEXT("created.\n\n"));?
????????if(hKey)??????????????????????????????//將密鑰句柄銷毀?
????{?
????????if(!(CryptDestroyKey(hKey)))?
????????{?
????????????MyHandleError(TEXT("Error?during?CryptDestroyKey."));?
????????}?
????????hKey?=?NULL;?
????}??
????下面這部分和上面是類似的,只不過密鑰類型不相同而已。?
????if(CryptGetUserKey(?
????????hCryptProv,?
????????AT_KEYEXCHANGE,?
????????&hKey))??
????{?
????????_tprintf(TEXT("An?exchange?key?exists.\n"));?
????}?
????else?
????{?
????????_tprintf(TEXT("No?exchange?key?is?available.\n"));?
????????//?Check?to?determine?whether?an?exchange?key??
????????//?needs?to?be?created.?
????????if(GetLastError()?==?NTE_NO_KEY)??
????????{??
????????????//?Create?a?key?exchange?key?pair.?
????????????_tprintf(TEXT("The?exchange?key?does?not?exist.\n"));?
????????????_tprintf(TEXT("Attempting?to?create?an?exchange?key?")?
????????????????TEXT("pair.\n"));?
????????????if(CryptGenKey(?
????????????????hCryptProv,?
????????????????AT_KEYEXCHANGE,?
????????????????0,?
????????????????&hKey))??
????????????{?
????????????????_tprintf(TEXT("Exchange?key?pair?created.\n"));?
????????????}?
????????????else?
????????????{?
????????????????MyHandleError(TEXT("Error?occurred?attempting?to?")?
????????????????????TEXT("create?an?exchange?key.\n"));?
????????????}?
????????}?
????????else?
????????{?
????????????MyHandleError(TEXT("An?error?other?than?NTE_NO_KEY?")?
????????????????TEXT("occurred.\n"));?
????????}?
????}?
????//?Destroy?the?exchange?key.?
????if(hKey)?
????{?
????????if(!(CryptDestroyKey(hKey)))?
????????{?
????????????MyHandleError(TEXT("Error?during?CryptDestroyKey."));?
????????}?
????????hKey?=?NULL;?
????}?
????//?Release?the?CSP.?
????if(hCryptProv)?
????{?
????????if(!(CryptReleaseContext(hCryptProv,?0)))?
????????{?
????????????MyHandleError(TEXT("Error?during?CryptReleaseContext."));?
????????}?
????}??
????_tprintf(TEXT("Everything?is?okay.?A?signature?key?"));?
????_tprintf(TEXT("pair?and?an?exchange?key?exist?in?"));?
????_tprintf(TEXT("the?%s?key?container.\n"),?pszContainerName);???
}?//?End?main.
?
? 下面我們再通過一個程序,用幾種不同的方法,將CryptAcquireContext和其他的API函數聯系起來,看看它們是如何與一個CSP和容器工作的。這個程序演示了以下內容和幾個函數。
一.? 用CryptAcquireContext獲取一個缺省容器的缺省CSP的句柄。如果缺省容器不存在,用CryptAcquireContext創建一個。
二.? 用CryptGetProvParam獲取CSP和容器的信息。
三.? 用CryptContextAddRef增加CSP的引用計數器的數值。
四.? 用CryptAcquireContext創建一個指定的容器
五.? 用CryptAcquireContext刪除一個容器
六.? 用一個新創建的容器獲取一個CSP的句柄。
#include?<stdio.h>?
#include?<tchar.h>?
#include?<windows.h>?
#include?<Wincrypt.h>?
異常處理函數省略?
void?main(void)?
{?
????HCRYPTPROV?hCryptProv;????????????????????????????//定義CSP句柄?
????if(CryptAcquireContext(?
????????&hCryptProv,??
????????NULL,???????????????????????????????????????????//缺省容器?
????????NULL,???????????????????????????????????????????//缺省CSP?
????????PROV_RSA_FULL,??
????????0))??
????{?
????????_tprintf(TEXT("CryptAcquireContext?succeeded.\n"));?
????}?
????else?
????{?
????????if?(GetLastError()?==?NTE_BAD_KEYSET)???????????????//同樣,如果當不存在這樣的容器的時候,創建一個?
????????{?
????????????if(CryptAcquireContext(?
????????????????&hCryptProv,??
????????????????NULL,??
????????????????NULL,??
????????????????PROV_RSA_FULL,??
????????????????CRYPT_NEWKEYSET))??????????????????????
????????????{?
????????????????_tprintf(TEXT("CryptAcquireContext?succeeded.\n"));?
????????????}?
????????????else?
????????????{?
????????????????MyHandleError(TEXT("Could?not?create?the?default?")?
????????????????????TEXT("key?container.\n"));?
????????????}?
????????}?
????????else?
????????{?
????????????MyHandleError(TEXT("A?general?error?running?")?
????????????????TEXT("CryptAcquireContext."));?
????????}?
????}?
????CHAR?pszName[1000];?
????DWORD?cbName;?
????cbName?=?1000;?
????if(CryptGetProvParam(?
????????hCryptProv,?????????????????????????????????????//CSP模塊句柄?
????????PP_NAME,?????????????????????????????????????//指定獲取哪些信息,這里是指定獲取CSP名字的信息?
????????(BYTE*)pszName,???????????????????????????????//緩沖區接受信息返回值?
????????&cbName,??
????????0))?
????{?
????????_tprintf(TEXT("CryptGetProvParam?succeeded.\n"));?
????????printf("Provider?name:?%s\n",?pszName);?
????}?
????else?
????{?
????????MyHandleError(TEXT("Error?reading?CSP?name.\n"));?
????}?
????//---------------------------------------------------------------?
????//?Read?the?name?of?the?key?container.?
????cbName?=?1000;?
????if(CryptGetProvParam(?
????????hCryptProv,??
????????PP_CONTAINER,???????????????????????????????????????//獲取容器名字?
????????(BYTE*)pszName,??
????????&cbName,??
????????0))?
????{?
????????_tprintf(TEXT("CryptGetProvParam?succeeded.\n"));?
????????printf("Key?Container?name:?%s\n",?pszName);?
????}?
????else?
????{?
????????MyHandleError(TEXT("Error?reading?key?container?name.\n"));?
????}?
????if(CryptContextAddRef(???????????????????????//?CryptContextAddRef是向一個CSP的引用計數器增加一個值的函數?
????????hCryptProv,??
????????NULL,????????????????????????????????//保留值,必須為NULL?
????????0))?????????????????????//保留值,必須為0?
????{?
????????_tprintf(TEXT("CryptcontextAddRef?succeeded.\n"));?
????}?
????else?
????{?
????????MyHandleError(TEXT("Error?during?CryptContextAddRef!\n"));?
????}?
????//---------------------------------------------------------------?
????//??The?reference?count?on?hCryptProv?is?now?greater?than?one.??
????//??The?first?call?to?CryptReleaseContext?will?not?release?the??
????//??provider?handle.??
????//---------------------------------------------------------------?
????//??Release?the?context?once.?
????if?(CryptReleaseContext(hCryptProv,?0))????????????????//?CryptReleaseContext是用來釋放CSP句柄的,當這個函數調用一次的時候,CSP里面的引用計數就減少一,當引用計數減少的0的時候。CSP將不能再被這個程序中的任何函數調用了。?
????{?
????????_tprintf(TEXT("The?first?call?to?CryptReleaseContext?")?
????????????TEXT("succeeded.\n"));?
????}?
????else?
????{?
????????MyHandleError(TEXT("Error?during?")?
????????????TEXT("CryptReleaseContext?#1!\n"));?
????}?
????if?(CryptReleaseContext(hCryptProv,?0))????????????????//再次釋放CSP模塊?
????{?
????????_tprintf(TEXT("The?second?call?to?CryptReleaseContext?")?
????????????TEXT("succeeded.\n"));?
????}?
????else?
????{?
????????MyHandleError(TEXT("Error?during?")?
????????????TEXT("CryptReleaseContext?#2!\n"));?
????}?
???下面是從PROV_RSA_FULL的CSP模塊中創建一個自己的容器?
????LPCTSTR?pszContainerName?=?TEXT("My?Sample?Key?Container");?
????hCryptProv?=?NULL;?
????if(CryptAcquireContext(?
????????&hCryptProv,??
????????pszContainerName,?
????????NULL,??
????????PROV_RSA_FULL,??
????????CRYPT_NEWKEYSET))??
????{?
????????_tprintf(TEXT("CryptAcquireContext?succeeded.?\n"));?
????????_tprintf(TEXT("New?key?set?created.?\n"));??
????????//-----------------------------------------------------------?
????????//?Release?the?provider?handle?and?the?key?container.?
????????if(hCryptProv)?
????????{?
????????????if(CryptReleaseContext(hCryptProv,?0))??
????????????{?
????????????????hCryptProv?=?NULL;?
????????????????_tprintf(TEXT("CryptReleaseContext?succeeded.?\n"));?
????????????}?
????????????else?
????????????{?
????????????????MyHandleError(TEXT("Error?during?")?
????????????????????TEXT("CryptReleaseContext!\n"));?
????????????}?
????????}?
????}?
????else?
????{?
????????if(GetLastError()?==?NTE_EXISTS)?
????????{?
????????????_tprintf(TEXT("The?named?key?container?could?not?be?")?
????????????????TEXT("created?because?it?already?exists.\n"));?
????????}?
????????else?
????????{?
????????????MyHandleError(TEXT("Error?during?CryptAcquireContext?")?
????????????????TEXT("for?a?new?key?container."));?
????????}?
????}?
????if(CryptAcquireContext(?
????????&hCryptProv,??
????????pszContainerName,??
????????NULL,??
????????PROV_RSA_FULL,?
????????0))??
????{?
????????_tprintf(TEXT("Acquired?the?key?set?just?created.?\n"));?
????}?
????else?
????{?
????????MyHandleError(TEXT("Error?during?CryptAcquireContext!\n"));?
????}?
????//---------------------------------------------------------------?
????//?Perform?cryptographic?operations.?
????//---------------------------------------------------------------?
???????if(CryptReleaseContext(?
????????hCryptProv,??
????????0))??
????{?
????????_tprintf(TEXT("CryptReleaseContext?succeeded.?\n"));?
????}?
????else?
????{?
????????MyHandleError(TEXT("Error?during?CryptReleaseContext!\n"));?
????}?
????if(CryptAcquireContext(?
????????&hCryptProv,??
????????pszContainerName,??
????????NULL,??
????????PROV_RSA_FULL,?
????????CRYPT_DELETEKEYSET))????????????????????//CRYPT_DELETEKEYSET意味著CryptAcquireContex刪除一個指定的容器?
????{?
????????_tprintf(TEXT("Deleted?the?key?container?just?created.?\n"));?
????}?
????else?
????{?
????????MyHandleError(TEXT("Error?during?CryptAcquireContext!\n"));?
????}?
}?
?
轉載于:https://www.cnblogs.com/wanghao111/archive/2009/05/25/1489031.html
總結
以上是生活随笔為你收集整理的Crypto API 学习笔记一的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 风云点评:Flash 与 Silverl
- 下一篇: SmtpClient 身份验证失败(au