CAPICOM在VC6下的使用
最近几天在弄数字证书的一些东西,windows平台下在非net平台下的原生编程,用的比较多的是微软提供的CAPICOM组件,从网上找了个例子,MS CAPICOM Samples
可惜在VC6下遇到了很多问题,究其原因,其代码一是采用了高版本vs,二是对于BSTR的处理上稍有不完善之处,没有考虑到CAPICOM_ENCODE_BASE64和CAPICOM_ENCODE_BINARY的差别,在使用CAPICOM_ENCODE_BINARY时,原版本会在采用证书解密(CertDecryptData)时,提示“[0x80093102]:COM:ASN1 异常的数据结尾。”(对应英文提示:“ASN1 bad tag value met”)
下面的代码是我修订过的版本:
// examCAPI.cpp : 定义控制台应用程序的入口点。 // #include "stdafx.h" #include <stdio.h> #include <tchar.h> #include <afxdisp.h> // 加载 CAPICOM 组件 #import "capicom.dll" using namespace CAPICOM; #define CAPICOM_MY_STORE _T("MY") //========================================================= // 工具方法 //========================================================= // 暂停 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 orgStr = pUtils->Base64Decode((char*)pbEncData); // 从解码输出的宽字符串中获取原始数据 DWORD cbOrgData = 0; BYTE* pbOrgData = NULL; getBSTRByte(orgStr, 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 orgStr = pEncryptedData->Content; BYTE* orgData = NULL; DWORD orgSize = 0; getBSTRByte(orgStr, 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 encStr = pEncryptedData->Encrypt(CAPICOM_ENCODE_BINARY); // 获取加密数据 DWORD cbEncData = 0; BYTE* pbEncData = NULL; getBSTRByte(encStr, 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 orgStr = pEncryptedData->Content; BYTE* orgData = NULL; DWORD orgSize = 0; getBSTRByte(orgStr, 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); _tprintf(_T(" SubjectCN: %s\n"), pCert->GetInfo(CAPICOM_CERT_INFO_SUBJECT_SIMPLE_NAME)); _tprintf(_T(" Issuser: %s\n"), pCert->IssuerName); _tprintf(_T("SerialNumber: %s\n"), pCert->SerialNumber); _tprintf(_T(" ValidDate: %s TO %s \n"), timeFrom.Format("%Y-%m-%d %H:%M:%S"), timeTo.Format("%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"彩动力", 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); 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; BSTR content = pSignedData->Content; getBSTRByte(content, 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"彩动力", 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); // 获取密文数据 #if 0 BYTE* encStr = (BYTE *)(char *)strCryptedStr; DWORD encSize = strCryptedStr.length(); #else BYTE* encStr; DWORD encSize; BSTR encBStr = strCryptedStr; getBSTRByte(encBStr, encStr, encSize); SysFreeString(encBStr); #endif // 输出 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 { // 证书解密 BSTR inBSTR = SysAllocStringByteLen((char *)pbOrgData, cbOrgData); _bstr_t inStr = inBSTR; const char *buf = inStr; HRESULT retCode = pEnvelopedData->Decrypt(inStr); if(FAILED(retCode)) { CancelByError(retCode, _T("Can not decrypt data! ")); } // 获取原文数据 BSTR orgBStr = pEnvelopedData->Content; 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); #ifdef _TEST_BASE64 // BASE64 Base64Encode((BYTE*)"123456789012345678", 15, NULL, "c:\\li.base64"); Base64Decode(NULL, 0, "c:\\li.base64", "c:\\li.org"); #endif #ifdef _TEST_HASH // HASH hashSHA1((BYTE*)"1234567890", 10, NULL, "c:\\li.sha1"); hashSHA1(NULL, 0, "c:\\li.txt", "c:\\li.sha1"); #endif #ifdef _TEST_ENDECRYPT // 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"); #endif #ifdef _TEST_VIEWSTORE // CertStore & Cert viewSystemCertStore("MY"); // CAPICOM_MY_STORE viewSystemCertStore("CA"); // CAPICOM_CA_STORE viewSystemCertStore("ROOT"); // CAPICOM_ROOT_STORE viewSystemCertStore("AddressBook"); // CAPICOM_OTHER_STORE #endif #ifdef _TEST_VIEWFILE viewCrtCertStore("c:\\temp\\ca\\test.p7b"); viewCrtCertStore("c:\\temp\\ca\\test.cer"); viewPfxCertStore("c:\\temp\\ca\\test.pfx", "123456"); #endif #ifdef _TEST_SIGNDATA // TACHED SignData callSignedData((BYTE*)"123456789012345", 15, NULL, FALSE, "c:\\li.tch.sig"); VerifySignedData("c:\\li.tch.sig"); #endif #ifdef _TEST_DETACHEDSIGNDATA // DETACHED SignData callSignedData((BYTE*)"1234567890", 10, NULL, TRUE, "c:\\li.detch.sig"); VerifyDetachedSignedData((BYTE*) "1234567890", 10, NULL, "c:\\li.detch.sig"); #endif // 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); ===================================================================================**/ |