【问题标题】:Updating an MD5 Hash?更新 MD5 哈希?
【发布时间】:2016-12-26 00:15:44
【问题描述】:

我目前有一个非常基本的 MD5 哈希算法在工作。 (我只能调用 atm 是 MD5(const char*))但是,它将仅限于小文件。即 32 位系统最多只能给我 4GB 或更少的文件。再加上为什么我想将任何接近 1GB 的东西加载到内存中。 ;) 所以这让我想到了这个问题......

如何散列大文件?我注意到 OpenSSL(我将在将来的某个时间使用)在将文件的一部分加载到内存时使用 MD5 哈希更新函数。那么当“更新”一个 MD5 哈希时究竟会发生什么?互联网上是否有执行此操作的伪代码或任何地方的示例?

P.S 我对加密世界有点陌生。因此,如果我对任何人的回答提出任何后续问题,请原谅我。在我采取简单的方法之前,喜欢先尝试困难的方法。最好的学习方式! ;)

我的 MD5 标头

    #ifndef MD5_H
    #define MD5_H

    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    #include <math.h>
    #include <ctype.h>

    #define MAX_MD5_HASH_LENGTH 32


    typedef union uwb {
        unsigned w;
        unsigned char b[4];
    } WBunion;

    typedef unsigned Digest[4];

    unsigned f0( unsigned abcd[] );

    unsigned f1( unsigned abcd[] );

    unsigned f2( unsigned abcd[] );

    unsigned f3( unsigned abcd[] );

    typedef unsigned (*DgstFctn)(unsigned a[]);

    unsigned *calcKs( unsigned *k);
    unsigned rol( unsigned v, short amt );
    unsigned *md5( const char *msg, int mlen);

    char* convertRawMd5HashToString(unsigned* rawMd5);
    int isValidMd5(const char* md5String);

    #endif

源文件

#include "md5.h"

unsigned *calcKs( unsigned *k)
{
    double s, pwr;
    int i;

    pwr = pow( 2, MAX_MD5_HASH_LENGTH);
    for (i=0; i<64; i++) {
        s = fabs(sin(1+i));
        k[i] = (unsigned)( s * pwr );
    }
    return k;
}

// ROtate v Left by amt bits
unsigned rol( unsigned v, short amt )
{
    unsigned  msk1 = (1<<amt) -1;
    return ((v>>(MAX_MD5_HASH_LENGTH-amt)) & msk1) | ((v<<amt) & ~msk1);
}

unsigned *md5( const char *message, int messageLength) 
{
    static const Digest h0 = { 0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476 };
    static const DgstFctn ff[] = { &f0, &f1, &f2, &f3 };
    static const short M[] = { 1, 5, 3, 7 };
    static const short O[] = { 0, 1, 5, 0 };
    static const short rot0[] = { 7,12,17,22};
    static const short rot1[] = { 5, 9,14,20};
    static const short rot2[] = { 4,11,16,23};
    static const short rot3[] = { 6,10,15,21};
    static const short *rots[] = {rot0, rot1, rot2, rot3 };
    static unsigned kspace[64];
    static unsigned *k;

    static Digest h;
    Digest abcd;
    DgstFctn fctn;
    short m, o, g;
    unsigned f;
    short *rotn;
    union {
        unsigned w[16];
        char     b[64];
    }mm;
    int os = 0;
    int grp, grps, q, p;
    unsigned char *msg2;

    if (k==NULL) k= calcKs(kspace);

    for (q=0; q<4; q++) h[q] = h0[q];   // initialize
    {
        grps  = 1 + (messageLength+8)/64;
        msg2 = malloc( 64*grps);
        memcpy( msg2, message, messageLength);
        msg2[messageLength] = (unsigned char)0x80;  
        q = messageLength + 1;
        while (q < 64*grps){ msg2[q] = 0; q++ ; }
        {
            WBunion u;
            u.w = 8*messageLength;
            q -= 8;
            memcpy(msg2+q, &u.w, 4 );
        }
    }

    for (grp=0; grp<grps; grp++)
    {
        memcpy( mm.b, msg2+os, 64);
        for(q=0;q<4;q++) abcd[q] = h[q];
        for (p = 0; p<4; p++) {
            fctn = ff[p];
            rotn = rots[p];
            m = M[p]; o= O[p];
            for (q=0; q<16; q++) {
                g = (m*q + o) % 16;
                f = abcd[1] + rol( abcd[0]+ fctn(abcd) + k[q+16*p] + mm.w[g], rotn[q%4]);

                abcd[0] = abcd[3];
                abcd[3] = abcd[2];
                abcd[2] = abcd[1];
                abcd[1] = f;
            }
        }
        for (p=0; p<4; p++)
            h[p] += abcd[p];
        os += 64;
    }

    if( msg2 )
        free( msg2 );

    return h;
}

