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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7627723/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 09:47:14  来源:igfitidea点击:

How to create a md5 hash of a string in C?

cmd5

提问by Takkun

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

回答by Chris Eberle

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

回答by todd

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

回答by Mysticial

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. You would read the file in smaller chunks and call MD5Updateon them.

例如,如果您正在对一个 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);

回答by NPE

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 stris a C string you want the hash of, and digestis the resulting MD5 digest.

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

回答by dmckee --- ex-moderator kitten

It would appear that you should

看起来你应该

  • Create a struct MD5contextand pass it to MD5Initto get it into a proper starting condition
  • Call MD5Updatewith the context and your data
  • Call MD5Finalto get the resulting hash
  • 创建一个struct MD5context并将其传递MD5Init给以使其进入正确的起始条件
  • MD5Update使用上下文和您的数据调用
  • 调用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).

作者本可以通过使结构成为抽象类型来隐藏更多的实现,但是这样你每次都将被迫在堆上分配结构(而不​​是现在你可以把它放在堆栈上,如果你这样做的话欲望)。

回答by devtty1er

All of the existing answers use the deprecatedMD5Init(), MD5Update(), and MD5Final().

现有的所有答案都使用过时MD5Init()MD5Update()MD5Final()

Instead, use EVP_DigestInit_ex(), EVP_DigestUpdate(), and EVP_DigestFinal_ex(), e.g.

相反,使用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);
}