随笔-10  评论-36  文章-6  trackbacks-0
本文是 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 飞鹰 阅读(1835) 评论(2)  编辑  收藏 所属分类: C++

评论:
# re: MS CAPICOM Samples 2013-06-19 01:33 | 薛建辉
我操,哥们牛逼!!!!!

哥们这几天正搞到这里,真心感谢!!!!  回复  更多评论
  
# re: MS CAPICOM Samples 2015-06-18 16:50 | 大智
感谢楼主分享,非常详细。
在使用
// 证书加密
_bstr_t strCryptedStr = pEnvelopedData->Encrypt(CAPICOM_ENCODE_BINARY);
的地方如果编码后结果含有0x00,在下面解码时会出错,最好用
// 证书加密
_bstr_t strCryptedStr = pEnvelopedData->Encrypt(CAPICOM_ENCODE_BASE64);  回复  更多评论
  

只有注册用户登录后才能发表评论。


网站导航: