1. 程式人生 > >Java 加解密技術之SHA

Java 加解密技術之SHA

上一篇文章中介紹了基本的單向加密演算法 — — MD5,也大致的說了說它實現的原理。這篇文章繼續之前提到的單向加密,主要講的是 SHA,同 MD5 一樣,SHA 同樣也是一個系列,它包括 SHA-1,SHA-224,SHA-256,SHA-384,和 SHA-512 等幾種演算法。其中,SHA-1,SHA-224 和 SHA-256 適用於長度不超過 2^64 二進位制位的訊息。SHA-384 和 SHA-512 適用於長度不超過 2^128 二進位制位的訊息。

背景

開始正文之前,簡單的說一下背景。乍一說 SHA 你可能不知道,但說到雜湊和雜湊演算法,你一定會知道,也就是平常所指的 Hash。那麼,先了解一下什麼是雜湊。雜湊,是資訊的提煉,通常其長度要比資訊小得多,且為一個固定長度。加密性強的雜湊一定是不可逆的,這就意味著通過雜湊結果,無法推出任何部分的原始資訊。說的很明確,雜湊的結果是不可逆的,根據雜湊結果,無法推出原始資訊。

正文

瞭解了背景之後,我們就開始介紹 SHA 了。

SHA,全稱為“Secure Hash Algorithm”,中文名“安全雜湊演算法”,主要適用於數字簽名標準(Digital Signature Standard DSS)裡面定義的數字簽名演算法(Digital Signature Algorithm DSA)。對於長度小於 2^64 位的訊息,SHA1 會產生一個 160 位的訊息摘要。

該演算法的思想是接收一段明文,然後以一種不可逆的方式將它轉換成一段(通常更小)密文,也可以簡單的理解為取一串輸入碼(稱為預對映或資訊),並把它們轉化為長度較短、位數固定的輸出序列即雜湊值的過程。

上邊也提到了,SHA 規定了很多種演算法,包括了 SHA-1,SHA-224,SHA-256,等很多種。這裡我以 SHA-1 為例,講一下 SHA-1 是如何工作的。


SHA-1 有兩個特點:
不可以從訊息摘要中復原資訊
兩個不同的訊息,不會產生同樣的訊息摘要


SHA-1 是一種資料加密演算法,主要是接收一段明文,然後以一種不可逆的方式將它轉換成一段密文,也可以簡單的理解為取一串輸入碼,並把它們轉化為長度較短、位數固定的輸出序列即雜湊值的過程。

單向雜湊函式的安全性在於其產生雜湊值的操作過程具有較強的單向性。如果在輸入序列中嵌入密碼,那麼任何人在不知道密碼的情況下都不能產生正確的雜湊值,從而保證了其安全性。SHA 將輸入流按照每塊 512 位(64 個位元組)進行分塊,併產生 20 個位元組的被稱為資訊認證程式碼或資訊摘要的輸出。

該演算法輸入報文的長度不限,產生的輸出是一個 160 位的報文摘要。輸入是按 512 位的分組進行處理的。SHA-1 是不可逆的、防衝突,並具有良好的雪崩效應。


通過雜湊演算法可實現數字簽名實現,數字簽名的原理是將要傳送的明文通過一種函式運算(Hash)轉換成報文摘要(不同的明文對應不同的報文摘要),報文摘要加密後與明文一起傳送給接受方,接受方將接受的明文產生新的報文摘要與傳送方的發來報文摘要解密比較,比較結果一致表示明文未被改動,如果不一致表示明文已被篡改。

SHA-1 與 MD5 的比較


因為二者均由 MD4 匯出,SHA-1 和 MD5 彼此很相似。相應的,他們的強度和其他特性也是相似,但還有以下幾點不同:

對強行攻擊的安全性

最顯著和最重要的區別是 SHA-1 摘要比 MD5 摘要長 32 位。使用強行技術,產生任何一個報文使其摘要等於給定報摘要的難度對 MD5 是 2^128 數量級的操作,而對 SHA-1 則是 2^160 數量級的操作。這樣,SHA-1 對強行攻擊有更大的強度。

對密碼分析的安全性

由於 MD5 的設計,易受密碼分析的攻擊,SHA-1 顯得不易受這樣的攻擊。

速度

