前言:
Crypto是微軟的加密API,如果看懂了,使用起來是很簡(jiǎn)單的一件事,不過就是最開始沒有看懂,被虐了兩天。然后又被其他問題給虐了兩天。最后做出來的東西也不是讓自己十分滿意。不過還好,最后的結(jié)果還不算太糟。
本想對(duì)代碼進(jìn)行一次整理,寫一個(gè)demo代碼,不過現(xiàn)在有些慵懶了,還是隨便貼些筆記好了。
PS:
發(fā)現(xiàn)Delphi盒子要賣了。這似乎也驗(yàn)證了一句話,有商業(yè)價(jià)值的東西才會(huì)有持續(xù)的生命力。
Crypto 加密的基本流程
- 創(chuàng)建/獲取一個(gè)密碼容器CSP
- 創(chuàng)建/獲取/導(dǎo)入一個(gè)密鑰
- 使用密鑰進(jìn)行加密/解密
加密具體流程:
- 創(chuàng)建/獲取一個(gè)密碼容器CSP。這一部分基本上所有程序都一樣,直接復(fù)制過來到程序里就可以了。
//以下獲得一個(gè)CSP句柄
if(CryptAcquireContext(
&hProv, //out 密碼容器
NULL, //NULL表示使用默認(rèn)密鑰容器,默認(rèn)密鑰容器名為用戶登陸名。
NULL,
PROV_RSA_FULL, //in 使用RSA密鑰
0))
{
printf("A cryptographic provider has been acquired. \n");
}
else//密鑰容器不存在
{
if(CryptAcquireContext(
&hProv,
NULL,
NULL,
PROV_RSA_FULL,
CRYPT_NEWKEYSET))//創(chuàng)建密鑰容器
{
//創(chuàng)建密鑰容器成功,并得到CSP句柄
printf("A new key container has been created.\n");
}
else
{
HandleError("Could not create a new key container.\n");
}
}
- 創(chuàng)建/獲取一個(gè)密鑰。這里有些程序里會(huì)創(chuàng)建一個(gè)sessionKey會(huì)話密鑰用于對(duì)稱加密,這里創(chuàng)建的是非對(duì)稱加密的密鑰。
//--------------------------------------------------------------------
// 從密鑰容器中取交換密鑰
if(CryptGetUserKey(
hProv, //CSP句柄,也就是在一里面創(chuàng)建的,密碼容器。
AT_KEYEXCHANGE, //密鑰的類型,這里指名的是交換密鑰。還有一個(gè)AT_SIGNATURE,這個(gè)是數(shù)字簽名用的。
&hKey)) //out 獲取到的密鑰
{
printf("The signature key has been acquired. \n");
}
else
{
if(GetLastError() == NTE_NO_KEY) //密鑰容器里不存在key pair創(chuàng)建之
{
if(CryptGenKey(
hProv, //in CSP句柄
AT_SIGNATURE, //in 創(chuàng)建的密鑰對(duì)類型為signature key pair
0, //key類型,這里用默認(rèn)值
&hKey)) //out 創(chuàng)建成功返回新創(chuàng)建的密鑰對(duì)的句柄
{
printf("Created a signature key pair.\n");
}
else
{
MyHandleError("Error occurred creating a signature key.\n");
}
}
else
{
MyHandleError("Error during CryptGetUserKey for signkey.");
}
}
- 使用密鑰進(jìn)行加密
//--------------------------------------------------------------------
// 加密數(shù)據(jù)
if(!CryptEncrypt(
hKey, //in 密鑰
0, //如果數(shù)據(jù)同時(shí)進(jìn)行散列和加密,這里傳入一個(gè)散列對(duì)象
TRUE, //如果是最后一個(gè)被加密的塊,輸入TRUE.如果不是輸入FALSE.
//這里通過判斷是否到文件尾來決定是否為最后一塊。
0, //保留
pbBuffer, // in/out輸入被加密數(shù)據(jù),輸出加密后的數(shù)據(jù)。將pbBuffer分配大一些,防止長(zhǎng)度不夠。
&dwCount, // in/out輸入被加密數(shù)據(jù)實(shí)際長(zhǎng)度,輸出加密后數(shù)據(jù)長(zhǎng)度。這個(gè)需要根據(jù)pbBuffer的實(shí)際輸入長(zhǎng)度進(jìn)行計(jì)算(strlen?),不然不能正常運(yùn)行。
dwBufferLen)) //in pbBuffer的大小。這里填大點(diǎn),
{
HandleError("Error during CryptEncrypt. \n");
}
到這里加密就已經(jīng)做完了,加密后的數(shù)據(jù)保存在pbBuffer中。
- 導(dǎo)出公/私鑰
私鑰在加密的時(shí)候需要,以后使用的時(shí)候不再生成,直接導(dǎo)入。(備注:如果需要導(dǎo)出私鑰需要在創(chuàng)建密鑰時(shí)候設(shè)置參數(shù),具體見MSDN)
解密的時(shí)候需要用到公鑰,需要將公鑰分發(fā)給解密用戶。
//--------------------------------------------------------------------
// 因?yàn)榻邮障⒄咭?yàn)證數(shù)字簽名,所以要導(dǎo)出公鑰給接收者。
if(CryptExportKey(
hKey, //in 密鑰句柄
NULL,
PUBLICKEYBLOB,// out 公鑰輸出數(shù)據(jù)。在導(dǎo)出后,需要將公鑰的數(shù)據(jù)保存成文件等,以便分發(fā)。
0,
NULL,
&dwBlobLen)) //out 得到公鑰的大小
{
printf("Size of the BLOB for the public key determined. \n");
}
else
{
MyHandleError("Error computing BLOB length.");
}
- 銷毀容器和Key
在完成加密后,需要對(duì)key和容器進(jìn)行銷毀,相關(guān)函數(shù)如下。
if(hKey)
CryptDestroyKey(hKey);
if(hCryptProv)
CryptReleaseContext(hCryptProv, 0);
解密的具體流程:
- 同加密流程
- 導(dǎo)入解密用的公鑰。
HCRYPTKEY hPubKey;
if(CryptImportKey(
hProv,//in CSP密碼容器
pbKeyBlob,//in 需要導(dǎo)入的公鑰數(shù)據(jù)(在加密的時(shí)候?qū)С龅墓€,加密中的4)
dwBlobLen,//in 公鑰數(shù)據(jù)的長(zhǎng)度
0,
0,
&hPubKey))//out 公鑰導(dǎo)入得到的公鑰句柄
{
printf("The key has been imported.\n");
}
else
{
MyHandleError("Public key import failed.");
}
- 解密
解密的參數(shù)和加密的參數(shù)基本相同。
//--------------------------------------------------------------------
// Decrypt data.
if(!CryptDecrypt(
hPubKey, //in 解密用的公鑰,也就是在2中導(dǎo)入的公鑰
0,
TRUE, //如果是最后一個(gè)被加密的塊,輸入TRUE.如果不是輸入FALSE.
0,
pbBuffer, // in/out輸入被解密數(shù)據(jù),輸出加密后的數(shù)據(jù)。將pbBuffer分配大一些,防止長(zhǎng)度不夠。
&dwCount)) // in/out輸入被解密數(shù)據(jù)實(shí)際長(zhǎng)度,輸出加密后數(shù)據(jù)長(zhǎng)度。這個(gè)需要根據(jù)pbBuffer的實(shí)際輸入長(zhǎng)度進(jìn)行計(jì)算(strlen?),不然不能正常運(yùn)行。
{
HandleError("Error during CryptDecrypt!");
}
- 銷毀容器和Key
同加密
相關(guān)參考資料:
學(xué)習(xí)CRYPTOAPI第一天(這個(gè)網(wǎng)站還有另外的兩篇 二/三天) http://www.wangchao.org/bbsdetail_66820.html
VC知識(shí)庫(kù)文檔中心(Microsoft CryptoAPI加密技術(shù) 一/二) http://www.vckbase.com/document/listdoc.asp?mclsid=&sclsid=109&page=1
Crypto API 學(xué)習(xí)筆記一/二/三(另外兩篇baidu下) http://www.pediy.com/bbshtml/bbs8/pediy8-364.htm