char* convertRawMd5HashToString(unsigned* rawMd5)
{
    static char* outputBuffer[MAX_MD5_HASH_LENGTH];
    memset(outputBuffer, 0, MAX_MD5_HASH_LENGTH);

    int j, k;
    WBunion u;
    for (j=0;j<4; j++){
        u.w = rawMd5[j];
        for (k=0;k<4;k++) sprintf(outputBuffer, "%s%02x", outputBuffer, u.b[k]);
    }

    return outputBuffer;
}

unsigned f0( unsigned abcd[] ){
    return ( abcd[1] & abcd[2]) | (~abcd[1] & abcd[3]); }

unsigned f1( unsigned abcd[] ){
    return ( abcd[3] & abcd[1]) | (~abcd[3] & abcd[2]);}

unsigned f2( unsigned abcd[] ){
    return  abcd[1] ^ abcd[2] ^ abcd[3];}

unsigned f3( unsigned abcd[] ){
    return abcd[2] ^ (abcd[1] |~ abcd[3]);}

int isValidMd5(const char* md5String)
{
    if(strlen(md5String) != MAX_MD5_HASH_LENGTH)
        return 0;

    for (int i = 0; i < MAX_MD5_HASH_LENGTH; ++i) {
        char c = tolower(md5String[i]);
        if((c >= 'a' && c <= 'f') || isdigit(c)) {
            continue;
        } else {
            return 0;
        }
    }

    return 1;
}

我找不到原作者,但如果有人知道这篇 sn-p 的大部分内容是谁写的,请告诉我。谢谢。 :)

【问题讨论】:

  • 您是否尝试将文件分成块/块(如 128 字节的块)并将它们连续或并行提供给 MD5。也许您应该查看此主题以获得更多帮助,link
  • @ajm113 你为什么要声明static char* outputBuffer[MAX_MD5_HASH_LENGTH]; ??你不需要一个指向char的指针数组,你需要一个char数组
  • 为什么是memcpy( msg2, message, messageLength);,这会使内存占用加倍。这确实不是好代码。
  • @ajm113 请谨慎使用此代码。它来自Rosettacode-MD5,带有警告“需要审查 - 与 openssl 实现相比观察到最后 8 个字符的差异”。
  • 次要:避免使用UB,使用unsigned msk1 = (1u&lt;&lt;amt) -1;(添加u)。

标签: c md5


【解决方案1】:

填充发生在第一个 for 循环中,您需要将其推迟到数据末尾。然后你可以通过第二个 for 循环运行尽可能多的数据,直到你到达最后,然后添加填充。这也将允许代码进行更改,以便在不需要制作数据时进行复制。将其拆分为 init、update 和 finalize 函数。编写代码应该不难。

当然更好的办法是使用已经将函数拆分为 init、update、finalize 的版本。有趣的是,Apple Common Crypto 是开源的,并且是用“C”编写的,看看吧。 MD code 代码在CommonDigestPriv.h

【讨论】:

  • 非常酷,谢谢!我认为最好还是简单地重写我当前的实现,然后再做任何进一步的事情之前看看一些合法的更好的实现。
猜你喜欢
  • 2016-01-03
  • 2012-08-17
  • 1970-01-01
  • 2020-12-08
  • 1970-01-01
  • 1970-01-01
  • 2014-05-19
  • 1970-01-01
相关资源
最近更新 更多