分享
 
 
 

使用 Visual C++创建Crypto加/解密组件

王朝vc·作者佚名  2006-12-16
窄屏简体版  字體: |||超大  

简介

这篇文章将教你如何使用 Visual C++ 和 ATL 工具和 Microsoft CryptoAPI 建立一个能加/解密数据的组件。

Crypto 101

本文使用Microsoft® Cryptographic Application Programming Interface (CryptoAPI),将苦涩难懂的逻辑算法操作隐藏起来,如果想知道详细信息请参看MSDN Library.如果想知道更多的密码系统,我推荐你看看这本书 Bruce Schneier's Applied Cryptography: Protocols, Algorithms, and Source Code in C

建立组件

首先,用"ATL COM AppWizard”建立一个新project。在这个例子中,我将其命名为”CryptoProj”。在 server type中选择”Dynamic Link Library (DLL)”,点按”Finish”继续。

定义界面

在 insert 菜单中点按"New ATL Object...",选择 “Simple Object”,然后按 Next。

在 “Names” 栏中,设 short name 为 “Crypto”,其他项照下面的填写。

在 Attributes 栏,确定 Apartment Threading Model 被选上,Support IsupportErrorInfo 选项勾上,然后按 OK.

按右键点击 Icrypto ,点”Add Method”加一个方法.

将该方法取名为”Encrypt”,在参数栏输入"[in] BSTR bstrPlainText, [in] BSTR bstrPassword, [out, retval] VARIANT *vCipherText".

再加一个方法,取名为”Decrypt”,参数为"[in] VARIANT vCipherText, [in] BSTR bstrPassword, [out, retval] BSTR *bstrPlainText"

实现加密方法

需要包括 CryptoAPI 库,在 Crypto.cpp 头加一句: #include <wincrypt.h>

现在来定义我们需要的各种变量。STDMETHODIMP CCrypto::Encrypt(BSTR bstrPlainText,

BSTR bstrPassword,

VARIANT *vCipherText)

