Home | 簡體中文 | 繁體中文 | 雜文 | 知乎專欄 | Github | OSChina 博客 | 雲社區 | 雲棲社區 | Facebook | Linkedin | 視頻教程 | 打賞(Donations) | About
知乎專欄多維度架構 微信號 netkiller-ebook | QQ群:128659835 請註明“讀者”

第 204 章 Message Digest (數字摘要)

目錄

204.1. MD5專題
204.1.1. md5sum
204.1.2. PHP md5()
204.1.3. MySQL md5()
204.1.4. Java MD5
204.1.4.1. JDK 1.2
204.1.4.2. JDK 1.5
204.1.4.3. JDK 1.8
204.1.5. perl md5
204.2. SHA 專題
204.2.1. sha1sum
204.2.2. PHP sha1()
204.2.3. Java SHA
204.2.3.1. SHA
204.2.3.2. SHA-256
204.2.4. Perl
204.3. CRC32
204.3.1. PHP CRC32
204.3.2. Java CRC32
204.4. 第三方工具
204.4.1. htpasswd
204.4.1.1. CRYPT
204.4.1.2. MD5
204.4.1.3. SHA
204.4.2. htdigest
204.4.3. md5sum
204.4.4. sha1sum

204.1. MD5專題

204.1.1. md5sum

MD5 為當前常用的 hash function,一般用來計算資料的雜湊值,俾利資料正確性之驗證;md5sum 則為用來檢查計算hash function 的的工具程序,具體的參數用法可去man md5sum 的用法。

生成雜湊值,有些文章叫指紋

md5sum file.txt

C:\GnuWin32\neo>md5sum file.txt
7012acbb1d394b20567dffbf0992b677 *file.txt

C:\GnuWin32\neo>md5sum file.txt > file.txt.md5

C:\GnuWin32\neo>md5sum -c file.txt.md5
file.txt: OK
		

生成指紋並重訂向到檔案

md5sum file.txt > file.txt.md5

C:\GnuWin32\neo>md5sum file.txt
7012acbb1d394b20567dffbf0992b677 *file.txt

C:\GnuWin32\neo>md5sum file.txt > file.txt.md5

C:\GnuWin32\neo>md5sum -c file.txt.md5
file.txt: OK
		

生成一組檔案

md5sum file0.txt > file.txt.md5
md5sum file1.txt >> file.txt.md5
md5sum file2.txt >> file.txt.md5
		

使用通配符

C:\GnuWin32\neo>md5sum *
7012acbb1d394b20567dffbf0992b677 *file.txt
d9226d4bd8779baa69db272f89a2e05c *message.txt

C:\GnuWin32\neo>md5sum * >file.txt.md5
		

驗證檔案是否被人更改過

md5sum -c file.txt.md5

C:\GnuWin32\neo>md5sum file.txt
7012acbb1d394b20567dffbf0992b677 *file.txt

C:\GnuWin32\neo>md5sum file.txt > file.txt.md5

C:\GnuWin32\neo>md5sum -c file.txt.md5
file.txt: OK
		

204.1.2. PHP md5()


# cat md5.php

<html>

<p>MD5 密碼產生器</p>

<form method=post action=des.php>

<p>password:<input name=passwd type=text size=20></p>

<input type=submit value=submit>

</form>

<?

$enpw=md5($passwd);

echo "password is: $enpw";

?>

			

204.1.3. MySQL md5()

select md5('password');


[chen@linux chen]$ mysql

Welcome to the MySQL monitor.  Commands end with ; or \g.

Your MySQL connection id is 11947 to server version: 4.0.13-log


Type 'help;' or '\h' for help. Type '\c' to clear the buffer.

mysql> select md5('chen');

+----------------------------------+
| md5('chen')                      |
+----------------------------------+
| a1a8887793acfc199182a649e905daab |
+----------------------------------+

1 row in set (0.00 sec)

mysql>


mysql> select md5('chen') as passwd;

+----------------------------------+
| passwd                           |
+----------------------------------+
| a1a8887793acfc199182a649e905daab |
+----------------------------------+

1 row in set (0.00 sec)

mysql>

			

204.1.4. Java MD5

204.1.4.1. JDK 1.2

1.2版之前的JDK沒有實現md5;

				
/************************************************
MD5 算法的Java Bean
@author:Topcat Tuppin
Last Modified:10,Mar,2001
*************************************************/
package netkiller.security;
import java.lang.reflect.*;
/*************************************************
md5 類實現了RSA Data Security, Inc.在提交給IETF
的RFC1321中的MD5 message-digest 算法。
*************************************************/

