MD5

MD5(Message-Digest Algorithm)是一个信息摘要算法。其目的是把一串任意长度的输入字符串转换为128“bit”长的“信息摘要”(或称“指纹”),通常用于确保信息传输的完整性,是计算机科学广泛使用的散列算法之一。

算法描述

假设我们有一串b-bit长的输入字符,我们需要为其生成摘要。这里,输入字符串长度b是一个任意非零整数,可以是0,不一定是8的整数倍,可以任意长。
 
不妨将这个字符串标记如下:
m_0 m_1 ... m_{b-1}
MD5算法通过以下五个步骤生成目标信息摘要。

Step 1. 数据填充

输入数据首先被“填充”(如填充长度为p bit),使其长度用512取模的值是448,即
(b + p) mod 512 = 448
也就是说填充后的字符串长度加64,能够被512整除。
 
通常情况下填充操作都会进行,即使原始信息本身的长度以用512取模已经是448。
 
“填充”过程如下:
 
“1”首先填充,然后是“0”,直至填充后的长度满足(b + p) mod 512 = 448。
 
总之,至少1 bit至多512 bit的数据将被“填充”。

Step 2. 添加长度信息

代表字符串长度(b)的64-bit值将被添加至前一步结果。通常这一步添加的是原始输入数据串的长度。如果原始字符串长度超过2^64 bit,那么 ( b mod 2^64 ) 将被添加。
 
这时,结果字符串的长度为512的整数倍。即,字长为32 bit的16个字(word)的整数倍。
 
不妨用:
M[0 ... N-1], N mod 16 = 0
来标识此操作后的结果

Step 3. 初始化MD缓冲区

一个4个字长的缓冲区 (A, B, C, D) 用来计算摘要结果。这里A、B、C、D都是32 bit长的字。
 
他们的值初始化如下(16进制,低位):
word A: 01 23 45 67
word B: 89 ab cd ef
word C: fe dc ba 98
word D: 76 54 32 10

Step 4. 以16-word的块为单位处理信息

首先定义四个外部函数,每个的输入为三个32-bit的字,输出是一个32-bit的字。
F(X,Y,Z) = XY v not(X) Z
G(X,Y,Z) = XZ v Y not(Z)
H(X,Y,Z) = X xor Y xor Z
I(X,Y,Z) = Y xor (X v not(Z))
我们还要用到一张由正弦函数构造的含有64个元素的表格T[1...64]。
其中,T[i]表示表中的第i个元素,它等于4294967296乘以abs(sin(i)的整数部分(这里,i是弧度)。
 
接下来,做如下操作:
/* Process each 16-word block. */ 
For i = 0 to N/16-1 do

  /* Copy block i into X. */
  For j = 0 to 15 do
    Set X[j] to M[i*16+j].
  end /* of loop on j */

  /* Save A as AA, B as BB, C as CC, and D as DD. */
  AA = A
  BB = B
  CC = C
  DD = D

  /* Round 1. */
  /* Let [abcd k s i] denote the operation
       a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */

  /* Do the following 16 operations. */
  [ABCD 0 7 1] [DABC 1 12 2] [CDAB 2 17 3] [BCDA 3 22 4]
  [ABCD 4 7 5] [DABC 5 12 6] [CDAB 6 17 7] [BCDA 7 22 8]
  [ABCD 8 7 9] [DABC 9 12 10] [CDAB 10 17 11] [BCDA 11 22 12]
  [ABCD 12 7 13] [DABC 13 12 14] [CDAB 14 17 15] [BCDA 15 22 16]

  /* Round 2. */
  /* Let [abcd k s i] denote the operation
       a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */

  /* Do the following 16 operations. */
  [ABCD 1 5 17] [DABC 6 9 18] [CDAB 11 14 19] [BCDA 0 20 20]
  [ABCD 5 5 21] [DABC 10 9 22] [CDAB 15 14 23] [BCDA 4 20 24]
  [ABCD 9 5 25] [DABC 14 9 26] [CDAB 3 14 27] [BCDA 8 20 28]
  [ABCD 13 5 29] [DABC 2 9 30] [CDAB 7 14 31] [BCDA 12 20 32]

  /* Round 3. */
  /* Let [abcd k s t] denote the operation
       a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */

  /* Do the following 16 operations. */
  [ABCD 5 4 33] [DABC 8 11 34] [CDAB 11 16 35] [BCDA 14 23 36]
  [ABCD 1 4 37] [DABC 4 11 38] [CDAB 7 16 39] [BCDA 10 23 40]
  [ABCD 13 4 41] [DABC 0 11 42] [CDAB 3 16 43] [BCDA 6 23 44]
  [ABCD 9 4 45] [DABC 12 11 46] [CDAB 15 16 47] [BCDA 2 23 48]

  /* Round 4. */
  /* Let [abcd k s t] denote the operation
       a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */

  /* Do the following 16 operations. */
  [ABCD 0 6 49] [DABC 7 10 50] [CDAB 14 15 51] [BCDA 5 21 52]
  [ABCD 12 6 53] [DABC 3 10 54] [CDAB 10 15 55] [BCDA 1 21 56]
  [ABCD 8 6 57] [DABC 15 10 58] [CDAB 6 15 59] [BCDA 13 21 60]
  [ABCD 4 6 61] [DABC 11 10 62] [CDAB 2 15 63] [BCDA 9 21 64]

  /* Then perform the following additions. (That is increment each
     of the four registers by the value it had before this block
     was started.) */

  A = A + AA
  B = B + BB
  C = C + CC
  D = D + DD

end /* of loop on i */

Step 5. 输出

算法的输出是A, B, C, D。即以低位的A开始,以高位的D结束。
 
这就是MD5算法的全部内容。
详细内容可参考下面的C算法。

/* md5.c */ 
/* typedef a 32 bit type */
typedef unsigned long int UINT4;

/* Data structure for MD5 (Message Digest) computation */
typedef struct {
  UINT4 i[2]; /* number of _bits_ handled mod 2^64 */
  UINT4 buf[4]; /* scratch buffer */
  unsigned char in[64]; /* input buffer */
  unsigned char digest[16]; /* actual digest after MD5Final call */
} MD5_CTX;

void MD5Init ();
void MD5Update ();
void MD5Final ();

/* forward declaration */
static void Transform ();

static unsigned char PADDING[64] = {
  0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

/* F, G and H are basic MD5 functions: selection, majority, parity */
#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
#define H(x, y, z) ((x) ^ (y) ^ (z))
#define I(x, y, z) ((y) ^ ((x) | (~z)))

/* ROTATE_LEFT rotates x left n bits */
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))

