Wie erstelle ich einen MD5-Hash einer Zeichenfolge in C?

Lesezeit: 5 Minuten

Ich habe md5-Code gefunden, der aus den folgenden Prototypen besteht …

Ich habe versucht herauszufinden, wo ich die Zeichenfolge ablegen muss, die ich hashen möchte, welche Funktionen ich aufrufen muss und wo ich die Zeichenfolge finden kann, nachdem sie gehasht wurde. Ich bin verwirrt darüber, was der uint32 buf[4] und uint32-Bit[2] sind in der Struktur.

struct MD5Context {
    uint32 buf[4];
    uint32 bits[2];
    unsigned char in[64];
};

/*
 * Start MD5 accumulation.  Set bit count to 0 and buffer to mysterious
 * initialization constants.
 */
void MD5Init(struct MD5Context *context);

/*
 * Update context to reflect the concatenation of another buffer full
 * of bytes.
 */
void MD5Update(struct MD5Context *context, unsigned char const *buf, unsigned len);

/*
 * Final wrapup - pad to 64-byte boundary with the bit pattern 
 * 1 0* (64-bit count of bits processed, MSB-first)
 */
void MD5Final(unsigned char digest[16], struct MD5Context *context);

/*
 * The core of the MD5 algorithm, this alters an existing MD5 hash to
 * reflect the addition of 16 longwords of new data.  MD5Update blocks
 * the data and converts bytes into longwords for this routine.
 */
void MD5Transform(uint32 buf[4], uint32 const in[16]);

Ich kenne diese spezielle Bibliothek nicht, aber ich habe sehr ähnliche Aufrufe verwendet. Also das ist meine beste Vermutung:

unsigned char digest[16];
const char* string = "Hello World";
struct MD5Context context;
MD5Init(&context);
MD5Update(&context, string, strlen(string));
MD5Final(digest, &context);

Dadurch erhalten Sie eine ganzzahlige Darstellung des Hashs zurück. Sie können dies dann in eine Hex-Darstellung umwandeln, wenn Sie es als Zeichenfolge weitergeben möchten.

char md5string[33];
for(int i = 0; i < 16; ++i)
    sprintf(&md5string[i*2], "%02x", (unsigned int)digest[i]);

  • Netter Gedanke, der die Umwandlung des Hashs in eine Zeichenfolge zeigt.

    – dmckee — Ex-Moderator-Kätzchen

    2. Oktober 2011 um 16:54 Uhr

  • Hm, ich bekomme error: storage size of ‘context’ isn’t known Ich schließe ein #include <openssl/md5.h>

    – SSH Dies

    1. März 2012 um 21:58 Uhr


  • Danke für die Antwort, ich habe dieses Beispiel verwendet: stackoverflow.com/questions/1220046/…

    – SSH Dies

    2. März 2012 um 15:58 Uhr

  • Ich bekomme die gleiche Antwort, aber openssl/md5.h scheint nicht in meinem Pfad gefunden zu werden.

    – vmonteco

    1. Juni 2015 um 13:48 Uhr

  • Auch hier bezog sich meine Antwort nicht auf openssl.

    – Chris Eberle

    24. Juli 2015 um 16:29 Uhr

Hier ist ein vollständiges Beispiel:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if defined(__APPLE__)
#  define COMMON_DIGEST_FOR_OPENSSL
#  include <CommonCrypto/CommonDigest.h>
#  define SHA1 CC_SHA1
#else
#  include <openssl/md5.h>
#endif

char *str2md5(const char *str, int length) {
    int n;
    MD5_CTX c;
    unsigned char digest[16];
    char *out = (char*)malloc(33);

    MD5_Init(&c);

    while (length > 0) {
        if (length > 512) {
            MD5_Update(&c, str, 512);
        } else {
            MD5_Update(&c, str, length);
        }
        length -= 512;
        str += 512;
    }

    MD5_Final(digest, &c);

    for (n = 0; n < 16; ++n) {
        snprintf(&(out[n*2]), 16*2, "%02x", (unsigned int)digest[n]);
    }

    return out;
}

    int main(int argc, char **argv) {
        char *output = str2md5("hello", strlen("hello"));
        printf("%s\n", output);
        free(output);
        return 0;
    }

  • Vorsicht, die Verwendung von 16*2 in sprintf ungültig ist, sollten Sie verwenden 3 stattdessen (vorausgesetzt, dass out groß genug ist).

    – Lekenstein

    27. November 2013 um 16:37 Uhr

  • MD5_Update nimmt die Länge in Einheiten von Bytes an. Sie können auch verwenden MD5(str, strlen(str), digest); da Sie die Länge vorher kennen. (MD5 ist in allen OpenSSL-Versionen gemäß seiner Handbuchseite verfügbar).

    – Lekenstein

    27. November 2013 um 16:49 Uhr