public class MD5 {
       /* 下面這些S11-S44實際上是一個4*4的矩陣,在原始的C實現中是用#define 實現的,
       這裡把它們實現成為static final是表示了只讀,切能在同一個進程空間內的多個
       Instance間共享*/

        static final int S11 = 7;
        static final int S12 = 12;
        static final int S13 = 17;
        static final int S14 = 22;

        static final int S21 = 5;
        static final int S22 = 9;
        static final int S23 = 14;
        static final int S24 = 20;

        static final int S31 = 4;
        static final int S32 = 11;
        static final int S33 = 16;
        static final int S34 = 23;

        static final int S41 = 6;
        static final int S42 = 10;
        static final int S43 = 15;
        static final int S44 = 21;



        static final byte[] PADDING = { -128, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
        /* 下面的三個成員是MD5計算過程中用到的3個核心數據,在原始的C實現中
           被定義到MD5_CTX結構中
         */

        private long[] state = new long[4];  // state (ABCD)
        private long[] count = new long[2];  // number of bits, modulo 2^64 (lsb first)
        private byte[] buffer = new byte[64]; // input buffer

       /* digestHexStr是MD5的唯一一個公共成員,是最新一次計算結果的
         16進制ASCII表示.
       */

        public String digestHexStr;

        /* digest,是最新一次計算結果的2進制內部表示,表示128bit的MD5值. */

        private byte[] digest = new byte[16];

       /*
         getMD5ofStr是類MD5最主要的公共方法,入口參數是你想要進行MD5變換的字元串
         返回的是變換完的結果,這個結果是從公共成員digestHexStr取得的.
       */

        public String getMD5ofStr(String inbuf) {

                md5Init();

                md5Update(inbuf.getBytes(), inbuf.length());

                md5Final();

                digestHexStr = "";

                for (int i = 0; i < 16; i++) {

                        digestHexStr += byteHEX(digest[i]);

                }

                return digestHexStr;



        }

        // 這是MD5這個類的標準建構子,JavaBean要求有一個public的並且沒有參數的建構子

        public MD5() {
                md5Init();
                return;
        }

        /* md5Init是一個初始化函數,初始化核心變數,裝入標準的幻數 */

        private void md5Init() {

                count[0] = 0L;

                count[1] = 0L;

                ///* Load magic initialization constants.



                state[0] = 0x67452301L;

                state[1] = 0xefcdab89L;

                state[2] = 0x98badcfeL;

                state[3] = 0x10325476L;



                return;

        }

        /* F, G, H ,I 是4個基本的MD5函數,在原始的MD5的C實現中,由於它們是

        簡單的位運算,可能出於效率的考慮把它們實現成了宏,在java中,我們把它們

       實現成了private方法,名字保持了原來C中的。 */



        private long F(long x, long y, long z) {

                return (x & y) | ((~x) & z);



        }

        private long G(long x, long y, long z) {

                return (x & z) | (y & (~z));



        }

        private long H(long x, long y, long z) {

                return x ^ y ^ z;

        }



        private long I(long x, long y, long z) {

                return y ^ (x | (~z));

        }



       /*

          FF,GG,HH和II將調用F,G,H,I進行近一步變換

          FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.

          Rotation is separate from addition to prevent recomputation.

       */



        private long FF(long a, long b, long c, long d, long x, long s,

                long ac) {

                a += F (b, c, d) + x + ac;

                a = ((int) a << s) | ((int) a >>> (32 - s));

                a += b;

                return a;

        }



        private long GG(long a, long b, long c, long d, long x, long s,

                long ac) {

                a += G (b, c, d) + x + ac;

                a = ((int) a << s) | ((int) a >>> (32 - s));

                a += b;

                return a;

        }

        private long HH(long a, long b, long c, long d, long x, long s,

                long ac) {

                a += H (b, c, d) + x + ac;

                a = ((int) a << s) | ((int) a >>> (32 - s));

                a += b;

                return a;

        }

        private long II(long a, long b, long c, long d, long x, long s,

                long ac) {

                a += I (b, c, d) + x + ac;

                a = ((int) a << s) | ((int) a >>> (32 - s));

                a += b;

                return a;

        }

        /*
         md5Update是MD5的主計算過程,inbuf是要變換的位元組串,inputlen是長度,這個
         函數由getMD5ofStr調用,調用之前需要調用md5init,因此把它設計成private的
        */

        private void md5Update(byte[] inbuf, int inputLen) {

                int i, index, partLen;

                byte[] block = new byte[64];

                index = (int)(count[0] >>> 3) & 0x3F;

                // /* Update number of bits */

                if ((count[0] += (inputLen << 3)) < (inputLen << 3))

                        count[1]++;

                count[1] += (inputLen >>> 29);

                partLen = 64 - index;

                // Transform as many times as possible.

                if (inputLen >= partLen) {

                        md5Memcpy(buffer, inbuf, index, 0, partLen);

                        md5Transform(buffer);

                        for (i = partLen; i + 63 < inputLen; i += 64) {

                                md5Memcpy(block, inbuf, 0, i, 64);

                                md5Transform (block);

                        }

                        index = 0;

                } else

                        i = 0;


                ///* Buffer remaining input */

                md5Memcpy(buffer, inbuf, index, i, inputLen - i);

        }

        /*
          md5Final整理和填寫輸出結果
        */

        private void md5Final () {

                byte[] bits = new byte[8];

                int index, padLen;

                ///* Save number of bits */

                Encode (bits, count, 8);


                ///* Pad out to 56 mod 64.

                index = (int)(count[0] >>> 3) & 0x3f;

                padLen = (index < 56) ? (56 - index) : (120 - index);

                md5Update (PADDING, padLen);

                ///* Append length (before padding) */

                md5Update(bits, 8);

                ///* Store state in digest */

                Encode (digest, state, 16);



        }

        /* md5Memcpy是一個內部使用的byte數組的塊拷貝函數,從input的inpos開始把len長度的

      位元組拷貝到output的outpos位置開始
        */

        private void md5Memcpy (byte[] output, byte[] input,

                int outpos, int inpos, int len)

        {

                int i;



                for (i = 0; i < len; i++)

                        output[outpos + i] = input[inpos + i];

        }

        /*
           md5Transform是MD5核心變換程序,有md5Update調用,block是分塊的原始位元組
        */

        private void md5Transform (byte block[]) {

                long a = state[0], b = state[1], c = state[2], d = state[3];

                long[] x = new long[16];



                Decode (x, block, 64);



                /* Round 1 */

                a = FF (a, b, c, d, x[0], S11, 0xd76aa478L); /* 1 */

                d = FF (d, a, b, c, x[1], S12, 0xe8c7b756L); /* 2 */

                c = FF (c, d, a, b, x[2], S13, 0x242070dbL); /* 3 */

                b = FF (b, c, d, a, x[3], S14, 0xc1bdceeeL); /* 4 */

                a = FF (a, b, c, d, x[4], S11, 0xf57c0fafL); /* 5 */

                d = FF (d, a, b, c, x[5], S12, 0x4787c62aL); /* 6 */

                c = FF (c, d, a, b, x[6], S13, 0xa8304613L); /* 7 */

                b = FF (b, c, d, a, x[7], S14, 0xfd469501L); /* 8 */

                a = FF (a, b, c, d, x[8], S11, 0x698098d8L); /* 9 */

                d = FF (d, a, b, c, x[9], S12, 0x8b44f7afL); /* 10 */

                c = FF (c, d, a, b, x[10], S13, 0xffff5bb1L); /* 11 */

                b = FF (b, c, d, a, x[11], S14, 0x895cd7beL); /* 12 */

                a = FF (a, b, c, d, x[12], S11, 0x6b901122L); /* 13 */

                d = FF (d, a, b, c, x[13], S12, 0xfd987193L); /* 14 */

                c = FF (c, d, a, b, x[14], S13, 0xa679438eL); /* 15 */

                b = FF (b, c, d, a, x[15], S14, 0x49b40821L); /* 16 */



                /* Round 2 */

                a = GG (a, b, c, d, x[1], S21, 0xf61e2562L); /* 17 */

                d = GG (d, a, b, c, x[6], S22, 0xc040b340L); /* 18 */

                c = GG (c, d, a, b, x[11], S23, 0x265e5a51L); /* 19 */

                b = GG (b, c, d, a, x[0], S24, 0xe9b6c7aaL); /* 20 */

                a = GG (a, b, c, d, x[5], S21, 0xd62f105dL); /* 21 */

                d = GG (d, a, b, c, x[10], S22, 0x2441453L); /* 22 */

                c = GG (c, d, a, b, x[15], S23, 0xd8a1e681L); /* 23 */

                b = GG (b, c, d, a, x[4], S24, 0xe7d3fbc8L); /* 24 */

                a = GG (a, b, c, d, x[9], S21, 0x21e1cde6L); /* 25 */

                d = GG (d, a, b, c, x[14], S22, 0xc33707d6L); /* 26 */

                c = GG (c, d, a, b, x[3], S23, 0xf4d50d87L); /* 27 */

                b = GG (b, c, d, a, x[8], S24, 0x455a14edL); /* 28 */

                a = GG (a, b, c, d, x[13], S21, 0xa9e3e905L); /* 29 */

                d = GG (d, a, b, c, x[2], S22, 0xfcefa3f8L); /* 30 */

                c = GG (c, d, a, b, x[7], S23, 0x676f02d9L); /* 31 */

                b = GG (b, c, d, a, x[12], S24, 0x8d2a4c8aL); /* 32 */



                /* Round 3 */

                a = HH (a, b, c, d, x[5], S31, 0xfffa3942L); /* 33 */

                d = HH (d, a, b, c, x[8], S32, 0x8771f681L); /* 34 */

                c = HH (c, d, a, b, x[11], S33, 0x6d9d6122L); /* 35 */

                b = HH (b, c, d, a, x[14], S34, 0xfde5380cL); /* 36 */

                a = HH (a, b, c, d, x[1], S31, 0xa4beea44L); /* 37 */

                d = HH (d, a, b, c, x[4], S32, 0x4bdecfa9L); /* 38 */

                c = HH (c, d, a, b, x[7], S33, 0xf6bb4b60L); /* 39 */

                b = HH (b, c, d, a, x[10], S34, 0xbebfbc70L); /* 40 */

                a = HH (a, b, c, d, x[13], S31, 0x289b7ec6L); /* 41 */

                d = HH (d, a, b, c, x[0], S32, 0xeaa127faL); /* 42 */

                c = HH (c, d, a, b, x[3], S33, 0xd4ef3085L); /* 43 */

                b = HH (b, c, d, a, x[6], S34, 0x4881d05L); /* 44 */

                a = HH (a, b, c, d, x[9], S31, 0xd9d4d039L); /* 45 */

                d = HH (d, a, b, c, x[12], S32, 0xe6db99e5L); /* 46 */

                c = HH (c, d, a, b, x[15], S33, 0x1fa27cf8L); /* 47 */

                b = HH (b, c, d, a, x[2], S34, 0xc4ac5665L); /* 48 */



                /* Round 4 */

                a = II (a, b, c, d, x[0], S41, 0xf4292244L); /* 49 */

                d = II (d, a, b, c, x[7], S42, 0x432aff97L); /* 50 */

                c = II (c, d, a, b, x[14], S43, 0xab9423a7L); /* 51 */

                b = II (b, c, d, a, x[5], S44, 0xfc93a039L); /* 52 */

                a = II (a, b, c, d, x[12], S41, 0x655b59c3L); /* 53 */

                d = II (d, a, b, c, x[3], S42, 0x8f0ccc92L); /* 54 */

                c = II (c, d, a, b, x[10], S43, 0xffeff47dL); /* 55 */

                b = II (b, c, d, a, x[1], S44, 0x85845dd1L); /* 56 */

                a = II (a, b, c, d, x[8], S41, 0x6fa87e4fL); /* 57 */

                d = II (d, a, b, c, x[15], S42, 0xfe2ce6e0L); /* 58 */

                c = II (c, d, a, b, x[6], S43, 0xa3014314L); /* 59 */

                b = II (b, c, d, a, x[13], S44, 0x4e0811a1L); /* 60 */

                a = II (a, b, c, d, x[4], S41, 0xf7537e82L); /* 61 */

                d = II (d, a, b, c, x[11], S42, 0xbd3af235L); /* 62 */

                c = II (c, d, a, b, x[2], S43, 0x2ad7d2bbL); /* 63 */

                b = II (b, c, d, a, x[9], S44, 0xeb86d391L); /* 64 */



                state[0] += a;

                state[1] += b;

                state[2] += c;

                state[3] += d;



        }

        /*Encode把long數組按順序拆成byte數組,因為java的long類型是64bit的,

          只拆低32bit,以適應原始C實現的用途

        */

        private void Encode (byte[] output, long[] input, int len) {

                int i, j;

                for (i = 0, j = 0; j < len; i++, j += 4) {

                        output[j] = (byte)(input[i] & 0xffL);

                        output[j + 1] = (byte)((input[i] >>> 8) & 0xffL);

                        output[j + 2] = (byte)((input[i] >>> 16) & 0xffL);

                        output[j + 3] = (byte)((input[i] >>> 24) & 0xffL);

                }

        }



        /*Decode把byte數組按順序合成成long數組,因為java的long類型是64bit的,

          只合成低32bit,高32bit清零,以適應原始C實現的用途
        */

        private void Decode (long[] output, byte[] input, int len) {

                int i, j;

                for (i = 0, j = 0; j < len; i++, j += 4)

                        output[i] = b2iu(input[j]) |

                                (b2iu(input[j + 1]) << 8) |

                                (b2iu(input[j + 2]) << 16) |

                                (b2iu(input[j + 3]) << 24);



                return;

        }

        /*
          b2iu是我寫的一個把byte按照不考慮正負號的原則的"升位"程序,因為java沒有unsigned運算
        */

        public static long b2iu(byte b) {

                return b < 0 ? b & 0x7F + 128 : b;

        }

       /*byteHEX(),用來把一個byte類型的數轉換成十六進制的ASCII表示,

        因為java中的byte的toString無法實現這一點,我們又沒有C語言中的

         sprintf(outbuf,"%02X",ib)

       */

        public static String byteHEX(byte ib) {

                char[] Digit = { '0','1','2','3','4','5','6','7','8','9',

                'A','B','C','D','E','F' };

                char [] ob = new char[2];

                ob[0] = Digit[(ib >>> 4) & 0X0F];

                ob[1] = Digit[ib & 0X0F];

                String s = new String(ob);

                return s;

        }



        public String getMD5String(String md5){
                      return getMD5ofStr(md5).toLowerCase();
        }

        public static void main(String args[]) {

                MD5 m = new MD5();

                if (Array.getLength(args) == 0) {   //如果沒有參數,執行標準的Test Suite



                    System.out.println("MD5 Test suite:");

                       System.out.println("MD5(\"\"):"+m.getMD5ofStr(""));

                       System.out.println("MD5(\"a\"):"+m.getMD5ofStr("a"));

                       System.out.println("MD5(\"abc\"):"+m.getMD5ofStr("abc"));

                       System.out.println("MD5(\"message digest\"):"+m.getMD5ofStr("message digest"));

                       System.out.println("MD5(\"abcdefghijklmnopqrstuvwxyz\"):"+

                        m.getMD5ofStr("abcdefghijklmnopqrstuvwxyz"));

                       System.out.println("MD5(\"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\"):"+

                            m.getMD5ofStr("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"));

                }

                else

                          System.out.println("MD5(" + args[0] + ")=" + m.getMD5ofStr(args[0]));





        }



}
				
				

204.1.4.2. JDK 1.5

以下使用JDK 1.5.x版實現;

				
import java.security.*;

public class md5Test {

