天天看点

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等,摘要的长度越长,信息越安全