myatl.cryptsignisnotafunct分析

发布时间:2023-05-20

一、不是一个有效函数

BOOL WINAPI CryptSignMessage(
  _In_  PCRYPT_SIGN_MESSAGE_PARA pSignPara,
  _In_  BOOL                     fDetachedSignature,
  _In_  DWORD                    cToBeSigned,
  _In_  const BYTE               *rgpbToBeSigned[],
  _In_  DWORD                    rgcbToBeSigned[],
  _Out_ BYTE                     *pbSignedBlob,
  _Inout_ DWORD                  *pcbSignedBlob
);

在Windows的CryptoAPI中,CryptSignMessage是一个用来产生数字签名的函数,返回值类型是BOOL。此函数需要传入一个PCRYPT_SIGN_MESSAGE_PARA结构体,包含数字证书、签名算法等签名相关的信息。 然而,在myatl.cryptsignisnotafunct中,CryptSignMessage的调用显然只传入了前两个参数,没有传入后续的to-be-signed数据等必备参数,因此无法返回有效的数字签名结果,因此可以得出结论,myatl.cryptsignisnotafunct本质上是无效的函数,其存在的本意应该是作为调试过程中的一个中间函数。

二、关于myatl的来历

#include "stdafx.h"
#include <atlbase.h>
extern CComModule _Module;
#include <atlcom.h>
#include "Example1.h"
HRESULT __stdcall myatl_cryptsignisnotafunct(BSTR bstrSubjectName)    //bstrSubjectName是数字证书的主题名
{
    CComBSTR bstrCertStoreName(L"MY");
    HCERTSTORE hCertStore = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, NULL, CERT_SYSTEM_STORE_CURRENT_USER, bstrCertStoreName);    //打开MY个人证书存储区
    if (!hCertStore)
    {
        return S_FALSE;
    }
    PCCERT_CONTEXT pCertContext = NULL;
    while (pCertContext = CertEnumCertificatesInStore(hCertStore, pCertContext))    //枚举证书存储区中的个人证书列表
    {
        if (lstrcmp(bstrSubjectName, pCertContext->pCertInfo->Subject.pbData) == 0)     //pbData是CERT_NAME_INFO结构体,表示Subject的二进制编码
        {
            CERT_SIGNED_CONTENT_INFO CertSignedContentInfo;
            memset(&CertSignedContentInfo, 0, sizeof(CertSignedContentInfo));
            DWORD dwMsgEncodingType = 0;
            DWORD dwSignedMessageBlobSize = 0;
            BYTE* pbSignedMessageBlob = NULL;
            if (CryptSignMessage(&pSignPara, FALSE, 0, NULL, rgcbToBeSigned, NULL, &dwSignedMessageBlobSize))
            {   
                pbSignedMessageBlob = new BYTE[dwSignedMessageBlobSize];
                if (CryptSignMessage(&pSignPara, FALSE, 0, NULL, rgcbToBeSigned, pbSignedMessageBlob, &dwSignedMessageBlobSize))
                {
                    CertSignedContentInfo.ToBeSigned.pbData = (BYTE*)rgpbToBeSigned[0];
                    CertSignedContentInfo.ToBeSigned.cbData = rgcbToBeSigned[0];
                    CertSignedContentInfo.SignatureAlgorithm.pszObjId = szOID_RSA_SHA1RSA;
                    CertSignedContentInfo.SignatureAlgorithm.Parameters.cbData = 0;
                    CertSignedContentInfo.SignatureAlgorithm.Parameters.pbData = NULL;
                    CertSignedContentInfo.Signature.pbData = pbSignedMessageBlob;
                    CertSignedContentInfo.Signature.cbData = dwSignedMessageBlobSize;
                    CERT_BLOB certBlob;
                    certBlob.cbData = pCertContext->cbCertEncoded;
                    certBlob.pbData = pCertContext->pbCertEncoded;
                    CERT_SIGNED_INFO CertSignedInfo;
                    CertSignedInfo.Issuer = pCertContext->pCertInfo->Issuer;
                    CertSignedInfo.SerialNumber = pCertContext->pCertInfo->SerialNumber;
                    CertSignedInfo.Algorithm.pszObjId = szOID_RSA_SHA1RSA;
                    CertSignedInfo.Algorithm.Parameters.cbData = 0;
                    CertSignedInfo.Algorithm.Parameters.pbData = NULL;
                    CertSignedInfo.AuthenticatedAttributes.cAttr = NULL;
                    CertSignedInfo.AuthenticatedAttributes.rgAttr = NULL;
                    CertSignedInfo.UnauthenticatedAttributes.cAttr = NULL;
                    CertSignedInfo.UnauthenticatedAttributes.rgAttr = NULL;
                    CertSignedInfo.EncryptedHash.cbData = 0;
                    CertSignedInfo.EncryptedHash.pbData = NULL;
                    BOOL bResult = ::CryptVerifyCertificateSignatureEx(
                        NULL,
                        X509_ASN_ENCODING,
                        0,
                        (void*)X509_CERTIFICATE_SIGNATURE,
                        &certBlob,
                        0,
                        &CertSignedContentInfo,
                        &CertSignedInfo);
                    if (bResult)
                    {
                        delete[] pbSignedMessageBlob;
                        CertFreeCertificateContext(pCertContext);
                        CertCloseStore(hCertStore, 0); 
                        return S_OK;
                    }
                }
                delete[] pbSignedMessageBlob;
            }
        }
    }
    CertCloseStore(hCertStore, 0);
    return S_FALSE;
}

