2010-02-09 17 views
0

我正在嘗試使用Microsoft'Crypt ...'函數從添加到哈希對象的數據生成MD5哈希鍵。我還試圖在向其添加數據之前使用'CryptSetHashParam'將哈希對象設置爲特定的哈希值。爲什麼在使用'CryptSetHashParam'之後,我不能再向我的MD5哈希對象添加數據?

根據Microsoft文檔(如果我正確解釋它),您應該可以通過創建原始對象的重複哈希來執行此操作,使用'CryptGetHashParam'函數檢索哈希大小,然後使用'CryptSetHashParam '在原始對象上相應地設置散列值。我知道在使用'CryptGetHashParam'之後,你無法向散列對象添加額外的數據(這就是爲什麼我認爲你需要創建一個副本),但我不能將數據添加到原始散列對象或重複使用'CryptGetHashParam'(如預期)或'CryptSetHashParam'(我沒有想到)之後的哈希對象。

下面是我寫的類代碼提取和我如何使用類函數的例子:

結果運行代碼後,我得到的是:

「AddDataToHash功能失敗 - 錯誤代碼:2148073484.「,它轉換爲:」哈希無效在指定狀態下使用。「。

我試過很多不同的方法來試圖按預期工作,但結果總是一樣的。我接受我做錯了什麼,但我不明白我做錯了什麼。請有任何想法嗎?

CLASS CONSTRUCTOR INITIALISATION。

CAuthentication::CAuthentication() 

{ 

    m_dwLastError = ERROR_SUCCESS; 

    m_hCryptProv = NULL; 

    m_hHash = NULL; 

    m_hDuplicateHash = NULL; 

    if(!CryptAcquireContext(&m_hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_MACHINE_KEYSET)) 

    { 
     m_dwLastError = GetLastError(); 

     if (m_dwLastError == 0x80090016) 
     { 
      if(!CryptAcquireContext(&m_hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_NEWKEYSET | CRYPT_MACHINE_KEYSET)) 
      { 
       m_dwLastError = GetLastError(); 

       m_hCryptProv = NULL; 
      } 
     } 
    } 

    if(!CryptCreateHash(m_hCryptProv, CALG_MD5, 0, 0, &m_hHash)) 
    { 
     m_dwLastError = GetLastError(); 

     m_hHash = NULL; 
    } 
} 

功能用於設置哈希對象的哈希值。

bool CAuthentication::SetHashKeyString(char* pszKeyBuffer) 

{ 

    bool bHashStringSet = false; 

    DWORD dwHashSize = 0; 
    DWORD dwHashLen = sizeof(DWORD); 

    BYTE byHash[DIGITAL_SIGNATURE_LENGTH/2]={0}; 

    if(pszKeyBuffer != NULL && strlen(pszKeyBuffer) == DIGITAL_SIGNATURE_LENGTH) 
    { 
     if(CryptDuplicateHash(m_hHash, NULL, 0, &m_hDuplicateHash)) 
     { 
      if(CryptGetHashParam(m_hDuplicateHash, HP_HASHSIZE, reinterpret_cast<BYTE*>(&dwHashSize), &dwHashLen, 0)) 
      {   
       if (dwHashSize == DIGITAL_SIGNATURE_LENGTH/2) 
       { 
        char*pPtr = pszKeyBuffer; 

        ULONG ulTempVal = 0; 

        for(ULONG ulIdx = 0; ulIdx < dwHashSize; ulIdx++) 
        { 
         sscanf(pPtr, "%02X", &ulTempVal); 

         byHash[ulIdx] = static_cast<BYTE>(ulTempVal); 

         pPtr+= 2; 
        } 

        if(CryptSetHashParam(m_hHash, HP_HASHVAL, &byHash[0], 0)) 
        { 
         bHashStringSet = true; 
        } 
        else 
        { 
         pszKeyBuffer = ""; 
         m_dwLastError = GetLastError(); 
        } 
       } 
      } 
      else 
      { 
       m_dwLastError = GetLastError(); 
      } 
     } 
     else 
     { 
      m_dwLastError = GetLastError(); 
     } 
    } 

    if(m_hDuplicateHash != NULL) 
    { 
     CryptDestroyHash(m_hDuplicateHash); 
    } 

    return bHashStringSet; 
} 

功能用於添加數據進行Hashing。

bool CAuthentication::AddDataToHash(BYTE* pbyHashBuffer, ULONG ulLength) 

{ 

    bool bHashDataAdded = false; 

    if(CryptHashData(m_hHash, pbyHashBuffer, ulLength, 0)) 
    { 
     bHashDataAdded = true; 
    } 
    else 
    { 
     m_dwLastError = GetLastError(); 
    } 

    return bHashDataAdded; 
} 

主要功能類用法:

CAuthentication auth; 

.....

auth.SetHashKeyString("0DD72A4F2B5FD48EF70B775BEDBCA14C"); 

.....

if(!auth.AddDataToHash(pbyHashBuffer, ulDataLen)) 

{ 

    TRACE("CryptHashData function failed - Errorcode: %lu.\n", auth.GetAuthError()); 
} 

回答

1

你不能這樣做,因爲它沒有任何意義。具有HP_HASHVAL選項的CryptGetHashParam完成散列,因此無法向其添加數據。如果你想「分叉」散列,以便你可以在某個時刻完成它並向其中添加數據,那麼你必須在完成之前複製散列對象。然後將數據添加到其中一個哈希對象並最終確定另一個。例如,如果您希望在數據流的每個1024字節之後記錄累積散列,則可以這樣做。你不應該在你繼續添加數據的散列對象上調用CryptSetHashParam。

帶有HP_HASHVAL選項的CryptSetHashParam是克服CryptoAPI限制的殘酷攻擊手段。 CryptoAPI將只簽署一個哈希對象,所以如果你想簽署一些可能被哈希或在CAPI之外生成的數據,你必須將它「卡」到一個哈希對象中。

編輯:
根據你的評論,我認爲你正在尋找一種序列化哈希對象的方法。我無法找到CryptoAPI支持這一點的任何證據。但是,也有替代方案,它們基本上是我上面「1024字節」示例的變體。如果您正在散列一系列文件,則可以簡單地計算並保存每個文件的散列。如果你真的需要把它歸結爲一個值,那麼你可以計算一個修改後的散列,其中你爲文件散列的第一塊數據是文件0,1,2,...,的最終散列 -1。所以:
H-1 = empty,
Hi = MD5 (Hi-1 || filei)

你走,你可以保存上一次成功計算Hi值。如果發生中斷,可以在文件i+1處重新啓動。請注意,與任何消息摘要一樣,上述內容對訂單和內容都完全敏感。這是在動態更改文件系統時要考慮的事情。如果在散列操作期間可以添加或更改文件,則散列值的含義將受到影響。它可能會變得毫無意義。您可能需要確定在哈希的整個持續時間內,您哈希的文件的內容序列都被凍結。

+0

我想我應該解釋爲什麼我要用預定義的開始散列值來初始化散列對象,以突出顯示我想要克服的問題。數據我哈希來自一個包含數百個文件的NAS。在對每個文件中的數據進行散列處理之後,我希望在本地保留MD5散列,以便如果哈希應用程序遭受中斷並重新啓動,則會在中斷點處使用散列值初始化新的散列對象,從而防止需要再次從NAS開始哈希。有沒有辦法做到這一點? – 2010-02-11 09:20:22

+0

如果沒有更多的文件被添加到NAS中,並且MD5哈希對所有文件中包含的所有數據都沒有中斷地執行,那麼如果所有數據再次被散列,結果散列值不會不同,但是這次中斷遇到。如果我正確地解釋了之前所說的內容,則表明在中斷之前計算的散列值在下一個文件數據之前被送入散列對象。這不會導致散列數據被計算在散列數據上,從而導致不同的最終散列值與不間斷散列值的散列值不同? – 2010-02-12 10:46:44

+0

您跟蹤上次成功散列文件。當散列文件i + 1中間發生中斷時,您只需丟棄部分結果並重新開始,重新計算MD5(H_i || file_ {i + 1})= H_ {i + 1}。 – 2010-02-13 00:51:33

相關問題