MyException - 我的异常网
当前位置:我的异常网» Android » Android MD5校验码的生成与算法兑现

Android MD5校验码的生成与算法兑现

www.MyException.Cn  网友分享于:2013-08-10  浏览:138次
Android MD5校验码的生成与算法实现

在Java中,java.security.MessageDigest (rt.jar中)已经定义了 MD5 的计算,所以我们只需要简单地调用即可得到 MD5 的128 位整数。然后将此 128 位计 16 个字节转换成 16 进制表示即可。 

 

    下面是一个可生成字符串或文件MD5校验码的例子,测试过,可当做工具类直接使用,其中最主要的是getMD5String(String s)和getFileMD5String(File file)两个方法,分别用于生成字符串的md5校验值和生成文件的md5校验值,getFileMD5String_old(File file)方法可删除,不建议使用:

 

Java代码  收藏代码
  1. package  com.why.md5;  
  2.   
  3. import  java.io.File;  
  4. import  java.io.FileInputStream;  
  5. import  java.io.IOException;  
  6. import  java.io.InputStream;  
  7. import  java.nio.MappedByteBuffer;  
  8. import  java.nio.channels.FileChannel;  
  9. import  java.security.MessageDigest;  
  10. import  java.security.NoSuchAlgorithmException;  
  11.   
  12. public   class  MD5Util {  
  13.     /**  
  14.      * 默认的密码字符串组合,用来将字节转换成 16 进制表示的字符,apache校验下载的文件的正确性用的就是默认的这个组合  
  15.      */   
  16.     protected   static   char  hexDigits[] = {  '0' '1' '2' '3' '4' '5' '6' ,  
  17.             '7' '8' '9' 'a' 'b' 'c' 'd' 'e' 'f'  };  
  18.   
  19.     protected   static  MessageDigest messagedigest =  null ;  
  20.     static  {  
  21.         try  {  
  22.             messagedigest = MessageDigest.getInstance("MD5" );  
  23.         } catch  (NoSuchAlgorithmException nsaex) {  
  24.             System.err.println(MD5Util.class .getName()  
  25.                     + "初始化失败,MessageDigest不支持MD5Util。" );  
  26.             nsaex.printStackTrace();  
  27.         }  
  28.     }  
  29.       
  30.     /**  
  31.      * 生成字符串的md5校验值  
  32.      *   
  33.      * @param s  
  34.      * @return  
  35.      */   
  36.     public   static  String getMD5String(String s) {  
  37.         return  getMD5String(s.getBytes());  
  38.     }  
  39.       
  40.     /**  
  41.      * 判断字符串的md5校验码是否与一个已知的md5码相匹配  
  42.      *   
  43.      * @param password 要校验的字符串  
  44.      * @param md5PwdStr 已知的md5校验码  
  45.      * @return  
  46.      */   
  47.     public   static   boolean  checkPassword(String password, String md5PwdStr) {  
  48.         String s = getMD5String(password);  
  49.         return  s.equals(md5PwdStr);  
  50.     }  
  51.       
  52.     /**  
  53.      * 生成文件的md5校验值  
  54.      *   
  55.      * @param file  
  56.      * @return  
  57.      * @throws IOException  
  58.      */   
  59.     public   static  String getFileMD5String(File file)  throws  IOException {         
  60.         InputStream fis;  
  61.         fis = new  FileInputStream(file);  
  62.         byte [] buffer =  new   byte [ 1024 ];  
  63.         int  numRead =  0 ;  
  64.         while  ((numRead = fis.read(buffer)) >  0 ) {  
  65.             messagedigest.update(buffer, 0 , numRead);  
  66.         }  
  67.         fis.close();  
  68.         return  bufferToHex(messagedigest.digest());  
  69.     }  
  70.   
  71.     /**  
  72.      * JDK1.4中不支持以MappedByteBuffer类型为参数update方法,并且网上有讨论要慎用MappedByteBuffer,  
  73.      * 原因是当使用 FileChannel.map 方法时,MappedByteBuffer 已经在系统内占用了一个句柄,  
  74.      * 而使用 FileChannel.close 方法是无法释放这个句柄的,且FileChannel有没有提供类似 unmap 的方法,  
  75.      * 因此会出现无法删除文件的情况。  
  76.      *   
  77.      * 不推荐使用  
  78.      *   
  79.      * @param file  
  80.      * @return  
  81.      * @throws IOException  
  82.      */   
  83.     public   static  String getFileMD5String_old(File file)  throws  IOException {  
  84.         FileInputStream in = new  FileInputStream(file);  
  85.         FileChannel ch = in.getChannel();  
  86.         MappedByteBuffer byteBuffer = ch.map(FileChannel.MapMode.READ_ONLY, 0 ,  
  87.                 file.length());  
  88.         messagedigest.update(byteBuffer);  
  89.         return  bufferToHex(messagedigest.digest());  
  90.     }  
  91.   
  92.     public   static  String getMD5String( byte [] bytes) {  
  93.         messagedigest.update(bytes);  
  94.         return  bufferToHex(messagedigest.digest());  
  95.     }  
  96.   
  97.     private   static  String bufferToHex( byte  bytes[]) {  
  98.         return  bufferToHex(bytes,  0 , bytes.length);  
  99.     }  
  100.   
  101.     private   static  String bufferToHex( byte  bytes[],  int  m,  int  n) {  
  102.         StringBuffer stringbuffer = new  StringBuffer( 2  * n);  
  103.         int  k = m + n;  
  104.         for  ( int  l = m; l < k; l++) {  
  105.             appendHexPair(bytes[l], stringbuffer);  
  106.         }  
  107.         return  stringbuffer.toString();  
  108.     }  
  109.   
  110.     private   static   void  appendHexPair( byte  bt, StringBuffer stringbuffer) {  
  111.         char  c0 = hexDigits[(bt &  0xf0 ) >>  4 ]; // 取字节中高 4 位的数字转换, >>> 为逻辑右移,将符号位一起右移,此处未发现两种符号有何不同    
  112.         char  c1 = hexDigits[bt &  0xf ]; // 取字节中低 4 位的数字转换    
  113.         stringbuffer.append(c0);  
  114.         stringbuffer.append(c1);  
  115.     }  
  116.       
  117.     public   static   void  main(String[] args)  throws  IOException {  
  118.         long  begin = System.currentTimeMillis();  
  119.   
  120.         File file = new  File( "C:/12345.txt" );  
  121.         String md5 = getFileMD5String(file);  
  122.   
  123. //      String md5 = getMD5String("a");   
  124.           
  125.         long  end = System.currentTimeMillis();  
  126.         System.out.println("md5:"  + md5 +  " time:"  + ((end - begin) /  1000 ) +  "s" );  
  127.     }  
  128. }  
