Java中的MD5加密

来源:互联网 发布:unix网络编程卷3 pdf 编辑:程序博客网 时间:2024/06/14 23:14
简介:
Message Digest Algorithm MD5(中文名为消息摘要算法第五版)为计算机安全领域广泛使用的一种散列函数,用以提供消息的完整性保护。该算法的文件号为RFC 1321(R.Rivest,MIT Laboratory for Computer Science and RSA Data Security Inc. April 1992)

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

安全访问认证
    MD5还广泛用于操作系统的登陆认证上,如Unix、各类BSD系统登录密码、数字签名等诸多方面。如在UNⅨ系统中用户的密码是以MD5(或其它类似的算法)经Hash运算后存储在文件系统中。当用户登录的时候,系统把用户输入的密码进行MD5 Hash运算,然后再去和保存在文件系统中的MD5值进行比较,进而确定输入的密码是否正确。通过这样的步骤,系统在并不知道用户密码的明码的情况下就可以确定用户登录系统的合法性。这可以避免用户的密码被具有系统管理员权限的用户知道。MD5将任意长度的“字节串”映射为一个128bit的大整数,并且是通过该128bit反推原始字符串是困难的,换句话说就是,即使你看到源程序和算法描述,也无法将一个MD5的值变换回原始的字符串,从数学原理上说,是因为原始的字符串有无穷多个,这有点象不存在反函数的数学函数。所以,要遇到了md5密码的问题,比较好的办法是:你可以用这个系统中的md5()函数重新设一个密码,如admin,把生成的一串密码的Hash值覆盖原来的Hash值就行了。
正是因为这个原因,现在被黑客使用最多的一种破译密码的方法就是一种被称为"跑字典"的方法。有两种方法得到字典,一种是日常搜集的用做密码的字符串表,另一种是用排列组合方法生成的,先用MD5程序计算出这些字典项的MD5值,然后再用目标的MD5值在这个字典中检索。我们假设密码的最大长度为8位字节(8 Bytes),同时密码只能是字母和数字,共26+26+10=62个字符,排列组合出的字典的项数则是P(62,1)+P(62,2)….+P(62,8),那也已经是一个很天文的数字了,存储这个字典就需要TB级的磁盘阵列,而且这种方法还有一个前提,就是能获得目标账户的密码MD5值的情况下才可以。这种加密技术被广泛的应用于UNⅨ系统中,这也是为什么UNⅨ系统比一般操作系统更为坚固一个重要原因。

原理:
    对MD5算法简要的叙述可以为:MD5以512位分组来处理输入的信息,且每一分组又被划分为16个32位子分组,经过了一系列的处理后,算法的输出由四个32位分组组成,将这四个32位分组级联后将生成一个128位散列值。
在MD5算法中,首先需要对信息进行填充,使其位长对512求余的结果等于448。因此,信息的位长(Bits Length)将被扩展至N*512+448,N为一个非负整数,N可以是零。填充的方法如下,在信息的后面填充一个1和无数个0,直到满足上面的条件时才停止用0对信息的填充。然后,在这个结果后面附加一个以64位二进制表示的填充前信息长度。经过这两步的处理,现在的信息的位长=N*512+448+64=(N+1)*512,即长度恰好是512的整数倍。这样做的原因是为满足后面处理中对信息长度的要求。总体流程如下图所示,表示第i个分组,每次的运算都由前一轮的128位结果值和第i块512bit值进行运算。初始的128位值为初试链接变量,这些参数用于第一轮的运算,以大端字节序来表示,他们分别为:A=0x01234567,B=0x89ABCDEF,C=0xFEDCBA98,D=0x76543210。


JAVA的MD5加密方法:源代码
package com.sunnylocus.util;    import java.security.MessageDigest;    /**   * 对密码进行加密和验证的类  */  public class CipherUtil{            //十六进制下数字到字符的映射数组      private final static String[] hexDigits = {"0", "1", "2", "3", "4",          "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"};            /** * 把inputString加密     */      public static String generatePassword(String inputString){          return encodeByMD5(inputString);      }              /**        * 验证输入的密码是否正确      * @param password    加密后的密码      * @param inputString    输入的字符串      * @return    验证结果,TRUE:正确 FALSE:错误      */      public static boolean validatePassword(String password, String inputString){          if(password.equals(encodeByMD5(inputString))){              return true;          } else{              return false;          }      }      /**  对字符串进行MD5加密     */      private static String encodeByMD5(String originString){          if (originString != null){              try{                  //创建具有指定算法名称的信息摘要                  MessageDigest md = MessageDigest.getInstance("MD5");                  //使用指定的字节数组对摘要进行最后更新,然后完成摘要计算                  byte[] results = md.digest(originString.getBytes());                  //将得到的字节数组变成字符串返回                  String resultString = byteArrayToHexString(results);                  return resultString.toUpperCase();              } catch(Exception ex){                  ex.printStackTrace();              }          }          return null;      }            /**       * 转换字节数组为十六进制字符串      * @param     字节数组      * @return    十六进制字符串      */      private static String byteArrayToHexString(byte[] b){          StringBuffer resultSb = new StringBuffer();          for (int i = 0; i < b.length; i++){              resultSb.append(byteToHexString(b[i]));          }          return resultSb.toString();      }            /** 将一个字节转化成十六进制形式的字符串     */      private static String byteToHexString(byte b){          int n = b;          if (n < 0)              n = 256 + n;          int d1 = n / 16;          int d2 = n % 16;          return hexDigits[d1] + hexDigits[d2];      }  }  


 

 

Java代码
  package com.sunnylocus.util;    public class Main {      public static void main(String[] args) {          String pwd1="123";          String pwd2="";          CipherUtil cipher = new CipherUtil();          System.out.println("未加密的密码:"+pwd1);          //将123加密          pwd2 = cipher.generatePassword(pwd1);          System.out.println("加密后的密码:"+pwd2);                    System.out.print("验证密码是否下确:");          if(cipher.validatePassword(pwd2, pwd1)) {              System.out.println("正确");          }          else {              System.out.println("错误");          }      }  }  


 

结果输出:

Java代码  未加密的密码:123  
加密后的密码:202CB962AC59075B964B07152D234B70  
验证密码是否下确:正确