2014年4月20日 星期日

Java 的 MD5 加密

現在公司上上下下在瘋資安, 所有的資訊系統都要進行管控, 以往登入比對都是用明碼 (趕時間上線, 能用就行), 管理員都知道每一個人的密碼, 為了怕瓜田李下, 我都要人家隨便用 123 就好, 反正內部網路, 也不怕外部入侵. 但資安來了就不能便宜行事, 所以登入密碼都要加密.

最常用的加密系統是 md5, 例如 PHP 就提供了 md5() 函式, 非常方便.

# http://www.w3school.com.cn/php/func_string_md5.asp


那 Java 該怎麼做呢? 這要用到 java.security.MessageDigest 這個抽象類別, 呼叫其 getInstance() 並傳入 "MD5" 字串指定其加密演算法就會傳回一個實作此演算法的 MessageDigest 物件, 呼叫此物件的 digest() 方法, 並將欲加密的字串以 byte 陣列方式傳入, 就會傳回以 MD5 加密之 byte 陣列. 其 API 見 :

# http://docs.oracle.com/javase/7/docs/api/java/security/MessageDigest.html

以下範例是我參考 "Java 程式開發 349 例" 一書中的例子改寫的, 

import java.security.MessageDigest;
public class mytest {
  public static void main(String[] args) {
    String str="I love you";
    System.out.println(md5(str));  //輸出 E4F58A805A6E1FD0F6BEF58C86F9CEB3
    }
  public static String md5(String str) {
    String md5=null;
    try {
      MessageDigest md=MessageDigest.getInstance("MD5");
      byte[] barr=md.digest(str.getBytes());  //將 byte 陣列加密
      StringBuffer sb=new StringBuffer();  //將 byte 陣列轉成 16 進制
      for (int i=0; i < barr.length; i++) {sb.append(byte2Hex(barr[i]));}
      String hex=sb.toString();
      md5=hex.toUpperCase(); //一律轉成大寫
      }
    catch(Exception e) {e.printStackTrace();}
    return md5;
    }
  public static String byte2Hex(byte b) {
    String[] h={"0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f"};
    int i=b;
    if (i < 0) {i += 256;}
    return h[i/16] + h[i%16];
    }
  }

這裡的 byte2Hex() 方法是用來將經過 md5 加密的每一個 byte 轉成 16 進位表示, 所以 "I love you" 經加密運算後會變成 "E4F58A805A6E1FD0F6BEF58C86F9CEB3". 依據 Wiki 的 MD5 說明, MD5 是一種雜湊演算法, 它會固定生成 32 位的 16 進制數字 (即 128 位元). 即使原文只變動一點點, 演算出來的值卻變動相當大. 例如我們在上面例子中加個驚嘆號 "I love you!", 其 MD5 演算結果變成 "690A8CDA8894E37A6FFF4D1790D53B33", 幾乎完全不一樣了.

最重要的特性是, MD5 是不可逆的, 也就是沒辦法從 "E4F58A805A6E1FD0F6BEF58C86F9CEB3" 反推算出 "I love you", 除非利用超級電腦, 但那也需要很久的時間, 所以只能把它的對應關係記下來. 我在網路上找到下面這個號稱能反解譯的網站, 大約 5 秒就說解出 "I love you" 了, 但要看結果要給錢, 哇咧.

# md5在线查询破解,md5解密加密


據說 MD5 在 2009 年被破解了, 在一般電腦只需幾秒鐘, 搞不好這網站是利用這種破解法來做生意的.


2 則留言 :

Wayne Yeh 提到...

話說 MD5 並不是加密。主要差異在於,MD5 並非唯一,也就是多種不同本文可以產生相同的 MD5。此外,MD5 設計上也無法解密,其中一個原因也是因為多個本文可以產生相同的 MD5,因此某個 MD5 無法正確辨識是由哪個本文產生來的。比較正確的描述應該就是稱呼它為「雜湊」。在密碼學中,雜湊(Hash Algorithm)自己是個獨立的領域,不會視為是加密演算法(Encryption Algorithm)的一種

而 MD5 用來存放密碼的主要問題,不在於 MD5 能否被反向演算,而是在於 MD5 無法避免碰撞(collision)。碰撞的意思是,用兩組不同的字串,可以算出相同的 MD5。這意味著,如果系統使用 MD5 來存放密碼,那麼攻擊者不一定需要知道原始的密碼,只要能找到任意一個能產生相同 MD5 的字串,就能通過系統的密碼驗證。這會導致攻擊者實際需要破解系統的難度並不到原本系統預期的難度,例如系統原本要求使用者要輸入 16 個字作為密碼,本來應該是個難度高到爆表的密碼長度,但卻因為背後使用了 MD5 來存放密碼,導致難度從本來預期算出一個密碼要花幾年、大幅下降成只要幾秒。

小狐狸事務所 提到...

原來如此, 還是要找一些時間來看密碼學才能深入了解. 感謝您賜教.