Std::ifstream читать файл как BYTE (беззнаковый символ), а не символ

Я использую Microsoft CNG Cryptography API для вычисления хэша файла, пока все работает нормально, за исключением того, что вычисленный хэш неверен по сравнению с хешем, вычисленным с помощью внешней сторонней программы.

Я не уверен на 100%, но думаю, проблема в том, что я читаю файл в массив signed char, а не в массив BYTE (беззнаковый символ).

Ниже приведен код, как я сейчас читаю файл: (Примечание: я пропустил код проверки ошибок)

std::ifstream file;
file.open("sample.txt", std::ifstream::binary | std::ifstream::in | std::ifstream::ate);
const int file_length = file.tellg();

char* data = new char[file_length];
file.seekg(file.beg);
file.read(data, file_length);

Проблема с приведенным выше кодом заключается в том, что данные считываются в массив знаков со знаком, но криптографические функции ожидают unsigned char / BYTE, и я предполагаю, что мой вычисленный хэш неверен.

Приведенный ниже код - это то, что я хотел бы сделать, но он не работает (добавлен комментарий), поскольку метод ifstream::read() ожидает массив char, а не unsigned char / BYTE

std::ifstream file;
file.open("sample.txt", std::ifstream::binary | std::ifstream::in | std::ifstream::ate);
const int file_length = file.tellg();

PBYTE data = new BYTE[file_length];
file.seekg(file.beg);
file.read(data, file_length); // error PBYTE is incompatibe with char*

Итак, мой вопрос: как мне читать данные как BYTE, а не char, нужно ли мне использовать CreateFile API или есть способ с std::ifstream?

Может быть, есть что-то еще, вызывающее плохой вычисленный хэш, я не знаю, скажите мне об этом.

Обновлено: Ниже приведен полностью рабочий код для вычисления хэша SHA256 для заданного имени файла, но хэш неверный. (т.е. не так, как если бы это делалось с помощью сторонней хеш-утилиты)

#include <windows.h>
#include <bcrypt.h>
#include <iostream>
#include <sstream>
#include <iomanip>
#include <fstream>


#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
#define STATUS_UNSUCCESSFUL ((NTSTATUS)0xC0000001L)

std::string ByteToHex(PBYTE data, size_t len)
{
    std::stringstream ss;
    ss << std::hex << std::setfill('0') << std::uppercase;

    for (size_t i = 0; i < len; ++i)
    {
        ss << std::setw(2) << static_cast<short>(data[i]);
    }

    return ss.str();
}

int main()
{
    BCRYPT_ALG_HANDLE hAlg = nullptr;
    BCRYPT_HASH_HANDLE hHash = nullptr;
    DWORD cbHash, cbObject, cbData;
    PBYTE pbHash, pbObject;
    NTSTATUS status = STATUS_UNSUCCESSFUL;

    std::ifstream file;
    file.open("sample.exe", std::ifstream::binary | std::ifstream::in | std::ifstream::ate);
    const int file_length = file.tellg();

    if (!file.is_open())
    {
        abort();
    }

    PBYTE data = new BYTE[file_length];
    file.seekg(file.beg);
    file.read(reinterpret_cast<char*>(data), file_length);

    status = BCryptOpenAlgorithmProvider(
        &hAlg,
        BCRYPT_SHA256_ALGORITHM,
        nullptr,
        0);

    if (NT_SUCCESS(status))
    {
        status = BCryptGetProperty(
            hAlg,
            BCRYPT_OBJECT_LENGTH,
            reinterpret_cast<PBYTE>(&cbObject),
            sizeof(DWORD),
            &cbData,
            0);
    }
    else
    {
        abort();
    }

    pbObject = reinterpret_cast<PBYTE>(
        HeapAlloc(GetProcessHeap(), 0, cbObject));

    if (!pbObject)
    {
        abort();
    }

    if (NT_SUCCESS(status))
    {
        status = BCryptGetProperty(
            hAlg,
            BCRYPT_HASH_LENGTH,
            reinterpret_cast<PBYTE>(&cbHash),
            sizeof(DWORD),
            &cbData,
            0);
    }
    else
    {
        abort();
    }

    pbHash = reinterpret_cast<PBYTE>(
        HeapAlloc(GetProcessHeap(), 0, cbHash));

    if (!pbHash)
    {
        abort();
    }

    if (NT_SUCCESS(status))
    {
        status = BCryptCreateHash(
            hAlg,
            &hHash,
            pbObject,
            cbObject,
            nullptr,
            0,
            0);
    }
    else
    {
        abort();
    }

    if (NT_SUCCESS(status))
    {
        status = BCryptHashData(
            hHash,
            (PBYTE)(data),
            sizeof(data),
            0);
    }
    else
    {
        abort();
    }

    if (NT_SUCCESS(status))
    {
        status = BCryptFinishHash(
            hHash,
            pbHash,
            cbHash,
            0);
    }
    else
    {
        abort();
    }

    std::cout << ByteToHex(pbHash, cbHash).c_str();
    delete[] data;

    if (hAlg) BCryptCloseAlgorithmProvider(hAlg, 0);
    if (hHash) BCryptDestroyHash(hHash);
    if (pbHash) HeapFree(GetProcessHeap(), 0, pbHash);
    if (pbObject) HeapFree(GetProcessHeap(), 0, pbObject);
    return 0;
}
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
0
649
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

При вызове read или write это одна из немногих ситуаций, когда можно использовать reinterpret_cast. В некоторых случаях нет другого жизнеспособного решения.

Итак, для вашего случая:

file.read(reinterpret_cast<char*>(data), file_length);

Вычисленный хэш по-прежнему неверен, так же, как если бы я читал как char. Знаете ли вы, почему вычисленный хэш неверен?

user11157650 08.04.2019 09:19

@zebanovich Возможно, проблема не в чтении? Может проблема в данных? Возможно, проблема в has-вычислении? Пожалуйста, задайте об этом вопрос новый.

Some programmer dude 08.04.2019 09:25

Спасибо! Ваше решение работает, и я обнаружил, что проблема с моим кодом заключалась в том, что я хэшировал только первый BYTE вместо записи file_lenght :)

user11157650 08.04.2019 09:37

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