简体   繁体   English

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

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

I've found some md5 code that consists of the following prototypes...我发现了一些由以下原型组成的 md5 代码......

I've been trying to find out where I have to put the string I want to hash, what functions I need to call, and where to find the string once it has been hashed.我一直试图找出我必须将要散列的字符串放在哪里,需要调用哪些函数,以及在散列后在哪里可以找到该字符串。 I'm confused with regards to what the uint32 buf[4] and uint32 bits[2] are in the struct.我对 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]);

I don't know this particular library, but I've used very similar calls.我不知道这个特定的库,但我使用过非常相似的调用。 So this is my best guess:所以这是我最好的猜测:

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

This will give you back an integer representation of the hash.这会给你一个散列的整数表示。 You can then turn this into a hex representation if you want to pass it around as a string.如果您想将其作为字符串传递,则可以将其转换为十六进制表示。

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

Here's a complete example:这是一个完整的例子:

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

As other answers have mentioned, the following calls will compute the hash:正如其他答案所提到的,以下调用将计算散列:

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

The purpose of splitting it up into that many functions is to let you stream large datasets.将其拆分为多个函数的目的是让您流式传输大型数据集。

For example, if you're hashing a 10GB file and it doesn't fit into ram, here's how you would go about doing it.例如,如果您正在对一个 10GB 的文件进行哈希处理并且它不适合 ram,那么您将如何进行此操作。 You would read the file in smaller chunks and call MD5Update on them.您可以以较小的块读取文件并对它们调用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);

To be honest, the comments accompanying the prototypes seem clear enough.老实说,原型附带的评论似乎很清楚。 Something like this should do the trick:像这样的事情应该可以解决问题:

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

where str is a C string you want the hash of, and digest is the resulting MD5 digest.其中str是您想要散列的 C 字符串, digest是生成的 MD5 摘要。

It would appear that you should看起来你应该

  • Create a struct MD5context and pass it to MD5Init to get it into a proper starting condition创建一个struct MD5context并将其传递给MD5Init以使其进入正确的启动条件
  • Call MD5Update with the context and your data使用上下文和您的数据调用MD5Update
  • Call MD5Final to get the resulting hash调用MD5Final获取结果哈希

These three functions and the structure definition make a nice abstract interface to the hash algorithm.这三个函数和结构定义为散列算法提供了一个很好的抽象接口。 I'm not sure why you were shown the core transform function in that header as you probably shouldn't interact with it directly.我不确定为什么在该标题中向您显示核心转换函数,因为您可能不应该直接与其交互。

The author could have done a little more implementation hiding by making the structure an abstract type, but then you would have been forced to allocate the structure on the heap every time (as opposed to now where you can put it on the stack if you so desire).作者本可以通过使结构成为抽象类型来隐藏更多的实现,但是这样你每次都将被迫在堆上分配结构(而不​​是现在你可以将它放在堆栈上,如果你这样做的话)欲望)。

All of the existing answers use the deprecated MD5Init() , MD5Update() , and MD5Final() .所有现有答案都使用已弃用的MD5Init()MD5Update()MD5Final()

Instead, use EVP_DigestInit_ex() , EVP_DigestUpdate() , and EVP_DigestFinal_ex() , eg相反,使用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