1. 程式人生 > >深入理解 SHA 系列加密演算法及Go語言運用

深入理解 SHA 系列加密演算法及Go語言運用

SHA 是一系列的加密演算法,有 SHA-1、SHA-2、SHA-3 三大類,而 SHA-1 已經被破解,SHA-3 應用較少,目前應用廣泛相對安全的是 SHA-2 演算法,這也是本篇文章重點要講述的演算法。

一、演算法核心思想和特點

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

1. 單向性

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

2. 數字簽名

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

二、hash碰撞

雜湊演算法的一個重要功能是產生獨特的雜湊,當兩個不同的值或檔案可以產生相同的雜湊,則稱碰撞。保證數字簽名的安全性,就是在不發生碰撞時才行。碰撞對於雜湊演算法來說是極其危險的,因為碰撞允許兩個檔案產生相同的簽名。當計算機檢查簽名時,即使該檔案未真正簽署,也會被計算機識別為有效的。

一個雜湊位有 0 和 1 兩個可能值,則每一個獨立的雜湊值通過位的可能值的數量對於 SHA-256,有 2 的 256 次方種組合,這是一個龐大的數值。雜湊值越大,碰撞的機率就越小。每個雜湊演算法,包括安全演算法,都會發生碰撞,而 SHA-1 的大小結構發生碰撞的機率比較大,所以 SHA-1 被認為是不安全的。

三、Go語言使用SHA256演算法

//方法一
func digest1(data []byte)([]byte,error){
	h := sha256.Sum256(data)
	return h[:],nil
}

//方法二
func digest2(data []byte) ([]byte, error) {
	h := sha256.New()
	h.Write(data)

	return h.Sum(nil),nil
}

四、SHA 256 演算法原理解析

SHA-256 演算法輸入報文的最大長度不超過2^64 bit,輸入按512-bit 分組進行處理,產生的輸出是一個256-bit 的報文摘要。

SHA256演算法主流程分三大模組:常量的初始化、資訊預處理、使用到的邏輯運算。

1. 常量的初始化

這些常量的作用是和資料來源進行計算,增加資料的加密性,那麼大家可以想一下,如果常量是一些如 1、2、3 之類的整數,是不是就沒什麼加密可言了,所以需要這些常量很複雜,生成的規則是:對自然數中前 8 個(或 64 個)質數(2、3、5、7、11、13、17、19)的平方根的小數部分取前 32 bit(在後面的對映的過程中會用到這些常量)。

例如,2 的平方根的小數部分約為 0.414213562373095048,然後 0.414213562373095048 ≈ 6 ∗ 16−1 + a ∗ 16−2 + 0 ∗ 16−3+…

所以 2 的平方根的小數部分取前 32 bit 就得到:0 x 6a09e667。

2. SHA256 中用到兩種常量

(1)8 個雜湊初值=>自然數中前 8 個質數(2、3、5、7、11、13、17、19)的平方根的小數部分取前 32bit:

  			h0 := 0x6a09e667
  			h1 := 0xbb67ae85
  			h2 := 0x3c6ef372
  			h3 := 0xa54ff53a
  			h4 := 0x510e527f
  			h5 := 0x9b05688c
  			h6 := 0x1f83d9ab
  			h7 := 0x5be0cd19

(2)64 個雜湊常量=>自然數中前 64 個質數(2、3、5、7、11、13、17、19、23、29、31、37、41、43、47、53、59、61、67、71、73、79、83、89、97…)的立方根的小數部分取前 32 bit:

  			428a2f98 71374491 b5c0fbcf e9b5dba5
  			3956c25b 59f111f1 923f82a4 ab1c5ed5
  			d807aa98 12835b01 243185be 550c7dc3
  			72be5d74 80deb1fe 9bdc06a7 c19bf174
  			e49b69c1 efbe4786 0fc19dc6 240ca1cc
  			2de92c6f 4a7484aa 5cb0a9dc 76f988da
  			983e5152 a831c66d b00327c8 bf597fc7
  			c6e00bf3 d5a79147 06ca6351 14292967
  			27b70a85 2e1b2138 4d2c6dfc 53380d13
  			650a7354 766a0abb 81c2c92e 92722c85
  			a2bfe8a1 a81a664b c24b8b70 c76c51a3
  			d192e819 d6990624 f40e3585 106aa070
  			19a4c116 1e376c08 2748774c 34b0bcb5
  			391c0cb3 4ed8aa4a 5b9cca4f 682e6ff3
  			748f82ee 78a5636f 84c87814 8cc70208
  			90befffa a4506ceb bef9a3f7 c67178f2

3. 資訊預處理

預處理分兩部分,第一部分是附加填充位元,第二部分是附加長度。目的是讓整個訊息滿足指定的結構,從而處理起來可以統一化、格式化,這個也是計算機的基本思維方式,就是把複雜的資料轉化為特定的格式,化繁為簡、“去偽存真”。

4.附加填充位元

在報文末尾進行填充,使報文長度在對 512 取模以後的餘數是 448。具體是:先補第一個位元為 1,然後都補 0,直到長度滿足對 512 取模後餘數是 448。需要注意即使長度已經滿足對 512 取模後餘數是 448,補位也必須要進行,這時要填充 512 個位元。所以,填充是至少補一位,最多補 512 位。例如:“abc”補位的過程。

  • a、b、c 對應的 ASCII 碼分別是 97、98、99。
  • 對應的二進位制編碼為:01100001 01100010 01100011;
  • 首先補一個“1”:0110000101100010 01100011 1;
  • 然後補 423 個“0”:01100001 01100010 01100011 10000000 00000000 … 00000000;
  • 補位完成後的資料如下:
  			61626380 00000000 00000000 00000000
  			00000000 00000000 00000000 00000000
  			00000000 00000000 00000000 00000000
  			00000000 00000000

5. 附加長度值

是將原始資料的長度資訊補到已經進行了填充操作的訊息後面(就是第一步預處理後的資訊),SHA256 用一個 64 位的資料來表示原始訊息的長度。所以 SHA256 加密的原始資訊長度最大是 264。

用上面的訊息“abc”來操作,3 個字元,佔用 24 個 bit,在進行了補長度的操作以後,整個訊息就變成:

  		61626380 00000000 00000000 00000000
  		00000000 00000000 00000000 00000000
  		00000000 00000000 00000000 00000000
  		00000000 00000000 00000000 00000018

6. 邏輯運算

  • ∧ → 按位“與”
  • ¬ → 按位“補”
  • ⊕ → 按位“異或”
  • Sn → 右移 n 個 bit
  • Rn → 迴圈右移 n 個 bit

7. 核心演算法

準備工作做好了,下面開始進入演算法階段。

**資料分解:**將原始資料分解成 512-bit 大小的塊,例如,訊息 M 可以被分解為 n 個塊,於是整個演算法需要做的就是完成 n 次迭代,n 次迭代的結果就是最終的雜湊值,即 256bit 的數字摘要。

每次迭代進行的對映用 Map(Hi−1)=Hi 表示,摘要的初始值 H0,經過第一個對映後,得到 H1,即完成了第一次迭代,H1 經過第二次對映得到 H2,……,依次處理,最後得到 Hn,Hn 即為最終的 256-bit 訊息摘要。

在 SHA256 演算法中的最小運算單元稱為“字”(Word),一個字是 32 位(byte),就是 4 個位元組(bit),256 個位元組(bit)就是 64 個字(word)。

對映 Map(Hi−1)=Hi 包含了 64 次加密迴圈,即進行 64 次加密迴圈即可完成一次迭代,通過維基百科上的流程圖來看更直觀一些:

說明:

  • 深藍色方塊是事先定義好的非線性函式,裡面是邏輯運算。
  • ABCDEFGH 一開始分別是八個初始值,就是預處理中第一部分的 8 個常量。
  • Kt 是第 t 個金鑰,金鑰從預處理中第二部分 64 個常量裡取。
  • Wt 是本區塊產生第 t 個 word。

原訊息被切成固定長度的區塊,對每一個區塊,產生 n 個 word,透過重複運作迴圈 n 次對 ABCDEFGH 這八個工作區塊迴圈加密。最後一次迴圈所產生的八段字串合起來即是此區塊對應到的雜湊字串。若原訊息包含數個區塊,則最後還要將這些區塊產生的雜湊字串加以混合才能產生最後的雜湊字串。