加解密数据组件

 
 
作者 : 讨饭猫
 
  简介
这篇文章将教你如何使用 Visual C++ 和ATL 工具和Microsoft CryptoAPI 建立一个能加/解密数据的组件。
Crypto 101
本文使用 Microsoft® Cryptographic Application Programming Interface (CryptoAPI),将苦涩难懂的逻辑算法操作隐藏起来,如果想知道详细信息请参看[url href=http://premium.microsoft.com/msdn/library/]MSDN Library[/url].如果想知道更多的密码系统,我推荐你看看这本书[url href=http://www.aspzone.com/books/bookRedir.asp?url=http://www.amazon.com/exec/obidos/ASIN/0471117099/aspzonecom]Bruce Schneiers Applied Cryptography: Protocols, Algorithms, and Source Code in C[/url]
 
建立组件
首先,用 "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", MS_DEF_PROV,
PROV_RSA_FULL, CRYPT_MACHINE_KEYSET))
{
if (! CryptAcquireContext(&hProv,
"aspZoneCryptoComponent", 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",
MS_DEF_PROV, PROV_RSA_FULL, CRYPT_MACHINE_KEYSET))
{
if (! CryptAcquireContext(&hProv, "aspZoneCryptoComponent",
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;
}
 
 
sm2加解密开源组件是指基于国密算法SM2设计的加密解密算法在开源社区中所开发的组件。SM2是中国自主研发的非对称加密算法,具有高安全性和高效率的特点。开源组件是指其源代码公开,可以自由访问、使用和修改的软件或工具。 sm2加解密开源组件在信息安全领域中起到了重要的作用。通过这些组件,开发者可以使用SM2算法对数据进行加密和解密操作,确保数据的保密性和完整性。SM2加密算法比RSA加密算法更适合用于国密标准的实施,同时拥有更高的性能。因此,sm2加解密开源组件在国内外的信息安全领域中具有广泛的应用。 开源组件的开发和维护通常由开源社区中的开发者共同完成。他们通过对SM2算法的深入研究和理解,开发出了相应的加解密组件,并将其源代码公开。这使得更多的开发者可以参与到组件的开发中来,共同改进组件的功能和性能,提高整体的安全性。 开源组件的优势在于可以增加代码的透明度和可信度。开放源代码可以让其他开发者审查组件的实现细节,发现潜在的漏洞和安全风险,从而进一步提高组件的安全性。此外,开源组件还可以促进学术研究和技术创新,使得SM2算法在更广泛的应用场景中得到使用。 总之,sm2加解密开源组件是基于国密算法SM2设计的加密解密算法在开源社区中开发的组件,其源代码公开,可以自由使用和修改。这些组件在信息安全领域中具有重要的作用,可以保护数据的安全和完整性,同时促进学术研究和技术创新。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值