關於SHA算法原理與常用實現方式
看本文前,最好先看看之前的這一篇關於MD5算法的介紹。
MD5算法原理與常用實現
定義
SHA算法(Secure Hash Algorithm),又叫安全散列算法。
SHA算法是基於MD4算法的基礎上,演變而來。
但SHA算法出生好,是美國國傢安全局設計的。
SHA算法,是一個系列傢族,包括SHA-1,SHA-2(SHA-224、SHA-256、SHA-384、SHA-512),括號中的四個通常被統稱為SHA-2。
JDK中對SHA-1、SHA-256、SHA-384、SHA-512都有實現。
- SHA-1的最終密碼長度是160位。
- SHA-256的最終密碼長度是256位。
- SHA-384的最終密碼長度是384位。
- SHA-512的最終密碼長度是512位。
SHA算法,實際上也是一種消息摘要算法,這個和MD算法是類似的。
本文主要介紹SHA-256算法。
任意長度的消息文件,通過SHA-256算法加密,最終得到的密文都是256位(32字節),通常用一個長度為64的十六進制字符串來表示。
效果上,SHA算法,與MD5算法都差不多,主要特點都是不可逆。
MD5和SHA-1的碰撞問題
碰撞問題,就是指對於一個算法,由明文生成的密文,並不是唯一的,甚至可以人為的通過構造新的明文去得到指定的密文。
對於能出現這種情況的算法,我們就說這個算法是有碰撞問題的,簡單理解就是兩個不同的明文,通過算法加密,卻得到瞭同樣的密文。
目前為止,MD5算法和SHA-1算法,都被證實瞭存在碰撞問題。
所以在安全性特別高的場景下,都不會用MD5算法和SHA-1算法,至少都用SHA-256算法瞭。
常見應用場景
1、類似MD5的應用場景
MD5的應用場景,SHA算法基本也都可以使用。
2、比特幣
比特幣中,挖礦算法其實就是SHA-256算法,礦工們根據不斷修改隨機數,不斷的進行SHA-256運算,最終算的快的挖到礦。
3、https簽名算法會用到
打開瀏覽器,以谷歌為例,查看任意一個整數的詳情:
簽名算法就是:帶 RSA 加密的 SHA-256,如下圖:
SHA-256算法原理
SHA傢族的基本算法思想,都和MD5一樣,先定義常量,然後循環計算,最後組裝,不同的就是循環裡面的計算方式。
1、填補信息
類似MD5
2、拿到初始值
MD5中有4個初始值,而SHA-256中,有8個。
h0 := 0x6a09e667 h1 := 0xbb67ae85 h2 := 0x3c6ef372 h3 := 0xa54ff53a h4 := 0x510e527f h5 := 0x9b05688c h6 := 0x1f83d9ab h7 := 0x5be0cd19
3、真正的計算
計算分為多次循環,每次循環,都是用ABCD和原文在第一步填補完的信息,進行計算,最終得到新的ABCD。最後將最後一次ABCD拼成字符串,就是最終的密文。
- 循環先分為主循環,每個主循環中又套有子循環。
- 主循環次數 = 原文長度/512。
- 子循環次數 = 64次。
我們看看單次子循環都做瞭什麼:
下面是單次子循環真正的計算邏輯(這段實現摘自網友):
java實現和使用
其實看過上一篇MD5介紹的,就會發現,其實SHA的java實現,和MD5的java實現,幾乎一模一樣。
唯一的不同,就是MessageDigest.getInstance(“SHA”);這個方法中:
- SHA-1算法的入參是SHA
- SHA-256算法的入參是SHA-256
- SHA-384算法的入參是SHA-384
- SHA-512算法的入參是SHA-512
MD5的入參是MD5
public class SHA1Util { public static void main(String[] args) throws IOException { System.out.println(encodeString("123")); } public static String encodeString(String plainText) throws UnsupportedEncodingException { return encodeBytes(plainText.getBytes("UTF-8")); } public static String encodeBytes(byte[] bytes) { try { MessageDigest md = MessageDigest.getInstance("SHA"); md.update(bytes); byte b[] = md.digest(); int i; StringBuffer buf = new StringBuffer(""); for (int offset = 0; offset < b.length; offset++) { i = b[offset]; if (i < 0) { i += 256; } if (i < 16) { buf.append("0"); } buf.append(Integer.toHexString(i)); } return buf.toString(); } catch (Exception e) { e.printStackTrace(); } return ""; } }
以上為個人經驗,希望能給大傢一個參考,也希望大傢多多支持WalkonNet。
推薦閱讀:
- JAVA對字符串進行32位MD5加密的實踐
- Java 實現字符串SHA1加密方法
- Java基礎入門語法–String類
- Java實現MD5加密的方式與實例代碼
- 詳解Java中String,StringBuffer和StringBuilder的使用