	private static String dumpBytes(byte[] bytes) {
	    int i;
	    StringBuffer sb = new StringBuffer();
	    for (i = 0; i < bytes.length; i++) {
	      if (i % 32 == 0 && i != 0) {
	        sb.append("\n");
	      }
	      String s = Integer.toHexString(bytes[i]);
	      if (s.length() < 2) {
	        s = "0" + s;
	      }
	      if (s.length() > 2) {
	        s = s.substring(s.length() - 2);
	      }
	      sb.append(s);
	    }
	    return sb.toString();
	}
	public static void main(String[] args) {

		String passwd = "netkiller";
	    MessageDigest md = null;
		try {
			md = MessageDigest.getInstance("MD5");
			md.update("chen".getBytes());
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		}

	    System.out.println(dumpBytes(md.digest()));
	}

}
				
				

編譯運行,輸入字元串:a1a8887793acfc199182a649e905daab

204.1.4.3. JDK 1.8

JDK 1.8

String hash = DatatypeConverter.printHexBinary(MessageDigest.getInstance("MD5").digest("Helloword!!!".getBytes("UTF-8")));		
				

204.1.5. perl md5

			
 # Functional style
 use Digest::MD5 qw(md5 md5_hex md5_base64);

 $digest = md5($data);
 $digest = md5_hex($data);
 $digest = md5_base64($data);

 # OO style
 use Digest::MD5;

 $ctx = Digest::MD5->new;

 $ctx->add($data);
 $ctx->addfile(*FILE);

 $digest = $ctx->digest;
 $digest = $ctx->hexdigest;
 $digest = $ctx->b64digest;