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

Java代码  

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

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

Android MD5校验码的生成与算法实现的相关文章

java生成MD5校验码

在Java中,java.security.MessageDigest (rt.jar中)已经定义了 MD5 的计算,所以我们只需要简单地调用即可得到 MD5 的128 位整数.然后将此 128 位计 16 个字节转换成 16 进制表示即可. 下面是一个可生成字符串或文件MD5校验码的例子,测试过,可当做工具类直接使用,其中最主要的是getMD5String(String s)和getFileMD5String(File file)两个方法,分别用于生成字符串的md5校验值和生成文件的md5校验值

Java 获取 文件md5校验码

讯雷下载的核心思想是校验文件的md5值,两个文件若md5相同则为同一文件. 当得到用户下载某个文件的请求后它根据数据库中保留的文件md5比对出拥有此文件的url, 将用户请求挂接到此url上并仿造一个虚假的断点续传请求,从若干url上将一个正常文件拼接出来. 查了下资料,java也可以实现文件md5校验码获取,代码如下: import java.io.File;import java.io.FileInputStream;import java.io.IOException;import jav

C# 获取文件MD5校验码

using System; using System.IO; using System.Security.Cryptography; using System.Text; public class MD5Code { /// <summary> /// Get 文件的MD5校验码 /// </summary> /// <param name="fileName">文件名称</param> /// <returns></r

Android二维码的生成算法原理简介

二维码的定义:二维码 (2-dimensional bar code),是用某种特定的几何图形按一定规律在平面(二维方向上)分布的黑白相间的图形记录数据符号信息的.在许多种类的二维条码中,常用的码制有:Data Matrix, Maxi Code, Aztec, QR Code, Vericode, PDF417, Ultracode, Code 49, Code 16K等.1.堆叠式/行排式二维条码,如,Code 16K.Code 49.PDF417(如下图)等2.矩阵式二维码,最流行莫过于Q

030_根据 md5 校验码,检测文件是否被修改

#!/bin/bash#本示例脚本检测的是/etc 目录下所有的 conf 结尾的文件,根据实际情况,可以修改为其他目录或文件#本脚本在目标数据没有被修改时执行一次,当怀疑数据被人篡改,再执行一次#将两次执行的结果做对比,MD5 码发生改变的文件,就是被人篡改的文件 for i in $(ls /etc/*.conf)do     md5sum "$i" >> /var/log/conf_file.logdone 原文地址:https://www.cnblogs.com/l

md5和SHA校验码

md5已经不安全了,中国山东大学女学霸王小云破解了一系列密码,当真是巾帼不让须眉.说是破解,其实就是给你一个md5码,让你求出这个md5码所对应的原始信息,显然一个md5对应无数种原始信息.而md5的特性就是难以还原初始信息,但是王小云可以迅速找到给定md5码的可行解.md5的解空间虽然巨大,但是却难以捕捉到解. md5虽然已经不安全了,但是仍然可以用于校验. md5不是编码,编码是能够还原初始信息的,而md5只是固定的16byte,它只能从总体上反映初始信息的一些特征,却无法完整的还原出来,因

Java 自带MD5 校验文件

http://www.iteye.com/topic/1127319 前天第一次发表博客到论坛,关于Java文件监控一文,帖子地址在:http://www.iteye.com/topic/1127281 评论的朋友很多,下载代码的朋友很不少,感谢在论坛上看我帖子的朋友,还有回复评论的朋友,给我提供建议的朋友. 从这些建议中,虽然语言简短,但是却有的是一语中的,这里说一下一下关于帖子的代码中HashFile中的MD5文件校验算法, 该算法是使用Java自带的MessageDigest类,测试结果,

2016年最牛逼的分类Android项目源码免费一次性打包下载!

之前发过一个帖子,但是那个帖子有点问题我就重新发一个吧,下面的源码是我从今年开始不断整理源码区和其他网站上的安卓例子源码,目前总共有810套左右,根据实现的功能被我分成了100多个类,总共接近2.5G,还在不断更新.初学者可以快速方便的找到自己想要的例子,大神也可以看一下别人的方法实现.虽然的例子都是我一个人辛辛苦苦花了很多时间和精力整理的,但是既然这些例子是来自于社区那就让他们免费回归社区吧,(是的!特么的不要一分钱!最看不起那些挂羊头卖狗的)你可以在本帖里面按Ctrl+F查找你需要的关键字,

常用校验码(奇偶校验,海明校验,CRC)学习总结

常用校验码(奇偶校验,海明校验,CRC)学习总结 一.为什么要有校验码? 因为在数据存取和传送的过程中,由于元器件或者噪音的干扰等原因会出现错误,这个时候我们就需要采取相应的措施,发现并纠正错误,对于错误的检测和校正,大多采取"冗余校验"的思想,即除原数据外,额外增加若干位编码,这些新增的代码称为校验位. 二.数据是如何校验的? 输入的数据m经过f得到p校验位. 数据m和校验位一起通过存储器或传输线路,分别得到m'和p',这两者可能和m,f相同,也可能由于传输储存发生问题而不同. 由数