Verwendung von SHA1-Hashing in der C-Programmierung

Lesezeit: 7 Minuten

Benutzer-Avatar
spassen

Ich versuche, ein C-Programm zu schreiben, das beweist, dass SHA1 nahezu kollisionsfrei ist, aber ich kann nicht herausfinden, wie ich den Hash für meine Eingabewerte tatsächlich erstellen soll. Ich muss nur den Hash erstellen und den Hex-Wert in einem Array speichern. Nach einigen Google-Suchen habe ich eine OpenSSL-Dokumentation gefunden, die mich anweist, Folgendes zu verwenden:

 #include <openssl/sha.h>

 unsigned char *SHA1(const unsigned char *d, unsigned long n,
                  unsigned char *md);

 int SHA1_Init(SHA_CTX *c);
 int SHA1_Update(SHA_CTX *c, const void *data,
                  unsigned long len);
 int SHA1_Final(unsigned char *md, SHA_CTX *c);

Ich glaube, ich sollte entweder unsigned char *SHA1 oder SHA1_Init verwenden, aber ich bin mir nicht sicher, was die Argumente wären, da x meine zu hashende Eingabe ist. Würde das bitte jemand für mich klären? Vielen Dank.

  • Was sind Ihre Eingabewerte: In-Memory-Strings oder Dateiinhalte?

    – Basile Starynkevitch

    14. Februar 2012 um 21:31 Uhr

  • Ich schreibe einen Geburtstagsangriff, der einen neuen Hash erstellen und ihn jedes Mal am Ende hinzufügen soll, wenn ich das Array durchlaufe. Ich wollte es einfach halten und den Wert von i hashen. Schnelle Antwort, in Speicherzeichenfolgen.

    – spassen

    14. Februar 2012 um 21:34 Uhr


  • Was meinst du mit “beweisen, dass SHA1 nahezu kollisionsfrei ist”? SHA1 ist ein 160-Bit-Hash, also gibt es 2 ^ 160 mögliche Werte, aber es gibt weit mehr als 2 ^ 160 mögliche Zeichenfolgen (z. B. kürzer als 1 MB), also gibt es Tonnen von Kollisionen. Wenn Sie nur testen möchten, ob Sie Kollisionen von einer Reihe zufällig generierter Zeichenfolgen erhalten, ist die Anzahl der Zeichenfolgen, die für eine halbwegs zuverlässige Antwort benötigt werden, undurchführbar hoch (es sei denn, Sie finden zufällig früh eine Kollision, aber SHA1 ist gut genug getestet, um dies zuzuweisen eine vernachlässigbar kleine Wahrscheinlichkeit).

    – Daniel Fischer

    14. Februar 2012 um 21:41 Uhr

  • Mir ist klar, dass es viele mögliche Kollisionen gibt, aber das Ziel ist zu beweisen, dass es viel Zeit in Anspruch nehmen würde, eine Kollision zu finden (etwa 2 ^ 80) und noch mehr Zeit in Anspruch nehmen würde, um eine Kollision zu finden, die einem bestimmten Hash entspricht.

    – spassen

    14. Februar 2012 um 21:44 Uhr

  • Aber realistischerweise können Sie nicht mehr als 2 ^ 34 Saiten oder so testen. Selbst wenn SHA1 so verzerrt wäre, dass Sie nur 2 ^ 50-Strings für eine Kollision benötigen würden, werden Sie es mit ziemlicher Sicherheit nicht sehen.

    – Daniel Fischer

    14. Februar 2012 um 22:10 Uhr

Benutzer-Avatar
Adam Rosenfield

Wenn Sie alle Ihre Daten auf einmal haben, verwenden Sie einfach die SHA1 Funktion:

// The data to be hashed
char data[] = "Hello, world!";
size_t length = strlen(data);

unsigned char hash[SHA_DIGEST_LENGTH];
SHA1(data, length, hash);
// hash now contains the 20-byte SHA-1 hash

Wenn Sie andererseits Ihre Daten nur Stück für Stück erhalten und den Hash berechnen möchten, während Sie diese Daten erhalten, verwenden Sie die anderen Funktionen:

// Error checking omitted for expository purposes

// Object to hold the current state of the hash
SHA_CTX ctx;
SHA1_Init(&ctx);

// Hash each piece of data as it comes in:
SHA1_Update(&ctx, "Hello, ", 7);
...
SHA1_Update(&ctx, "world!", 6);
// etc.
...
// When you're done with the data, finalize it:
unsigned char hash[SHA_DIGEST_LENGTH];
SHA1_Final(hash, &ctx);

  • Ich habe versucht, die sha1-Funktion zu verwenden, aber wenn ich im Terminal kompiliere, heißt es Undefinierter Verweis auf SHA1. Über alles andere bekomme ich keine Beschwerden. Irgendeine Ahnung, was mir fehlt?

    – spassen

    14. Februar 2012 um 22:02 Uhr

  • Sie müssen mit der OpenSSL-Laufzeitbibliothek verknüpfen. Angenommen, Sie verwenden gcc, fügen Sie hinzu -lcrypto zu Ihrer Linker-Befehlszeile.

    – Adam Rosenfield

    14. Februar 2012 um 22:33 Uhr

  • wie würde man hmacsha1 generieren?

    – Kmag

    15. Mai 2013 um 14:31 Uhr

  • Keine Fehlerbehandlung erforderlich? Für mich stürzt SHA1_Final ab, habe aber keine Ahnung warum. Gibt es eine Möglichkeit den Fehler auszudrucken?

    – BTR Naidu

    6. Mai 2016 um 11:22 Uhr

  • Wie bekommt man die hash Wert? Ich bekomme �*���qE)DDF:� �4� mit printf("<<sha1=%s>>\n", hash);

    – Kostjantyn

    11. November 2017 um 6:57 Uhr


Es sind zwei verschiedene Wege, um dasselbe zu erreichen.

Genauer gesagt, Sie entweder verwenden SHA_Initdann SHA_Update so oft wie nötig, um Ihre Daten durchzugeben und dann SHA_Final um die Zusammenfassung zu bekommen, oder Sie SHA1.

Der Grund für zwei Modi ist, dass es beim Hashen großer Dateien üblich ist, die Datei in Blöcken zu lesen, da die Alternative viel Speicher verbrauchen würde. Behalten Sie daher den Überblick SHA_CTX – Der SHA-Kontext – as you go ermöglicht es Ihnen, dies zu umgehen. Der Algorithmus passt intern auch zu diesem Modell – das heißt, Daten werden blockweise übergeben.

Das SHA Methode sollte ziemlich einfach sein. Der andere funktioniert so:

unsigned char md[SHA_DIGEST_LENGTH];
SHA_CTX context;
int SHA1_Init(&context);

for ( i = 0; i < numblocks; i++ )
{
    int SHA1_Update(&context, pointer_to_data, data_length);
}
int SHA1_Final(md, &context);

Entscheidend, am Ende md enthält den binären Digest, keine hexadezimale Darstellung – es ist keine Zeichenfolge und sollte nicht als solche verwendet werden.

  • wie würde man hmacsha1 generieren?

    – Kmag

    15. Mai 2013 um 14:47 Uhr

  • @Clustermagnet hmacsha1 ist ein HMAC-Algorithmus, der SHA1 als Hash verwendet. Es ist die gleiche Idee wie in meiner Antwort hier (siehe hier) sondern für die EVP_MD HMAC-spezifisches Argument, das Sie angeben EVP_sha1().

    Benutzer257111

    15. Mai 2013 um 15:12 Uhr

  • @Cmag – siehe EVP Signieren und Verifizieren | HMAC im OpenSSL-Wiki. Siehe auch Verwenden von HMAC vs. EVP-Funktionen in OpenSSL auf Stack Overflow.

    – jww

    13. Juni 2016 um 0:11 Uhr

