2010-02-09 75 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

相关问题