Go實現RSA數字簽名算法(附代碼)

數字簽名如何工作
  • 數字簽名由兩部分組成:
    • 使用私鑰從消息創建簽名的算法;
    • 允許任何人驗證簽名的算法;
數字簽名應該滿足的要求
  • 簽名不可僞造性
  • 簽名不可抵賴性
  • 簽名可信任,簽名的識別應用相對容易,任何人都可以驗證簽名的有效性
  • 簽名不可複製、簽名與原文是不可分割的整體;
  • 簽名消息不可篡改,因爲任意比特數據被篡改,其簽名便被隨之改變,那麼任何人可以驗證而拒絕接受此簽名。
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
}

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章