2013-02-28 39 views
0

我一直在嘗試編寫一些代碼來使用Microsoft CryptoAPI。目標很簡單:加密並解密一個字符串。我似乎有它幾乎工作,但最後一次對CryptDecryptMessage的調用失敗。CryptDecryptMessage失敗

所以,我能夠成功地加密我的字符串。然後,當我接收加密的二進制字符串並嘗試解密它時,除了最後一次調用CryptDecryptMessage外,其他所有方法都可以正常工作。下面是我使用的解密代碼。

由於代碼的立場,第一次調用CryptDecryptMessage,以獲得所需的輸出緩衝區大小,成功,但它總是返回一個大小等於明文字符串大小加6.然後,我的輸出緩衝區,並且CryptDecryptMessage的下一次調用失敗(返回值爲零,dwSizeRequired設置爲零,輸出緩衝區中沒有內容,並且GetLastError返回NTE_BAD_KEY)。

另一方面,如果我取消註釋#define TESTING_INCORRECT一行,行爲會稍有不同。 CryptDecryptMessage的第一個調用成功。它的返回值是零,但GetLastError返回ERROR_MORE_DATA,這是人們所期望的,最重要的是dwSizeRequired被設置爲被編碼的原始明文字符串的大小。然後我再次分配並調用CryptDecryptMessage,如上所述再次失敗。

最後,我的密鑰庫中有私鑰證書密鑰。

有沒有人有任何想法這裏有什麼錯?謝謝。

void decrypt(std::string& sClearTextString , const std::vector<T_Byte>& sEncryptedBinaryString, const std::string& sKey) 
{ 
    BOOL bResult; 

    HCRYPTPROV hProv; 
    bResult = CryptAcquireContext(&hProv, NULL, MS_DEF_PROV, PROV_RSA_FULL, 0); 
    CHECK_CRYPT_ERR(!bResult , "Unable to find crypto context"); 

    HCERTSTORE hStore(NULL); 
    const char* const pcKey = sKey.empty()? "MY" : sKey.c_str(); 
    hStore = CertOpenSystemStore(0, pcKey); 
    CHECK_CRYPT_ERR(hStore==NULL, "unable to open certificate store."); 

    HCERTSTORE CertStoreArray[] = {hStore}; 

    CRYPT_DECRYPT_MESSAGE_PARA DecryptParams; 
    DWORD DecryptParamsSize = sizeof(DecryptParams); 
    memset(&DecryptParams, 0, DecryptParamsSize); 
    DecryptParams.cbSize = DecryptParamsSize; 
    DecryptParams.dwMsgAndCertEncodingType = (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING); 
    DecryptParams.cCertStore = sizeof(CertStoreArray)/sizeof(HCERTSTORE); 
    DecryptParams.rghCertStore = CertStoreArray; 

    const BYTE* const pbContent = &sEncryptedBinaryString[0]; 
    DWORD dwSize = STATICCAST<DWORD>(sEncryptedBinaryString.size()); 
    DWORD dwSizeRequired = 0; 

    BYTE* pbOutBuffer = NULL; 
//#define TESTING_INCORRECT 
#ifdef TESTING_INCORRECT 
    std::string sDummyBuffer(2,'\0'); 
    pbOutBuffer = (BYTE*)(&sDummyBuffer[0]); 
#endif 

    // Get required buffer size. 
    bResult = CryptDecryptMessage(&DecryptParams, pbContent, dwSize, pbOutBuffer, &dwSizeRequired, NULL); 
    CHECK_CRYPT_ERR(!bResult && ERROR_MORE_DATA != GetLastError() , "Unable to get buffer length"); 

    //Allocate buffer 
    sClearTextString.clear(); 
    sClearTextString.resize(dwSizeRequired+1,0); 
    pbOutBuffer = (BYTE*)(&sClearTextString[0]); 

    //Now actually decryt 
    bResult = CryptDecryptMessage(&DecryptParams, pbContent, dwSize, pbOutBuffer, &dwSizeRequired, NULL); 
    CHECK_CRYPT_ERR(!bResult , "Unable to decrypt"); 

    CertCloseStore(hStore, CERT_CLOSE_STORE_CHECK_FLAG); 
    CryptReleaseContext(hProv, 0); 
} 
+0

好吧,我最初並沒有發現返回的GetLastError值實際上是NTE_BAD_KEY。 CryptDecryptMessage文檔底部的提示暗示了這個錯誤,但是提供了「NTE_BAD_KEY - 80090003 - -2146893821」,如果你沒有注意到-2146893821之前的那個「 - 」,可能會引起混淆,因爲事實上GetLastError返回一個無符號數,其值爲+2148073475,所以我一開始並沒有意識到這是NTE_BAD_KEY。可能這是問題.... – 2013-02-28 17:54:23

回答

2

我會調查正在使用的密鑰。 2148073475的返回碼實際轉換爲0x80090003,即NTE_BAD_KEY。 GetLastError的234是ERR_MORE_DATA,表示一個尺寸不足的緩衝區。

認爲問題在於預期到CryptDecryptMessage第一個電話將收到NULL作爲指針pbDecrypted,因爲它是一個尺寸電話,但由於其非空與刪除註釋,它給人的234結果認爲它試圖解密的東西是已經大小的

如果大小(第一次)調用的接收緩衝區應該爲空的假設是正確的,那麼這導致我暗示按照NTE_BAD_KEY錯誤代碼的某種方式可能懷疑密鑰。

希望能激起你一些有益的想法。

+0

是的,這基本上是我上面評論的內容,但是你的回答不像我的評論那麼神祕,並且爲其他人提供了更多的信息。謝謝。 – 2013-02-28 21:36:59

+0

沒問題 - 抱歉,我發佈答案時沒有看到您的筆記! – 2013-02-28 21:53:12