1. 程式人生 > >密碼學04--go語言與單向雜湊函式

密碼學04--go語言與單向雜湊函式

目錄

1.單向雜湊函式One-way hash function

1.1 定義

1.2 術語

1.3 特性

1.3.1 雜湊值長度固定

1.3.2 雜湊值計算快速

1.3.3 雜湊值抗碰撞性極強

1.3.4 雜湊值計算是單向不可逆

1.4 應用

1.5 常見型別

2.go語言中使用單向雜湊函式

2.1 選擇不同單向雜湊值函式包,直接執行包內對應的sum函式

2.2 建立Hash物件,通過Hash物件的writer指標擴充資料後執行Sum函式

1.單向雜湊函式One-way hash function

1.1 定義

單向雜湊函式,是能夠把任意長的輸入訊息串變化成固定長的輸出串,並且由輸出串難以得到輸入串的一種函式。(以上定義摘自百度百科)對於單向雜湊函式而言,無論原始資料多大,成的雜湊集合的大小是固定的,而且這個過程是“單向”的不可逆操作。

1.2 術語

  • 單向雜湊函式:也稱訊息摘要函式(message digest function)、雜湊函式(hash function)、雜湊函式(hash function)
  • 單向雜湊函式的輸入內容:也稱訊息(message)、原像(pre-image)
  • 單向雜湊函式的輸出內容:也稱雜湊值(hash value)、雜湊值(hash value)、訊息摘要(message digest)、指紋(fingerprint)
  • 單向雜湊函式的完整性:也稱為單向雜湊函式的一致性(uniformity)

1.3 特性

1.3.1 雜湊值長度固定

根據任意長度的訊息,可以算出固定長度的雜湊值。不管原像是1kB的資料還是10GB的資料,對於單向雜湊函式而言它們最終生成的雜湊值都是固定的。

1.3.2 雜湊值計算快速

能夠快速的計算出雜湊值。儘管隨著原像資料的增大計算雜湊值的時間必然會隨之增大,但雜湊值的計算速度仍然非常快。

1.3.3 雜湊值抗碰撞性極強

訊息不同的雜湊值截然不同(雪崩效應),因此雜湊值的抗碰撞性極強。由於不同訊息想要生成兩個完全相同的雜湊值的概率無限小(當然不同演算法有不同的概率,比如時代烙印的MD4和MD5,當然還有SHA1已經被攻破?),因此想要通過生成的雜湊值逆向推測生成它們的原像非常之困難。

1.3.4 雜湊值計算是單向不可逆

雜湊值的計算不是加密,因為加密是可逆的。顯然10GB的資料如果計算出16byte的雜湊值,還能夠被還原回10GB,那全世界都會為這種演算法沸騰。所以雜湊值的計算顯然是單向的,指的就是原像能夠計算出雜湊值,而雜湊值卻無法還原回原像。

1.4 應用

  • 檢測軟體是否被篡改
  • 訊息認證
  • 數字簽名
  • 偽隨機數生成器
  • 一次性口令(很多軟體只有密碼修改,沒有密碼找回)

1.5 常見型別

  • MD4 已被攻破,不安全
  • MD5 已被攻破,相對不安全 (誕生時間是1991年,產生的雜湊值長度是128bit)
  • SHA-1 已被攻破,相對不安全 (1995年正式釋出版本,產生的雜湊值長度是160bit)
  • SHA-2 暫未被攻破,安全
  • SHA-3 暫未被攻破,安全

事實上MD5和SHA-1都是比較著名的、使用範圍較廣泛的單向雜湊函式,其中SHA-1是由NIST(National Institute Of Standardsand Technology,美國國家標準技術研究所)設計的一種能夠產生160bit雜湊值的單向雜湊函式。1993年被作為美國聯邦資訊處理標準規格(FIPS PUB 180)釋出的是SHA版本(ps:傳說中生命賊短的SHA-0),在1995年釋出的修訂版中正式更名為FIPS PUB 180-1,也就是後來大名鼎鼎的SHA-1。

SHA-2單向雜湊函式是一個標準泛指,其中包括SHA-224、SHA-256、SHA-384、SHA-512四種不同標準。數字224、256、384、512指的都是單向雜湊函式執行後生成的雜湊值長度,就像SHA-1生成的是160bit雜湊值一樣。很顯然生成的雜湊值越長就越難以被攻破,所以SHA-2標準暫時是比較安全的。

