Generieren Sie SHA-Hash in C ++ mithilfe der OpenSSL-Bibliothek


74

Wie kann ich mit der OpenSSL- Bibliothek SHA1- oder SHA2-Hashes generieren?

Ich habe bei Google gesucht und konnte keinen Funktions- oder Beispielcode finden.

Antworten:


81

Über die Befehlszeile ist es einfach:

printf "compute sha1" | openssl sha1

Sie können die Bibliothek folgendermaßen aufrufen:

#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
Vergessen Sie nicht, gegen libcrypto und libssl zu verlinken
AbiusX

6
Verwenden Sie SHA256 (ibuf, strlen (ibuf), obuf); es ist sicherer.
HighLife

8
In C ++ gibt Ihr Code ::: 'strlen': Parameter 1 kann nicht von 'unsigned char [13]' in 'const char *' konvertiert werden
Robel Sharma

3
Das Befehlszeilenbeispiel ist unvollständig. Damit echo den nachfolgenden Zeilenumbruch unterdrückt, sollten Sie '-n' wie folgt hinzufügen: echo -n "compute sha1" | openssl sha1
matt bezark

8
Keine Ahnung, warum diese Antwort akzeptiert wurde, weil sie nicht kompiliert wird.

59

OpenSSL hat eine schreckliche Dokumentation ohne Codebeispiele, aber hier sind Sie:

#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;
}

Verwendung:

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

Danach mdenthält die binäre SHA-256 Message Digest. Ein ähnlicher Code kann für die anderen Mitglieder der SHA-Familie verwendet werden. Ersetzen Sie einfach "256" im Code.

Wenn Sie größere Daten haben, sollten Sie natürlich Datenblöcke bei ihrem Eintreffen füttern (mehrere SHA256_UpdateAnrufe).


2
Der Code ist gut, lässt jedoch die Überprüfung des Rückgabewerts aus. Es könnte seit seinem Code mit hoher Integrität verbessert werden. Viele Leute werden es kopieren / einfügen, ohne nachzudenken oder zu überprüfen.
Jww

Es gibt keinen Rückgabewert. Schauen Sie sich einfach die verknüpfte Dokumentation an.
AndiDog

9
Hmm, eigentlich beschreibt mein Link die Rückgabewerte, aber die, die ich beim Googeln gefunden habe, haben es nicht getan. Aktualisiert den Beispielcode. (Natürlich ist das Kopieren ohne nachzudenken nicht mein Problem, sondern ein branchenweites Problem;)
AndiDog

3

Die korrekte Syntax in der Befehlszeile sollte lauten

echo -n "compute sha1" | openssl sha1

Andernfalls wird auch das nachfolgende Zeilenumbruchzeichen gehasht.


3

Anpassung der @ AndiDog-Version für große Dateien:

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();
}

1

Hier ist ein OpenSSL- Beispiel für die Berechnung des sha-1- Digests mit 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;
    }
}

Es ist zwar länger als nur das Aufrufen von SHA1Funktionen aus OpenSSL , aber es ist universeller und kann für die Verwendung mit Dateistreams überarbeitet werden (wodurch Daten beliebiger Länge verarbeitet werden).


0

C-Version des @ Nofe-Codes, die SHA1-Hash aus der Datei generiert:

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

static const int K_READ_BUF_SIZE = { 1024 * 16 };
unsigned char* calculateSHA1(char *filename)
{
    if (!filename) {
        return NULL;
    }

    FILE *fp = fopen(filename, "rb");
    if (fp == NULL) {
        return NULL;
    }

    unsigned char* sha1_digest = malloc(sizeof(char)*SHA_DIGEST_LENGTH);
    SHA_CTX context;

    if(!SHA1_Init(&context))
        return NULL;

    unsigned char buf[K_READ_BUF_SIZE];
    while (!feof(fp))
    {
        size_t total_read = fread(buf, 1, sizeof(buf), fp);
        if(!SHA1_Update(&context, buf, total_read))
        {
            return NULL;
        }
    }
    fclose(fp);

    if(!SHA1_Final(sha1_digest, &context))
        return NULL;

    return sha1_digest;
}

Es kann wie folgt verwendet werden:

unsigned char *sha1digest = calculateSHA1("/tmp/file1");

Die Variable res enthält den sha1-Hash.

Sie können es mit der folgenden for-Schleife auf dem Bildschirm drucken:

char *sha1hash = (char *)malloc(sizeof(char) * 41);
sha1hash[41] = '\0';
int i;
for (i = 0; i < SHA_DIGEST_LENGTH; i++)
{
    sprintf(&sha1hash[i*2], "%02x", sha1digest[i]);
}
printf("SHA1 HASH: %s\n", sha1hash);
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.