簡體   English   中英

如何在C中創建字符串的md5哈希?

[英]How to create a md5 hash of a string in C?

我發現了一些由以下原型組成的 md5 代碼......

我一直試圖找出我必須將要散列的字符串放在哪里,需要調用哪些函數,以及在散列后在哪里可以找到該字符串。 我對 uint32 buf[4] 和 uint32 bits[2] 在結構中的內容感到困惑。

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]);

我不知道這個特定的庫,但我使用過非常相似的調用。 所以這是我最好的猜測:

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

這會給你一個散列的整數表示。 如果您想將其作為字符串傳遞,則可以將其轉換為十六進制表示。

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

這是一個完整的例子:

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

正如其他答案所提到的,以下調用將計算散列:

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

將其拆分為多個函數的目的是讓您流式傳輸大型數據集。

例如,如果您正在對一個 10GB 的文件進行哈希處理並且它不適合 ram,那么您將如何進行此操作。 您可以以較小的塊讀取文件並對它們調用MD5Update

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

老實說,原型附帶的評論似乎很清楚。 像這樣的事情應該可以解決問題:

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

其中str是您想要散列的 C 字符串, digest是生成的 MD5 摘要。

看起來你應該

  • 創建一個struct MD5context並將其傳遞給MD5Init以使其進入正確的啟動條件
  • 使用上下文和您的數據調用MD5Update
  • 調用MD5Final獲取結果哈希

這三個函數和結構定義為散列算法提供了一個很好的抽象接口。 我不確定為什么在該標題中向您顯示核心轉換函數,因為您可能不應該直接與其交互。

作者本可以通過使結構成為抽象類型來隱藏更多的實現,但是這樣你每次都將被迫在堆上分配結構(而不​​是現在你可以將它放在堆棧上,如果你這樣做的話)欲望)。

所有現有答案都使用已棄用的MD5Init()MD5Update()MD5Final()

相反,使用EVP_DigestInit_ex()EVP_DigestUpdate()EVP_DigestFinal_ex() ,例如

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM