Почему после использования CryptSetHashParam я больше не могу добавлять данные в мой хэш-объект MD5?
Я пытаюсь использовать функции Microsoft "Crypt..." для генерации хеш-ключа MD5 из данных, добавляемых в хеш-объект. Я также пытаюсь использовать 'CryptSetHashParam', чтобы установить хеш-объект к определенному хеш-значению, прежде чем добавлять к нему данные.
Согласно документации Microsoft (если я правильно ее интерпретирую), вы сможете сделать это, создав дублирующий хеш исходного объекта, используйте функцию CryptGetHashParam для получения размера хеша, а затем используйте "CryptSetHashParam" для оригинала. Объект для установки значения хеша соответственно. Мне известно, что после использования CryptGetHashParam вы не можете добавить дополнительные данные в хеш-объект (именно поэтому я подумал, что вам нужно создать дубликат), но я не могу добавить данные ни в исходный хеш-объект, ни в дубликат. хэш-объект после использования CryptGetHashParam (как ожидалось) или CryptSetHashParam (чего я не ожидал).
Ниже приведены выдержки из кода класса, который я пишу, и пример того, как я использую функции класса:
Результат, который я получаю после запуска кода:
Msgstr "Ошибка функции AddDataToHash - код ошибки: 2148073484.", что означает: "Хэш недопустим для использования в указанном состоянии."
Я пробовал много разных способов, чтобы попытаться заставить это работать как задумано, но результат всегда одинаков. Я принимаю, что я делаю что-то не так, но я не вижу, что я делаю не так. Есть идеи, пожалуйста?
КЛАССНАЯ СТРОИТЕЛЬНАЯ ИНИЦИАЛИЗАЦИЯ.
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;
}
Функция, используемая для добавления данных для хеширования.
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 ответ
Вы не можете сделать это, потому что это не имеет никакого смысла. CryptGetHashParam с параметром HP_HASHVAL завершает хэш, поэтому нет возможности добавить к нему данные. Если вы хотите "раскошелиться" на хеш, чтобы вы могли в какой-то момент завершить его, а также добавить к нему данные, вы должны продублировать объект хеша перед финализацией. Затем вы добавляете данные в один из хеш-объектов и завершаете другой. Например, вы можете сделать это, если хотите записать накопительный хэш после каждых 1024 байтов потока данных. Вы не должны вызывать CryptSetHashParam для хеш-объекта, к которому вы продолжаете добавлять данные.
CryptSetHashParam с параметром HP_HASHVAL - это жестокий взлом, чтобы преодолеть ограничение в CryptoAPI. CryptoAPI будет подписывать только хеш-объект, поэтому, если вы хотите подписать некоторые данные, которые могли быть хешированы или сгенерированы вне CAPI, вы должны "сжать" их в хеш-объект.
РЕДАКТИРОВАТЬ:
Исходя из вашего комментария, я думаю, что вы ищете способ сериализации объекта хеша. Я не могу найти никаких доказательств того, что CryptoAPI поддерживает это. Однако есть альтернативы, которые в основном являются вариантами моего примера "1024 байта" выше. Если вы хэшируете последовательность файлов, вы можете просто вычислить и сохранить хэш каждого файла. Если вам действительно нужно свести его к одному значению, то вы можете вычислить модифицированный хеш, где первый фрагмент данных, который вы хешируете для файла i, является окончательным хешем для файлов 0, 1, 2,..., i-1. Так: H-1 = empty,
Hi = MD5 (Hi-1 || filei)
По мере продвижения вы можете сохранить последний успешно рассчитанный Hi
значение. В случае прерывания вы можете перезагрузить файл i+1
, Обратите внимание, что, как и любой дайджест сообщения, вышеприведенное полностью зависит как от порядка, так и от содержания. Это то, что нужно учитывать в динамически изменяющейся файловой системе. Если файлы могут быть добавлены или изменены во время операции хеширования, это повлияет на значение хеш-значения. Это может стать бессмысленным. Возможно, вы захотите убедиться, что последовательность и содержимое файлов, которые вы хэшируете, заморожены в течение всего периода хэширования.