在Windows中使用C

时间:2019-12-27 05:00:40

标签: c windows certificate pfx

我目前有一个项目已经使用PFX证书在C#中签署了我需要的字符串,但是现在,我不得不将该项目的一部分转换为C,以使其与其他项目兼容...

我在MSDN https://docs.microsoft.com/en-us/windows/win32/seccrypto/example-c-program-signing-a-message-and-verifying-a-message-signature中找到了这篇文章,该文章展示了如何通过从Windows存储中加载证书来对字符串进行加密和签名。...

但是此示例的结果与预期不符,因为在我的情况下,我只需要对字符串进行签名而不是加密和签名,因此我检查是否有仅要签名的函数,但没有找到。

另一点,我如何加载.PFX / .P12文件,并将其与Windows函数一起使用,而不必在计算机上安装证书...

我在C#中签名字符串的方法是这样的:

    public byte[] SignString(string mensagem)
    {
        var certificado = SearchCertificate();
        CmsSigner signer = new CmsSigner(SubjectIdentifierType.IssuerAndSerialNumber, certificado);
        signer.DigestAlgorithm = new Oid("2.16.840.1.101.3.4.2.1"); //SHA256

        ContentInfo content = new ContentInfo(new Oid(Configuration.ContentOid), new System.Text.UTF8Encoding().GetBytes(mensagem));
        SignedCms signedCms = new SignedCms(content, false);

        signedCms.ComputeSignature(signer, false);
        var signedStringBytes = signedCms.Encode();

        return signedStringBytes;
    }

1 个答案:

答案 0 :(得分:0)

Encode类的SignedCms函数在内部使用wincrypt.h库,并调用方法CryptMsgOpenToEncodeCryptMsgUpdateCryptMsgGetParam。 / p>

Microsoft文档还包含完整的example

#pragma comment(lib, "crypt32.lib")

#include <stdio.h>
#include <windows.h>
#include <Wincrypt.h>
#define MY_ENCODING_TYPE  (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING)
void MyHandleError(char *s);

void main(void)
{
//-------------------------------------------------------------------
// Copyright (C) Microsoft.  All rights reserved.
// Declare and initialize variables.

BYTE* pbContent = (BYTE*) "Security is our only business.";
                                    // a byte pointer
DWORD cbContent = strlen((char *) pbContent)+1;
                                    // the size of the message
HCERTSTORE hStoreHandle;
HCRYPTPROV hCryptProv;
PCCERT_CONTEXT pSignerCert;         // signer's certificate
PCCERT_CONTEXT pRecipCert;          // receiver's certificate
LPWSTR pswzRecipientName = L"Hortense";
LPWSTR pswzCertSubject = L"Full Test Cert";
PCERT_INFO RecipCertArray[1];
DWORD ContentEncryptAlgSize;
CRYPT_ALGORITHM_IDENTIFIER ContentEncryptAlgorithm;
CMSG_ENVELOPED_ENCODE_INFO EnvelopedEncodeInfo;
DWORD cbEncodedBlob;
BYTE *pbEncodedBlob;
DWORD cbSignedBlob;
BYTE *pbSignedBlob;
HCRYPTMSG hMsg;
DWORD HashAlgSize;
CRYPT_ALGORITHM_IDENTIFIER HashAlgorithm;
CMSG_SIGNER_ENCODE_INFO SignerEncodeInfo;
CERT_BLOB SignerCertBlob;
CERT_BLOB SignerCertBlobArray[1];
CMSG_SIGNER_ENCODE_INFO SignerEncodeInfoArray[1];
CMSG_SIGNED_ENCODE_INFO SignedMsgEncodeInfo;

//-------------------------------------------------------------------
// Begin processing. Display the original message.

printf("The original message => %s\n",pbContent);  

//-------------------------------------------------------------------
// Acquire a cryptographic provider. 

if(CryptAcquireContext(
        &hCryptProv,      // address for handle to be returned
        NULL,             // use the current user's logon name
        NULL,             // use the default provider
        PROV_RSA_FULL,    // provider type
        0))               // zero allows access to private keys
{
    printf("Context CSP acquired. \n");
}
else
{
   if ( GetLastError() == NTE_BAD_KEYSET)
   {
        printf("A Usable private key was not found \n");
        printf("in the default key container. Either a \n");
        printf("private key must be generated in that container \n");
        printf("or CryptAquireCertificatePrivateKey can be used \n");
        printf("to gain access to the needed private key.");
   }
    MyHandleError("CryptAcquireContext failed.");
}
//-------------------------------------------------------------------
// Open the My system certificate store.

if(hStoreHandle = CertOpenStore(
       CERT_STORE_PROV_SYSTEM,
       0,
       NULL,
       CERT_SYSTEM_STORE_CURRENT_USER,
       L"MY"))
{
    printf("The MY system store is open. \n");
}
else
{
    MyHandleError( "Error getting store handle.");
}
//-------------------------------------------------------------------
// Get the signer's certificate. This certificate must be in the
// My store, and its private key must be available.

if(pSignerCert = CertFindCertificateInStore(
   hStoreHandle,
   MY_ENCODING_TYPE,
   0,
   CERT_FIND_SUBJECT_STR,
   pswzCertSubject,
   NULL))
{
    printf("Found certificate for %S.\n",pswzCertSubject);
}
else
{
    MyHandleError("Signer certificate not found.");
}
//-------------------------------------------------------------------
// Initialize the algorithm identifier structure.

HashAlgSize = sizeof(HashAlgorithm);
memset(&HashAlgorithm, 0, HashAlgSize);    // initialize to zero
HashAlgorithm.pszObjId = szOID_RSA_MD5;    // initialize the 
                                           // necessary member
//-------------------------------------------------------------------
// Initialize the CMSG_SIGNER_ENCODE_INFO structure.

memset(&SignerEncodeInfo, 0, sizeof(CMSG_SIGNER_ENCODE_INFO));
SignerEncodeInfo.cbSize = sizeof(CMSG_SIGNER_ENCODE_INFO);
SignerEncodeInfo.pCertInfo = pSignerCert->pCertInfo;
SignerEncodeInfo.hCryptProv = hCryptProv;
SignerEncodeInfo.dwKeySpec = AT_KEYEXCHANGE;
SignerEncodeInfo.HashAlgorithm = HashAlgorithm;
SignerEncodeInfo.pvHashAuxInfo = NULL;

//-------------------------------------------------------------------
// Create an array of one. 
// Note: The current program is set up for only a single signer.

SignerEncodeInfoArray[0] = SignerEncodeInfo;

//-------------------------------------------------------------------
// Initialize the CMSG_SIGNED_ENCODE_INFO structure.

SignerCertBlob.cbData = pSignerCert->cbCertEncoded;
SignerCertBlob.pbData = pSignerCert->pbCertEncoded;

//-------------------------------------------------------------------
// Initialize the array of one CertBlob.

SignerCertBlobArray[0] = SignerCertBlob;
memset(&SignedMsgEncodeInfo, 0, sizeof(CMSG_SIGNED_ENCODE_INFO));
SignedMsgEncodeInfo.cbSize = sizeof(CMSG_SIGNED_ENCODE_INFO);
SignedMsgEncodeInfo.cSigners = 1;
SignedMsgEncodeInfo.rgSigners = SignerEncodeInfoArray;
SignedMsgEncodeInfo.cCertEncoded = 1;
SignedMsgEncodeInfo.rgCertEncoded = SignerCertBlobArray;
SignedMsgEncodeInfo.rgCrlEncoded = NULL;

//-------------------------------------------------------------------
// Get the size of the encoded, signed message BLOB.

if(cbSignedBlob = CryptMsgCalculateEncodedLength(
    MY_ENCODING_TYPE,       // message encoding type
    0,                      // flags
    CMSG_SIGNED,            // message type
    &SignedMsgEncodeInfo,   // pointer to structure
    NULL,                   // inner content OID
    cbContent))             // size of content
{
    printf("%d, the length of data calculated. \n",cbSignedBlob);
}
else
{
   if ( GetLastError() == NTE_BAD_KEYSET)
   {
        printf("A Usable private key was not found \n");
        printf("in the default key container. Either a \n");
        printf("private key must be generated in that container \n");
        printf("or CryptAquireCertificatePRivateKey can be used \n");
        printf("to gain access to the needed private key.");
    }
    MyHandleError("Getting cbSignedBlob length failed.");
}
//-------------------------------------------------------------------
// Allocate memory for the encoded BLOB.

if(pbSignedBlob = (BYTE *) malloc(cbSignedBlob))
{
   printf("Memory has been allocated for the signed message. \n");
}
else
{
   MyHandleError("Memory allocation failed.");
}
//-------------------------------------------------------------------
// Open a message to encode.

if(hMsg = CryptMsgOpenToEncode(
    MY_ENCODING_TYPE,        // encoding type
    0,                       // flags
    CMSG_SIGNED,             // message type
    &SignedMsgEncodeInfo,    // pointer to structure
    NULL,                    // inner content OID
    NULL))                   // stream information (not used)
{
    printf("The message to be encoded has been opened. \n");
}
else
{
    MyHandleError("OpenToEncode failed.");
}
//-------------------------------------------------------------------
// Update the message with the data.

if(CryptMsgUpdate(
     hMsg,         // handle to the message
     pbContent,    // pointer to the content
     cbContent,    // size of the content
     TRUE))        // last call
{
    printf("Content has been added to the encoded message. \n");
}
else
{
    MyHandleError("MsgUpdate failed.");
}
//-------------------------------------------------------------------
// Get the resulting message.

if(CryptMsgGetParam(
    hMsg,                      // handle to the message
    CMSG_CONTENT_PARAM,        // parameter type
    0,                         // index
    pbSignedBlob,              // pointer to the BLOB
    &cbSignedBlob))            // size of the BLOB
{
    printf("Message encoded successfully. \n");
}
else
{
    MyHandleError("MsgGetParam failed.");
}
//-------------------------------------------------------------------
// pbSignedBlob now points to the encoded, signed content.

//-------------------------------------------------------------------
// Get a pointer to the recipient certificate.
// For this program, the recipient's certificate must also be in the
// My store. At this point, only the recipient's public key is needed.
// To open the enveloped message, however, the recipient's 
// private key must also be available.

if(pRecipCert=CertFindCertificateInStore(      
      hStoreHandle,
      MY_ENCODING_TYPE,            // use X509_ASN_ENCODING
      0,                           // no dwFlags needed
      CERT_FIND_SUBJECT_STR,       // find a certificate with a
                                   // subject that matches the 
                                   // string in the next parameter
      pswzRecipientName,           // the Unicode string to be found
                                   // in a certificate's subject
      NULL))                       // NULL for the first call to the
                                   // function
                                   // in all subsequent
                                   // calls, it is the last pointer
                                   // returned by the function
{
     printf("Certificate for %S found. \n", pswzRecipientName);
}
else
{
     MyHandleError("Could not find the countersigner's "
         "certificate.");
}
//-------------------------------------------------------------------
// Initialize the first element of the array of CERT_INFOs. 
// In this example, there is only a single recipient.

RecipCertArray[0] = pRecipCert->pCertInfo;

//-------------------------------------------------------------------
// Initialize the symmetric-encryption algorithm identifier
// structure.

ContentEncryptAlgSize = sizeof(ContentEncryptAlgorithm);
memset(&ContentEncryptAlgorithm, 
       0,
       ContentEncryptAlgSize);               // initialize to zero

//-------------------------------------------------------------------
// Initialize the necessary members. This particular OID does not
// need any parameters. Some OIDs, however, will require that
// the other members be initialized.

ContentEncryptAlgorithm.pszObjId = szOID_RSA_RC4;

//-------------------------------------------------------------------
// Initialize the CMSG_ENVELOPED_ENCODE_INFO structure.

memset(&EnvelopedEncodeInfo, 
       0,
       sizeof(CMSG_ENVELOPED_ENCODE_INFO));
EnvelopedEncodeInfo.cbSize = sizeof(CMSG_ENVELOPED_ENCODE_INFO);
EnvelopedEncodeInfo.hCryptProv = hCryptProv;
EnvelopedEncodeInfo.ContentEncryptionAlgorithm = 
                                        ContentEncryptAlgorithm;
EnvelopedEncodeInfo.pvEncryptionAuxInfo = NULL;
EnvelopedEncodeInfo.cRecipients = 1;
EnvelopedEncodeInfo.rgpRecipients = RecipCertArray;

//-------------------------------------------------------------------
// Get the size of the encoded message BLOB.

if(cbEncodedBlob = CryptMsgCalculateEncodedLength(
     MY_ENCODING_TYPE,        // message encoding type
     0,                       // flags
     CMSG_ENVELOPED,          // message type
     &EnvelopedEncodeInfo,    // pointer to structure
     szOID_RSA_signedData,    // inner content OID
     cbSignedBlob))           // size of content
{
    printf("Length of the encoded BLOB will be %d.\n",cbEncodedBlob);
}
else
{
    MyHandleError("Getting enveloped cbEncodedBlob length failed.");
}
//--------------------------------------------------------------------
// Allocate memory for the encoded BLOB.

if(pbEncodedBlob = (BYTE *) malloc(cbEncodedBlob))
{
    printf("Memory has been allocated for the BLOB. \n");
}
else
{
    MyHandleError("Enveloped malloc operation failed.");
}
//-------------------------------------------------------------------
// Open a message to encode.

if(hMsg = CryptMsgOpenToEncode(
     MY_ENCODING_TYPE,        // encoding type
     0,                       // flags
     CMSG_ENVELOPED,          // message type
     &EnvelopedEncodeInfo,    // pointer to structure
     szOID_RSA_signedData,    // inner content OID
     NULL))                   // stream information (not used)
{
    printf("The message to encode is open. \n");
}
else
{
    MyHandleError("Enveloped OpenToEncode failed.");
}
//-------------------------------------------------------------------
// Update the message with the data.

if(CryptMsgUpdate(
     hMsg,              // handle to the message
     pbSignedBlob,      // pointer to the signed data BLOB
     cbSignedBlob,      // size of the data BLOB
     TRUE))             // last call
{
    printf("The signed BLOB has been added to the message. \n");
}
else
{
    MyHandleError("Enveloped MsgUpdate failed.");
}
//-------------------------------------------------------------------
// Get the resulting message.

if(CryptMsgGetParam(
     hMsg,                  // handle to the message
     CMSG_CONTENT_PARAM,    // parameter type
     0,                     // index
     pbEncodedBlob,         // pointer to the enveloped,
                            // signed data BLOB
     &cbEncodedBlob))       // size of the BLOB
{
    printf("Enveloped message encoded successfully. \n");
}
else
{
    MyHandleError("Enveloped MsgGetParam failed.");
}
//-------------------------------------------------------------------
// Clean up.

CertFreeCertificateContext(pRecipCert);
if(CertCloseStore(
     hStoreHandle,
     CERT_CLOSE_STORE_CHECK_FLAG))
{
  printf("The certificate store closed without a certificate "
      "left open. \n");
}
else
{
  printf("The store closed but a certificate was still open. \n");
}
if(hMsg)
   CryptMsgClose(hMsg);
if(hCryptProv) 
   CryptReleaseContext(hCryptProv,0);
} // end main

//-------------------------------------------------------------------
// This example uses the function MyHandleError, a simple error
// handling function to print an error message and exit 
// the program. 
// For most applications, replace this function with one 
// that does more extensive error reporting.

void MyHandleError(char *s)
{
    fprintf(stderr,"An error occurred in running the program. \n");
    fprintf(stderr,"%s\n",s);
    fprintf(stderr, "Error number %x.\n", GetLastError());
    fprintf(stderr, "Program terminating. \n");
    exit(1);
} // end MyHandleError