流程概述

  1. 一般情况下整个过程存在两对公私钥。A:开发者持有私钥,提供服务的平台(如支付宝、衫德等)持有公钥;B:提供服务的平台持有私钥,开发者持有公钥。
  2. 开发者使用A私钥加签后发送请求到平台,平台使用A公钥验签,确定数据有效后,平台会将执行结果使用B私钥加签后发送给开发者(常见就是回调),此时开发者拿到数据需要验签确定数据有效

衫德(SHA1WithRSA方式加签)秘钥格式转化

openssl pkcs12 -in xxx.pfx -nodes -out xxx.pem

openssl x509 -inform der -in xxx.cer -out xxx.pem

加载秘钥文件获取需要的公私钥

func LoadPrivateKey(pemPath string) (string, *rsa.PrivateKey, error) {
	key, err := ioutil.ReadFile(pemPath)
	if err != nil {
		return "", nil, err
	}
	block, _ := pem.Decode(key)
	if block == nil {
		return "", nil, nil
	}
	p, err := x509.ParsePKCS8PrivateKey(block.Bytes)
	if err != nil {
		return "", nil, err
	} else {
		pk := p.(*rsa.PrivateKey)
		return "", pk, nil
	}
}

func LoadPublicKey(pemPath string) (*rsa.PublicKey, error) {
	key, err := ioutil.ReadFile(pemPath)
	if err != nil {
		return nil, err
	}
	block, _ := pem.Decode(key)
	if block == nil {
		return nil, err
	}

	certBody, err := x509.ParseCertificate(block.Bytes)
	if err != nil {
		return nil, err
	}
	pb := certBody.PublicKey.(*rsa.PublicKey)
	return pb, nil
}

加签

func _sign(signStr string) (sign string, err error) {
	h := crypto.Hash.New(crypto.SHA1)
	//对数据进行签名
	h.Write([]byte(signStr))
	hashed := h.Sum(nil)

	signature, err := rsa.SignPKCS1v15(rand.Reader, A私钥,
		crypto.SHA1, hashed)
	if err != nil {
		return
	}
	sign = base64.StdEncoding.EncodeToString(signature)
	return
}

验签

func VerifySign(signData string, sign []byte, pk *rsa.PublicKey) error {
	hash := crypto.SHA1
	if !hash.Available() {
		return fmt.Errorf("crypto: requested hash function (%s) is unavailable", hash.String())
	}

	h := hash.New()
	h.Write([]byte(signData))

	return rsa.VerifyPKCS1v15(pk, hash, h.Sum(nil), sign)
}

衫德云账户账户侧加签验签demo:

//SignAccount 云账户账户侧签名
func SignAccount(signData []byte) (sign, encryptKey, encryptData string, err error) {
	//0返回一个16位字符串
	aes := SandAES{}
	rand16 := aes.RandStr(16)
	//1使用加签公钥 对16位随机数加密
	encryptKeyByte, err := rsa.EncryptPKCS1v15(rand.Reader, B公钥, []byte(rand16))
	if err != nil {
		return
	}
	encryptKey = base64.StdEncoding.EncodeToString(encryptKeyByte)

	//2使用16位随机数 对内容进行ase加密,得到data报文体
	aes.Key = []byte(rand16)
	encryptData = aes.Encypt5(signData)
	//3通过私钥获取签名
	h := crypto.Hash.New(crypto.SHA1)
	//对data参数进行签名
	h.Write([]byte(encryptData))
	hashed := h.Sum(nil)

	signature, err := rsa.SignPKCS1v15(rand.Reader, A私钥,
		crypto.SHA1, hashed)
	if err != nil {
		return
	}
	sign = base64.StdEncoding.EncodeToString(signature)
	return
}

// DataAccount 账户侧解析返回数据
func DataAccount(signData, data, encryptKey string) ([]byte, error) {
	sign, err := base64.StdEncoding.DecodeString(strings.Replace(signData, " ", "+", -1))
	if err != nil {
		return nil, err
	}
	err = VerifySign(data, sign, B公钥)
	if err != nil {
		err = VerifySign(data, sign, A公钥)
		if err != nil {
			return nil, err
		}
	}
	encryptKey1, err := base64.StdEncoding.DecodeString(encryptKey)
	if err != nil {
		return nil, err
	}
	rand16, err := rsa.DecryptPKCS1v15(rand.Reader, A私钥, encryptKey1)
	if err != nil {
		return nil, err
	}
	aes := SandAES{}
	data1, err := base64.StdEncoding.DecodeString(data)
	if err != nil {
		return nil, err
	}
	originData := aes.EcbDecrypt(data1, rand16)
	return originData, nil
}

AES加密解密可借鉴:

import (
	"bytes"
	"crypto/aes"
	"crypto/cipher"
	"encoding/base64"
	"errors"
	"math/rand"
	"strings"
)

type SandAES struct {
	Key []byte
}

func (s *SandAES) Pkcs7Padding(data []byte, blockSize int) []byte {
	//判断缺少几位长度。最少1,最多 blockSize
	padding := blockSize - len(data)%blockSize
	//补足位数。把切片[]byte{byte(padding)}复制padding个
	padText := bytes.Repeat([]byte{byte(padding)}, padding)
	return append(data, padText...)
}

// pkcs7UnPadding 填充的反向操作
func (s *SandAES) Pkcs7UnPadding(data []byte) ([]byte, error) {
	length := len(data)
	if length == 0 {
		return nil, errors.New("加密字符串错误")
	}
	// 获取填充的个数
	unPadding := int(data[length-1])
	return data[:(length - unPadding)], nil
}

func (s *SandAES) AESEncrypt(data []byte) ([]byte, error) {
	// 创建加密实例
	block, err := aes.NewCipher(s.Key)
	if err != nil {
		return nil, err
	}
	//判断加密块的大小
	blockSize := block.BlockSize()
	//填充
	encryptBytes := s.Pkcs7Padding(data, blockSize)
	// 初始化加密数据接受切片
	crypted := make([]byte, len(encryptBytes))
	// 使用cbc加密
	blockMod := cipher.NewCBCEncrypter(block, s.Key[:blockSize])

	// 执行加密
	blockMod.CryptBlocks(crypted, encryptBytes)
	return crypted, nil
}

// 解密
func (s *SandAES) AESDecrypt(data []byte) ([]byte, error) {
	//创建实例
	block, err := aes.NewCipher(s.Key)
	if err != nil {
		return nil, err
	}
	//获取块的大小
	blockSize := block.BlockSize()
	//使用cbc
	blockMode := cipher.NewCBCDecrypter(block, s.Key[:blockSize])

	//初始化数据
	crypted := make([]byte, len(data))
	//执行解密
	blockMode.CryptBlocks(crypted, data)
	//去处填充
	crypted, err = s.Pkcs7UnPadding(crypted)
	if err != nil {
		return nil, err
	}
	return crypted, nil
}

func (s *SandAES) EncryptByAES(data []byte) (string, error) {
	res, err := s.AESEncrypt(data)
	if err != nil {
		return "", err
	}
	return base64.StdEncoding.EncodeToString(res), nil
}

//解密

func (s *SandAES) DecryptByAES(data string) ([]byte, error) {
	dataByte, err := base64.StdEncoding.DecodeString(data)
	if err != nil {
		return nil, err
	}
	return s.AESDecrypt(dataByte)
}

func (s *SandAES) RandStr(n int) string {
	str := []string{"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"}
	strData := strings.Builder{}
	for i := 0; i < n; i++ {
		index := rand.Intn(len(str))
		strData.WriteString(str[index])
	}
	res := strData.String()
	return res
}

func (s *SandAES) Encypt5(data []byte) string {
	block, _ := aes.NewCipher(s.Key)
	data = s.Pkcs7Padding(data, block.BlockSize())
	decrypted := make([]byte, len(data))
	size := block.BlockSize()

	for bs, be := 0, size; bs < len(data); bs, be = bs+size, be+size {
		block.Encrypt(decrypted[bs:be], data[bs:be])
	}

	return base64.StdEncoding.EncodeToString(decrypted)
}

func (s *SandAES) EcbDecrypt(data, key []byte) []byte {
	block, _ := aes.NewCipher(key)
	decrypted := make([]byte, len(data))
	size := block.BlockSize()

	for bs, be := 0, size; bs < len(data); bs, be = bs+size, be+size {
		block.Decrypt(decrypted[bs:be], data[bs:be])
	}

	b, _ := s.Pkcs7UnPadding(decrypted)
	return b
}