Почему после использования 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, Обратите внимание, что, как и любой дайджест сообщения, вышеприведенное полностью зависит как от порядка, так и от содержания. Это то, что нужно учитывать в динамически изменяющейся файловой системе. Если файлы могут быть добавлены или изменены во время операции хеширования, это повлияет на значение хеш-значения. Это может стать бессмысленным. Возможно, вы захотите убедиться, что последовательность и содержимое файлов, которые вы хэшируете, заморожены в течение всего периода хэширования.

Другие вопросы по тегам