加解密数据组件

本文介绍如何利用Visual C++与ATL技术结合Microsoft Crypto API开发一个用于数据加解密的组件。该组件以DLL形式提供,并通过COM接口实现对外的数据加密和解密功能。
 
 
作者: 讨饭猫
 
  简介
这篇文章将教你如何使用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;
}
 
 
代码转载自:https://pan.quark.cn/s/a4b39357ea24 本文重点阐述了利用 LabVIEW 软件构建的锁相放大器的设计方案及其具体实施流程,并探讨了该设备在声波相位差定位系统中的实际运用情况。 锁相放大器作为一项基础测量技术,其核心功能在于能够精确锁定微弱信号的频率参数并完成相关测量工作。 在采用 LabVIEW 软件开发的锁相放大器系统中,通过计算测量信号与两条参考信号之间的互相关函数,实现对微弱信号的频率锁定,同时输出被测信号的幅值信息。 虚拟仪器技术是一种基于计算机硬件平台的仪器系统,其显著特征在于用户可以根据实际需求自主设计仪器功能,配备虚拟化操作界面,并将测试功能完全由专用软件程序实现。 虚拟仪器系统的基本架构主要由计算机主机、专用软件程序以及硬件接口模块等核心部件构成。 虚拟仪器最突出的优势在于其功能完全取决于软件编程,用户可以根据具体应用场景灵活调整系统功能参数。 在基于 LabVIEW 软件开发的锁相放大器系统中,主要运用 LabVIEW 软件平台完成锁相放大器功能的整体设计。 LabVIEW 作为一个图形化编程环境,能够高效地完成虚拟仪器的开发工作。 借助 LabVIEW 软件,可以快速构建锁相放大器的用户操作界面,并且可以根据实际需求进行灵活调整和功能扩展。 锁相放大器系统的关键构成要素包括测量信号输入通道、参考信号输入通道、频率锁定处理单元以及信号幅值输出单元。 测量信号是系统需要检测的对象,参考信号则用于引导系统完成对测量信号的频率锁定。 频率锁定处理单元负责实现测量信号的锁定功能,信号幅值输出单元则负责输出被测信号的幅值大小。 在锁相放大器的实际实现过程中,系统采用了双路参考信号输入方案来锁定测量信号。 通过分析两路参考信号之间的相...
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值