{

BYTE *pbData;

BYTE *pbPassword;

SAFEARRAY* psa;

HCRYPTPROV hProv = 0;

HCRYPTHASH hHash = 0;

HCRYPTKEY hKey = 0;

DWORD dwCryptDataLen = 0;

DWORD dwDataLen = 0;

DWORD dwError = 0;

char buffer[200];

USES_CONVERSION;

由于许多CryptoAPI 调用要用注册表,所以需要执行一句RevertToSelf().RevertToSelf();

下一步,我们需要将输入变量转化为我们能用的格式。dwDataLen = SysStringLen(bstrPlainText);

pbData = (BYTE*)OLE2A(bstrPlainText);

pbPassword = (BYTE*)OLE2A(bstrPassword);

然后,用CryptAcquireContext function取得省缺 Crypto provider的句柄。// Get handle to the default provider.

if (! CryptAcquireContext(&hProv,

"aspZoneCryptoComponent\0", MS_DEF_PROV,

PROV_RSA_FULL, CRYPT_MACHINE_KEYSET))

{

if (! CryptAcquireContext(&hProv,

"aspZoneCryptoComponent\0", MS_DEF_PROV,

PROV_RSA_FULL, (CRYPT_NEWKEYSET |

CRYPT_MACHINE_KEYSET)))

{

dwError = GetLastError();

sprintf(buffer, "Error %x during CryptAcquireContext",

dwError);

return Error(buffer);

}

}

我们通过创建一个 one-way-hash密码得到session key。 // Create a hash object.

if ( ! CryptCreateHash(hProv, CALG_MD5, 0, 0, &hHash)) {

dwError = GetLastError();

sprintf(buffer, "Error %x during CryptCreateHash", dwError);

return Error(buffer);

}

// Hash in the password.

if ( ! CryptHashData(hHash, pbPassword, SysStringLen(bstrPassword), 0)) {

dwError = GetLastError();

sprintf(buffer, "Error %x during CryptHashData", dwError);

return Error(buffer);

}

// Derive a session key from the hash object.

if ( ! CryptDeriveKey(hProv, ENCRYPT_ALGORITHM, hHash, 0, &hKey)) {

dwError = GetLastError();

sprintf(buffer, "Error %x during CryptDeriveKey", dwError);

return Error(buffer);

}

// Destroy hash object.

CryptDestroyHash(hHash);

hHash = 0;

现在来加密我们的数据。// Encrypt the Data.

dwCryptDataLen = dwDataLen;

if ( ! CryptEncrypt(hKey, 0, true, 0, pbData, &dwCryptDataLen, dwDataLen)) {

dwError = GetLastError();

sprintf(buffer, "Error %x during CryptEncrypt", dwError);

return Error(buffer);

}

我们将加密后的数据放入一个数组中,而不是一个string里,因为它可能会包含null。虽然 BSTR 能处理null的情况,但不能保证用户调用环境能正确处理,所以一个数组是最好的选择。// Place Encrypted Data into a VARIANT SAFEARRAY of VARIANT BYTE

SAFEARRAYBOUND rgsabound[] = {dwCryptDataLen, 0};

psa = SafeArrayCreate(VT_VARIANT, 1, rgsabound);

VARIANT* rgElems;

SafeArrayAccessData(psa, (LPVOID*)&rgElems);

for(DWORD i=0;i<dwCryptDataLen;i++){

VariantInit(&rgElems[i]);

rgElems[i].vt = VT_UI1;

rgElems[i].uiVal = pbData[i];

}

SafeArrayUnaccessData(psa);

VariantInit(vCipherText);

vCipherText->vt = (VT_ARRAY | VT_VARIANT) ;

vCipherText->parray = psa;

稍微整理一下,搞定。// Destroy session key.

if(hKey) CryptDestroyKey(hKey);

// Release provider handle.

if(hProv) CryptReleaseContext(hProv, 0);

return S_OK;

实现解密方法

首先定义变量。STDMETHODIMP CCrypto::Decrypt(VARIANT vCipherText,

BSTR bstrPassword,

BSTR *bstrPlainText)

{

HCRYPTPROV hProv = 0;

HCRYPTHASH hHash = 0;

HCRYPTKEY hKey = 0;

SAFEARRAY* psa;

VARIANT HUGEP *pVar;

BYTE *pbData;

BYTE *pbPassword;

long lBound, uBound;

DWORD dwCryptDataLen = 0;

DWORD dwOffset = 0;

DWORD dwError = 0;

char buffer[200];

USES_CONVERSION;

同样的原因,我们要调用RevertToSelf()RevertToSelf();

现在,当接收一个数组参数作为变量,该数组可能藏在结构中的某个地方,所以需要一个判断嵌套。//Get the safe array out of the Variant.

if (vCipherText.vt == (VT_VARIANT | VT_BYREF))

{

if (vCipherText.pvarVal->vt == (VT_ARRAY | VT_VARIANT))

SafeArrayCopy(vCipherText.pvarVal->parray, &psa);

else

{

if (vCipherText.pvarVal->vt == (VT_ARRAY | VT_VARIANT | VT_BYREF))

SafeArrayCopy(*(vCipherText.pvarVal->pparray), &psa);

}

}

else

{

if (vCipherText.vt == (VT_ARRAY | VT_VARIANT | VT_BYREF))

SafeArrayCopy(*(vCipherText.pparray), &psa);

else

{

if (vCipherText.vt == (VT_ARRAY | VT_VARIANT))

SafeArrayCopy(vCipherText.parray, &psa);

else

return DISP_E_TYPEMISMATCH;

}

}

需要密文和密码都是BYTE*类型。//Convert the SAFEARRAY into a form we can use.

SafeArrayAccessData(psa, (void HUGEP* FAR*)&pVar);

SafeArrayGetLBound(psa, 1, &lBound);

SafeArrayGetUBound(psa, 1, &uBound);

dwOffset = 0 - lBound;

dwCryptDataLen = uBound + dwOffset + 1;

//Allocate memory

pbData = (BYTE *)malloc(dwCryptDataLen);

//Copy the array

for(DWORD i = lBound; i <= uBound; i++){ if( ! (pVar[i].vt & VT_UI1)){ //Data Elements must be VT_UI1 (Bytes). free(pbData); return DISP_E_TYPEMISMATCH; } pbData[i + dwOffset]="pVar[i].uiVal;" } //Get Password pbPassword="(BYTE*)OLE2A(bstrPassword);</PRE">

取得 Crypto Provider 的句柄。// Get handle to the default provider.

if (! CryptAcquireContext(&hProv, "aspZoneCryptoComponent\0",

MS_DEF_PROV, PROV_RSA_FULL, CRYPT_MACHINE_KEYSET))

{

if (! CryptAcquireContext(&hProv, "aspZoneCryptoComponent\0",

MS_DEF_PROV, PROV_RSA_FULL, (CRYPT_NEWKEYSET | CRYPT_MACHINE_KEYSET)))

{

dwError = GetLastError();

sprintf(buffer, "Error %x during CryptAcquireContext", dwError);

return Error(buffer);

}

}

从 password 中得到 session key.// Create a hash object.

if ( ! CryptCreateHash(hProv, CALG_MD5, 0, 0, &hHash)) {

dwError = GetLastError();

sprintf(buffer, "Error %x during CryptCreateHash", dwError);

return Error(buffer);

}

// Hash in the password.

if ( ! CryptHashData(hHash, pbPassword, SysStringLen(bstrPassword), 0)) {

dwError = GetLastError();

sprintf(buffer, "Error %x during CryptHashData", dwError);

return Error(buffer);

}

// Derive a session key from the hash object.

if ( ! CryptDeriveKey(hProv, ENCRYPT_ALGORITHM, hHash, 0, &hKey)) {

dwError = GetLastError();

sprintf(buffer, "Error %x during CryptDeriveKey", dwError);

return Error(buffer);

}

// Destroy hash object.

CryptDestroyHash(hHash);

hHash = 0;

将密文解密到纯文本中。// Decrypt the Data.

if ( ! CryptDecrypt(hKey, 0, true, 0, pbData, &dwCryptDataLen)) {

dwError = GetLastError();

sprintf(buffer, "Error %x during CryptDecrypt", dwError);

return Error(buffer);

}

//Terminate the string with a null

pbData[dwCryptDataLen] = NULL;

设置返回值,大扫除,然后搞定。//Place Decrypted data into retval

*bstrPlainText = SysAllocString(A2OLE((const char *)pbData));

// Destroy session key.

if(hKey) CryptDestroyKey(hKey);

// Release provider handle.

if(hProv) CryptReleaseContext(hProv, 0);

return S_OK;

}

翻译:讨饭猫

Jan,10 2000

下载doc文档(带图):

http://64.13.189.254/cafecat/build a crypto component using Visual C++ and ATL .doc

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有