做過很多對接第三方平台的業務,幾乎所有的接口對接都會用到Rsa進行簽名,Rsa算法是使用私鑰簽名,公鑰驗簽。
下面直接上代碼:
package main
import (
"crypto"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/base64"
"encoding/pem"
"fmt"
"io/ioutil"
"testing"
)
//通過檔案加載私鑰對象
func LoadPrivateKey(privateKeyContent string,isPath bool) (privateKey *rsa.PrivateKey, err error) {
var privateKeyBytes []byte
//如果傳入是私鑰路徑直接讀取,如果傳入是私鑰内容則格式化成正确的私鑰格式
if isPath {
privateKeyBytes, err = ioutil.ReadFile(privateKeyContent)
if err != nil {
return nil, fmt.Errorf("讀取私鑰證書失敗 file err:%s", err.Error())
}
}else {
//var publicHeader = "-----BEGIN RSA PRIVATE KEY-----\n"
//var publicTail = "-----END RSA PRIVATE KEY-----\n"
var publicHeader = "-----BEGIN PRIVATE KEY-----\n"
var publicTail = "-----END PRIVATE KEY-----\n"
var temp string
split(privateKeyContent,&temp)
privateKeyBytes = []byte(publicHeader+temp+publicTail)
}
block, _ := pem.Decode(privateKeyBytes)
if block == nil {
return nil, fmt.Errorf("解碼私鑰失敗")
}
key, err := x509.ParsePKCS8PrivateKey(block.Bytes)
if err != nil {
return nil, fmt.Errorf("解析私鑰失敗 err:%s", err.Error())
}
privateKey, ok := key.(*rsa.PrivateKey)
if !ok {
return nil, fmt.Errorf("非法私鑰檔案,檢查私鑰檔案")
}
return privateKey, nil
}
//64個字元換行
func split(key string,temp *string){
if len(key)<=64 {
*temp = *temp+key+"\n"
}
for i:=0;i<len(key);i++{
if (i+1)%64==0{
*temp = *temp+key[:i+1]+"\n"
key = key[i+1:]
split(key,temp)
break
}
}
}
//簽名
func Sign(privateKey *rsa.PrivateKey,message string) (signature string, err error) {
//這裡采用摘要格式是SHA256,常用的摘要格式還有MD5,SHA1等
h := crypto.Hash.New(crypto.SHA256)
_, err = h.Write([]byte(message))
if err != nil {
return "", nil
}
hashed := h.Sum(nil)
signatureByte, err := rsa.SignPKCS1v15(rand.Reader, privateKey, crypto.SHA256, hashed)
if err != nil {
return "", err
}
//一般簽名需要轉一下base64
return base64.StdEncoding.EncodeToString(signatureByte), nil
}
//執行測試
func TestRas(t *testing.T){
//通過私鑰檔案路徑加載私鑰
//privateKey,err := LoadPrivateKey("私鑰檔案路徑",true)
//通過私鑰文本加載私鑰
privateKey,err := LoadPrivateKey("私鑰文本内容",false)
if err != nil{
t.Error(err.Error())
return
}
signature,err := Sign(privateKey,"要加簽的資訊")
if err != nil{
t.Error(err.Error())
return
}
fmt.Printf("簽名:%s \n",signature)
}
在開發中使用RAS還要注意下面的一些細節的變化
1) PKCS1和PKCS8 這兩種類型的封包頭是不同的,要分别使用不同的處理方法
//PKCS1
x509.ParsePKCS1PrivateKey(der []byte) (*rsa.PrivateKey, error)
//PKCS8
x509.ParsePKCS8PrivateKey(der []byte) (key interface{}, err error)
2)摘要算法的不同,常用的摘要算法有md5,sha1,sha256,sha512等,摘要的長度越長,資訊越安全