Створіть хеш SHA в C ++ за допомогою бібліотеки OpenSSL


Відповіді:


82

З командного рядка це просто:

printf "compute sha1" | openssl sha1

Ви можете викликати бібліотеку так:

#include <stdio.h>
#include <string.h>
#include <openssl/sha.h>

int main()
{
    unsigned char ibuf[] = "compute sha1";
    unsigned char obuf[20];

    SHA1(ibuf, strlen(ibuf), obuf);

    int i;
    for (i = 0; i < 20; i++) {
        printf("%02x ", obuf[i]);
    }
    printf("\n");

    return 0;
}


8
не забудьте встановити посилання проти libcrypto та libssl
AbiusX

6
Використовуйте SHA256 (ibuf, strlen (ibuf), obuf) ;, це більш безпечно.
HighLife

8
в c ++ ваш код give ::: 'strlen': не вдається перетворити параметр 1 із 'unsigned char [13]' в 'const char *'
Robel Sharma

3
приклад командного рядка неповний. для того, щоб echo придушував кінцевий новий рядок, слід додати '-n' як у: echo -n "обчислити sha1" | openssl sha1
matt bezark

8
Не знаю, чому цю відповідь прийняли, оскільки вона не компілюється.

61

OpenSSL має жахливу документацію без прикладів коду, але ось ви:

#include <openssl/sha.h>

bool simpleSHA256(void* input, unsigned long length, unsigned char* md)
{
    SHA256_CTX context;
    if(!SHA256_Init(&context))
        return false;

    if(!SHA256_Update(&context, (unsigned char*)input, length))
        return false;

    if(!SHA256_Final(md, &context))
        return false;

    return true;
}

Використання:

unsigned char md[SHA256_DIGEST_LENGTH]; // 32 bytes
if(!simpleSHA256(<data buffer>, <data length>, md))
{
    // handle error
}

Згодом mdбуде містити двійковий дайджест повідомлення SHA-256. Подібний код можна використовувати для інших членів сім'ї SHA, просто замініть "256" у коді.

Якщо у вас є більші дані, ви, звичайно, повинні подавати фрагменти даних у міру надходження (кілька SHA256_Updateдзвінків).


2
Код хороший, але він опускає перевірку поверненого значення. Він може бути вдосконалений завдяки коду високої цілісності. Багато людей скопіюють / вставлять його, не думаючи та не перевіряючи.
jww

Поверненого значення немає. Просто перегляньте пов'язану документацію.
AndiDog

9
Хм, насправді моє посилання описує повернені значення, але ті, які я знайшов за допомогою googling, ні. Оновить приклад коду. (Звичайно, копіювання людей без роздумів - це не моя проблема, а більше загальноосвітня проблема;)
AndiDog

4

Адаптація версії @AndiDog для великого файлу:

static const int K_READ_BUF_SIZE{ 1024 * 16 };

std::optional<std::string> CalcSha256(std::string filename)
{
    // Initialize openssl
    SHA256_CTX context;
    if(!SHA256_Init(&context))
    {
        return std::nullopt;
    }

    // Read file and update calculated SHA
    char buf[K_READ_BUF_SIZE];
    std::ifstream file(filename, std::ifstream::binary);
    while (file.good())
    {
        file.read(buf, sizeof(buf));
        if(!SHA256_Update(&context, buf, file.gcount()))
        {
            return std::nullopt;
        }
    }

    // Get Final SHA
    unsigned char result[SHA256_DIGEST_LENGTH];
    if(!SHA256_Final(result, &context))
    {
        return std::nullopt;
    }

    // Transform byte-array to string
    std::stringstream shastr;
    shastr << std::hex << std::setfill('0');
    for (const auto &byte: result)
    {
        shastr << std::setw(2) << (int)byte;
    }
    return shastr.str();
}

3

правильний синтаксис у командному рядку повинен бути

echo -n "compute sha1" | openssl sha1

інакше ви також хешуєте кінцевий символ нового рядка.


1

Ось приклад OpenSSL обчислення дайджесту sha-1 за допомогою BIO :

#include <openssl/bio.h>
#include <openssl/evp.h>

std::string sha1(const std::string &input)
{
    BIO * p_bio_md  = nullptr;
    BIO * p_bio_mem = nullptr;

    try
    {
        // make chain: p_bio_md <-> p_bio_mem
        p_bio_md = BIO_new(BIO_f_md());
        if (!p_bio_md) throw std::bad_alloc();
        BIO_set_md(p_bio_md, EVP_sha1());

        p_bio_mem = BIO_new_mem_buf((void*)input.c_str(), input.length());
        if (!p_bio_mem) throw std::bad_alloc();
        BIO_push(p_bio_md, p_bio_mem);

        // read through p_bio_md
        // read sequence: buf <<-- p_bio_md <<-- p_bio_mem
        std::vector<char> buf(input.size());
        for (;;)
        {
            auto nread = BIO_read(p_bio_md, buf.data(), buf.size());
            if (nread  < 0) { throw std::runtime_error("BIO_read failed"); }
            if (nread == 0) { break; } // eof
        }

        // get result
        char md_buf[EVP_MAX_MD_SIZE];
        auto md_len = BIO_gets(p_bio_md, md_buf, sizeof(md_buf));
        if (md_len <= 0) { throw std::runtime_error("BIO_gets failed"); }

        std::string result(md_buf, md_len);

        // clean
        BIO_free_all(p_bio_md);

        return result;
    }
    catch (...)
    {
        if (p_bio_md) { BIO_free_all(p_bio_md); }
        throw;
    }
}

Хоча це довше, ніж просто виклик SHA1функції з OpenSSL , але вона є більш універсальною і може бути перероблена для використання з потоками файлів (таким чином, обробка даних будь-якої довжини).


0

C версія коду @Nayfe, що генерує хеш SHA1 з файлу:

Його можна використовувати наступним чином:

У дозволі змінна містить SHA1 хеш.

Ви можете роздрукувати його на екрані, використовуючи такий цикл for:

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.