Wie andere Antworten bereits erwähnt haben, berechnen die folgenden Aufrufe den Hash:

MD5Context md5;
MD5Init(&md5);
MD5Update(&md5, data, datalen);
MD5Final(digest, &md5);

Der Zweck der Aufteilung in so viele Funktionen besteht darin, dass Sie große Datensätze streamen können.

Wenn Sie beispielsweise eine 10-GB-Datei hashen und sie nicht in den RAM passt, gehen Sie wie folgt vor. Sie würden die Datei in kleineren Stücken lesen und anrufen MD5Update auf sie.

MD5Context md5;
MD5Init(&md5);

fread(/* Read a block into data. */)
MD5Update(&md5, data, datalen);

fread(/* Read the next block into data. */)
MD5Update(&md5, data, datalen);

fread(/* Read the next block into data. */)
MD5Update(&md5, data, datalen);

...

//  Now finish to get the final hash value.
MD5Final(digest, &md5);

Um ehrlich zu sein, scheinen die Kommentare zu den Prototypen klar genug zu sein. So etwas sollte den Zweck erfüllen:

void compute_md5(char *str, unsigned char digest[16]) {
    MD5Context ctx;
    MD5Init(&ctx);
    MD5Update(&ctx, str, strlen(str));
    MD5Final(digest, &ctx);
}

wo str ist ein C-String, von dem Sie den Hash haben möchten, und digest ist der resultierende MD5-Verdau.

Es scheint, dass Sie sollten

  • Ein … kreieren struct MD5context und übergebe es an MD5Init um es in einen guten Startzustand zu bringen
  • Anruf MD5Update mit dem Kontext und Ihren Daten
  • Anruf MD5Final um den resultierenden Hash zu erhalten

Diese drei Funktionen und die Strukturdefinition bilden eine schöne abstrakte Schnittstelle zum Hash-Algorithmus. Ich bin mir nicht sicher, warum Ihnen die Kerntransformationsfunktion in diesem Header angezeigt wurde, da Sie wahrscheinlich nicht direkt damit interagieren sollten.

Der Autor hätte die Implementierung ein wenig mehr verstecken können, indem er die Struktur zu einem abstrakten Typ gemacht hätte, aber dann wären Sie gezwungen gewesen, die Struktur jedes Mal auf dem Haufen zuzuordnen (im Gegensatz zu jetzt, wo Sie sie auf den Stapel legen können, wenn Sie dies tun Verlangen).

Benutzeravatar von devtty1er
devtty1er

Alle vorhandenen Antworten verwenden die veraltet MD5Init(), MD5Update()und MD5Final().

Verwenden Sie stattdessen EVP_DigestInit_ex(), EVP_DigestUpdate()und EVP_DigestFinal_ex()z.B

// example.c
//
// gcc example.c -lssl -lcrypto -o example

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

void bytes2md5(const char *data, int len, char *md5buf) {
  // Based on https://www.openssl.org/docs/manmaster/man3/EVP_DigestUpdate.html
  EVP_MD_CTX *mdctx = EVP_MD_CTX_new();
  const EVP_MD *md = EVP_md5();
  unsigned char md_value[EVP_MAX_MD_SIZE];
  unsigned int md_len, i;
  EVP_DigestInit_ex(mdctx, md, NULL);
  EVP_DigestUpdate(mdctx, data, len);
  EVP_DigestFinal_ex(mdctx, md_value, &md_len);
  EVP_MD_CTX_free(mdctx);
  for (i = 0; i < md_len; i++) {
    snprintf(&(md5buf[i * 2]), 16 * 2, "%02x", md_value[i]);
  }
}

int main(void) {
  const char *hello = "hello";
  char md5[33]; // 32 characters + null terminator
  bytes2md5(hello, strlen(hello), md5);
  printf("%s\n", md5);
}

1390300cookie-checkWie erstelle ich einen MD5-Hash einer Zeichenfolge in C?

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

Privacy policy