首頁 > 軟體

關於SHA演演算法原理與常用實現方式

2022-08-18 14:01:08

看本文前,最好先看看之前的這一篇關於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 "";
    }
}

以上為個人經驗,希望能給大家一個參考,也希望大家多多支援it145.com。 


IT145.com E-mail:sddin#qq.com