天天看點

golang RAS簽名

做過很多對接第三方平台的業務,幾乎所有的接口對接都會用到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等,摘要的長度越長,資訊越安全