Go-哈希函數與消息認證詳解(含代碼)

 

 


哈希函數

簡介

哈希函數也稱散列函數、雜湊函數等,是一種單向密碼體制,即它是一個從明文到密文的不可逆映射,即只有「加密」過程,不存在「解密」過程。同時,Hash函數能夠將「任意」長度的輸入通過變換之後獲得固定長度的輸出。Hash函數的這種單向特徵和輸出數據長度固定的特徵使得它能夠生成消息或數據塊的「數據指紋」(也稱消息摘要、哈希值或散列值),所以,哈希函數在數據完整性和數字簽名等領域有普遍的應用。
使用公式表示爲:
h = H ( m ) h=H(m) h=H(m)算法

  • M:任意長度的消息
  • H:哈希(Hash)函數或雜湊函數或散列函數
  • h:固定長度的哈希值

歷史

Hash的概念起源於1956年,Dumey用它來解決symbol table question(符號表問題), 使得數據表的插入、刪除、查詢操做能夠在更短的時間內完成。
散列算法MD族是在上個世紀90年代初由Ron●Rivest設計的,MD表明消息摘要(message-digest), MD2(1989)、MD4(1990)和MD5(1991)都產生一個128位的信息摘要。
SHA系列算法是美國國家標準與技術研究院(NIST)根據Rivest設計的MD4和MD5而開發的算法,國家安全當局發佈SHA做爲美國政府標準,SHA(Secure Hash Algorithm)表示安全散列算法。安全

特性

  • 輸入:消息是任意有限長度。
  • 輸出:哈希值是固定長度。
  • 容易計算:對於任意給定的消息,容易計算其哈希值(正向容易)。
  • 單向性:對於給定的哈希值h,要找到M使得H(M)=h在計算上是不可行的。(逆向不可行)

安全性

  • 抗弱碰撞性:對於給定的消息M,要發現另外一個消息M2,知足 H ( M 1 ) = H ( M 2 ) H(M_1)=H(M_2) H(M1​)=H(M2​)在計算上是不可行的。
  • 抗強碰撞性:找任意一對不一樣的消息M, M2,使 H ( M 1 ) = H ( M 2 ) H(M_1)=H(M_2) H(M1​)=H(M2​)在計算上是不可行的。
  • 隨機性:當一個輸入位發生變化時,輸出位將發生很大變化。(雪崩效應)

MD族

md4

MD4 由Ron Rivest設計 1990年
具備3輪16步,輸出位長度爲128位。
特色:對任意長度的輸入,產生128位輸出;其安全性不依賴任何假設,適合高速實現
MD4公佈不久,一些密碼學家發現,若是去掉MD4算法的第一輪和最後一輪,則算法是不安全的,但他們並無證實整個算法是不安全的。網絡

md5

MD5 由Ron Rivest設計 1991年 對MD4的改進
具備4輪16步,輸出位長128位。
輸入分組 512bit
輸出 128bitide

SHA系列

SHA系列包括多個散列算法標準,其中, SHA-1是數字簽名標準中要求使用的算法。
SHA-0:正式地稱做SHA,這個版本在發行後不久被指出存在弱點。
SHA-1:NIST於1994年發佈的,它與MD4和MD5散列算法很是類似,被認爲是MD4和MD5的後繼者。(160位)
SHA-2:實際上分爲SHA-22四、 SHA-25六、SHA-384和SHA512算法。函數

SHA-1

SHA-1接受任何有限長度的輸入消息,併產生長度爲160比特的Hash值(MD5僅僅生成128位的摘要),所以抗窮舉***的能力更強。SHA-1設計原理.與MD4相同,它有5個參與運算的32位寄存器字,消息分組和填充方式與MD5相同,主循環也一樣是4輪,但每輪進行20次操做,非線性運算、移位和加法運算也與MD5相似,但非線性函數、加法常數和循環左移操做的設計有一些區別。加密

SHA-2

  • SHA-256:具備64輪單步,輸出位長度爲256位。spa

  • SHA-384:實際上與SHA-512相同,除了輸出被截斷爲383位。設計

  • SHA-512:具備80個單步的輪數和512位的輸出位長度。code

消息認證

網絡系統安全通常要考慮兩個方面:
一方面,加密保護傳送的信息,使其能夠抵抗被動***;
另外一方面,就是要能防止對手對系統進行主動***,如僞造、篡改信息等。認證是對抗主動***的主要手段,它對於開放的網絡中的各類信息系統的安全性有重要做用。認證分爲實體認證消息認證blog

在一個開放通訊網絡的環境中,信息面臨的***包括竊聽、僞造、修改、插入、刪除、否定等。所以,須要提供用來驗證消息完整性的一種機制或服務–消息認證。這種服務的主要功能包括:

  • 確保收到的消息確實和發送的同樣;
  • 確保消息的來源真實有效;

注:對稱密碼體制和公鑰密碼體制均可提供這種服務,但用於消息認證的最多見的密碼技術是基於哈希函數的消息認證碼

消息認證的目的

驗證信息的來源是真實的,而不是冒充的,此爲消息源認證。
驗證消息的完整性,即驗證信息在傳送或存儲過程當中是否被修改。

消息認證碼

消息認證碼(MAC,Messages Authentication Codes),是與密鑰相關的的單向散列函數,也稱爲消息鑑別碼或是消息校驗和。此時須要通訊雙方A和B共享一密鑰K。
設A欲發送給B的消息是M,A首先計算 M A C = C k ( M ) MAC=C_k(M) MAC=Ck​(M),其中 C k ( ● ) C_k(●) Ck​(●)是密鑰控制的公開函數(如哈希函數),而後向B發送M||MAC,B收到後作與A相同的計算,求得一MAC,並與收到的MAC作比較。
HMAC由H.Krawezyk,M.Bellare,R.Canetti於1996年提出的一種基於Hash函數和密鑰進行消息認證的方法,並於1997年做爲RFC2104被公佈,並在IPSec和其餘網絡協議(如SSL)中得以普遍應用,如今已經成爲事實上的Internet安全標準。

認證碼與檢錯碼

現代密碼學中的消息認證碼與通訊學的消息檢錯碼有密切的聯繫,並由其演變而來,但其根源和目的是不一樣的,採用的技術手段有本質的差異

  • 檢錯碼是檢測因爲通訊的缺陷而致使消息發生錯誤的方法。(客觀環境形成的)
  • 認證碼是用來檢查因爲惡意或有目的等方式修改消息的技術。(人爲緣由形成的)
HMAC的Go實現

crypto/hmac包

func New(h func() hash.Hash, key []byte) hash.Hash

New函數返回一個採用hash.Hash做爲底層hash接口、key做爲密鑰的HMAC算法的hash接口。

func Equal(mac1, mac2 []byte) bool

比較兩個MAC是否相同,而不會泄露對比時間信息。(以規避時間側信道***:指經過計算比較時花費的時間的長短來獲取密碼的信息,用於密碼破解)

hash包

io.Writer

經過嵌入的匿名io.Writer接口的Write方法向hash中添加更多數據,永遠不返回錯誤

Sum(b []byte) []byte

返回添加b到當前的hash值後的新切片,不會改變底層的hash狀態

crypto/sha1包

func New() hash.Hash

返回一個新的使用SHA1校驗的hash.Hash接口。

代碼實現

生成MAC
1.使用hmac.New生成hash.Hash(這裏使用的sha1,以後的數字簽名文章會使用sha2)
2.使用Hash接口的Write添加原消息
3.使用hash.Sum獲取MAC

func GenerateMAC(plainText,key []byte) []byte {
	hash := hmac.New(sha1.New,key)
	hash.Write(plainText)
	hashText := hash.Sum(nil)
	return hashText
}

驗證MAC
1.使用hmac.New生成hash.Hash
2.使用Hash接口的Write添加原消息
3.使用hash.Equal驗證MAC

func VerifyMAC(plainText,key,hashText []byte) bool {
	hash := hmac.New(sha1.New,key)
	hash.Write(plainText)
	return hmac.Equal(hashText,hash.Sum(nil))
}

所有代碼

package main

import (
	"crypto/hmac"
	"crypto/sha1"
	"fmt"
)

// 生成消息認證碼
// plainText 明文
// key 密鑰
// 返回 消息認證碼
func GenerateMAC(plainText,key []byte) []byte {
	hash := hmac.New(sha1.New,key)
	hash.Write(plainText)
	hashText := hash.Sum(nil)
	return hashText
}

// 消息認證
// plainText 明文
// key 密鑰
// hashText 消息認證碼
// 返回 是不是原消息
func VerifyMAC(plainText,key,hashText []byte) bool {
	hash := hmac.New(sha1.New,key)
	hash.Write(plainText)
	return hmac.Equal(hashText,hash.Sum(nil))
}

func main()  {
	plainText := []byte("消息")
	key := []byte("私鑰")
	hashText := GenerateMAC(plainText,key)
	ok := VerifyMAC(plainText,key,hashText)
	if ok{
		fmt.Printf("%s 是原消息\n",plainText)
	}
	fakeText := []byte("假消息")
	ok = VerifyMAC(plainText,key,fakeText)
	if !ok{
		fmt.Printf("%s 是假消息\n",fakeText)
	}
}

截圖

在這裏插入圖片描述

相關文章
相關標籤/搜索