2.go語言中使用單向雜湊函式

由於go語言是一個封裝非常完備的“漂亮”語言,所以對於如何使用單向雜湊函式對資料進行雜湊值計算都已經封裝到了不同的包中。因此在go語言中使用單向雜湊函式是一個非常簡單的操作。通常情況下有兩種方式使用單向雜湊函式。

2.1 選擇不同單向雜湊值函式包,直接執行包內對應的sum函式

在go語言的crypto包中包括了常見的各種單向雜湊函式包。

import "crypto/md5"
import "crypto/sha1"
import "crypto/sha256"    //sha224和sha256共用
import "crypto/sha512"    //sha384和sha512共用

在這些包中,每一個包內部都能夠看到一個封裝好的Sum介面。

在需要計算雜湊值的資料量比較小的情況下,直接呼叫sum函式即可生成對應的雜湊值。

func main(){
	result1 := md5.Sum([]byte("helloworldd"))
	result2 := sha1.Sum([]byte("helloworldd"))
	fmt.Printf("%s\n",result1);
	fmt.Printf("%s\n",result2);
}

2.2 建立Hash物件,通過Hash物件的writer指標擴充資料後執行Sum函式

事實上這一種方式和第一種本質上也沒什麼區別,都是使用go語言提供的不同單向雜湊函式包中的sum函式來進行雜湊值計算。但不同的第一種方式由於Sum的引數是一個[]byte型別,因此記憶體空間有限的前提下無法直接將過大的資料直接進行傳參操作,畢竟記憶體放不下;而第二種則是利用了系統提供的Hash物件中的io.Writer指標中的write方法對資料進行不斷的“拼接”,最後一次性將所有拼接在一起的資料進行一次雜湊值計算。

type Hash interface {
     // 通過嵌入的匿名io.Writer介面的Write方法向hash中新增更多資料,永遠不返回錯誤
     io.Writer
     // 返回新增b到當前的hash值後的新切片,不會改變底層的hash狀態
     Sum(b []byte) []byte
     // 重設hash為無資料輸入的狀態
     Reset()
     // 返回Sum會返回的切片的長度
     Size() int
     // 返回hash底層的塊大小;Write方法可以接受任何大小的資料,
     // 但提供的資料是塊大小的倍數時效率更高
     BlockSize() int
 }
type Writer interface {
     Write(p []byte) (n int, err error)
 }

在資料較大的情況下可以進行如下操作,來進行hashValue的計算。以SHA-2標準下的SHA-256為例,畢竟比特幣的計算方式就是這種

package main

import (
	"crypto/sha256"
	"encoding/hex"
	"fmt"
	"os"
)
/*
	名稱:frankGenerateSha256Hash
	引數:需要生成hash值的檔名
	結果:生成的hash值
    目的:生成256bit的hash值,即32byte長度
         但實際應當是64byte長度,因為16進位制下兩個字元描述一個字元。例如6E描述一個小寫字母n
*/
func frankGenerateSha256Hash(fileName string) string{
	//1.將檔案當中的內容讀出存入緩衝區,預備獲取hash值
	publicFile,_ := os.Open(fileName)
	defer publicFile.Close()
	fileInfo,_ := publicFile.Stat()
	buffer := make([]byte, fileInfo.Size())
	publicFile.Read(buffer)
	//2.使用對應雜湊值演算法包的方法,呼叫New()方法生成一個hash物件
	hash256 := sha256.New()
	//3.向hash物件中新增資料,如果必要可以新增多次
	hash256.Write(buffer)
	//4.計算結果sum,此時資料已經都存放於buffer中,所以Sum這裡不需要在新增任何內容,此時結果為2進位制
	hashValue := hash256.Sum(nil)
	//5.使用hex16進位制包中的格式化方法EncodeToString將hashValue格式化為16進位制的字串
	//  因為2進位制資料中存在不可見字元!
	hashString := hex.EncodeToString(hashValue)
	//6.將生成的hash字串返回
	return hashString
}
func main(){
	hashValue := frankGenerateSha256Hash("frankMsg")
	fmt.Printf("%s", hashValue)
}

程式碼中的“frankMsg”檔案內容如下:

而最終程式碼的執行結果是:

而其他單向雜湊函式包中的雜湊值計算與上面操作幾乎完全相同。再一次感謝go語言對與方法封裝的如此完備。