Почему после использования CryptSetHashParam я больше не могу добавлять данные в мой хеш-объект MD5? - PullRequest
0 голосов
/ 09 февраля 2010

Я пытаюсь использовать функции Microsoft 'Crypt ...', чтобы сгенерировать хеш-ключ MD5 из данных, добавляемых в хеш-объект. Я также пытаюсь использовать CryptSetHashParam, чтобы установить хеш-объект для определенного хеш-значения перед добавлением в него данных.

Согласно документации Microsoft (если я правильно ее интерпретирую), вы должны быть в состоянии сделать это путем создания дублирующего хеша исходного объекта, используйте функцию 'CryptGetHashParam', чтобы получить размер хеша, затем используйте 'CryptSetHashParam' на исходном объекте, чтобы установить значение хеша соответственно. Мне известно, что после использования CryptGetHashParam вы не можете добавить дополнительные данные в хеш-объект (поэтому я подумал, что вам нужно создать дубликат), но я не могу добавить данные ни в исходный хеш-объект, ни в дубликат хэш-объект после использования CryptGetHashParam (как ожидалось) или CryptSetHashParam (чего я не ожидал).

Ниже приведены выдержки из кода класса, который я пишу, и пример того, как я использую функции класса:

Результат, полученный после запуска кода:

«Ошибка функции 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 Ответ

1 голос
/ 10 февраля 2010

Вы не можете сделать это, потому что это не имеет никакого смысла. CryptGetHashParam с параметром HP_HASHVAL завершает хэш, поэтому нет возможности добавить к нему данные. Если вы хотите «раскошелиться» на хеш, чтобы вы могли в какой-то момент завершить его, а также добавить к нему данные, вы должны продублировать хеш-объект перед финализацией. Затем вы добавляете данные в один из хеш-объектов и завершаете другой. Например, вы можете сделать это, если хотите записать накопительный хэш после каждых 1024 байтов потока данных. Не следует вызывать CryptSetHashParam для хеш-объекта, к которому вы продолжаете добавлять данные.

CryptSetHashParam с параметром HP_HASHVAL - это жестокий взлом, чтобы преодолеть ограничение в CryptoAPI. CryptoAPI будет подписывать только хеш-объект, поэтому, если вы хотите подписать некоторые данные, которые могли быть хешированы или сгенерированы за пределами CAPI, вы должны «сжать» их в хеш-объект.

EDIT:
Исходя из вашего комментария, я думаю, что вы ищете способ сериализации объекта хеша. Я не могу найти никаких доказательств того, что CryptoAPI поддерживает это. Однако есть альтернативы, которые в основном являются вариантами моего примера «1024 байта» выше. Если вы хэшируете последовательность файлов, вы можете просто вычислить и сохранить хэш каждого файла. Если вам действительно нужно свести его к одному значению, то вы можете вычислить модифицированный хеш, где первый фрагмент данных, который вы хешируете для файла i , является окончательным хешем для файлов 0, 1, 2, .. ., i -1. Итак:
H<sub>-1</sub> = <i>empty</i>,
H<sub>i</sub> = MD5 (H<sub>i-1</sub> || file<sub>i</sub>)

По мере продвижения вы можете сохранить последнее успешно вычисленное значение H<sub>i</sub>. В случае прерывания вы можете перезапустить файл i+1. Обратите внимание, что, как и любой дайджест сообщения, вышеприведенное полностью зависит от порядка и содержимого. Это то, что нужно учитывать в динамически изменяющейся файловой системе. Если файлы могут быть добавлены или изменены во время операции хеширования, это повлияет на значение хеш-значения. Это может стать бессмысленным. Возможно, вы захотите убедиться, что содержимое и последовательности файлов, которые вы хэшируете, замораживаются на протяжении всего периода хеширования.

...