一、不是一个有效函数
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.h
,atlbase.h
,atlcom.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编程和数字签名技术都有一定的参考意义。