/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4 */
/* Rotation is separate from addition to prevent recomputation */
#define FF(a, b, c, d, x, s, ac)\
  {(a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
  (a) = ROTATE_LEFT ((a), (s)); \
  (a) += (b); \
  }

#define GG(a, b, c, d, x, s, ac) \
  {(a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
  (a) = ROTATE_LEFT ((a), (s)); \
  (a) += (b); \
  }

#define HH(a, b, c, d, x, s, ac) \
  {(a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
  (a) = ROTATE_LEFT ((a), (s)); \
  (a) += (b); \
  }

#define II(a, b, c, d, x, s, ac) \
  {(a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
  (a) = ROTATE_LEFT ((a), (s)); \
  (a) += (b); \
  }

void MD5Init (MD5_CTX *mdContext)
{
  mdContext->i[0] = mdContext->i[1] = (UINT4)0;

  /* Load magic initialization constants.
   */

  mdContext->buf[0] = (UINT4)0x67452301;
  mdContext->buf[1] = (UINT4)0xefcdab89;
  mdContext->buf[2] = (UINT4)0x98badcfe;
  mdContext->buf[3] = (UINT4)0x10325476;
}

void MD5Update (MD5_CTX *mdContext, unsigned char *inBuf, unsigned int inLen)
{
  UINT4 in[16];
  int mdi;
  unsigned int i, ii;

  /* compute number of bytes mod 64 */
  mdi = (int)((mdContext->i[0] >> 3) & 0x3F);

  /* update number of bits */
  if ((mdContext->i[0] + ((UINT4)inLen << 3)) < mdContext->i[0])
    mdContext->i[1]++;
  mdContext->i[0] += ((UINT4)inLen << 3);
  mdContext->i[1] += ((UINT4)inLen >> 29);

  while (inLen--)
    {
      /* add new character to buffer, increment mdi */
      mdContext->in[mdi++] = *inBuf++;

      /* transform if necessary */
      if (mdi == 0x40) {
        for (i = 0, ii = 0; i < 16; i++, ii += 4)
          in[i] = (((UINT4)mdContext->in[ii+3]) << 24) |
            (((UINT4)mdContext->in[ii+2]) << 16) |
            (((UINT4)mdContext->in[ii+1]) << 8) |
            ((UINT4)mdContext->in[ii]);
        Transform (mdContext->buf, in);
        mdi = 0;
      }
    }
}

void MD5Final (MD5_CTX *mdContext)
{
  UINT4 in[16];
  int mdi;
  unsigned int i, ii;
  unsigned int padLen;

  /* save number of bits */
  in[14] = mdContext->i[0];
  in[15] = mdContext->i[1];

  /* compute number of bytes mod 64 */
  mdi = (int)((mdContext->i[0] >> 3) & 0x3F);

  /* pad out to 56 mod 64 */
  padLen = (mdi < 56) ? (56 - mdi) : (120 - mdi);
  MD5Update (mdContext, PADDING, padLen);

  /* append length in bits and transform */
  for (i = 0, ii = 0; i < 14; i++, ii += 4)
    in[i] = (((UINT4)mdContext->in[ii+3]) << 24) |
      (((UINT4)mdContext->in[ii+2]) << 16) |
      (((UINT4)mdContext->in[ii+1]) << 8) |
      ((UINT4)mdContext->in[ii]);
  Transform (mdContext->buf, in);

  /* store buffer in digest */
  for (i = 0, ii = 0; i < 4; i++, ii += 4) {
    mdContext->digest[ii] = (unsigned char)(mdContext->buf[i] & 0xFF);
    mdContext->digest[ii+1] =
      (unsigned char)((mdContext->buf[i] >> 8) & 0xFF);
    mdContext->digest[ii+2] =
      (unsigned char)((mdContext->buf[i] >> 16) & 0xFF);
    mdContext->digest[ii+3] =
      (unsigned char)((mdContext->buf[i] >> 24) & 0xFF);
  }
}

/* Basic MD5 step. Transform buf based on in.
 */

static void Transform (UINT4 *buf, UINT4 *in)
{
  UINT4 a = buf[0], b = buf[1], c = buf[2], d = buf[3];

  /* Round 1 */
#define S11 7
#define S12 12
#define S13 17
#define S14 22
  FF ( a, b, c, d, in[ 0], S11, 3614090360U); /* 1 */
  FF ( d, a, b, c, in[ 1], S12, 3905402710U); /* 2 */
  FF ( c, d, a, b, in[ 2], S13, 606105819U); /* 3 */
  FF ( b, c, d, a, in[ 3], S14, 3250441966U); /* 4 */
  FF ( a, b, c, d, in[ 4], S11, 4118548399U); /* 5 */
  FF ( d, a, b, c, in[ 5], S12, 1200080426U); /* 6 */
  FF ( c, d, a, b, in[ 6], S13, 2821735955U); /* 7 */
FF ( b, c, d, a, in[ 7], S14, 4249261313U); /* 8 */
  FF ( a, b, c, d, in[ 8], S11, 1770035416U); /* 9 */
  FF ( d, a, b, c, in[ 9], S12, 2336552879U); /* 10 */
  FF ( c, d, a, b, in[10], S13, 4294925233U); /* 11 */
  FF ( b, c, d, a, in[11], S14, 2304563134U); /* 12 */
  FF ( a, b, c, d, in[12], S11, 1804603682U); /* 13 */
  FF ( d, a, b, c, in[13], S12, 4254626195U); /* 14 */
  FF ( c, d, a, b, in[14], S13, 2792965006U); /* 15 */
  FF ( b, c, d, a, in[15], S14, 1236535329U); /* 16 */

  /* Round 2 */
#define S21 5
#define S22 9
#define S23 14
#define S24 20
  GG ( a, b, c, d, in[ 1], S21, 4129170786U); /* 17 */
  GG ( d, a, b, c, in[ 6], S22, 3225465664U); /* 18 */
  GG ( c, d, a, b, in[11], S23, 643717713U); /* 19 */
  GG ( b, c, d, a, in[ 0], S24, 3921069994U); /* 20 */
  GG ( a, b, c, d, in[ 5], S21, 3593408605U); /* 21 */
  GG ( d, a, b, c, in[10], S22, 38016083U); /* 22 */
  GG ( c, d, a, b, in[15], S23, 3634488961U); /* 23 */
  GG ( b, c, d, a, in[ 4], S24, 3889429448U); /* 24 */
  GG ( a, b, c, d, in[ 9], S21, 568446438U); /* 25 */
  GG ( d, a, b, c, in[14], S22, 3275163606U); /* 26 */
  GG ( c, d, a, b, in[ 3], S23, 4107603335U); /* 27 */
  GG ( b, c, d, a, in[ 8], S24, 1163531501U); /* 28 */
  GG ( a, b, c, d, in[13], S21, 2850285829U); /* 29 */
  GG ( d, a, b, c, in[ 2], S22, 4243563512U); /* 30 */
  GG ( c, d, a, b, in[ 7], S23, 1735328473U); /* 31 */
  GG ( b, c, d, a, in[12], S24, 2368359562U); /* 32 */

  /* Round 3 */
#define S31 4
#define S32 11
#define S33 16
#define S34 23
  HH ( a, b, c, d, in[ 5], S31, 4294588738U); /* 33 */
  HH ( d, a, b, c, in[ 8], S32, 2272392833U); /* 34 */
  HH ( c, d, a, b, in[11], S33, 1839030562U); /* 35 */
  HH ( b, c, d, a, in[14], S34, 4259657740U); /* 36 */
  HH ( a, b, c, d, in[ 1], S31, 2763975236U); /* 37 */
  HH ( d, a, b, c, in[ 4], S32, 1272893353U); /* 38 */
  HH ( c, d, a, b, in[ 7], S33, 4139469664U); /* 39 */
  HH ( b, c, d, a, in[10], S34, 3200236656U); /* 40 */
  HH ( a, b, c, d, in[13], S31, 681279174U); /* 41 */
  HH ( d, a, b, c, in[ 0], S32, 3936430074U); /* 42 */
  HH ( c, d, a, b, in[ 3], S33, 3572445317U); /* 43 */
  HH ( b, c, d, a, in[ 6], S34, 76029189U); /* 44 */
  HH ( a, b, c, d, in[ 9], S31, 3654602809U); /* 45 */
  HH ( d, a, b, c, in[12], S32, 3873151461U); /* 46 */
  HH ( c, d, a, b, in[15], S33, 530742520U); /* 47 */
  HH ( b, c, d, a, in[ 2], S34, 3299628645U); /* 48 */

  /* Round 4 */
#define S41 6
#define S42 10
#define S43 15
#define S44 21
  II ( a, b, c, d, in[ 0], S41, 4096336452U); /* 49 */
  II ( d, a, b, c, in[ 7], S42, 1126891415U); /* 50 */
  II ( c, d, a, b, in[14], S43, 2878612391U); /* 51 */
  II ( b, c, d, a, in[ 5], S44, 4237533241U); /* 52 */
  II ( a, b, c, d, in[12], S41, 1700485571U); /* 53 */
  II ( d, a, b, c, in[ 3], S42, 2399980690U); /* 54 */
  II ( c, d, a, b, in[10], S43, 4293915773U); /* 55 */
  II ( b, c, d, a, in[ 1], S44, 2240044497U); /* 56 */
  II ( a, b, c, d, in[ 8], S41, 1873313359U); /* 57 */
  II ( d, a, b, c, in[15], S42, 4264355552U); /* 58 */
  II ( c, d, a, b, in[ 6], S43, 2734768916U); /* 59 */
  II ( b, c, d, a, in[13], S44, 1309151649U); /* 60 */
  II ( a, b, c, d, in[ 4], S41, 4149444226U); /* 61 */
  II ( d, a, b, c, in[11], S42, 3174756917U); /* 62 */
  II ( c, d, a, b, in[ 2], S43, 718787259U); /* 63 */
  II ( b, c, d, a, in[ 9], S44, 3951481745U); /* 64 */

  buf[0] += a;
  buf[1] += b;
  buf[2] += c;
  buf[3] += d;
}
#include <stdio.h>
#include <sys/types.h>
#include <time.h>
#include <string.h>

static void MDPrint (MD5_CTX *mdContext)
{
  int i;

  for (i = 0; i < 16; i++)
    printf ("%02x", mdContext->digest[i]);
}

/* Computes the message digest for a specified file.
   Prints out message digest, a space, the file name, and a carriage
   return.
*/

static void MDFile (char *filename)
{
  FILE *inFile = fopen (filename, "rb");
  MD5_CTX mdContext;
  int bytes;
  unsigned char data[1024];

  if (inFile == NULL) {
    printf ("%s can't be opened.\n", filename);
    return;
  }

  MD5Init (&mdContext);
  while ((bytes = fread (data, 1, 1024, inFile)) != 0)
    MD5Update (&mdContext, data, bytes);
  MD5Final (&mdContext);
  MDPrint (&mdContext);
  printf (" %s\n", filename);
  fclose (inFile);
}

int main (int argc,char *argv[])
{
  if (argc != 2)
    {
      printf("Error parameter!\nExample:./md5 filename\n");
    }
  else
    {
      MDFile (argv[1]);
    }

  return 0;
}
参考文档:
 




posted @ 2011-12-18 21:06  __BSD__  阅读(344)  评论(0编辑  收藏  举报