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.

Uli Köhler
quelle

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

Brianegge
quelle
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).

AndiDog
quelle
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.

Mecano
quelle
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();
}
Nayfe
quelle
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).

anton_rh
quelle
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);
Alan CN
quelle