欢迎光临
我们一直在努力

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

建站超值云服务器,限时71元/月

简介

这篇文章将教你如何使用 visual c++ 和 atl 工具和 microsoft cryptoapi 建立一个能加/解密数据的组件。

crypto 101

本文使用microsoft® cryptographic application programming interface (cryptoapi),将苦涩难懂的逻辑算法操作隐藏起来,如果想知道详细信息请参看msdn library.如果想知道更多的密码系统,我推荐你看看这本书 bruce schneiers 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

赞(0)
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com 特别注意:本站所有转载文章言论不代表本站观点! 本站所提供的图片等素材,版权归原作者所有,如需使用,请与原作者联系。未经允许不得转载:IDC资讯中心 » 使用 Visual C++创建Crypto加/解密组件
分享到: 更多 (0)