密碼學奇妙之旅、03 HMAC單向散列消息認證碼、Golang代碼

HMAC 單向散列消息認證碼消息認證碼MAC是用于確認完整性并進行認證的技術 , 消息認證碼的輸入包括任意長度的消息和一個發送者和接收者之間共享的密鑰(可能還需要共享鹽值) 。
HMAC是使用單向散列函數來構造消息認證碼的方法 , 任何高強度單向散列函數都可以被用于HMAC,具體方法如下圖所示 。
【密碼學奇妙之旅、03 HMAC單向散列消息認證碼、Golang代碼】發送者需要同時把消息和認證碼發送給接收者,接收者接收了兩者,并根據接收到的消息和共享的密鑰生成認證碼進行比較 。如果相同則消息未被篡改且認證成功 。
MAC不能保證信息的機密性!MAC無法對第三方"C"證明,因為"A","B"兩者都有密鑰,都可以生成消息和MAC 。因此第三方不知道是誰生成的,更不知道消息的真實性 。MAC無法防止否認 。

密碼學奇妙之旅、03 HMAC單向散列消息認證碼、Golang代碼

文章插圖
加鹽鹽是通過偽隨機數生成器生成的隨機數,會和密鑰一起被輸入單向散列函數 。
主要目的是為了防御字典攻擊 。字典攻擊是一種事先進行計算并準備好候選密鑰列表的方法 。是一種暴力攻擊破解手段 。加了鹽 , 密鑰便多了n個數量級的可能,加大破解難度 。
HMAC利用單向散列函數的單向性和抗碰撞性來保證無法根據MAC值推測出密鑰 。
代碼package mainimport ( "crypto/hmac" "crypto/rand" "crypto/sha256" "crypto/sha512" "encoding/base64" "fmt" "hash" "io")var secretKey = "114514abcdefghijklmn"var salt = generateSalt()// 生成一個包含 16 字節數據的鹽字符串func generateSalt() string { randomBytes := make([]byte, 16) if _, err := rand.Read(randomBytes); err != nil {return "" } return base64.URLEncoding.EncodeToString(randomBytes)}// 提供散列函數、密鑰、鹽值、消息返回HMACfunc HMAC(h func() hash.Hash, secretKey string, salt string, message string) []byte { hash := hmac.New(h, []byte(secretKey)) io.WriteString(hash, message+salt) return hash.Sum(nil)}func main() { /* ----------------------------------- 發送方 ---------------------------------- */ message := "A請求B轉賬10000" fmt.Println("\n\t消息: " + message) fmt.Println("\t加鹽: " + salt) fmt.Printf("\n\tHMAC-Sha256: %x", HMAC(sha256.New, secretKey, salt, message)) fmt.Printf("\n\tHMAC-Sha256: %x", HMAC(sha512.New, secretKey, salt, message)) /* ----------------------------------- 修改一個字母 ---------------------------------- */ messageChange := "C請求B轉賬10000" fmt.Printf("\n\n\tHMAC-Sha256: %x", HMAC(sha256.New, secretKey, salt, messageChange)) fmt.Printf("\n\tHMAC-Sha256: %x\n\n", HMAC(sha512.New, secretKey, salt, messageChange)) /* --------------------------- 接收方分別收到了發送者的消息、HMac值 -------------------------- */ // ^ 假定消息和HMAC均被黑客截獲,黑客進行重放攻擊 sendMessgage := message// @ 發送者發送消息 sendHMAC := string(HMAC(sha256.New, secretKey, salt, sendMessgage)) // @ 發送者計算HMAC并與消息一起發給接收者 hackerGetHMAC := sendHMAC// @ 黑客竊聽到HMAC hackerGetMessage := sendMessgage// @ 黑客竊聽到消息 receiveHMAC := hackerGetHMAC// @ 接收者收到HMAC receiveMessage := hackerGetMessage// @ 接收者收到MESSAGE if string(HMAC(sha256.New, secretKey, salt, receiveMessage)) == receiveHMAC {fmt.Println("\t第1次重放攻擊" + message) } receiveHMAC = hackerGetHMAC// @ 接收者收到HMAC receiveMessage = hackerGetMessage // @ 接收者收到MESSAGE if string(HMAC(sha256.New, secretKey, salt, receiveMessage)) == receiveHMAC {fmt.Println("\t第2次重放攻擊" + message) } // ^ 假定消息和HMAC都是黑客發送的,但黑客并不知道密鑰和鹽值 sendMessgage = "今天是KFC V我小能喵喵喵50速速"http:// @ 發送者發送消息 sendHMAC = string(HMAC(sha256.New, "miyueshishenme", "114514", sendMessgage)) // @ 黑客計算HMAC并與消息一起發給接收者 receiveHMAC = sendHMAC// @ 接收者收到HMAC receiveMessage = sendMessgage// @ 接收者收到MESSAGE if string(HMAC(sha256.New, secretKey, salt, receiveMessage)) != receiveHMAC {fmt.Println("\t消息不一致、認證失敗") }}PS C:\Users\小能喵喵喵\Desktop\Go\Cryptography\HMAC> go run .消息: A請求B轉賬10000加鹽: S_XlM8K_dhAvsgch_N3o1w==HMAC-Sha256: b8dd30d2a418262494f298bcdaf6c12f442c6e8f89a31822dad03561887f3bedHMAC-Sha256: ba934567837ec98ba89853b09f6652ce56955cfeedd0c4495bd6cba7fc2f8293635fdc59b90180564bd0fdb1d1bffc52644fc2bd8164d6379ae11510e200954cHMAC-Sha256: 2db84d209e2418f314fc5bb0583cfb50cde90d954d8493d3ed0e3b369fb092d7HMAC-Sha256: 7b192cedb1d89fd71889189a0094e1df06d26d977bc3bed4f53b16928aa2d58084cb8890d52cb40f665bb9ac62eeb4092495efe7d59292470ed597a3536dea56第1次重放攻擊A請求B轉賬10000第2次重放攻擊A請求B轉賬10000消息不一致、認證失敗如何防止重放攻擊