【问题标题】:How to create a md5 hash of a string in C?如何在 C 中创建字符串的 md5 哈希?
【发布时间】:2011-11-29 11:23:15
【问题描述】:

我发现了一些由以下原型组成的 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]);

【问题讨论】:

    标签: c md5


    【解决方案1】:

    我不知道这个特定的库,但我使用过非常相似的调用。所以这是我最好的猜测:

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

    【讨论】:

    • 好主意,展示了哈希到字符串的转换。
    • 嗯,我收到error: storage size of ‘context’ isn’t known 我包括#include &lt;openssl/md5.h&gt;
    • 感谢回复,我用了这个例子:stackoverflow.com/questions/1220046/…
    • 我得到了相同的答案,但在我的路径中似乎找不到 openssl/md5.h。​​
    • 再一次,我的回复与 openssl 无关。
    【解决方案2】:

    这是一个完整的例子:

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

    【讨论】:

    • 注意,sprintf 中使用16*2 无效,应使用3 代替(假设out 足够大)。
    • MD5_Update 以字节为单位获取长度。您也可以使用MD5(str, strlen(str), digest);,因为您事先知道长度。 (根据其手册页,MD5 在所有 OpenSSL 版本中都可用)。
    【解决方案3】:

    正如其他答案所提到的,以下调用将计算哈希:

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

    【讨论】:

      【解决方案4】:

      说实话,原型附带的 cmets 看起来已经足够清晰了。像这样的东西应该可以解决问题:

      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 摘要。

      【讨论】:

        【解决方案5】:

        看来你应该

        • 创建一个struct MD5context 并将其传递给MD5Init 以使其进入正确的启动条件
        • 使用上下文和您的数据致电 MD5Update
        • 调用MD5Final 以获取生成的哈希

        这三个函数和结构定义为哈希算法提供了一个很好的抽象接口。我不确定为什么你会在该标题中看到核心转换函数,因为你可能不应该直接与它交互。

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

        【讨论】:

          【解决方案6】:

          所有现有答案都使用deprecatedMD5Init()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);
          }
          

          【讨论】:

          • 这条线是做什么用的?常量 EVP_MD *md = EVP_md5();
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2011-12-20
          • 2015-01-05
          • 2012-10-10
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-07-12
          相关资源
          最近更新 更多