【问题标题】:How to encrypt data using a certificate?如何使用证书加密数据?
【发布时间】:2012-10-03 18:53:16
【问题描述】:

如何在 Microsoft Crypto API 中使用 “证书” 加密数据?


我知道如何使用 Microsoft Crypto API 使用 AES 加密来加密数据:

keyBlob.hdr.bType := PLAINTEXTKEYBLOB;
keyBlob.hdr.bVersion := CUR_BLOB_VERSION;
keyBlob.hdr.reserved := 0;
keyBlob.hdr.aiKeyAlg := CALG_AES_128;
keyBlob.cbKeySize := 16;
Move(data[0], keyBlob.key[0], 16);


/*
   Set ProviderName to either
   providerName = "Microsoft Enhanced RSA and AES Cryptographic Provider"
   providerName = "Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)"  //Windows XP and earlier
*/
MS_ENH_RSA_AES_PROV_W: WideString = 'Microsoft Enhanced RSA and AES Cryptographic Provider';
providerName := MS_ENH_RSA_AES_PROV_W;

CryptAcquireContextW(provider, nil, PWideChar(providerName), PROV_RSA_AES, CRYPT_VERIFYCONTEXT);
CryptImportKey(provider, PByte(@keyBlob), sizeof(keyBlob), 0, 0, importedKey);

mode := CRYPT_MODE_CBC;
CryptSetKeyParam(importedKey, KP_MODE, @mode, 0);

//CryptEncrypt encrypts in-place. Copy stuff to be encrypted into new byte buffer
utf8PlainText := TCrypt.WideStringToUTF8(szPlainText);
dataLen := Length(utf8PlainText);
bufferLen := dataLen+16; //allocate a buffer larger than we need to hold the data we want to encrypt
SetLength(data, bufferLen);
Move(utf8PlainText[1], data[0], dataLen);

if not CryptEncrypt(importedKey, 0, True, 0, @data[0], {var}dataLen, bufferLen) then
begin
   le := GetLastError;
   if le = ERROR_MORE_DATA  then
   begin
      /*
         If the buffer allocated for pbData is not large enough to hold the encrypted data,
         GetLastError returns ERROR_MORE_DATA and stores the required buffer size,
         in bytes, in the DWORD value pointed to by pdwDataLen.
      */
      bufferLen := dataLen;
      SetLength(data, bufferLen);
      CryptEncrypt(importedKey, 0, True, 0, @data[0], {var}dataLen, bufferLen);
   end;
   CryptDestroyKey(importedKey);
   CryptReleaseContext(provider, 0);
end;

现在我需要做同样的事情,除了对称加密,我需要使用公钥进行加密,使用私钥进行解密。


注意:这 15 行对称加密代码花了 3 天时间。我希望有人能和我一样把我的头撞到墙上一周,但我最终走错了路,认为我必须安装 OpenSSL。更糟糕的是,如果我尝试拨打 COM Objects from native code

注意:我只包含代码示例作为用无关紧要的垃圾填充问题的一种方式。如果问题只包含一行,有些人会投票结束。

【问题讨论】:

    标签: public-key-encryption certificate cryptoapi


    【解决方案1】:

    Microsoft Crypto API 包含用于使用证书进行非对称加密和解密的高级函数。看看CryptEncryptessageCryptDecryptMessage

    在解密情况下,您的 CERT_CONTEXT 必须具有 CERT_KEY_PROV_INFO_PROP_ID 属性。

    我可以给你一个用法的例子:

    const wchar_t message[] = L"This is a simple test message.";
    PCCERT_CONTEXT hCert = NULL;
    HCERTSTORE hStore = NULL;
    
    static bool openCertStoreMY(CDialog *parent)
    {
        if(!hStore)
        {
            hStore = CertOpenSystemStore(NULL, L"MY");
    
            if(!hStore)
            {
                parent->MessageBox(L"Cannot open \"MY\"", L"Error", MB_ICONERROR);
                return false;
            }
        }
    
        return true;
    }
    
    void CTestDlg::OnEncryptClicked()
    {
        if(!hCert)
        {
            if(!openCertStoreMY(this))
                return;
    
            hCert = CryptUIDlgSelectCertificateFromStore(hStore, GetSafeHwnd(), NULL, NULL, 0, 0, 0);
    
            if(!hCert)
                return;
        }
    
        CRYPT_ENCRYPT_MESSAGE_PARA params;
        memset(&params, 0, sizeof(CRYPT_ENCRYPT_MESSAGE_PARA));
        params.cbSize = sizeof(CRYPT_ENCRYPT_MESSAGE_PARA);
        params.dwMsgEncodingType = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING;
        params.ContentEncryptionAlgorithm.pszObjId = "2.16.840.1.101.3.4.1.2"; //AES128
    
        DWORD msz;
        DWORD cbMsg = sizeof(message);
        const BYTE *pbMsg = (PBYTE)message;
        if(!CryptEncryptMessage(&params, 1, &hCert, pbMsg, cbMsg, NULL, &msz))
            return;
    
        PBYTE outBuf = new BYTE[msz];
        if(CryptEncryptMessage(&params, 1, &hCert, pbMsg, cbMsg, outBuf, &msz))
        {
            FILE *fil = _wfopen(filename, L"wb");
            if(fil)
            {
                fwrite(outBuf, 1, msz, fil);
                fclose(fil);
                MessageBox(L"Complete");
            }
            else
                MessageBox(L"Cannot open file", L"Error", MB_ICONERROR);
        }
    
        delete [] outBuf;
    }
    
    void CTestDlg::OnDecryptClicked()
    {
        if(!openCertStoreMY(this))
            return;
    
        CRYPT_DECRYPT_MESSAGE_PARA params;
        params.cbSize = sizeof(CRYPT_DECRYPT_MESSAGE_PARA);
        params.dwMsgAndCertEncodingType = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING;
        params.cCertStore = 1;
        params.rghCertStore = &hStore;
        params.dwFlags = 0;
    
        DWORD cbMsg;
        PBYTE pbMsg;
    
        FILE *fil = _wfopen(filename, L"rb");
        if(fil)
        {
            fseek(fil, 0 ,2);
            cbMsg = ftell(fil);
            fseek(fil, 0, 0);
            pbMsg = new BYTE[cbMsg];
    
            fread(pbMsg, 1, cbMsg, fil);
            fclose(fil);
        } else {
            MessageBox(L"Cannot open file", L"Error", MB_ICONERROR);
            return;
        }
    
        DWORD msz;
        if(!CryptDecryptMessage(&params, pbMsg, cbMsg, NULL, &msz, NULL))
        {
            delete [] pbMsg;
            return;
        }
    
        PBYTE outBuf = new BYTE[msz];
        if(CryptDecryptMessage(&params, pbMsg, cbMsg, outBuf, &msz, NULL))
            MessageBox((LPCWSTR)outBuf);
    
        delete [] pbMsg;
        delete [] outBuf;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-11-24
      • 2014-12-13
      • 2016-10-20
      • 2016-06-10
      • 1970-01-01
      • 2016-08-15
      • 2015-03-21
      • 2012-05-16
      相关资源
      最近更新 更多