Die erste Funktion (SHA1()) die übergeordnete ist, ist es wahrscheinlich die, die Sie wollen. Das Dokument ist ziemlich klar in Bezug auf die Verwendung – d eingegeben wird, n ist seine Größe u md Hier wird das Ergebnis platziert (Sie weisen es zu).

Was die anderen 3 Funktionen betrifft – diese sind niedriger und ich bin mir ziemlich sicher, dass sie intern von der ersten verwendet werden. Sie eignen sich besser für größere Eingaben, die blockweise verarbeitet werden müssen.

Ich glaube, ich sollte beide verwenden unsigned char *SHA1 oder SHA1_Init

Für spätere Versionen der OpenSSL-Bibliothek, wie 1.0.2 und 1.1.0, empfiehlt das Projekt die Verwendung der EVP-Schnittstelle. Ein Anwendungsbeispiel EVP-Nachrichtenzusammenfassungen mit SHA256 ist im OpenSSL-Wiki verfügbar:

#define handleErrors abort

EVP_MD_CTX *ctx;

if((ctx = EVP_MD_CTX_create()) == NULL)
    handleErrors();

if(1 != EVP_DigestInit_ex(ctx, EVP_sha256(), NULL))
    handleErrors();

unsigned char message[] = "abcd .... wxyz";
unsinged int message_len = sizeof(message);

if(1 != EVP_DigestUpdate(ctx, message, message_len))
    handleErrors();

unsigned char digest[EVP_MAX_MD_SIZE];
unsigned int digest_len = sizeof(digest);

if(1 != EVP_DigestFinal_ex(ctx, digest, &digest_len))
    handleErrors();

EVP_MD_CTX_destroy(ctx);

Die Antwort von Adam Rosenfield ist in Ordnung, aber verwenden Sie strlen anstelle von sizeof, da sonst Hash einschließlich Nullterminator berechnet wird. Was in diesem Fall wahrscheinlich in Ordnung ist, aber nicht, wenn Sie Ihren Hash mit einem von einem anderen Tool generierten vergleichen müssen.

// The data to be hashed
char data[] = "Hello, world!";
size_t length = strlen(data);

unsigned char hash[SHA_DIGEST_LENGTH];
SHA1(data, length, hash);
// hash now contains the 20-byte SHA-1 hash

Benutzer-Avatar
linux_art

Berechnen Sie Hash wie folgt

// Object to hold the current state of the hash
SHA_CTX ctx;
SHA1_Init(&ctx);

// Hash each piece of data as it comes in:
SHA1_Update(&ctx, "Hello, ", 7);
...
SHA1_Update(&ctx, "world!", 6);
// etc.
...
// When you're done with the data, finalize it:
unsigned char tmphash[SHA_DIGEST_LENGTH];
SHA1_Final(tmphash, &ctx);

Schließlich können Sie Hash mit Code wie diesem in eine für Menschen lesbare Form decodieren.

unsigned char hash[SHA_DIGEST_LENGTH*2];

int i = 0;
for (i=0; i < SHA_DIGEST_LENGTH; i++) {
    sprintf((char*)&(hash[i*2]), "%02x", tmphash[i]);
}
// And print to stdout
printf("Hash: %s\n", hash);

Benutzer-Avatar
Koch Gladiator

Lassen Sie den Code sprechen

Der SQLite-Entwicklungsbaum enthält eine Quelle für das Tool DBHASH zum Anwenden von SHA1 auf ganze Datenbanken. Komplett mit SHA1-Implementierung.

Vielleicht finden Sie es machbar, diesen Code zu studieren.

ps: Gibt es auch SHA1 als SQLite-benutzerdefiniert implementiert Funktion.

1378400cookie-checkVerwendung von SHA1-Hashing in der C-Programmierung

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy