【密码学五】数字签名、RSA实现数字签名和验证
消息認證碼&數字簽名
消息認證碼(message authentication code)是一種確認完整性并進行認證的技術,取三個單詞的首字母,簡稱為MAC。
消息認證碼的輸入包括任意長度的消息和一個發送者與接收者之間共享的密鑰,它可以輸出固定長度的數據,這個數據稱為MAC值。
根據任意長度的消息輸出固定長度的數據,這一點和單向散列函數很類似。但是單向散列函數中計算散列值時不需要密鑰,而消息認證碼中則需要使用發送者與接收者之間共享的密鑰。
要計算MAC必須持有共享密鑰,沒有共享密鑰的人就無法計算MAC值,消息認證碼正是利用這一性質來完成認證的。此外,和單向散列函數的散列值一樣,哪怕消息中發生1比特的變化,MAC值也會產生變化,消息認證碼正是利用這一性質來確認完整性的。
消息認證碼有很多種實現方法,大家可以暫且這樣理解:消息認證碼是一種與密鑰相關聯的單向散列函數。
Alice 和 Bob 的故事
像以前一樣,我們還是從一個Alice和Bob的故事開始講起。不過,這一次Alice和Bob分別是兩家銀行,Alice銀行通過網絡向Bob銀行發送了一條匯款請求,Bob銀行收到的請求內容是:
從賬戶A?5374向賬戶B?6671匯款1000萬元從賬戶A-5374 向賬戶B-6671匯款1000萬元 從賬戶A?5374向賬戶B?6671匯款1000萬元
當然,Bob銀行所收到的匯款請求內容必須與Alice銀行所發送的內容是完全一致的。如果主動攻擊者Mallory在中途將Alice銀行發送的匯款請求進行了篡改,那么Bob銀行就必須要能夠識別出這種篡改,否則如果Mallory將收款賬戶改成了自己的賬戶,那么1000萬元就會被盜走。
話說回來,這條匯款請求到底是不是Alice銀行發送的呢?有可能Alice銀行根本就沒有發送過匯款請求,而是由主動攻擊者Mallory偽裝成Alice銀行發送的。如果匯款請求不是來自Alice銀行,那么就絕對不能執行匯款。
現在我們需要關注的問題是匯款請求(消息)的 “完整性" 和 “認證" 這兩個性質。
消息的完整性(integrity), 指的是:消息沒有被篡改"這一性質,完整性也叫一致性。如果能夠確認匯款請求的內容與Alice銀行所發出的內容完全一致,就相當于是確認了消息的完整性,也就意味著消息沒有被篡改。
消息的認證(authentication)指的是“消息來自正確的發送者"這一性質。如果能夠確認匯款請求確實來自Alice銀行,就相當于對消息進行了認證,也就意味著消息不是其他人偽裝成發送者所發出的。
通過使用本章中要介紹的消息認證碼,我們就可以同時識別出篡改和偽裝,也就是既可以確認消息的完整性,也可以進行認證。
數字簽名是一種將相當于現實世界中的蓋章、簽字的功能在計算機世界中進行實現的技術。使用數字簽名可以識別篡改和偽裝,還可以防止否認。
從消息認證到數字簽名
-
消息認證碼的局限性
消息認證碼,我們可以識別消息是否被篡改或者發送者身份是否被偽裝,也就是可以校驗消息的完整性,還可以對消息進行認證。然而,比如在出具借條的場景中卻無法使用消息認證碼,因為消息認證碼無法防止否認。
消息認證碼之所以無法防止否認,是因為消息認證碼需要在發送者Alice和接收者Bob兩者之間共享同一個密鑰。正是因為密鑰是共享的,所以能夠使用消息認證碼計算出正確MAC值的并不只有發送者Alice,接收者Bob也可以計算出正確的MAC值。由于Alice和Bob雙方都能夠計算出正確的MAC值,因此對于第三方來說,我們無法證明這條消息的確是由Alice生成的。
-
通過數字簽名解決問題
下面請大家開動一下腦筋。假設發送者Alice和接收者Bob不需要共享一個密鑰,也就是說,Alice和Bob各自使用不同的密鑰。
我們假設Alice使用的密鑰是一個只有Alice自己才知道的私鑰。當Alice發送消息時,她用私鑰生成一個“簽名"。相對地,接收者Bob則使用一個和Alice不同的密鑰對簽名進行驗證。使用Bob的密鑰無法根據消息生成簽名,但是用Bob的密鑰卻可以對Alice所計算的簽名進行驗證,也就是說可以知道這個簽名是否是通過Alice的密鑰計算出來的。如果真有這么一種方法的話,那么不管是識別篡改、偽裝還是防止否認就都可以實現了吧 ?
實際上,這種看似很神奇的技術早就已經問世了,這就是數字簽名(digital signature)。
簽名的生成和驗證
讓我們來稍微整理一下。
在數字簽名技術中,出現了下面兩種行為:
- 生成消息簽名的行為
- 驗證消息簽名的行為
生成消息簽名這一行為是由消息的發送者Alice來完成的,也稱為“對消息簽名”。生成簽名就是根據消息內容計算數字簽名的值,這個行為意味著 “我認可該消息的內容"。
驗證數字簽名這一行為一般是由消息的接收者Bob來完成的,但也可以由需要驗證消息的第三方來完成,這里的第三方我們暫且將其命名為驗證者Victor。驗證簽名就是檢查該消息的簽名是否真的屬于Alice,驗證的結果可以是成功或者失敗,成功就意味著這個簽名是屬于Alice的,失敗則意味著這個簽名不是屬于Alice的。
在數字簽名中,生成簽名和驗證簽名這兩個行為需要使用各自專用的密鑰來完成。
Alice使用“簽名密鑰"來生成消息的簽名,而Bob和Victor則使用“驗證密鑰"來驗證消息的簽名。數字簽名對簽名密鑰和驗證密鑰進行了區分,使用驗證密鑰是無法生成簽名的。這一點非常重要。此外,簽名密鑰只能由簽名的人持有,而驗證密鑰則是任何需要驗證簽名的人都可以持有。
通過RSA實現數字簽名
前邊章節已經介紹過了如何通過自己編寫的go代碼生成非對稱加密算法RSA的公鑰和私鑰文件, 假設公鑰文件的文件名為 public.pem,私鑰文件對應的文件名為 private.pem。
生成數字簽名
// SignatureRSA // myData 要簽名的數據 func SignatureRSA(myData []byte) ([]byte, error) {// 1. 從秘鑰文件中讀生成的秘鑰內容fp, err := os.Open("private.pem")if err != nil {return nil, errors.New("打開私鑰文件 - private.pem 失敗")}// 2. 讀文件內容fileInfo, _ := fp.Stat()all := make([]byte, fileInfo.Size())_, err = fp.Read(all)if err != nil {return nil, errors.New("讀文件內容失敗")}fmt.Println("文件內容: ", string(all))// 3. 關閉文件defer fp.Close()// 4. 將數據解析成pem格式的數據塊block, _ := pem.Decode(all)// 5. 解析pem數據塊, 得到私鑰privKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)if err != nil {return nil, errors.New("解析私鑰失敗")}// 6. 將數據通過哈希函數生成信息摘要myHash := sha256.New()myHash.Write(myData)result := myHash.Sum(nil)// 7. 生成簽名mySignature, err := rsa.SignPKCS1v15(rand.Reader, privKey, crypto.SHA256, result)if err != nil {return nil, errors.New("生成簽名失敗")}return mySignature, nil }驗證數字簽名
// VerifyRSA // src 簽名數據 // myData 元數據 func VerifyRSA(src, myData []byte) error {// 1. 從秘鑰文件中讀生成的秘鑰內容fp, err := os.Open("public.pem")if err != nil {return errors.New("打開公鑰文件 - public.pem 失敗")}// 2. 讀文件內容fileInfo, _ := fp.Stat()all := make([]byte, fileInfo.Size())num, err := fp.Read(all)if err != nil {return errors.New("讀文件內容失敗")}fmt.Println("文件大小: ", num)// 3. 關閉文件defer fp.Close()// 4. 將公鑰數據解析為pem格式的數據塊block, _ := pem.Decode(all)// 5. 將公鑰從pem數據塊中提取出來pubInterface, err := x509.ParsePKIXPublicKey(block.Bytes)if err != nil {return errors.New("解析公鑰失敗")}// 6. 公鑰接口轉換為公鑰對象pubKey := pubInterface.(*rsa.PublicKey)// 7. 將數據通過哈希函數生成信息摘要myHash := sha256.New()myHash.Write(myData)result := myHash.Sum(nil)// 7. 數據認證err = rsa.VerifyPKCS1v15(pubKey, crypto.SHA256, result, src)if err != nil {return err}fmt.Println("數字簽名驗證成功, 恭喜o(* ̄︶ ̄*)o恭喜")return nil }總結
以上是生活随笔為你收集整理的【密码学五】数字签名、RSA实现数字签名和验证的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux命令查看服务器的型号、序列号、
- 下一篇: <Zhuuu_ZZ>那些年我们踩过的Ha