2

Microsoft Crypto APIの「証明書」を使用してデータを暗号化するにはどうすればよいですか?


AES暗号化を使用してMicrosoftCryptoAPIでデータを暗号化する方法を知っています。

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日かかりました。誰かが私の頭を壁にぶつけた1週間から私を同じにできることを望んでいます、そして私はOpenSSLをインストールしなければならないと思って間違った道をたどってしまいます。さらに悪いことに、ネイティブコードからCOMオブジェクト を呼び出そうとすると

:私は、質問を無関係ながらくたで埋める方法として、コード例のみを含めました。質問に1行しかない場合は、質問を閉じることに投票する人もいます。

4

1 に答える 1

5

Microsoft Crypto APIには、証明書を使用した非対称暗号化および復号化のための高レベルの関数が含まれています。とを見てCryptEncryptessageくださいCryptDecryptMessage

復号化の場合、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;
}
于 2012-10-05T15:20:22.020 に答える