數字簽名如何工作
- 數字簽名由兩部分組成:
- 使用私鑰從消息創建簽名的算法;
- 允許任何人驗證簽名的算法;
數字簽名應該滿足的要求
- 簽名不可僞造性
- 簽名不可抵賴性
- 簽名可信任,簽名的識別應用相對容易,任何人都可以驗證簽名的有效性
- 簽名不可複製、簽名與原文是不可分割的整體;
- 簽名消息不可篡改,因爲任意比特數據被篡改,其簽名便被隨之改變,那麼任何人可以驗證而拒絕接受此簽名。
RSA數字簽名的核心步驟
1.RSA數字簽名的核心步驟
- 選擇hash算法,對需要簽名的數據進行hash 運算
- 讀取私鑰文件,解析出私鑰對象
- 1.1讀取私鑰文件,獲取私鑰字節
- 1.2對私鑰文件進行解碼,生成加密快對象
- 1.3解析DER編碼的私鑰,生成私鑰對象 - RSA數字簽名,生成base64編碼的簽名字符串
2.RSA驗證數字簽名的核心步驟
- 對base64編碼的簽名內容進行解碼,返回簽名字節
- 選擇hash算法,對需要簽名的數據進行hash運算
- 讀取公鑰文件,解析出公鑰對象
- 讀取公鑰文件,獲取公鑰字節
- 解碼公鑰字節,生成加密快對象
- 解析DER編碼的公鑰,生成公鑰接口
- 公鑰接口轉型成公鑰對象 - RSA驗證數字簽名
GO 實現RSA數字簽名代碼
package main
import (
"crypto"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/base64"
"encoding/pem"
"errors"
"fmt"
"io/ioutil"
)
func main() {
str := "will be best"
base64Sig,_ := RSASign([]byte(str),"./files/private.pem")
fmt.Println("簽名後信息",base64Sig)
err := RSAVerify([]byte(str),base64Sig,"./files/public.pem")
if err == nil {
fmt.Println("驗證簽名ok!")
} else {
fmt.Println("驗證失敗!")
}
}
func RSASign(data []byte,filename string) (string,error) {
//1.選擇hash算法,對需要簽名的數據進行hash運算
myhash := crypto.SHA256
hashInstance := myhash.New()
hashInstance.Write(data)
hashed := hashInstance.Sum(nil)
//2.讀取私鑰文件,解析出私鑰對象
privateKey,err :=ReadParsePrivateKey(filename)
if err != nil {
return "",err
}
//3.RSA數字簽名
bytes,err := rsa.SignPKCS1v15(rand.Reader,privateKey,myhash,hashed)
if err != nil {
return "",err
}
return base64.StdEncoding.EncodeToString(bytes),nil
}
//公鑰驗證數據簽名是否正確
func RSAVerify(data []byte,base64Sig,filename string) error {
//- 對base64編碼的簽名內容進行解碼,返回簽名字節
bytes,err := base64.StdEncoding.DecodeString((base64Sig))
if err != nil {
return err
}
//- 選擇hash算法,對需要簽名的數據進行hash運算
myhash := crypto.SHA256
hashInstance := myhash.New()
hashInstance.Write(data)
hashed := hashInstance.Sum(nil)
//- 讀取公鑰文件,解析出公鑰對象
publicKey,err := ReadParsePublicKey(filename)
if err != nil {
return err
}
//- RSA驗證數字簽名
return rsa.VerifyPKCS1v15(publicKey,myhash,hashed,bytes)
}
//讀取公鑰文件,解析出公鑰對象
func ReadParsePublicKey(filename string) (*rsa.PublicKey,error) {
//--1.讀取公鑰文件,獲取公鑰字節
publicKeyBytes,err := ioutil.ReadFile(filename)
if err != nil {
return nil,err
}
//--2.解碼公鑰字節,生成加密對象
block,_ := pem.Decode(publicKeyBytes)
if block == nil {
return nil,errors.New("公鑰信息錯誤")
}
//--3.解析DER編碼的公鑰,生成公鑰接口
publicKeyInterface,err :=x509.ParsePKIXPublicKey(block.Bytes)
if err != nil {
return nil,err
}
//--4.公鑰接口轉型成公鑰對象
publicKey := publicKeyInterface.(*rsa.PublicKey)
return publicKey,nil
}
//讀取私鑰文件,解析出私鑰對象
func ReadParsePrivateKey(filename string) (*rsa.PrivateKey,error) {
//--1.讀取私鑰文件,獲取私鑰字節
privateKeyBytes,_ := ioutil.ReadFile(filename)
//--2.對私鑰文件進行編碼,生成加密對象
block,_ := pem.Decode(privateKeyBytes)
if block == nil {
return nil,errors.New("私鑰信息錯誤")
}
//3.解析DER編碼的私鑰,生成私鑰對象
privateKey,err := x509.ParsePKCS1PrivateKey(block.Bytes)
if err != nil {
return nil,err
}
return privateKey,err
}