package com.why.md5;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class MD5Util {
	/**
	 * 默认的密码字符串组合,用来将字节转换成 16 进制表示的字符,apache校验下载的文件的正确性用的就是默认的这个组合
	 */
	protected static char hexDigits[] = { '0', '1', '2', '3', '4', '5', '6',
			'7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };

	protected static MessageDigest messagedigest = null;
	static {
		try {
			messagedigest = MessageDigest.getInstance("MD5");
		} catch (NoSuchAlgorithmException nsaex) {
			System.err.println(MD5Util.class.getName()
					+ "初始化失败,MessageDigest不支持MD5Util。");
			nsaex.printStackTrace();
		}
	}
	
	/**
	 * 生成字符串的md5校验值
	 * 
	 * @param s
	 * @return
	 */
	public static String getMD5String(String s) {
		return getMD5String(s.getBytes());
	}
	
	/**
	 * 判断字符串的md5校验码是否与一个已知的md5码相匹配
	 * 
	 * @param password 要校验的字符串
	 * @param md5PwdStr 已知的md5校验码
	 * @return
	 */
	public static boolean checkPassword(String password, String md5PwdStr) {
		String s = getMD5String(password);
		return s.equals(md5PwdStr);
	}
	
	/**
	 * 生成文件的md5校验值
	 * 
	 * @param file
	 * @return
	 * @throws IOException
	 */
	public static String getFileMD5String(File file) throws IOException {		
		InputStream fis;
	    fis = new FileInputStream(file);
	    byte[] buffer = new byte[1024];
	    int numRead = 0;
	    while ((numRead = fis.read(buffer)) > 0) {
	    	messagedigest.update(buffer, 0, numRead);
	    }
	    fis.close();
		return bufferToHex(messagedigest.digest());
	}

	/**
	 * JDK1.4中不支持以MappedByteBuffer类型为参数update方法,并且网上有讨论要慎用MappedByteBuffer,
	 * 原因是当使用 FileChannel.map 方法时,MappedByteBuffer 已经在系统内占用了一个句柄,
	 * 而使用 FileChannel.close 方法是无法释放这个句柄的,且FileChannel有没有提供类似 unmap 的方法,
	 * 因此会出现无法删除文件的情况。
	 * 
	 * 不推荐使用
	 * 
	 * @param file
	 * @return
	 * @throws IOException
	 */
	public static String getFileMD5String_old(File file) throws IOException {
		FileInputStream in = new FileInputStream(file);
		FileChannel ch = in.getChannel();
		MappedByteBuffer byteBuffer = ch.map(FileChannel.MapMode.READ_ONLY, 0,
				file.length());
		messagedigest.update(byteBuffer);
		return bufferToHex(messagedigest.digest());
	}

	public static String getMD5String(byte[] bytes) {
		messagedigest.update(bytes);
		return bufferToHex(messagedigest.digest());
	}

	private static String bufferToHex(byte bytes[]) {
		return bufferToHex(bytes, 0, bytes.length);
	}

	private static String bufferToHex(byte bytes[], int m, int n) {
		StringBuffer stringbuffer = new StringBuffer(2 * n);
		int k = m + n;
		for (int l = m; l < k; l++) {
			appendHexPair(bytes[l], stringbuffer);
		}
		return stringbuffer.toString();
	}

	private static void appendHexPair(byte bt, StringBuffer stringbuffer) {
		char c0 = hexDigits[(bt & 0xf0) >> 4];// 取字节中高 4 位的数字转换, >>> 为逻辑右移,将符号位一起右移,此处未发现两种符号有何不同 
		char c1 = hexDigits[bt & 0xf];// 取字节中低 4 位的数字转换 
		stringbuffer.append(c0);
		stringbuffer.append(c1);
	}
	
	public static void main(String[] args) throws IOException {
		long begin = System.currentTimeMillis();

		File file = new File("C:/12345.txt");
		String md5 = getFileMD5String(file);

//		String md5 = getMD5String("a");
		
		long end = System.currentTimeMillis();
		System.out.println("md5:" + md5 + " time:" + ((end - begin) / 1000)	+ "s");
	}
}

 

   MD5的全称是Message-digest Algorithm 5(信息-摘要算法),用于确保信息传输完整一致。90年代初由MIT的计算机科学实验室和RSA Data Security Inc的Ronald L. Rivest开发出来,经MD2、MD3和MD4发展而来。

 

    任何一个字符串或文件,无论是可执行程序、图像文件、临时文件或者其他任何类型的文件,也不管它体积多大,都有且只有一个独一无二的MD5信息码,并且如果这个文件被修改过,它的MD5码也将随之改变。

 

    Message-Digest泛指字节串(Message)的Hash变换,就是把一个任意长度的字节串变换成一定长的大整数。注意这里说的是“字节串”而不是“字符串”,因为这种变换只与字节的值有关,与字符集或编码方式无关。

 

    MD5用的是哈希函数,在计算机网络中应用较多的不可逆加密算法有RSA公司发明的MD5算法和由美国国家技术标准研究所建议的安全散列算法SHA。

 

    MD5将任意长度的“字节串”变换成一个128bit的大整数,并且它是一个不可逆的字符串变换算法,换句话说就是,即使你看到源程序和算法描述,也无法 将一个MD5的值变换回原始的字符串,从数学原理上说,是因为原始的字符串有无穷多个,这有点象不存在反函数的数学函数。所以,要遇到了md5密码的问 题,比较好的办法是:你可以用这个系统中的md5()函数重新设一个密码,如admin,把生成的一串密码的Hash值覆盖原来的Hash值就行了。

 

    MD5的典型应用是对一段Message(字节串)产生fingerprint(指纹),以防止被“篡改”。举个例子,你将一段话写在一个叫 readme.txt文件中,并对这个readme.txt产生一个MD5的值并记录在案,然后你可以传播这个文件给别人,别人如果修改了文件中的任何内 容,你对这个文件重新计算MD5时就会发现(两个MD5值不相同)。如果再有一个第三方的认证机构,用MD5还可以防止文件作者的“抵赖”,这就是所谓的 数字签名应用。


  MD5还广泛用于操作系统的登陆认证上,如Unix、各类BSD系统登录密码、数字签名等诸多方。如在UNIX系统中用户的密码是以 MD5(或其它类似的算法)经Hash运算后存储在文件系统中。当用户登录的时候,系统把用户输入的密码进行MD5 Hash运算,然后再去和保存在文件系统中的MD5值进行比较,进而确定输入的密码是否正确。通过这样的步骤,系统在并不知道用户密码的明码的情况下就可 以确定用户登录系统的合法性。这可以避免用户的密码被具有系统管理员权限的用户知道。

 

    现在被黑客使用最多的一种破译密码的方法就是一种被称为"跑字典"的方法。有两种方法得到字典,一种是日常搜集的用做密码的字符串表,另一种是用排列组合 方法生成的,先用MD5程序计算出这些字典项的MD5值,然后再用目标的MD5值在这个字典中检索。我们假设密码的最大长度为8位字节(8 Bytes),同时密码只能是字母和数字,共26+26+10=62个字符,排列组合出的字典的项数则是 P(62,1)+P(62,2)….+P(62,8),那也已经是一个很天文的数字了,存储这个字典就需要TB级的磁盘阵列,而且这种方法还有一个前提, 就是能获得目标账户的密码MD5值的情况下才可以。这种加密技术被广泛的应用于UNIX系统中,这也是为什么UNIX系统比一般操作系统更为坚固一个重要 原因。

 

MD5算法
      md5算法定义在RFC 1321中,由Ron Rivest(RSA公司)在1992年提出。然而很多学者已经找出了构造md5冲突的方法。这些人中包括中国山东大学的王教授和Hans Dobbertin。所以,单纯使用md5的信息认证模式变得不可靠了。但并不是说md5不能够使用。

 

    MD5以512位分组来处理输入的信息,且每一分组又被划分为16个32位子分组,经过了一系列的处理后,算法的输出由四个32位分组组成,将这四个32位分组级联后将生成一个128位散列值。

 

MD5算法的计算步骤:

1.通过添加一个1和若干个0的方式,把输入数据长度(按照字节算)变成64m+56
2.添加8个字节到输入数据中去,这样输入数据长度变成了64的倍数
3.把数据划分成块,每块64个字节
4.初始情况下,输出为:                                                                   
  m_state[0] = 0x67452301L;
  m_state[1] = 0xefcdab89L;
  m_state[2] = 0x98badcfeL;
  m_state[3] = 0x10325476L;
5.分别对每块进行计算。输出最后结果。

 

    MD5的算法在RFC1321中实际上已经提供了C的实现,需要注意的是,很多早期的C编译器的int类型是16 bit的,MD5使用了unsigned long int,并认为它是32bit的无符号整数。而在Java中int是32 bit的,long是64 bit的。在MD5的C实现中,使用了大量的位操作。这里需要指出的一点是,尽管Java提供了位操作,由于Java没有unsigned类型,对于右移 位操作多提供了一个无符号右移:>>>,等价于C中的 >> 对于unsigned 数的处理。

 

下面是一个MD5算法的Java实现:

 

Java代码  收藏代码
  1. package  com.why.md5;  
  2.   
  3. /*******************************************************************************  
  4.  * MD5_SRC 类实现了RSA Data Security, Inc.在提交给IETF的RFC1321中的MD5_SRC message-digest  
  5.  * 算法。  
  6.  ******************************************************************************/   
  7. public   class  MD5_SRC {  
  8.     /*  
  9.      * 下面这些S11-S44实际上是一个4*4的矩阵,在原始的C实现中是用#define 实现的, 这里把它们实现成为static  
  10.      * final是表示了只读,且能在同一个进程空间内的多个 Instance间共享  
  11.      */   
  12.     static   final   int  S11 =  7 ;  
  13.   
  14.     static   final   int  S12 =  12 ;  
  15.   
  16.     static   final   int  S13 =  17 ;  
  17.   
  18.     static   final   int  S14 =  22 ;  
  19.   
  20.     static   final   int  S21 =  5 ;  
  21.   
  22.     static   final   int  S22 =  9 ;  
  23.   
  24.     static   final   int  S23 =  14 ;  
  25.   
  26.     static   final   int  S24 =  20 ;  
  27.   
  28.     static   final   int  S31 =  4 ;  
  29.   
  30.     static   final   int  S32 =  11 ;  
  31.   
  32.     static   final   int  S33 =  16 ;  
  33.   
  34.     static   final   int  S34 =  23 ;  
  35.   
  36.     static   final   int  S41 =  6 ;  
  37.   
  38.     static   final   int  S42 =  10 ;  
  39.   
  40.     static   final   int  S43 =  15 ;  
  41.   
  42.     static   final   int  S44 =  21 ;  
  43.   
  44.     static   final   byte [] PADDING = { - 128 0 0 0 0 0 0 0 0 0 0 0 0 ,  
  45.             0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ,  
  46.             0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ,  
  47.             0 0 0 0 0 0 0  };  
  48.   
  49.     /*  
  50.      * 下面的三个成员是keyBean计算过程中用到的3个核心数据,在原始的C实现中 被定义到keyBean_CTX结构中  
  51.      */   
  52.     private   long [] state =  new   long [ 4 ];  // state (ABCD)   
  53.   
  54.     private   long [] count =  new   long [ 2 ];  // number of bits, modulo 2^64 (lsb first)   
  55.   
  56.     private   byte [] buffer =  new   byte [ 64 ];  // input buffer   
  57.   
  58.     /*  
  59.      * digestHexStr是keyBean的唯一一个公共成员,是最新一次计算结果的 16进制ASCII表示.  
  60.      */   
  61.   
  62.     public  String digestHexStr;  
  63.   
  64.     /*  
  65.      * digest,是最新一次计算结果的2进制内部表示,表示128bit的keyBean值.  
  66.      */   
  67.     private   byte [] digest =  new   byte [ 16 ];  
  68.   
  69.     /*  
  70.      * getkeyBeanofStr是类keyBean最主要的公共方法,入口参数是你想要进行keyBean变换的字符串  
  71.      * 返回的是变换完的结果,这个结果是从公共成员digestHexStr取得的.  
  72.      */   
  73.     public  String getkeyBeanofStr(String inbuf) {  
  74.         keyBeanInit();  
  75.         keyBeanUpdate(inbuf.getBytes(), inbuf.length());  
  76.         keyBeanFinal();  
  77.         digestHexStr = "" ;  
  78.         for  ( int  i =  0 ; i <  16 ; i++) {  
  79.             digestHexStr += byteHEX(digest[i]);  
  80.         }  
  81.         return  digestHexStr;  
  82.     }  
  83.   
  84.     // 这是keyBean这个类的标准构造函数,JavaBean要求有一个public的并且没有参数的构造函数   
  85.     public  MD5_SRC() {  
  86.         keyBeanInit();  
  87.         return ;  
  88.     }  
  89.   
  90.     /* keyBeanInit是一个初始化函数,初始化核心变量,装入标准的幻数 */   
  91.     private   void  keyBeanInit() {  
  92.         count[0 ] = 0L;  
  93.         count[1 ] = 0L;  
  94.         // /* Load magic initialization constants.   
  95.         state[0 ] = 0x67452301L;  
  96.         state[1 ] = 0xefcdab89L;  
  97.         state[2 ] = 0x98badcfeL;  
  98.         state[3 ] = 0x10325476L;  
  99.         return ;  
  100.     }  
  101.   
  102.     /*  
  103.      * F, G, H ,I 是4 个基本的keyBean函数,在原始的keyBean的C实现中,由于它们是  
  104.      * 简单的位运算,可能出于效率的考虑把它们实现成了宏,在java中,我们把它们 实现成了private 方法,名字保持了原来C中的。  
  105.      */  
  106.     private   long  F( long  x,  long  y,  long  z) {  
  107.         return  (x & y) | ((~x) & z);  
  108.     }  
  109.   
  110.     private   long  G( long  x,  long  y,  long  z) {  
  111.         return  (x & z) | (y & (~z));  
  112.     }  
  113.   
  114.     private   long  H( long  x,  long  y,  long  z) {  
  115.         return  x ^ y ^ z;  
  116.     }  
  117.   
  118.     private   long  I( long  x,  long  y,  long  z) {  
  119.         return  y ^ (x | (~z));  
  120.     }  
  121.   
  122.     /*  
  123.      * FF,GG,HH和II将调用F,G,H,I进行近一步变换 FF, GG, HH, and II transformations for  
  124.      * rounds 1, 2, 3, and 4. Rotation is separate from addition to prevent  
  125.      * recomputation.  
  126.      */   
  127.     private   long  FF( long  a,  long  b,  long  c,  long  d,  long  x,  long  s,  long  ac) {  
  128.         a += F(b, c, d) + x + ac;  
  129.         a = ((int ) a << s) | (( int ) a >>> ( 32  - s));  
  130.         a += b;  
  131.         return  a;  
  132.     }  
  133.   
  134.     private   long  GG( long  a,  long  b,  long  c,  long  d,  long  x,  long  s,  long  ac) {  
  135.         a += G(b, c, d) + x + ac;  
  136.         a = ((int ) a << s) | (( int ) a >>> ( 32  - s));  
  137.         a += b;  
  138.         return  a;  
  139.     }  
  140.   
  141.     private   long  HH( long  a,  long  b,  long  c,  long  d,  long  x,  long  s,  long  ac) {  
  142.         a += H(b, c, d) + x + ac;  
  143.         a = ((int ) a << s) | (( int ) a >>> ( 32  - s));  
  144.         a += b;  
  145.         return  a;  
  146.     }  
  147.   
  148.     private   long  II( long  a,  long  b,  long  c,  long  d,  long  x,  long  s,  long  ac) {  
  149.         a += I(b, c, d) + x + ac;  
  150.         a = ((int ) a << s) | (( int ) a >>> ( 32  - s));  
  151.         a += b;  
  152.         return  a;  
  153.     }  
  154.   
  155.     /*  
  156.      * keyBeanUpdate是keyBean的主计算过程,inbuf是要变换的字节串,inputlen是长度,这个  
  157.      * 函数由getkeyBeanofStr调用,调用之前需要调用keyBeaninit,因此把它设计成private的  
  158.      */   
  159.     private   void  keyBeanUpdate( byte [] inbuf,  int  inputLen) {  
  160.         int  i, index, partLen;  
  161.         byte [] block =  new   byte [ 64 ];  
  162.         index = (int ) (count[ 0 ] >>>  3 ) &  0x3F ;  
  163.         // /* Update number of bits */   
  164.         if  ((count[ 0 ] += (inputLen <<  3 )) < (inputLen <<  3 ))  
  165.             count[1 ]++;  
  166.         count[1 ] += (inputLen >>>  29 );  
  167.         partLen = 64  - index;  
  168.         // Transform as many times as possible.   
  169.         if  (inputLen >= partLen) {  
  170.             keyBeanMemcpy(buffer, inbuf, index, 0 , partLen);  
  171.             keyBeanTransform(buffer);  
  172.             for  (i = partLen; i +  63  < inputLen; i +=  64 ) {  
  173.                 keyBeanMemcpy(block, inbuf, 0 , i,  64 );  
  174.                 keyBeanTransform(block);  
  175.             }  
  176.             index = 0 ;  
  177.         } else   
  178.             i = 0 ;  
  179.         // /* Buffer remaining input */   
  180.         keyBeanMemcpy(buffer, inbuf, index, i, inputLen - i);  
  181.     }  
  182.   
  183.     /*  
  184.      * keyBeanFinal整理和填写输出结果  
  185.      */   
  186.     private   void  keyBeanFinal() {  
  187.         byte [] bits =  new   byte [ 8 ];  
  188.         int  index, padLen;  
  189.         // /* Save number of bits */   
  190.         Encode(bits, count, 8 );  
  191.         // /* Pad out to 56 mod 64.   
  192.         index = (int ) (count[ 0 ] >>>  3 ) &  0x3f ;  
  193.         padLen = (index < 56 ) ? ( 56  - index) : ( 120  - index);  
  194.         keyBeanUpdate(PADDING, padLen);  
  195.         // /* Append length (before padding) */   
  196.         keyBeanUpdate(bits, 8 );  
  197.         // /* Store state in digest */   
  198.         Encode(digest, state, 16 );  
  199.     }  
  200.   
  201.     /*  
  202.      * keyBeanMemcpy是一个内部使用的byte数组的块拷贝函数,从input的inpos开始把len长度的  
  203.      * 字节拷贝到output的outpos位置开始  
  204.      */   
  205.     private   void  keyBeanMemcpy( byte [] output,  byte [] input,  int  outpos,  
  206.             int  inpos,  int  len) {  
  207.         int  i;  
  208.         for  (i =  0 ; i < len; i++)  
  209.             output[outpos + i] = input[inpos + i];  
  210.     }  
  211.   
  212.     /*  
  213.      * keyBeanTransform是keyBean核心变换程序,由keyBeanUpdate调用,block是分块的原始字节  
  214.      */   
  215.     private   void  keyBeanTransform( byte  block[]) {  
  216.         long  a = state[ 0 ], b = state[ 1 ], c = state[ 2 ], d = state[ 3 ];  
  217.         long [] x =  new   long [ 16 ];  
  218.         Decode(x, block, 64 );  
  219.         /* Round 1 */   
  220.         a = FF(a, b, c, d, x[0 ], S11, 0xd76aa478L);  /* 1 */   
  221.         d = FF(d, a, b, c, x[1 ], S12, 0xe8c7b756L);  /* 2 */   
  222.         c = FF(c, d, a, b, x[2 ], S13, 0x242070dbL);  /* 3 */   
  223.         b = FF(b, c, d, a, x[3 ], S14, 0xc1bdceeeL);  /* 4 */   
  224.         a = FF(a, b, c, d, x[4 ], S11, 0xf57c0fafL);  /* 5 */   
  225.         d = FF(d, a, b, c, x[5 ], S12, 0x4787c62aL);  /* 6 */   
  226.         c = FF(c, d, a, b, x[6 ], S13, 0xa8304613L);  /* 7 */   
  227.         b = FF(b, c, d, a, x[7 ], S14, 0xfd469501L);  /* 8 */   
  228.         a = FF(a, b, c, d, x[8 ], S11, 0x698098d8L);  /* 9 */   
  229.         d = FF(d, a, b, c, x[9 ], S12, 0x8b44f7afL);  /* 10 */   
  230.         c = FF(c, d, a, b, x[10 ], S13, 0xffff5bb1L);  /* 11 */   
  231.         b = FF(b, c, d, a, x[11 ], S14, 0x895cd7beL);  /* 12 */   
  232.         a = FF(a, b, c, d, x[12 ], S11, 0x6b901122L);  /* 13 */   
  233.         d = FF(d, a, b, c, x[13 ], S12, 0xfd987193L);  /* 14 */   
  234.         c = FF(c, d, a, b, x[14 ], S13, 0xa679438eL);  /* 15 */   
  235.         b = FF(b, c, d, a, x[15 ], S14, 0x49b40821L);  /* 16 */   
  236.         /* Round 2 */   
  237.         a = GG(a, b, c, d, x[1 ], S21, 0xf61e2562L);  /* 17 */   
  238.         d = GG(d, a, b, c, x[6 ], S22, 0xc040b340L);  /* 18 */   
  239.         c = GG(c, d, a, b, x[11 ], S23, 0x265e5a51L);  /* 19 */   
  240.         b = GG(b, c, d, a, x[0 ], S24, 0xe9b6c7aaL);  /* 20 */   
  241.         a = GG(a, b, c, d, x[5 ], S21, 0xd62f105dL);  /* 21 */   
  242.         d = GG(d, a, b, c, x[10 ], S22, 0x2441453L);  /* 22 */   
  243.         c = GG(c, d, a, b, x[15 ], S23, 0xd8a1e681L);  /* 23 */   
  244.         b = GG(b, c, d, a, x[4 ], S24, 0xe7d3fbc8L);  /* 24 */   
  245.         a = GG(a, b, c, d, x[9 ], S21, 0x21e1cde6L);  /* 25 */   
  246.         d = GG(d, a, b, c, x[14 ], S22, 0xc33707d6L);  /* 26 */   
  247.         c = GG(c, d, a, b, x[3 ], S23, 0xf4d50d87L);  /* 27 */   
  248.         b = GG(b, c, d, a, x[8 ], S24, 0x455a14edL);  /* 28 */   
  249.         a = GG(a, b, c, d, x[13 ], S21, 0xa9e3e905L);  /* 29 */   
  250.         d = GG(d, a, b, c, x[2 ], S22, 0xfcefa3f8L);  /* 30 */   
  251.         c = GG(c, d, a, b, x[7 ], S23, 0x676f02d9L);  /* 31 */   
  252.         b = GG(b, c, d, a, x[12 ], S24, 0x8d2a4c8aL);  /* 32 */   
  253.         /* Round 3 */   
  254.         a = HH(a, b, c, d, x[5 ], S31, 0xfffa3942L);  /* 33 */   
  255.         d = HH(d, a, b, c, x[8 ], S32, 0x8771f681L);  /* 34 */   
  256.         c = HH(c, d, a, b, x[11 ], S33, 0x6d9d6122L);  /* 35 */   
  257.         b = HH(b, c, d, a, x[14 ], S34, 0xfde5380cL);  /* 36 */   
  258.         a = HH(a, b, c, d, x[1 ], S31, 0xa4beea44L);  /* 37 */   
  259.         d = HH(d, a, b, c, x[4 ], S32, 0x4bdecfa9L);  /* 38 */   
  260.         c = HH(c, d, a, b, x[7 ], S33, 0xf6bb4b60L);  /* 39 */   
  261.         b = HH(b, c, d, a, x[10 ], S34, 0xbebfbc70L);  /* 40 */   
  262.         a = HH(a, b, c, d, x[13 ], S31, 0x289b7ec6L);  /* 41 */   
  263.         d = HH(d, a, b, c, x[0 ], S32, 0xeaa127faL);  /* 42 */   
  264.         c = HH(c, d, a, b, x[3 ], S33, 0xd4ef3085L);  /* 43 */   
  265.         b = HH(b, c, d, a, x[6 ], S34, 0x4881d05L);  /* 44 */   
  266.         a = HH(a, b, c, d, x[9 ], S31, 0xd9d4d039L);  /* 45 */   
  267.         d = HH(d, a, b, c, x[12 ], S32, 0xe6db99e5L);  /* 46 */   
  268.         c = HH(c, d, a, b, x[15 ], S33, 0x1fa27cf8L);  /* 47 */   
  269.         b = HH(b, c, d, a, x[2 ], S34, 0xc4ac5665L);  /* 48 */   
  270.         /* Round 4 */   
  271.         a = II(a, b, c, d, x[0 ], S41, 0xf4292244L);  /* 49 */   
  272.         d = II(d, a, b, c, x[7 ], S42, 0x432aff97L);  /* 50 */   
  273.         c = II(c, d, a, b, x[14 ], S43, 0xab9423a7L);  /* 51 */   
  274.         b = II(b, c, d, a, x[5 ], S44, 0xfc93a039L);  /* 52 */   
  275.         a = II(a, b, c, d, x[12 ], S41, 0x655b59c3L);  /* 53 */   
  276.         d = II(d, a, b, c, x[3 ], S42, 0x8f0ccc92L);  /* 54 */   
  277.         c = II(c, d, a, b, x[10 ], S43, 0xffeff47dL);  /* 55 */   
  278.         b = II(b, c, d, a, x[1 ], S44, 0x85845dd1L);  /* 56 */   
  279.         a = II(a, b, c, d, x[8 ], S41, 0x6fa87e4fL);  /* 57 */   
  280.         d = II(d, a, b, c, x[15 ], S42, 0xfe2ce6e0L);  /* 58 */   
  281.         c = II(c, d, a, b, x[6 ], S43, 0xa3014314L);  /* 59 */   
  282.         b = II(b, c, d, a, x[13 ], S44, 0x4e0811a1L);  /* 60 */   
  283.         a = II(a, b, c, d, x[4 ], S41, 0xf7537e82L);  /* 61 */   
  284.         d = II(d, a, b, c, x[11 ], S42, 0xbd3af235L);  /* 62 */   
  285.         c = II(c, d, a, b, x[2 ], S43, 0x2ad7d2bbL);  /* 63 */   
  286.         b = II(b, c, d, a, x[9 ], S44, 0xeb86d391L);  /* 64 */   
  287.         state[0 ] += a;  
  288.         state[1 ] += b;  
  289.         state[2 ] += c;  
  290.         state[3 ] += d;  
  291.     }  
  292.   
  293.     /*  
  294.      * Encode把long数组按顺序拆成byte数组,因为java的long类型是64bit的,只拆低32bit,以适应原始C实现的用途  
  295.      */   
  296.     private   void  Encode( byte [] output,  long [] input,  int  len) {  
  297.         int  i, j;  
  298.         for  (i =  0 , j =  0 ; j < len; i++, j +=  4 ) {  
  299.             output[j] = (byte ) (input[i] & 0xffL);  
  300.             output[j + 1 ] = ( byte ) ((input[i] >>>  8 ) & 0xffL);  
  301.             output[j + 2 ] = ( byte ) ((input[i] >>>  16 ) & 0xffL);  
  302.             output[j + 3 ] = ( byte ) ((input[i] >>>  24 ) & 0xffL);  
  303.         }  
  304.     }  
  305.   
  306.     /*  
  307.      * Decode把byte数组按顺序合成成long数组,因为java的long类型是64bit的,  
  308.      * 只合成低32bit,高32bit清零,以适应原始C实现的用途  
  309.      */   
  310.     private   void  Decode( long [] output,  byte [] input,  int  len) {  
  311.         int  i, j;  
  312.   
  313.         for  (i =  0 , j =  0 ; j < len; i++, j +=  4 )  
  314.             output[i] = b2iu(input[j]) | (b2iu(input[j + 1 ]) <<  8 )  
  315.                     | (b2iu(input[j + 2 ]) <<  16 ) | (b2iu(input[j +  3 ]) <<  24 );  
  316.         return ;  
  317.     }  
  318.   
  319.     /*  
  320.      * b2iu是我写的一个把byte按照不考虑正负号的原则的”升位”程序,因为java没有unsigned运算  
  321.      */   
  322.     public   static   long  b2iu( byte  b) {  
  323.         return  b <  0  ? b &  0x7F  +  128  : b;  
  324.     }  
  325.   
  326.     /*  
  327.      * byteHEX(),用来把一个byte类型的数转换成十六进制的ASCII表示,  
  328.      * 因为java中的byte的toString无法实现这一点,我们又没有C语言中的 sprintf(outbuf,"%02X",ib)  
  329.      */   
  330.     public   static  String byteHEX( byte  ib) {  
  331.         char [] Digit = {  '0' '1' '2' '3' '4' '5' '6' '7' '8' '9' 'A' ,  
  332.                 'B' 'C' 'D' 'E' 'F'  };  
  333.         char [] ob =  new   char [ 2 ];  
  334.         ob[0 ] = Digit[(ib >>>  4 ) &  0X0F ];  
  335.         ob[1 ] = Digit[ib &  0X0F ];  
  336.         String s = new  String(ob);  
  337.         return  s;  
  338.     }  
  339.   
  340.     public   static   void  main(String args[]) {  
  341.   
  342.         MD5_SRC m = new  MD5_SRC();  
  343.         System.out.println("keyBean Test suite:" );  
  344.         System.out.println("keyBean(\"\"):" +m.getkeyBeanofStr( "" ));  
  345.         System.out.println("keyBean(\"a\"):" +m.getkeyBeanofStr( "a" ));  
  346.         System.out.println("keyBean(\"abc\"):" +m.getkeyBeanofStr( "abc" ));  
  347.         System.out.println("keyBean(\"message digest\"):" +m.getkeyBeanofStr( "message digest" ));  
  348.         System.out.println("keyBean(\"abcdefghijklmnopqrstuvwxyz\"):" +  
  349.                 m.getkeyBeanofStr("abcdefghijklmnopqrstuvwxyz" ));  
  350.         System.out.println("keyBean(\"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\"):" +  
  351.                 m.getkeyBeanofStr("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" ));  
  352.           
  353.     }  

文章评论

程序员都该阅读的书
程序员都该阅读的书
程序员和编码员之间的区别
程序员和编码员之间的区别
程序员周末都喜欢做什么?
程序员周末都喜欢做什么?
写给自己也写给你 自己到底该何去何从
写给自己也写给你 自己到底该何去何从
鲜为人知的编程真相
鲜为人知的编程真相
我是如何打败拖延症的
我是如何打败拖延症的
团队中“技术大拿”并非越多越好
团队中“技术大拿”并非越多越好
为什么程序员都是夜猫子
为什么程序员都是夜猫子
程序员应该关注的一些事儿
程序员应该关注的一些事儿
60个开发者不容错过的免费资源库
60个开发者不容错过的免费资源库
10个帮程序员减压放松的网站
10个帮程序员减压放松的网站
“懒”出效率是程序员的美德
“懒”出效率是程序员的美德
10个调试和排错的小建议
10个调试和排错的小建议
我跳槽是因为他们的显示器更大
我跳槽是因为他们的显示器更大
什么才是优秀的用户界面设计
什么才是优秀的用户界面设计
聊聊HTTPS和SSL/TLS协议
聊聊HTTPS和SSL/TLS协议
编程语言是女人
编程语言是女人
做程序猿的老婆应该注意的一些事情
做程序猿的老婆应该注意的一些事情
十大编程算法助程序员走上高手之路
十大编程算法助程序员走上高手之路
 程序员的样子
程序员的样子
科技史上最臭名昭著的13大罪犯
科技史上最臭名昭著的13大罪犯
老美怎么看待阿里赴美上市
老美怎么看待阿里赴美上市
Java程序员必看电影
Java程序员必看电影
如何成为一名黑客
如何成为一名黑客
总结2014中国互联网十大段子
总结2014中国互联网十大段子
如何区分一个程序员是“老手“还是“新手“?
如何区分一个程序员是“老手“还是“新手“?
Web开发人员为什么越来越懒了?
Web开发人员为什么越来越懒了?
我的丈夫是个程序员
我的丈夫是个程序员
看13位CEO、创始人和高管如何提高工作效率
看13位CEO、创始人和高管如何提高工作效率
Java 与 .NET 的平台发展之争
Java 与 .NET 的平台发展之争
那些争议最大的编程观点
那些争议最大的编程观点
程序员最害怕的5件事 你中招了吗?
程序员最害怕的5件事 你中招了吗?
漫画:程序员的工作
漫画:程序员的工作
不懂技术不要对懂技术的人说这很容易实现
不懂技术不要对懂技术的人说这很容易实现
“肮脏的”IT工作排行榜
“肮脏的”IT工作排行榜
每天工作4小时的程序员
每天工作4小时的程序员
程序员眼里IE浏览器是什么样的
程序员眼里IE浏览器是什么样的
程序员的鄙视链
程序员的鄙视链
旅行,写作,编程
旅行,写作,编程
老程序员的下场
老程序员的下场
一个程序员的时间管理
一个程序员的时间管理
Web开发者需具备的8个好习惯
Web开发者需具备的8个好习惯
为啥Android手机总会越用越慢?
为啥Android手机总会越用越慢?
程序员必看的十大电影
程序员必看的十大电影
代码女神横空出世
代码女神横空出世
软件开发程序错误异常ExceptionCopyright © 2009-2015 MyException 版权所有