在相同的硬體上,SHA-1 的執行速度比 MD5 慢。


程式碼實現

  1. package com.sica.sha;
  2. import com.google.common.base.Strings;
  3. import java.security.MessageDigest;
  4. /**
  5. * Created by xiang.li on 2015/2/11.
  6. */
  7. publicclass SHA {
  8. /**
  9. * 定義加密方式
  10. */
  11. privatefinalstaticString KEY_SHA ="SHA";
  12. privatefinalstaticString KEY_SHA1 ="SHA-1";
  13. /**
  14. * 全域性陣列
  15. */
  16. privatefinalstaticString[] hexDigits ={"0","1","2","3","4","5",
  17. "6","7","8","9","a","b","c","d","e","f"};
  18. /**
  19. * 建構函式
  20. */
  21. public SHA(){
  22. }
  23. /**
  24. * SHA 加密
  25. * @param data 需要加密的位元組陣列
  26. * @return 加密之後的位元組陣列
  27. * @throws Exception
  28. */
  29. publicstaticbyte[] encryptSHA(byte[] data)throwsException{
  30. // 建立具有指定演算法名稱的資訊摘要
  31. // MessageDigest sha = MessageDigest.getInstance(KEY_SHA);
  32. MessageDigest sha =MessageDigest.getInstance(KEY_SHA1);
  33. // 使用指定的位元組陣列對摘要進行最後更新
  34. sha.update(data);
  35. // 完成摘要計算並返回
  36. return sha.digest();
  37. }
  38. /**
  39. * SHA 加密
  40. * @param data 需要加密的字串
  41. * @return 加密之後的字串
  42. * @throws Exception
  43. */
  44. publicstaticString encryptSHA(String data)throwsException{
  45. // 驗證傳入的字串
  46. if(Strings.isNullOrEmpty(data)){
  47. return"";
  48. }
  49. // 建立具有指定演算法名稱的資訊摘要
  50. MessageDigest sha =MessageDigest.getInstance(KEY_SHA);
  51. // 使用指定的位元組陣列對摘要進行最後更新
  52. sha.update(data.getBytes());
  53. // 完成摘要計算
  54. byte[] bytes = sha.digest();
  55. // 將得到的位元組陣列變成字串返回
  56. return byteArrayToHexString(bytes);
  57. }
  58. /**
  59. * 將一個位元組轉化成十六進位制形式的字串
  60. * @param b 位元組陣列
  61. * @return 字串
  62. */
  63. privatestaticString byteToHexString(byte b){
  64. int ret = b;
  65. //System.out.println("ret = " + ret);
  66. if(ret <0){
  67. ret +=256;
  68. }
  69. int m = ret /16;
  70. int n = ret %16;
  71. return hexDigits[m]+ hexDigits[n];
  72. }
  73. /**
  74. * 轉換位元組陣列為十六進位制字串
  75. * @param bytes 位元組陣列
  76. * @return 十六進位制字串
  77. */
  78. privatestaticString byteArrayToHexString(byte[] bytes){
  79. StringBuffer sb =newStringBuffer();
  80. for(int i =0; i < bytes.length; i++){
  81. sb.append(byteToHexString(bytes[i]));
  82. }
  83. return sb.toString();
  84. }
  85. /**
  86. * 測試方法
  87. * @param args
  88. */
  89. publicstaticvoid main(String[] args)throwsException{
  90. String key ="123";
  91. System.out.println(encryptSHA(key));
  92. }
  93. }

結束語

看到這,我想 SHA-1 的簡單原理你應該是瞭解了,而且,對於應用來說也並不難,可以參考上述的 Java 程式碼。回過頭來在想想 MD5,通過上面的文章,你就能知道,其實,SHA-1 與 MD5 是同出一轍的,只是他們各自的實現方式不同,SHA-1 在位運算元量級上也要比 MD5 更加的複雜,因此,對於安全的考慮,SHA-1 相對來說還是很可靠的。
 
至於什麼時候會用到它,那麼就要考慮 SHA-1 的特點了。很明確的,不可逆性,以及唯一性。那麼,我想,適用於 MD5 的加密的,也同樣適用於 SHA-1。而且,在安全性上來說,SHA-1 更勝於 MD5,如果是對速度有嚴格要求的話,那麼,還是優先考慮 MD5 吧。