本文是 MS CryptoAPI Samples 的姐妹篇,演示如何使用微软的CAPICOM组件。CAPICOM组件是建立在CryptoAPI基础上的ActiveX控件,供JavaScript、VBScript以及其他非C/C++语言使用。使用该组件,极大简化加密、签名应用程序的编写,但功能略受限制。
// examCAPI.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <ATLComTime.h>
// 加载 CAPICOM 组件
#import "capicom.dll"
using namespace CAPICOM;
//=========================================================
// 工具方法
//=========================================================
// 暂停
void pause()
{
_tprintf(_T("\nPress ENTER key to continue \n"));
getchar();
}
// 错误报告
void CancelByError(HRESULT errCode, TCHAR* errStr)
{
_tprintf(_T("\nFAULT:\n"));
_tprintf(_T("An error occurred in running the program. \n"));
_tprintf(_T("%s \n"), errStr);
throw errCode;
}
// 字节反序
void reverse(BYTE* data, int nLen)
{
for(int ii=0; ii < nLen/2; ii++)
{
BYTE c = data[ii];
data[ii] = data[nLen -ii -1];
data[nLen -ii -1] = c;
}
}
// 输出文件
void writeFile(const char* sFileName, BYTE* data, DWORD nSize)
{
FILE* fp = fopen(sFileName, "wb");
if(fp == NULL)
{
CancelByError(0, _T("Open file for write failed!"));
}
if(fwrite(data, 1, nSize, fp) != nSize)
{
fclose(fp);
CancelByError(0, _T("Write to file failed!"));
}
fclose(fp);
printf("Write %d bytes to file '%s'! \n", nSize, sFileName);
}
// 读取文件(data = NULL for get file size ONLY)
void readFile(const char* sFileName, BYTE* data, DWORD & nSize)
{
nSize = 0;
FILE* fp = fopen(sFileName, "rb");
if(fp == NULL)
{
CancelByError(0, _T("Open file for read failed!"));
}
fseek(fp, 0, SEEK_END);
nSize = ftell(fp);
fseek(fp, 0, SEEK_SET);
if(data != NULL)
{
if(fread(data, 1, nSize, fp) != nSize)
{
fclose(fp);
CancelByError(0, _T("Read from file failed!"));
}
printf("Read %d bytes from file '%s'! \n", nSize, sFileName);
}
fclose(fp);
}
// 显示HEX码
void showData(BYTE* data, DWORD nSize)
{
printf("\n****\n");
for(DWORD ii=0; ii < nSize; ii++)
{
printf("%02x ", data[ii]);
if((ii+1) % 16 ==0) printf("\n");
}
printf("\n**** %d bytes\n", nSize);
}
// 准备数据(Auto new outData)
void prepareData(BYTE* inData, DWORD inSize, LPCSTR inFileName, BYTE* &outData, DWORD& outSize)
{
if(inData == NULL && inFileName != NULL)
{
// Read from file
readFile(inFileName, NULL, outSize);
if(outSize != 0)
{
outData = (BYTE*) new char[outSize +1];
memset(outData, 0, outSize +1);
if(outData == NULL) CancelByError(0, _T("Not enough memory. \n"));
readFile(inFileName, outData, outSize);
}
}
else
{
// Read from buffer
outSize = inSize;
outData = (BYTE*) new char[outSize];
if(outData == NULL) CancelByError(0, _T("Not enough memory. \n"));
memcpy(outData, inData, outSize);
}
}
// 获取BSTR的长度及字节值
void getBSTRByte(BSTR& bstr, BYTE* (&data), DWORD& nSize)
{
data = (BYTE*) bstr;
nSize = *((DWORD*)bstr - 1);
}
//=========================================================
// 编码与解码
//=========================================================
// BASE64编码
void Base64Encode(BYTE* inData, int inSize, LPCSTR inFileName = NULL, LPCSTR outFileName = NULL)
{
// 准备原始数据
DWORD cbOrgData = 0;
BYTE* pbOrgData = NULL;
prepareData(inData, inSize, inFileName, pbOrgData, cbOrgData);
// 注意:
// 原始数据是二进制值,应使用原值,以避免转换为宽字符串参数时导致失真。
// SysAllocStringByteLen 会禁用多字节到宽字节的转换,因而可以保证内容无损地转换为宽字符串。
_bstr_t orgStr;
BSTR orgBStr = SysAllocStringByteLen((LPCSTR)pbOrgData, cbOrgData);
orgStr.Assign(orgBStr);
SysFreeString(orgBStr);
if(pbOrgData != NULL) delete [] pbOrgData;
// 创建 Utilities 对象
IUtilitiesPtr pUtils(__uuidof(Utilities));
try
{
// 编码
_bstr_t encStr = pUtils->Base64Encode(orgStr);
// 输出
// 注意:编码输出转换为多字节不会导致失真,直接转换。
char* pEncStr = encStr;
printf("[%s]\n", pEncStr);
if(outFileName != NULL)
{
writeFile(outFileName, (BYTE*)pEncStr, strlen(pEncStr));
}
}
catch(_com_error e)
{
// 转换宽字符错误信息为多字节错误信息串
_bstr_t strErrMesg(e.ErrorMessage());
printf("[%#x]:COM:%s.\n", e.Error(), (char*)strErrMesg);
}
catch (HRESULT errCode)
{
_tprintf(_T("[%#x]:CAPICOM error. \n"), errCode);
}
catch()
{
_tprintf(_T("Unknown error. \n"));
}
// 清理
pUtils.Release();
}
// BASE64解码
void Base64Decode(BYTE* inData, int inSize, LPCSTR inFileName = NULL, LPCSTR outFileName = NULL)
{
// 准备编码数据
DWORD cbEncData = 0;
BYTE* pbEncData = NULL;
prepareData(inData, inSize, inFileName, pbEncData, cbEncData);
// 创建 Utilities 对象
IUtilitiesPtr pUtils(__uuidof(Utilities));
try
{
// 解码
// 注意:编码数据转换为宽字符参数不会导致失真,因此直接转换。
_bstr_t orgStr = pUtils->Base64Decode((char*)pbEncData);
// 从解码输出的宽字符串中获取原始数据
DWORD cbOrgData = 0;
BYTE* pbOrgData = NULL;
getBSTRByte(orgStr.GetBSTR(), pbOrgData, cbOrgData);
// 输出
showData(pbOrgData, cbOrgData);
if(outFileName != NULL)
{
writeFile(outFileName, pbOrgData, cbOrgData);
}
}
catch(_com_error e)
{
// 转换宽字符错误信息为多字节错误信息串
_bstr_t strErrMesg(e.ErrorMessage());
printf("[%#x]:COM:%s.\n", e.Error(), (char*)strErrMesg);
}
catch (HRESULT errCode)
{
_tprintf(_T("[%#x]:CAPICOM error. \n"), errCode);
}
catch()
{
_tprintf(_T("Unknown error. \n"));
}
// 清理
if(pbEncData != NULL) delete [] pbEncData;
pUtils.Release();
}
//=========================================================
// 数字摘要
//=========================================================
// SHA1
void hashSHA1(BYTE* inData, int inSize, LPCSTR inFileName = NULL, LPCSTR outFileName = NULL)
{
// 准备原始数据
DWORD cbOrgData = 0;
BYTE* pbOrgData = NULL;
prepareData(inData, inSize, inFileName, pbOrgData, cbOrgData);
_bstr_t orgStr;
BSTR orgBStr = SysAllocStringByteLen((LPCSTR)pbOrgData, cbOrgData);
orgStr.Assign(orgBStr);
SysFreeString(orgBStr);
if(pbOrgData != NULL) delete [] pbOrgData;
// 创建 HashData 对象
IHashedDataPtr pHash(__uuidof(HashedData));
try
{
// 计算数字摘要
pHash->Algorithm = CAPICOM_HASH_ALGORITHM_SHA1;
pHash->Hash(orgStr);
_bstr_t outStr = pHash->Value;
const char* encStr = (char*) outStr;
printf("%s\n", encStr);
if(outFileName != NULL)
{
writeFile(outFileName, (BYTE*)encStr, strlen(encStr));
}
}
catch(_com_error e)
{
// 转换宽字符错误信息为多字节错误信息串
_bstr_t strErrMesg(e.ErrorMessage());
printf("[%#x]:COM:%s.\n", e.Error(), (char*)strErrMesg);
}
catch (HRESULT hr)
{
_tprintf(_T("[%#x]:CAPICOM error. \n"), hr);
}
catch()
{
_tprintf(_T("Unknown error. \n"));
}
// 清理
pHash.Release();
}
//===============================================================
// 对称加密
// CAPICOM 加密使用非PKCS#7标准的格式,只能使用 CAPICOM 解密。
//===============================================================
// DES 加密
void DESEncrypt(BYTE* key, BYTE* inData, int inSize, LPCSTR inFileName = NULL, LPCSTR outFileName = NULL)
{
// 准备原始数据
DWORD cbOrgData = 0;
BYTE* pbOrgData = NULL;
prepareData(inData, inSize, inFileName, pbOrgData, cbOrgData);
// 转换为宽字符串参数
_bstr_t orgStr;
BSTR orgBStr = SysAllocStringByteLen((LPCSTR)pbOrgData, cbOrgData);
orgStr.Assign(orgBStr);
SysFreeString(orgBStr);
if(pbOrgData != NULL) delete [] pbOrgData;
// 创建加密对象
IEncryptedDataPtr pEncryptedData(__uuidof(EncryptedData));
try
{
// 加密
pEncryptedData->Content = orgStr;
pEncryptedData->SetSecret((char*)key, CAPICOM_SECRET_PASSWORD);
pEncryptedData->Algorithm->Name = CAPICOM::CAPICOM_ENCRYPTION_ALGORITHM_DES;
_bstr_t encStr = pEncryptedData->Encrypt(CAPICOM_ENCODE_BASE64);
// 输出加密结果
char* pEncStr = encStr;
printf("%s", pEncStr);
if(outFileName != NULL)
{
writeFile(outFileName, (BYTE*) pEncStr, strlen(pEncStr));
}
}
catch(_com_error e)
{
_bstr_t strErrMesg(e.ErrorMessage());
printf("[%#x]:COM:%s.\n", e.Error(), (char*)strErrMesg);
}
catch (HRESULT retCode)
{
_tprintf(_T("[%#x]:CAPICOM error. \n"), retCode);
}
catch()
{
_tprintf(_T("Unknown error. \n"));
}
// 清理
pEncryptedData.Release();
}
// DES 解密
void DESDecrypt(BYTE* key, BYTE* inData, int inSize, LPCSTR inFileName = NULL, LPCSTR outFileName = NULL)
{
// 准备数据
DWORD cbEncData = 0;
BYTE* pbEncData = NULL;
prepareData(inData, inSize, inFileName, pbEncData, cbEncData);
// 创建加密对象
IEncryptedDataPtr pEncryptedData(__uuidof(EncryptedData));
try
{
// 解密
pEncryptedData->SetSecret((char*)key, CAPICOM_SECRET_PASSWORD);
pEncryptedData->Algorithm->Name = CAPICOM::CAPICOM_ENCRYPTION_ALGORITHM_DES;
pEncryptedData->Decrypt((char*)pbEncData);
// 获取原始数据
_bstr_t orgStr = pEncryptedData->Content;
BYTE* orgData = NULL;
DWORD orgSize = 0;
getBSTRByte(orgStr.GetBSTR(), orgData, orgSize);
showData(orgData, orgSize);
if(outFileName != NULL)
{
writeFile(outFileName, orgData, orgSize);
}
}
catch(_com_error e)
{
_bstr_t strErrMesg(e.ErrorMessage());
printf("[%#x]:COM:%s.\n", e.Error(), (char*)strErrMesg);
}
catch (HRESULT errCode)
{
_tprintf(_T("[%#x]:CAPICOM error. \n"), errCode);
}
catch()
{
_tprintf(_T("Unknown error. \n"));
}
// 清理
if(pbEncData != NULL) delete [] pbEncData;
pEncryptedData.Release();
}
// DES 加密(bin)
void DESEncryptBin(BYTE* key, BYTE* inData, int inSize, LPCSTR inFileName = NULL, LPCSTR outFileName = NULL)
{
// 准备原始数据
DWORD cbOrgData = 0;
BYTE* pbOrgData = NULL;
prepareData(inData, inSize, inFileName, pbOrgData, cbOrgData);
// 转换为宽字符参数
_bstr_t orgStr;
BSTR orgBStr = SysAllocStringByteLen((LPCSTR)pbOrgData, cbOrgData);
orgStr.Assign(orgBStr);
SysFreeString(orgBStr);
if(pbOrgData != NULL) delete [] pbOrgData;
// 创建加密对象
IEncryptedDataPtr pEncryptedData(__uuidof(EncryptedData));
try
{
// 加密
pEncryptedData->Content = orgStr;
pEncryptedData->SetSecret((char*)key, CAPICOM_SECRET_PASSWORD);
pEncryptedData->Algorithm->Name = CAPICOM::CAPICOM_ENCRYPTION_ALGORITHM_DES;
_bstr_t encStr = pEncryptedData->Encrypt(CAPICOM_ENCODE_BINARY);
// 获取加密数据
DWORD cbEncData = 0;
BYTE* pbEncData = NULL;
getBSTRByte(encStr.GetBSTR(), pbEncData, cbEncData);
// 输出
showData(pbEncData, cbEncData);
if(outFileName != NULL)
{
writeFile(outFileName, pbEncData, cbEncData);
}
}
catch(_com_error e)
{
_bstr_t strErrMesg(e.ErrorMessage());
printf("[%#x]:COM:%s.\n", e.Error(), (char*)strErrMesg);
}
catch (HRESULT retCode)
{
_tprintf(_T("[%#x]:CAPICOM error. \n"), retCode);
}
catch()
{
_tprintf(_T("Unknown error. \n"));
}
// 清理
pEncryptedData.Release();
}
// DES 解密(bin)
void DESDecryptBin(BYTE* key, BYTE* inData, int inSize, LPCSTR inFileName = NULL, LPCSTR outFileName = NULL)
{
// 准备数据
DWORD cbEncData = 0;
BYTE* pbEncData = NULL;
prepareData(inData, inSize, inFileName, pbEncData, cbEncData);
// 转换为宽字符参数
_bstr_t encStr;
BSTR encBStr = SysAllocStringByteLen((LPCSTR)pbEncData, cbEncData);
encStr.Assign(encBStr);
SysFreeString(encBStr);
if(pbEncData != NULL) delete [] pbEncData;
// 创建加密对象
IEncryptedDataPtr pEncryptedData(__uuidof(EncryptedData));
try
{
// 解密
pEncryptedData->SetSecret((char*)key, CAPICOM_SECRET_PASSWORD);
pEncryptedData->Algorithm->Name = CAPICOM::CAPICOM_ENCRYPTION_ALGORITHM_DES;
pEncryptedData->Decrypt(encStr);
// 获取原始数据
_bstr_t orgStr = pEncryptedData->Content;
BYTE* orgData = NULL;
DWORD orgSize = 0;
getBSTRByte(orgStr.GetBSTR(), orgData, orgSize);
showData(orgData, orgSize);
if(outFileName != NULL)
{
writeFile(outFileName, orgData, orgSize);
}
}
catch(_com_error e)
{
_bstr_t strErrMesg(e.ErrorMessage());
printf("[%#x]:COM:%s.\n", e.Error(), (char*)strErrMesg);
}
catch (HRESULT errCode)
{
_tprintf(_T("[%#x]:CAPICOM error. \n"), errCode);
}
catch()
{
_tprintf(_T("Unknown error. \n"));
}
// 清理
pEncryptedData.Release();
}
//=========================================================
// 数字证书
//=========================================================
// 显式证书信息
void viewCertInfo(ICertificatePtr pCert)
{
COleDateTime timeFrom(pCert->ValidFromDate);
COleDateTime timeTo(pCert->ValidToDate);
_tprintf(_T(" Subject: %s\n"), pCert->SubjectName.GetBSTR());
_tprintf(_T(" SubjectCN: %s\n"), pCert->GetInfo(CAPICOM_CERT_INFO_SUBJECT_SIMPLE_NAME).GetBSTR());
_tprintf(_T(" Issuser: %s\n"), pCert->IssuerName.GetBSTR());
_tprintf(_T("SerialNumber: %s\n"), pCert->SerialNumber.GetBSTR());
_tprintf(_T(" ValidDate: %s TO %s \n"), timeFrom.Format(L"%Y-%m-%d %H:%M:%S"), timeTo.Format(L"%Y-%m-%d %H:%M:%S"));
// Check Certificate
ICertificateStatusPtr pStatus = pCert->IsValid();
pStatus->CheckFlag = CAPICOM_CHECK_TIME_VALIDITY;
_tprintf(_T(" Check-Time: %s\n"), (pStatus->Result) ? L"Yes" : L"NO");
pStatus->CheckFlag = CAPICOM_CHECK_SIGNATURE_VALIDITY;
_tprintf(_T(" Check-Sign: %s\n"), (pStatus->Result) ? L"Yes" : L"NO");
pStatus->CheckFlag = CAPICOM_CHECK_TRUSTED_ROOT;
_tprintf(_T(" Check-CA: %s\n"), (pStatus->Result) ? L"Yes" : L"NO");
pStatus->CheckFlag = CAPICOM_CHECK_COMPLETE_CHAIN;
_tprintf(_T(" Check-Chain: %s\n"), (pStatus->Result) ? L"Yes" : L"NO");
}
// 系统证书库
void viewSystemCertStore(LPCTSTR sCertName)
{
// 创建证书库对象
IStorePtr pStore(__uuidof(Store));
try
{
HRESULT retCode = pStore->Open(CAPICOM_CURRENT_USER_STORE, sCertName, CAPICOM_STORE_OPEN_READ_ONLY);
if(FAILED(retCode))
{
CancelByError(retCode, _T("Can not open certStore! "));
}
ICertificatesPtr pCerts = pStore->GetCertificates();
if(pCerts != NULL)
{
_tprintf(_T("======== L I S T C E R T I N S T O R E ============\n"));
for(int ii=0; ii<pCerts->Count; ii++)
{
_variant_t p = pCerts->GetItem(ii+1);
ICertificatePtr pCert = p.pdispVal;
if(pCert != NULL)
{
viewCertInfo(pCert);
_tprintf(_T("----------------------------------------------------\n"));
}
}
_tprintf(_T("======== %d Certs ============\n"), pCerts->Count);
}
}
catch(_com_error e)
{
_bstr_t strErrMesg(e.ErrorMessage());
printf("[%#x]:COM:%s.\n", e.Error(), (char*)strErrMesg);
}
catch (HRESULT errCode)
{
_tprintf(_T("[%#x]:CAPICOM error. \n"), errCode);
}
catch()
{
_tprintf(_T("Unknown error. \n"));
}
// 清理
pStore.Release();
}
// 文件证书库(crt/p7b)
void viewCrtCertStore(LPCSTR strCertFileName)
{
IStore2Ptr pStore(__uuidof(Store));
try
{
// 访问证书库
HRESULT retCode = pStore->Open(CAPICOM_MEMORY_STORE, strCertFileName, CAPICOM_STORE_OPEN_READ_WRITE);
if(FAILED(retCode))
{
CancelByError(retCode, _T("Can not open memory certStore! "));
}
// 加载证书文件到证书库
retCode = pStore->Load((char*)strCertFileName, "", CAPICOM_KEY_STORAGE_DEFAULT);
if(FAILED(retCode))
{
CancelByError(retCode, _T("Can not load certFile! "));
}
// 列出证书
ICertificatesPtr pCerts = pStore->GetCertificates();
if(pCerts != NULL)
{
_tprintf(_T("======== L I S T C E R T I N S T O R E ============\n"));
for(int ii=0; ii<pCerts->Count; ii++)
{
_variant_t p = pCerts->GetItem(ii+1);
ICertificatePtr pCert = p.pdispVal;
if(pCert != NULL)
{
viewCertInfo(pCert);
_tprintf(_T("----------------------------------------------------\n"));
}
}
_tprintf(_T("======== %d Certs ============\n"), pCerts->Count);
}
}
catch(_com_error e)
{
_bstr_t strErrMesg(e.ErrorMessage());
printf("[%#x]:COM:%s.\n", e.Error(), (char*)strErrMesg);
}
catch (HRESULT errCode)
{
_tprintf(_T("[%#x]:CAPICOM error. \n"), errCode);
}
catch()
{
_tprintf(_T("Unknown error. \n"));
}
// 清理
pStore.Release();
}
// 文件证书库(pfx)
void viewPfxCertStore(LPCSTR sPfxFileName, LPCSTR sPfxPwd)
{
// 创建证书对象
ICertificate2Ptr pCert(__uuidof(Certificate));
try
{
HRESULT retCode = pCert->Load(sPfxFileName, sPfxPwd, CAPICOM_KEY_STORAGE_DEFAULT, CAPICOM_CURRENT_USER_KEY);
if(FAILED(retCode))
{
CancelByError(retCode, _T("Can not open certStore! "));
}
viewCertInfo(pCert);
}
catch(_com_error e)
{
_bstr_t strErrMesg(e.ErrorMessage());
printf("[%#x]:COM:%s.\n", e.Error(), (char*)strErrMesg);
}
catch (HRESULT errCode)
{
_tprintf(_T("[%#x]:CAPICOM error. \n"), errCode);
}
catch()
{
_tprintf(_T("Unknown error. \n"));
}
// 清理
pCert.Release();
}
//=========================================================
// 数字签名
//=========================================================
// 数字签名
void callSignedData(BYTE* inData, int inSize, LPCSTR inFileName = NULL, BOOL bDetached = FALSE, LPCSTR outFileName = NULL)
{
// 准备原始数据
DWORD cbOrgData = 0;
BYTE* pbOrgData = NULL;
prepareData(inData, inSize, inFileName, pbOrgData, cbOrgData);
_bstr_t orgStr;
BSTR orgBStr = SysAllocStringByteLen((LPCSTR)pbOrgData, cbOrgData);
orgStr.Assign(orgBStr);
if(pbOrgData != NULL) delete [] pbOrgData;
SysFreeString(orgBStr);
// 创建对象
IStorePtr pStore(__uuidof(Store)); // 证书库对象
ISignerPtr pSigner(__uuidof(Signer)); // 签名者对象
ISignedDataPtr pSignedData(__uuidof(SignedData)); // 签名数据对象
try
{
// 设置原始数据
pSignedData->Content = orgStr;
// 访问证书库
HRESULT retCode = pStore->Open(CAPICOM_CURRENT_USER_STORE, CAPICOM_MY_STORE, CAPICOM_STORE_OPEN_READ_ONLY);
if(FAILED(retCode))
{
CancelByError(retCode, _T("Can not open certStore! "));
}
// 设置签名者证书
ICertificates2Ptr pSignerCerts = ((ICertificates2Ptr) pStore->Certificates)->Find(CAPICOM_CERTIFICATE_FIND_SUBJECT_NAME, L"lny", FALSE);
if(pSignerCerts == NULL || pSignerCerts->Count < 1)
{
CancelByError(0, _T("Can not find signer certificate! "));
}
pSigner->Certificate = (ICertificatePtr) pSignerCerts->GetItem(1).pdispVal;
viewCertInfo(pSigner->Certificate);
// 签名者签名
_bstr_t strSignedStr = pSignedData->Sign(pSigner, bDetached, CAPICOM_ENCODE_BASE64);
/**//* =============== 多签名者签名 ========================================
ISignerPtr pCoSigner(__uuidof(Signer)); // 协助签名者对象
// 设置协助签名者证书
ICertificates2Ptr pCoSignerCerts = ((ICertificates2Ptr) pStore->Certificates)->Find(CAPICOM_CERTIFICATE_FIND_SUBJECT_NAME, L"041@3BNKICNSZXXX@test9@00000001", FALSE);
if(pCoSignerCerts == NULL || pCoSignerCerts->Count < 1)
{
CancelByError(0, _T("Can not find CoSigner certificate! "));
}
pCoSigner->Certificate = (ICertificatePtr) pCoSignerCerts->GetItem(1).pdispVal;
viewCertInfo(pCoSigner->Certificate);
// 协助签名者签名
strSignedStr = pSignedData->CoSign(pCoSigner, CAPICOM_ENCODE_BASE64);
========================================================================= */
// 输出
_tprintf(_T("%s\n"), strSignedStr.GetBSTR());
char* pOutStr = strSignedStr;
if(outFileName != NULL)
{
writeFile(outFileName, (BYTE*)pOutStr, strlen((char*)pOutStr));
}
}
catch(_com_error e)
{
_bstr_t strErrMesg(e.ErrorMessage());
printf("[%#x]:COM:%s.\n", e.Error(), (char*)strErrMesg);
}
catch (HRESULT errCode)
{
_tprintf(_T("[%#x]:CAPICOM error. \n"), errCode);
}
catch()
{
_tprintf(_T("Unknown error. \n"));
}
// 清理
pStore.Release();
pSigner.Release();
pSignedData.Release();
}
// 核验带原文的数字签名
void VerifySignedData(LPCSTR inFileName)
{
// 准备签名数据
DWORD cbSigData = 0;
BYTE* pbSigData = NULL;
prepareData(NULL, 0, inFileName, pbSigData, cbSigData);
// 创建签名数据对象
ISignedDataPtr pSignedData(__uuidof(SignedData));
try
{
// 校验数字签名
HRESULT retCode = pSignedData->Verify((char*)pbSigData, FALSE, CAPICOM_VERIFY_SIGNATURE_ONLY);
if(FAILED(retCode))
{
CancelByError(retCode, _T("校验数字签名失败!"));
}
// 获取原文
BYTE* orgStr = NULL;
DWORD orgSize = 0;
getBSTRByte(pSignedData->Content.GetBSTR(), orgStr, orgSize);
printf("%s\n", orgStr);
// 显式签名者证书信息
_tprintf(_T("======== L I S T C E R T I N S T O R E ============\n"));
for(int ii=0; ii<pSignedData->Certificates->Count; ii++)
{
viewCertInfo(pSignedData->Certificates->GetItem(ii+1));
_tprintf(_T("----------------------------------------------------\n"));
}
_tprintf(_T("======== %d Certs ============\n"), pSignedData->Certificates->Count);
}
catch(_com_error e)
{
_bstr_t strErrMesg(e.ErrorMessage());
printf("[%#x]:COM:%s.\n", e.Error(), (char*)strErrMesg);
}
catch (HRESULT errCode)
{
_tprintf(_T("[%#x]:CAPICOM error. \n"), errCode);
}
catch()
{
_tprintf(_T("Unknown error. \n"));
}
// 清理
if(pbSigData != NULL) delete [] pbSigData;
pSignedData.Release();
}
// 核验无原文的数字签名
void VerifyDetachedSignedData(BYTE* inData, int inSize, LPCSTR inFileName, LPCSTR outFileName)
{
// 准备原始数据
DWORD cbOrgData = 0;
BYTE* pbOrgData = NULL;
prepareData(inData, inSize, inFileName, pbOrgData, cbOrgData);
BSTR orgBStr = SysAllocStringByteLen((LPCSTR)pbOrgData, cbOrgData);
// 准备签名数据
DWORD cbSigData = 0;
BYTE* pbSigData = NULL;
prepareData(NULL, 0, outFileName, pbSigData, cbSigData);
// 创建签名者对象
ISignerPtr pSigner(__uuidof(Signer));
// 创建签名数据对象
ISignedDataPtr pSignedData(__uuidof(SignedData));
try
{
// 设置原始数据
_bstr_t inStr;
inStr.Assign(orgBStr);
pSignedData->Content = inStr;
// 校验数字签名
HRESULT retCode = pSignedData->Verify((char*)pbSigData, TRUE, CAPICOM_VERIFY_SIGNATURE_ONLY);
if(FAILED(retCode))
{
CancelByError(retCode, _T("校验数字签名失败!"));
}
// 显式签名者证书信息
_tprintf(_T("======== L I S T C E R T I N S T O R E ============\n"));
for(int ii=0; ii<pSignedData->Certificates->Count; ii++)
{
viewCertInfo(pSignedData->Certificates->GetItem(ii+1));
_tprintf(_T("----------------------------------------------------\n"));
}
_tprintf(_T("======== %d Certs ============\n"), pSignedData->Certificates->Count);
}
catch(_com_error e)
{
// 转换宽字符错误信息为多字节错误信息串
_bstr_t strErrMesg(e.ErrorMessage());
printf("[%#x]:COM:%s.\n", e.Error(), (char*)strErrMesg);
}
catch (HRESULT errCode)
{
_tprintf(_T("[%#x]:CAPICOM error. \n"), errCode);
}
catch()
{
_tprintf(_T("Unknown error. \n"));
}
// 清理
if(pbOrgData != NULL) delete [] pbOrgData;
if(pbSigData != NULL) delete [] pbSigData;
SysFreeString(orgBStr);
pSigner.Release();
pSignedData.Release();
}
//=========================================================
// 数字信封(证书加密与解密)
//=========================================================
// 证书加密
void CertEncryptData(BYTE* inData, int inSize, LPCSTR inFileName, LPCSTR outFileName)
{
// 准备原始数据
DWORD cbOrgData = 0;
BYTE* pbOrgData = NULL;
prepareData(inData, inSize, inFileName, pbOrgData, cbOrgData);
BSTR orgBStr = SysAllocStringByteLen((LPCSTR)pbOrgData, cbOrgData);
// 创建证书库对象
IStorePtr pStore(__uuidof(Store));
// 创建签名数据对象
IEnvelopedDataPtr pEnvelopedData(__uuidof(EnvelopedData));
try
{
// 设置原始数据
_bstr_t inStr;
inStr.Assign(orgBStr);
pEnvelopedData->Content = inStr;
// 设置加密算法
pEnvelopedData->Algorithm->Name = CAPICOM_ENCRYPTION_ALGORITHM_3DES;
pEnvelopedData->Algorithm->KeyLength = CAPICOM_ENCRYPTION_KEY_LENGTH_MAXIMUM;
// 设置接收者证书(公钥)
// 1.访问证书库
HRESULT retCode = pStore->Open(CAPICOM_CURRENT_USER_STORE, CAPICOM_MY_STORE, CAPICOM_STORE_OPEN_READ_ONLY);
if(FAILED(retCode))
{
CancelByError(retCode, _T("Can not open certStore! "));
}
// 2.获取接收者证书
ICertificates2Ptr pReceiverCerts = ((ICertificates2Ptr) pStore->Certificates)->Find(CAPICOM_CERTIFICATE_FIND_SUBJECT_NAME, L"lny", FALSE);
if(pReceiverCerts == NULL || pReceiverCerts->Count < 1)
{
CancelByError(0, _T("Can not find receiver certificate! "));
}
pEnvelopedData->Recipients->Add((ICertificatePtr) pReceiverCerts->GetItem(1).pdispVal);
// 证书加密
_bstr_t strCryptedStr = pEnvelopedData->Encrypt(CAPICOM_ENCODE_BINARY);
// 获取密文数据
BSTR encBStr = strCryptedStr.GetBSTR();
BYTE* encStr = NULL;
DWORD encSize = 0;
getBSTRByte(encBStr, encStr, encSize);
SysFreeString(encBStr);
// 输出
showData(encStr, encSize);
if(outFileName != NULL)
{
writeFile(outFileName, encStr, encSize);
}
}
catch(_com_error e)
{
// 转换宽字符错误信息为多字节错误信息串
_bstr_t strErrMesg(e.ErrorMessage());
printf("[%#x]:COM:%s.\n", e.Error(), (char*)strErrMesg);
}
catch (HRESULT errCode)
{
_tprintf(_T("[%#x]:CAPICOM error. \n"), errCode);
}
catch()
{
_tprintf(_T("Unknown error. \n"));
}
// 清理
if(pbOrgData != NULL) delete [] pbOrgData;
SysFreeString(orgBStr);
pStore.Release();
pEnvelopedData.Release();
}
// 证书解密
void CertDecryptData(LPCSTR inFileName, LPCSTR outFileName)
{
// 准备原始数据
DWORD cbOrgData = 0;
BYTE* pbOrgData = NULL;
prepareData(NULL, 0, inFileName, pbOrgData, cbOrgData);
// 创建签名数据对象
IEnvelopedDataPtr pEnvelopedData(__uuidof(EnvelopedData));
try
{
// 证书解密
HRESULT retCode = pEnvelopedData->Decrypt((char*)pbOrgData);
if(FAILED(retCode))
{
CancelByError(retCode, _T("Can not decrypt data! "));
}
// 获取原文数据
BSTR orgBStr = pEnvelopedData->Content.GetBSTR();
BYTE* orgStr = NULL;
DWORD orgSize = 0;
getBSTRByte(orgBStr, orgStr, orgSize);
SysFreeString(orgBStr);
// 输出
showData(orgStr, orgSize);
if(outFileName != NULL)
{
writeFile(outFileName, orgStr, orgSize);
}
}
catch(_com_error e)
{
// 转换宽字符错误信息为多字节错误信息串
_bstr_t strErrMesg(e.ErrorMessage());
printf("[%#x]:COM:%s.\n", e.Error(), (char*)strErrMesg);
}
catch (HRESULT errCode)
{
_tprintf(_T("[%#x]:CAPICOM error. \n"), errCode);
}
catch()
{
_tprintf(_T("Unknown error. \n"));
}
// 清理
if(pbOrgData != NULL) delete [] pbOrgData;
pEnvelopedData.Release();
}
int _tmain(int argc, _TCHAR* argv[])
{
CoInitialize(0);
// BASE64
// Base64Encode((BYTE*)"123456789012345678", 15, NULL, "c:\\li.base64");
// Base64Decode(NULL, 0, "c:\\li.base64", "c:\\li.org");
// HASH
// hashSHA1((BYTE*)"1234567890", 10, NULL, "c:\\li.sha1");
// hashSHA1(NULL, 0, "c:\\li.txt", "c:\\li.sha1");
// Encrypt & Decrypt
// DESEncrypt((BYTE*)"12345678", (BYTE*)"1234567890\x00 12345", 15, NULL, "c:\\li.des");
// DESDecrypt((BYTE*)"12345678", NULL, 0, "c:\\li.des", "c:\\1.org");
// DESEncryptBin((BYTE*)"12345678", (BYTE*)"123456789012345", 15, NULL, "c:\\li.des");
// DESDecryptBin((BYTE*)"12345678", NULL, 0, "c:\\li.des", "c:\\1.org");
// CertStore & Cert
// viewSystemCertStore(L"MY"); // CAPICOM_MY_STORE
// viewSystemCertStore(L"CA"); // CAPICOM_CA_STORE
// viewSystemCertStore(L"ROOT"); // CAPICOM_ROOT_STORE
// viewSystemCertStore(L"AddressBook"); // CAPICOM_OTHER_STORE
// viewCrtCertStore("c:\\cfcaT.p7b");
// viewCrtCertStore("c:\\ca\\certs\\lny.crt");
// viewPfxCertStore("c:\\ca\\lny.pfx", "welcome2008");
// TACHED SignData
// callSignedData((BYTE*)"123456789012345", 15, NULL, FALSE, "c:\\li.tch.sig");
// VerifySignedData("c:\\li.tch.sig");
// DETACHED SignData
// callSignedData((BYTE*)"1234567890", 10, NULL, TRUE, "c:\\li.detch.sig");
// VerifyDetachedSignedData((BYTE*) "1234567890", 10, NULL, "c:\\li.detch.sig");
// Cert Encrypt & Decrypt
// CertEncryptData((BYTE*)"1234567890", 10, NULL, "c:\\li.enc");
// CertDecryptData("c:\\li.enc", "c:\\li.org");
CoUninitialize();
pause();
return 0;
}
/** *//**================================================================================
About BSTR
BSTR是"Basic STRing"的简称,是微软在COM/OLE中定义的标准字符串数据类型。
定义在wtypes.h文件中:
typedef wchar_t WCHAR;
typedef WCHAR OLECHAR;
typedef OLECHAR __RPC_FAR * BSTR;
COM字符(wchar_t)使用16bit,因此可以支持各种code pages,包括Unicode。
Windows系统可以简单理解为OLECHAR使用的就是Unicode 。
OLECHAR串与单字节字符串很类似,是一个以NULL(\x0\x0)结尾的buffer。
使用以NULL结尾字符串在COM component间传递不太方便,
因此,标准的BSTR是一个有长度前缀和NULL结束符的OLECHAR数组。
BSTR的前4字节是一个表示字符串长度的前缀,其值是不含NULL的字符串字节数。
BSTR和OLECHAR的交换可以使用COM提供了两个BSTR分配用的API:
SysAllocString / SysReallocString。
函数返回的指针指向BSTR的第一个字符,而不是BSTR在内存的第一个字节,即去掉前缀。
使用BSTR一定要注意释放该对象。SysFreeString()
_bstr_t是C++对BSTR的封装,VC中是为了兼容BSTR类型而增加的,也为实现LPCSTR与BSTR转换。
==================================================
BSTR转换成char*
方法一,使用ConvertBSTRToString。
#pragma comment(lib, 'comsupp.lib')
BSTR bstrText = ::SysAllocString(L"Test");
char* p = _com_util::ConvertBSTRToString(bstrText);
SysFreeString(bstrText); // 用完释放
delete[] lpszText2;
方法二,使用_bstr_t的赋值运算符重载。
_bstr_t b = bstrText;
char* lpszText2 = b;
-------------------------
char*转换成BSTR
方法一,使用SysAllocString等API函数。
BSTR bstrText = ::SysAllocString(L'Test');
BSTR bstrText = ::SysAllocStringLen(L'Test',4);
BSTR bstrText = ::SysAllocStringByteLen('Test',4);
方法二,使用COleVariant或_variant_t。
COleVariant strVar('This is a test');
_variant_t strVar('This is a test');
BSTR bstrText = strVar.bstrVal;
方法三,使用_bstr_t,这是一种最简单的方法。
BSTR bstrText = _bstr_t('This is a test');
方法四,使用CComBSTR。例如:
BSTR bstrText = CComBSTR('This is a test');
或
CComBSTR bstr('This is a test');
BSTR bstrText = bstr.m_str;
方法五,使用ConvertStringToBSTR。例如:
char* lpszText = 'Test';
BSTR bstrText = _com_util::ConvertStringToBSTR(lpszText);
===================================================================================**/
posted on 2009-08-19 10:10
飞鹰 阅读(2058)
评论(2) 编辑 收藏 所属分类:
C++