MD5

来源:互联网 发布:淘宝装修模板在线制作 编辑:程序博客网 时间:2024/04/27 18:22
 

1.来历
MD5
的全称是message-digest algorithm 5(信息-摘要算法,在90年代初由mit laboratory
for computer science
rsa data security incronald l. rivest开发出来,

md2md3md4发展而来。http://www.ietf.org/rfc/rfc1321.txt,是一份最权威的文档,
ronald l. rivest19928月向ieft提交。

2.用途
MD5
的作用是对一段信息(message)生成信息摘要(message-digest),该摘要对该信息具有
唯一性,可以作为数字签名。用于验证文件的有效性(是否有丢失或损坏的数据),对用户
密码的加密,在哈希函数中计算散列值。

3.特点
输入一个任意长度的字节串,生成一个128位的整数。由于算法的某些不可逆特征,在加密应用
上有较好的安全性。并且,MD5算法的使用不需要支付任何版权费用。

4.说明
唯一性和不可逆性都不是绝对的,从理论上分析是一种多对一的关系,但两个不同的信息产生
相同摘要的概率很小。不可逆是指从输出反推输入所需的运算量和计算时间太大,使用穷搜字
典的方法又需要太多的存储空间。

5.算法描述

算法输入是一个字节串,每个字节是8bit.
算法的执行分为以下几个步骤:

第一步,补位:
MD5
算法先对输入的数据进行补位,使得数据的长度(byte为单位)64求余的结果是56
即数据扩展至LEN=K*64+56个字节,K为整数。
补位方法:补一个1,然后补0至满足上述要求。相当于补一个0x80的字节,再补值
0的字节。这一步里总共补充的字节数为063个。

第二步,附加数据长度:
用一个64位的整数表示数据的原始长度(bit为单位),将这个数字的8个字节按低位的在前,
高位在后的顺序附加在补位后的数据后面。这时,数据被填补后的总长度为:
  LEN = K*64+56+8=(K+1)*64 Bytes

※注意那个64位整数是输入数据的原始长度而不是填充字节后的长度,我就在这里栽了跟头.

第三步,初始化MD5参数:
有四个32位整数变量 (A,B,C,D) 用来计算信息摘要,每一个变量被初始化成以下
以十六进制数表示的数值,低位的字节在前面。
  word A: 01 23 45 67
  word B: 89 ab cd ef
  word C: fe dc ba 98
  word D: 76 54 32 10
※注意低位的字节在前面指的是Little Endian平台上内存中字节的排列方式,
而在程序中书写时,要写成:
  A=0x67452301
  B=0xefcdab89
  C=0x98badcfe
  D=0x10325476

第四步,定义四个MD5基本的按位操作函数:
X
YZ32位整数。

  F(X,Y,Z) = (X and Y) or (not(X) and Z)
  G(X,Y,Z) = (X and Z) or (Y and not(Z))
  H(X,Y,Z) = X xor Y xor Z
  I(X,Y,Z) = Y xor (X or not(Z))

再定义四个分别用于四轮变换的函数。
Mj表示消息的第j个子分组(从015),<<<s表示循环左移s位,则四种操作为:
  FF(a,b,c,d,Mj,s,ti)
表示a=b+((a+(F(b,c,d)+Mj+ti)<<<s)
  GG(a,b,c,d,Mj,s,ti)
表示
a=b+((a+(G(b,c,d)+Mj+ti)<<<s)
  HH(a,b,c,d,Mj,s,ti)
表示
a=b+((a+(H(b,c,d)+Mj+ti)<<<s)
  II(a,b,c,d,Mj,s,ti)
表示a=b+((a+(I(b,c,d)+Mj+ti)<<<s)


第五步,对输入数据作变换。
处理数据,N是总的字节数,以64个字节为一组,每组作一次循环,每次循环进行四轮操作。
要变换的64个字节用1632位的整数数组M[0 ...15]表示。而数组T[1 ... 64]表示一组常数,
T[i]
4294967296*abs(sin(i))32位整数部分,i的单位是弧度,i的取值从164

具体过程如下:

/* 设置主循环变量 */
For i = 0 to N/16-1 do

/*每循环一次,把数据原文存放在16个元素的数组X. */
For j = 0 to 15 do
Set X[j] to M[i*16+j].
end /
结束对J的循环

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

/* 1*/
/*
[abcd k s i]表示如下操作

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]


/*
2* */
/*
[abcd k s i]表示如下操作

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]

/* 3*/
/*
[abcd k s i]表示如下操作

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]


/*
4*/
/*
[abcd k s i]表示如下操作

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]

/* 然后进行如下操作 */
A = A + AA
B = B + BB
C = C + CC
D = D + DD

Next i /* 结束对I的循环*/

第六步,输出结果。
A
BCD连续存放,共16个字节,128位。按十六进制依次输出这个16个字节。


最后,用程序语言实现算法后,可以输入以下几个信息对程序作一个简单的测试,
看看程序有没有错误。
 MD5 ("") = d41d8cd98f00b204e9800998ecf8427e
 
MD5 ("a") = 0cc175b9c0f1b6a831c399e269772661
 
MD5 ("abc") = 900150983cd24fb0d6963f7d28e17f72
 
MD5 ("message digest") = f96b697d7cb7938d525a2f31aaf161d0
 
MD5 ("abcdefghijklmnopqrstuvwxyz") = c3fcd3d76192e4007dfb496cca67e13b
 
MD5 ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789") =
d174ab98d277d9f5a5611c2c9f419d9f
  MD5 ("123456789012345678901234567890123456789012345678901234567890123456789
01234567890") = 57edf4a22be3c955ac49da2e2107b67a


MD5
算法之C#程序

MD5算法比较特别,最适合用汇编语言来写,好多高级语言对之无能无力或效率极低。
比如我最开始尝试用PythonEuphoria编写,发现不太容易。相比而言,C#作为C家簇
中新兴的一门.net语言,功能比较全面。花了一晚上的工夫终于用C#最先实现了MD5
主要是由于对算法的一些细节不太注意,结果输出总是不对,调试了好长时间。

[code]
//
源文件:
md5.cs
// MD5 Alogrithm
// by rufi 2004.6.20
http://rufi.yculblog.com/
using System;
using System.Collections;
using System.IO;

public class MD5 {
  //static state variables
  private static UInt32 A;
  private static UInt32 B;
  private static UInt32 C;
  private static UInt32 D;

  //number of bits to rotate in tranforming
  private const int  S11 = 7;
  private const int  S12 = 12;
  private const int  S13 = 17;
  private const int  S14 = 22;
  private const int  S21 = 5;
  private const int  S22 = 9;
  private const int  S23 = 14;
  private const int  S24 = 20;
  private const int  S31 = 4;
  private const int  S32 = 11;
  private const int  S33 = 16;
  private const int  S34 = 23;
  private const int  S41 = 6;
  private const int  S42 = 10;
  private const int  S43 = 15;
  private const int  S44 = 21;


  /* F, G, H and I are basic MD5 functions.
   *
四个非线性函数:
   *
   * F(X,Y,Z) =(X&Y)|((~X)&Z)
   * G(X,Y,Z) =(X&Z)|(Y&(~Z))
   * H(X,Y,Z) =X^Y^Z
   * I(X,Y,Z)=Y^(X|(~Z))
   *
   *
&与,|或,~非,^异或)

   */
  private static UInt32 F(UInt32 x,UInt32 y,UInt32 z){
    return (x&y)|((~x)&z);
  }
  private static UInt32 G(UInt32 x,UInt32 y,UInt32 z){
    return (x&z)|(y&(~z));
  }
  private static UInt32 H(UInt32 x,UInt32 y,UInt32 z){
    return x^y^z;
  }
  private static UInt32 I(UInt32 x,UInt32 y,UInt32 z){
    return y^(x|(~z));
  }

  /* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
   * Rotation is separate from addition to prevent recomputation.
   */
  private static void FF(ref UInt32 a,UInt32 b,UInt32 c,UInt32 d,UInt32 mj,int s,UInt32 ti){
    a = a + F(b,c,d) + mj + ti;
    a = a << s | a >> (32-s);
    a += b;
  }
  private static void GG(ref UInt32 a,UInt32 b,UInt32 c,UInt32 d,UInt32 mj,int s,UInt32 ti){
    a = a + G(b,c,d) + mj + ti;
    a = a << s | a >> (32-s);
    a += b;
  }
  private static void HH(ref UInt32 a,UInt32 b,UInt32 c,UInt32 d,UInt32 mj,int s,UInt32 ti){
    a = a + H(b,c,d) + mj + ti;
    a = a << s | a >> (32-s);
    a += b;
  }
  private static void II(ref UInt32 a,UInt32 b,UInt32 c,UInt32 d,UInt32 mj,int s,UInt32 ti){
    a = a + I(b,c,d) + mj + ti;
    a = a << s | a >> (32-s);
    a += b;
  }

  private static void MD5_Init(){
    A=0x67452301;  //in memory, this is 0x01234567
    B=0xefcdab89;  //in memory, this is 0x89abcdef
    C=0x98badcfe;  //in memory, this is 0xfedcba98
    D=0x10325476;  //in memory, this is 0x76543210
  }

  private static UInt32[] MD5_Append(byte[] input){
    int zeros=0;
    int ones =1;
    int size=0;
    int n = input.Length;
    int m = n%64;
    if( m < 56 ){
      zeros = 55-m;
      size=n-m+64;
    }
    else if (m==56){
      zeros = 0;
      ones = 0;
      size=n+8;
    }
    else{
      zeros = 63-m+56;
      size=n+64-m+64;
    }

    ArrayList bs = new ArrayList(input);
    if(ones==1){
      bs.Add( (byte)0x80 ); // 0x80 = $10000000
    }
    for(int i=0;i<zeros;i++){
      bs.Add( (byte)0 );
    }

    UInt64 N = (UInt64) n * 8;
    byte h1=(byte)(N&0xFF);
    byte h2=(byte)((N>>8)&0xFF);
    byte h3=(byte)((N>>16)&0xFF);
    byte h4=(byte)((N>>24)&0xFF);
    byte h5=(byte)((N>>32)&0xFF);
    byte h6=(byte)((N>>40)&0xFF);
    byte h7=(byte)((N>>48)&0xFF);
    byte h8=(byte)(N>>56);
    bs.Add(h1);
    bs.Add(h2);
    bs.Add(h3);
    bs.Add(h4);
    bs.Add(h5);
    bs.Add(h6);
    bs.Add(h7);
    bs.Add(h8);
    byte[] ts=(byte[])bs.ToArray(typeof(byte));

    /* Decodes input (byte[]) into output (UInt32[]). Assumes len is
     * a multiple of 4.
     */
    UInt32[] output = new UInt32[size/4];
    for(Int64 i=0,j=0;i<size;j++,i+=4){
      output[j]=(UInt32)(ts[i] | ts[i+1]<<8 | ts[i+2]<<16 | ts[i+3]<<24);
    }
    return output;
  }
  private static UInt32[] MD5_Trasform(UInt32[] x){

    UInt32 a,b,c,d;

    for(int k=0;k<x.Length;k+=16){
      a=A;
      b=B;
      c=C;
      d=D;
   
      /* Round 1 */
      FF (ref a, b, c, d, x[k+ 0], S11, 0xd76aa478); /* 1 */
      FF (ref d, a, b, c, x[k+ 1], S12, 0xe8c7b756); /* 2 */
      FF (ref c, d, a, b, x[k+ 2], S13, 0x242070db); /* 3 */
      FF (ref b, c, d, a, x[k+ 3], S14, 0xc1bdceee); /* 4 */
      FF (ref a, b, c, d, x[k+ 4], S11, 0xf57c0faf); /* 5 */
      FF (ref d, a, b, c, x[k+ 5], S12, 0x4787c62a); /* 6 */
      FF (ref c, d, a, b, x[k+ 6], S13, 0xa8304613); /* 7 */
      FF (ref b, c, d, a, x[k+ 7], S14, 0xfd469501); /* 8 */
      FF (ref a, b, c, d, x[k+ 8], S11, 0x698098d8); /* 9 */
      FF (ref d, a, b, c, x[k+ 9], S12, 0x8b44f7af); /* 10 */
      FF (ref c, d, a, b, x[k+10], S13, 0xffff5bb1); /* 11 */
      FF (ref b, c, d, a, x[k+11], S14, 0x895cd7be); /* 12 */
      FF (ref a, b, c, d, x[k+12], S11, 0x6b901122); /* 13 */
      FF (ref d, a, b, c, x[k+13], S12, 0xfd987193); /* 14 */
      FF (ref c, d, a, b, x[k+14], S13, 0xa679438e); /* 15 */
      FF (ref b, c, d, a, x[k+15], S14, 0x49b40821); /* 16 */

      /* Round 2 */
      GG (ref a, b, c, d, x[k+ 1], S21, 0xf61e2562); /* 17 */
      GG (ref d, a, b, c, x[k+ 6], S22, 0xc040b340); /* 18 */
      GG (ref c, d, a, b, x[k+11], S23, 0x265e5a51); /* 19 */
      GG (ref b, c, d, a, x[k+ 0], S24, 0xe9b6c7aa); /* 20 */
      GG (ref a, b, c, d, x[k+ 5], S21, 0xd62f105d); /* 21 */
      GG (ref d, a, b, c, x[k+10], S22,  0x2441453); /* 22 */
      GG (ref c, d, a, b, x[k+15], S23, 0xd8a1e681); /* 23 */
      GG (ref b, c, d, a, x[k+ 4], S24, 0xe7d3fbc8); /* 24 */
      GG (ref a, b, c, d, x[k+ 9], S21, 0x21e1cde6); /* 25 */
      GG (ref d, a, b, c, x[k+14], S22, 0xc33707d6); /* 26 */
      GG (ref c, d, a, b, x[k+ 3], S23, 0xf4d50d87); /* 27 */
      GG (ref b, c, d, a, x[k+ 8], S24, 0x455a14ed); /* 28 */
      GG (ref a, b, c, d, x[k+13], S21, 0xa9e3e905); /* 29 */
      GG (ref d, a, b, c, x[k+ 2], S22, 0xfcefa3f8); /* 30 */
      GG (ref c, d, a, b, x[k+ 7], S23, 0x676f02d9); /* 31 */
      GG (ref b, c, d, a, x[k+12], S24, 0x8d2a4c8a); /* 32 */

      /* Round 3 */
      HH (ref a, b, c, d, x[k+ 5], S31, 0xfffa3942); /* 33 */
      HH (ref d, a, b, c, x[k+ 8], S32, 0x8771f681); /* 34 */
      HH (ref c, d, a, b, x[k+11], S33, 0x6d9d6122); /* 35 */
      HH (ref b, c, d, a, x[k+14], S34, 0xfde5380c); /* 36 */
      HH (ref a, b, c, d, x[k+ 1], S31, 0xa4beea44); /* 37 */
      HH (ref d, a, b, c, x[k+ 4], S32, 0x4bdecfa9); /* 38 */
      HH (ref c, d, a, b, x[k+ 7], S33, 0xf6bb4b60); /* 39 */
      HH (ref b, c, d, a, x[k+10], S34, 0xbebfbc70); /* 40 */
      HH (ref a, b, c, d, x[k+13], S31, 0x289b7ec6); /* 41 */
      HH (ref d, a, b, c, x[k+ 0], S32, 0xeaa127fa); /* 42 */
      HH (ref c, d, a, b, x[k+ 3], S33, 0xd4ef3085); /* 43 */
      HH (ref b, c, d, a, x[k+ 6], S34,  0x4881d05); /* 44 */
      HH (ref a, b, c, d, x[k+ 9], S31, 0xd9d4d039); /* 45 */
      HH (ref d, a, b, c, x[k+12], S32, 0xe6db99e5); /* 46 */
      HH (ref c, d, a, b, x[k+15], S33, 0x1fa27cf8); /* 47 */
      HH (ref b, c, d, a, x[k+ 2], S34, 0xc4ac5665); /* 48 */

      /* Round 4 */
      II (ref a, b, c, d, x[k+ 0], S41, 0xf4292244); /* 49 */
      II (ref d, a, b, c, x[k+ 7], S42, 0x432aff97); /* 50 */
      II (ref c, d, a, b, x[k+14], S43, 0xab9423a7); /* 51 */
      II (ref b, c, d, a, x[k+ 5], S44, 0xfc93a039); /* 52 */
      II (ref a, b, c, d, x[k+12], S41, 0x655b59c3); /* 53 */
      II (ref d, a, b, c, x[k+ 3], S42, 0x8f0ccc92); /* 54 */
      II (ref c, d, a, b, x[k+10], S43, 0xffeff47d); /* 55 */
      II (ref b, c, d, a, x[k+ 1], S44, 0x85845dd1); /* 56 */
      II (ref a, b, c, d, x[k+ 8], S41, 0x6fa87e4f); /* 57 */
      II (ref d, a, b, c, x[k+15], S42, 0xfe2ce6e0); /* 58 */
      II (ref c, d, a, b, x[k+ 6], S43, 0xa3014314); /* 59 */
      II (ref b, c, d, a, x[k+13], S44, 0x4e0811a1); /* 60 */
      II (ref a, b, c, d, x[k+ 4], S41, 0xf7537e82); /* 61 */
      II (ref d, a, b, c, x[k+11], S42, 0xbd3af235); /* 62 */
      II (ref c, d, a, b, x[k+ 2], S43, 0x2ad7d2bb); /* 63 */
      II (ref b, c, d, a, x[k+ 9], S44, 0xeb86d391); /* 64 */

      A+=a;
      B+=b;
      C+=c;
      D+=d;
    }
    return new UInt32[]{A,B,C,D};
  }
  public static byte[] MD5Array(byte[] input){
    MD5_Init();
    UInt32[] block = MD5_Append(input);
    UInt32[] bits = MD5_Trasform(block);

    /* Encodes bits (UInt32[]) into output (byte[]). Assumes len is
     * a multiple of 4.
         */
    byte[] output=new byte[bits.Length*4];
    for(int i=0,j=0;i<bits.Length;i++,j+=4){
      output[j] = (byte)(bits[i] & 0xff);
      output[j+1] = (byte)((bits[i] >> 8) & 0xff);
      output[j+2] = (byte)((bits[i] >> 16) & 0xff);
      output[j+3] = (byte)((bits[i] >> 24) & 0xff);
    }
    return output;
  }

  public static string ArrayToHexString(byte[] array,bool uppercase){
    string hexString="";
    string format="x2";
    if(uppercase){
      format="X2";
    }
    foreach(byte b in array){
      hexString += b.ToString(format);
    }
    return hexString;
  }

  public static string MDString(string message){
    char[] c = message.ToCharArray();
    byte[] b = new byte[c.Length];
    for(int i=0;i<c.Length;i++){
      b[i]=(byte)c[i];
    }
    byte[] digest = MD5Array(b);
    return ArrayToHexString(digest,false);
  }
  public static string MDFile(string fileName){
    FileStream fs=File.Open(fileName,FileMode.Open,FileAccess.Read);
    byte[] array=new byte[fs.Length];
    fs.Read(array,0,(int)fs.Length);
    byte[] digest = MD5Array(array);
    fs.Close();
    return ArrayToHexString(digest,false);
  }

  public static string Test(string message){
    return "rnMD5 (""+message+"") = " + MD5.MDString(message);
  }
  public static string TestSuite(){   
    string s = "";
    s+=Test("");
    s+=Test("a");
    s+=Test("abc");
    s+=Test("message digest");
    s+=Test("abcdefghijklmnopqrstuvwxyz");
    s+=Test("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
    s+=Test("12345678901234567890123456789012345678901234567890123456789012345678901234567890");
    return s;   
  }
}
[/code]

 

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 龙之谷手游转职业装备怎么办 如果函数值和类型不一致怎么办 qq提现不到账怎么办 提现的钱不到账怎么办 联璧金融提现不到账怎么办 孕早期拉稀拉水怎么办 兔子嘴巴摔烂了怎么办 猫咪耳朵里有黑的东西怎么办 兔子的腿骨折了怎么办 德牧耳朵立不起来怎么办 童鞋魔术贴太长了怎么办? 许昌国贸360手机没电怎么办 滴滤油膜泡泡不破怎么办 商铺转让不出去怎么办 手机导航gps信号弱怎么办 卖家收到退货有破损怎么办 手办寄快递盒子坏了怎么办 淘宝收到衣服破损的怎么办 收到的快递少了怎么办 快递寄东西坏了怎么办 发快递东西坏了怎么办 寄快递东西碎了怎么办 手机全成英文了怎么办 冲好的奶粉结块怎么办 糖有点化了怎么办弄干 猪拉黑色稀粪便怎么办 盆栽花用肥多了怎么办 辊底式退火炉出炉温度高怎么办 黑枸杞长霉了怎么办 被子睡久了发黄怎么办 丝棉被淋了雨怎么办呢? 厚棉花被有霉味怎么办 可乐倒在棉絮上怎么办 酸奶倒在被子上怎么办 发现自家房屋墙壁发霉怎么办 布艺拖鞋发霉了怎么办 棉拖鞋洗了还臭怎么办 棉拖鞋洗了发黄怎么办 小狗5天不吃东西怎么办 手上猴子总是不停的起怎么办 真空压缩袋破了怎么办