myatl.cryptsignisnotafunct是一个Windows的COM组件,包含在头文件"Example1.h"中,由Visual Studio中的ATL工程使用。该组件的功能是对数字证书进行数字签名。同时,在头文件中可以看到这些头文件都被包含进来:stdafx.hatlbase.hatlcom.h。 COM的全称是Component Object Model,在Windows操作系统中起着重要作用,它是一种跨进程的通信机制,能够使用不同的语言编写的组件相互通信。Visual Studio的ATL是微软提供的一组库,它封装了COM API,可以方便地创建和使用COM组件。

三、数字签名的原理和实现

数字签名是一种确定数据的发送者是否可信的机制。在数字签名中,发送者使用自己的私钥对数据进行签名,接收者使用发送者的公钥对数据进行验证,如果验证通过,那么可信度就比较高。 为了保证数字签名的安全性,必须使用一种安全的加密算法。在myatl.cryptsignisnotafunct中,主要使用了SHA-1(安全散列算法)和RSA(公钥密码算法)来实现数字签名。 数字签名的核心代码部分如下所示:

if (CryptSignMessage(&pSignPara, FALSE, 0, NULL, rgcbToBeSigned, NULL, &dwSignedMessageBlobSize))
{   
    pbSignedMessageBlob = new BYTE[dwSignedMessageBlobSize];
    if (CryptSignMessage(&pSignPara, FALSE, 0, NULL, rgcbToBeSigned, pbSignedMessageBlob, &dwSignedMessageBlobSize))
    {
        CertSignedContentInfo.ToBeSigned.pbData = (BYTE*)rgpbToBeSigned[0];
        CertSignedContentInfo.ToBeSigned.cbData = rgcbToBeSigned[0];
        CertSignedContentInfo.SignatureAlgorithm.pszObjId = szOID_RSA_SHA1RSA;
        CertSignedContentInfo.SignatureAlgorithm.Parameters.cbData = 0;
        CertSignedContentInfo.SignatureAlgorithm.Parameters.pbData = NULL;
        CertSignedContentInfo.Signature.pbData = pbSignedMessageBlob;
        CertSignedContentInfo.Signature.cbData = dwSignedMessageBlobSize;
    }
    delete[] pbSignedMessageBlob;
}

CryptSignMessage函数用来对一段待签名数据进行数字签名,其中,pSignPara是一个PCRYPT_SIGN_MESSAGE_PARA结构体,包含数字证书、签名算法等签名相关的信息。rgcbToBeSigned参数是一个DWORD数组,表示各待签名数据块的字节数,rgpbToBeSigned则是包含所有待签名数据块的指针数组。在上述代码中,由于myatl.cryptsignisnotafunct仅仅是一段中间代码,没有提供实际数据供签名,因此CryptSignMessage的后续参数不需要给出。 完成数字签名后,myatl.cryptsignisnotafunct使用依次将待签名数据和签名算法等信息填入CERT_SIGNED_CONTENT_INFO结构体中并进行进一步处理。在这个结构体中,ToBeSigned成员是待签名数据,SignatureAlgorithm成员表示签名算法,Signature成员则保存了数字签名数据。

四、总结

myatl.cryptsignisnotafunct是一个不完整的Windows COM组件,其用途是为数字证书提供数字签名功能,同时也涉及了数字签名的实现原理。虽然这个组件存在一些问题,但是对学习COM编程和数字签名技术都有一定的参考意义。