feat:邮储支付fix
This commit is contained in:
parent
6df638f471
commit
4219e20d30
|
|
@ -1,6 +1,10 @@
|
|||
package payment
|
||||
|
||||
import (
|
||||
sm22 "PaymentCenter/app/third/paymentService/psbc/internal/gmutil/sm2"
|
||||
"PaymentCenter/app/third/paymentService/psbc/internal/gmutil/sm2/model"
|
||||
"PaymentCenter/app/third/paymentService/psbc/internal/gmutil/sm2/sdk"
|
||||
"PaymentCenter/app/third/paymentService/psbc/internal/gmutil/sm4"
|
||||
"bytes"
|
||||
"crypto/hmac"
|
||||
"crypto/rand"
|
||||
|
|
@ -19,7 +23,6 @@ import (
|
|||
|
||||
"PaymentCenter/app/third/paymentService/psbc/internal/sm2"
|
||||
psbcutil "PaymentCenter/app/third/paymentService/psbc/internal/util"
|
||||
"github.com/ZZMarquis/gm/sm4"
|
||||
)
|
||||
|
||||
// Client 支付客户端
|
||||
|
|
@ -111,53 +114,98 @@ func RandomNumber(n int) string {
|
|||
return string(result)
|
||||
}
|
||||
|
||||
// EncryptMobile 手机银行支付参数加密
|
||||
// 返回: tysdPayParams(base64), tysdEncryptKey(base64)
|
||||
// 使用 YouChuKoffee 加密包(psbc/internal/sm2 + psbc/internal/util)
|
||||
//// EncryptMobile 手机银行支付参数加密
|
||||
//// 返回: tysdPayParams(base64), tysdEncryptKey(base64)
|
||||
//// 使用 YouChuKoffee 加密包(psbc/internal/sm2 + psbc/internal/util)
|
||||
//func (c *Client) EncryptMobile(inputJson string, signStr string) (string, string, error) {
|
||||
// defer func() {
|
||||
// if err := recover(); err != nil {
|
||||
// fmt.Println("加密失败", err)
|
||||
// }
|
||||
// }()
|
||||
//
|
||||
// sm4Key := psbcutil.GenerateSM4Key()
|
||||
//
|
||||
// // SM2 加密 SM4 密钥(使用银行公钥,使用 YouChuKoffee 的 Sm2Encrypt)
|
||||
// bankPubKey, err := sm2.ReadPublicKeyFromHex(c.cfg.BankKey)
|
||||
// if err != nil {
|
||||
// return "", "", fmt.Errorf("读取银行公钥失败: %v", err)
|
||||
// }
|
||||
// encryptKeyBytes, err := psbcutil.Sm2Encrypt(bankPubKey, sm4Key)
|
||||
// if err != nil {
|
||||
// return "", "", fmt.Errorf("sm2加密失败: %v", err)
|
||||
// }
|
||||
// encryptKey := hex.EncodeToString(encryptKeyBytes)
|
||||
// if len(encryptKey) > 2 && encryptKey[0:2] == "04" {
|
||||
// encryptKeyBytes = encryptKeyBytes[1:]
|
||||
// }
|
||||
//
|
||||
// // SM2 签名(使用 YouChuKoffee 的 Sm2Sign,UserID 传 nil,默认值 1234567812345678)
|
||||
// merchantPrivKey, err := sm2.ReadPrivateKeyFromHex(c.cfg.PrivateKey)
|
||||
// if err != nil {
|
||||
// return "", "", fmt.Errorf("读取商户私钥失败: %v", err)
|
||||
// }
|
||||
// r, s, err := sm2.Sm2Sign(merchantPrivKey, []byte(signStr), nil, rand.Reader)
|
||||
// if err != nil {
|
||||
// return "", "", fmt.Errorf("签名失败: %v", err)
|
||||
// }
|
||||
// sig := encodeBase64(rsToBytes(r, s))
|
||||
//
|
||||
// // 拼接参数并 SM4 ECB 加密
|
||||
// // 对齐 YouChuKoffee: sm43.ECBEncrypt(sm4Key, sm43.PKCS5Padding([]byte(param), 16))
|
||||
// // sm4ECBEncrypt 内部已处理 padding,调用方不需要再 pad
|
||||
// param := fmt.Sprintf("%s&sign=%s", inputJson, sig)
|
||||
// tmp, err := sm4ECBEncrypt(sm4Key, []byte(param))
|
||||
// if err != nil {
|
||||
// return "", "", fmt.Errorf("sm4加密失败: %v", err)
|
||||
// }
|
||||
//
|
||||
// return encodeBase64(tmp), encodeBase64(encryptKeyBytes), nil
|
||||
//}
|
||||
|
||||
func (c *Client) EncryptMobile(inputJson string, signStr string) (string, string, error) {
|
||||
defer func() {
|
||||
defer func() error {
|
||||
if err := recover(); err != nil {
|
||||
fmt.Println("加密失败", err)
|
||||
return errors.New("加密失败")
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}()
|
||||
|
||||
sm4Key := psbcutil.GenerateSM4Key()
|
||||
|
||||
// SM2 加密 SM4 密钥(使用银行公钥,使用 YouChuKoffee 的 Sm2Encrypt)
|
||||
bankPubKey, err := sm2.ReadPublicKeyFromHex(c.cfg.BankKey)
|
||||
encryptKeyBytes, err := sm22.NewSm2().
|
||||
SetHexPublicKey(c.cfg.BankKey).
|
||||
SetData(sm4Key).
|
||||
SetSdk(sdk.NewCmbLifeSdk()).
|
||||
SetCipherType(model.C1C3C2).
|
||||
Encrypt().
|
||||
ToBytes()
|
||||
if err != nil {
|
||||
return "", "", fmt.Errorf("读取银行公钥失败: %v", err)
|
||||
}
|
||||
encryptKeyBytes, err := psbcutil.Sm2Encrypt(bankPubKey, sm4Key)
|
||||
if err != nil {
|
||||
return "", "", fmt.Errorf("sm2加密失败: %v", err)
|
||||
return "", "", errors.New("加密sm2key失败")
|
||||
}
|
||||
encryptKey := hex.EncodeToString(encryptKeyBytes)
|
||||
if len(encryptKey) > 2 && encryptKey[0:2] == "04" {
|
||||
if encryptKey[0:2] == "04" {
|
||||
encryptKeyBytes = encryptKeyBytes[1:]
|
||||
}
|
||||
|
||||
// SM2 签名(使用 YouChuKoffee 的 Sm2Sign,UserID 传 nil,默认值 1234567812345678)
|
||||
merchantPrivKey, err := sm2.ReadPrivateKeyFromHex(c.cfg.PrivateKey)
|
||||
pub, err := sm2.StringToPublicKey(c.cfg.Pubkey)
|
||||
if err != nil {
|
||||
return "", "", fmt.Errorf("读取商户私钥失败: %v", err)
|
||||
return "", "", errors.New("读取公钥失败")
|
||||
}
|
||||
r, s, err := sm2.Sm2Sign(merchantPrivKey, []byte(signStr), nil, rand.Reader)
|
||||
pri, err := sm2.StringToPrivateKey(c.cfg.PrivateKey, pub)
|
||||
if err != nil {
|
||||
return "", "", fmt.Errorf("签名失败: %v", err)
|
||||
return "", "", errors.New("读取私钥失败")
|
||||
}
|
||||
sig := encodeBase64(rsToBytes(r, s))
|
||||
|
||||
// 拼接参数并 SM4 ECB 加密
|
||||
// 对齐 YouChuKoffee: sm43.ECBEncrypt(sm4Key, sm43.PKCS5Padding([]byte(param), 16))
|
||||
// sm4ECBEncrypt 内部已处理 padding,调用方不需要再 pad
|
||||
rs, err := sm2.SignSm2(pri, []byte(signStr))
|
||||
if err != nil {
|
||||
return "", "", errors.New("签名失败")
|
||||
}
|
||||
var sig = base64.StdEncoding.EncodeToString(rs)
|
||||
param := fmt.Sprintf("%s&sign=%s", inputJson, sig)
|
||||
tmp, err := sm4ECBEncrypt(sm4Key, []byte(param))
|
||||
tmp, err := sm4.ECBEncrypt(sm4Key, sm4.PKCS5Padding([]byte(param), 16))
|
||||
if err != nil {
|
||||
return "", "", fmt.Errorf("sm4加密失败: %v", err)
|
||||
return "", "", errors.New("加密失败")
|
||||
}
|
||||
|
||||
return encodeBase64(tmp), encodeBase64(encryptKeyBytes), nil
|
||||
return base64.StdEncoding.EncodeToString(tmp), base64.StdEncoding.EncodeToString([]byte(encryptKeyBytes)), nil
|
||||
}
|
||||
|
||||
// DecryptResponse 解密银行响应
|
||||
|
|
|
|||
|
|
@ -0,0 +1,2 @@
|
|||
# gmutil
|
||||
蓝色兄弟 国密工具仓库
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
package sm2
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func (s *Sm2) SetError(err error) *Sm2 {
|
||||
s.err = append(s.err, err)
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *Sm2) encryptErrHandler() error {
|
||||
if len(s.data) == 0 {
|
||||
s.SetError(fmt.Errorf("data is empty"))
|
||||
}
|
||||
if s.publicKey == nil {
|
||||
s.SetError(fmt.Errorf("publicKey is nil"))
|
||||
}
|
||||
return s.errHandle()
|
||||
}
|
||||
|
||||
func (s *Sm2) decryptErrHandler() error {
|
||||
if len(s.data) == 0 {
|
||||
s.SetError(fmt.Errorf("data is empty"))
|
||||
}
|
||||
if s.privateKey == nil {
|
||||
s.SetError(fmt.Errorf("privateKey is nil"))
|
||||
}
|
||||
return s.errHandle()
|
||||
}
|
||||
|
||||
func (s *Sm2) verifyErrHandler() error {
|
||||
if len(s.data) == 0 {
|
||||
s.SetError(fmt.Errorf("data is empty"))
|
||||
}
|
||||
if s.publicKey == nil {
|
||||
s.SetError(fmt.Errorf("publicKey is nil"))
|
||||
}
|
||||
return s.errHandle()
|
||||
}
|
||||
|
||||
func (s *Sm2) signErrHandler() error {
|
||||
if len(s.data) == 0 {
|
||||
s.SetError(fmt.Errorf("data is empty"))
|
||||
}
|
||||
if s.privateKey == nil {
|
||||
s.SetError(fmt.Errorf("privateKey is nil"))
|
||||
}
|
||||
return s.errHandle()
|
||||
}
|
||||
|
||||
func (s *Sm2) errHandle() error {
|
||||
if len(s.err) > 0 {
|
||||
errStr := ""
|
||||
for _, e := range s.err {
|
||||
errStr += e.Error() + "\n"
|
||||
}
|
||||
return fmt.Errorf(errStr)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
package model
|
||||
|
||||
import (
|
||||
"crypto/elliptic"
|
||||
"math/big"
|
||||
)
|
||||
|
||||
var (
|
||||
One = new(big.Int).SetInt64(1)
|
||||
DefaultUid = []byte{0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38}
|
||||
VerifyFalse = []byte{0x30}
|
||||
VerifyTrue = []byte{0x31}
|
||||
)
|
||||
|
||||
type CipherType int32
|
||||
|
||||
const (
|
||||
C1C2C3 CipherType = 1
|
||||
C1C3C2 CipherType = 2
|
||||
)
|
||||
|
||||
type PublicKey struct {
|
||||
elliptic.Curve
|
||||
X, Y *big.Int
|
||||
}
|
||||
|
||||
type PrivateKey struct {
|
||||
*PublicKey
|
||||
D *big.Int
|
||||
}
|
||||
|
||||
type Signature struct {
|
||||
R, S *big.Int
|
||||
}
|
||||
|
|
@ -0,0 +1,116 @@
|
|||
package sdk
|
||||
|
||||
import (
|
||||
"PaymentCenter/app/third/paymentService/psbc/internal/gmutil/sm2/util"
|
||||
"crypto/elliptic"
|
||||
"encoding/binary"
|
||||
"math/big"
|
||||
)
|
||||
|
||||
type BaseSdk struct {
|
||||
}
|
||||
|
||||
func NewBaseSdk() SDK {
|
||||
return &BaseSdk{}
|
||||
}
|
||||
|
||||
func (b *BaseSdk) Kdf(c elliptic.Curve, x, y *big.Int, c2 []byte) error {
|
||||
data := elliptic.Marshal(c, x, y)
|
||||
ct := uint32(1)
|
||||
length := len(c2)
|
||||
end := (length + 31) / 32
|
||||
result := make([]byte, 0)
|
||||
for i := 1; i <= end; i++ {
|
||||
bytes, err := b.sm3hash(data, b.uint32ToBytes(ct))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
result = append(result, bytes...)
|
||||
ct++
|
||||
}
|
||||
last, err := b.sm3hash(data, b.uint32ToBytes(ct))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if length%32 == 0 {
|
||||
result = append(result, last...)
|
||||
} else {
|
||||
result = append(result, last[:length%32]...)
|
||||
}
|
||||
for i := 0; i < length; i++ {
|
||||
c2[i] ^= result[i]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *BaseSdk) CalculateHash(x *big.Int, c2 []byte, y *big.Int) []byte {
|
||||
digest := util.New()
|
||||
digest.Write(b.bigIntToByte(x))
|
||||
digest.Write(c2)
|
||||
digest.Write(b.bigIntToByte(y))
|
||||
result := digest.Sum(nil)[:32]
|
||||
return result
|
||||
}
|
||||
|
||||
func (b *BaseSdk) GetZ(x *big.Int, y *big.Int, uid []byte) []byte {
|
||||
z := util.New()
|
||||
uidLen := len(uid) * 8
|
||||
z.Write([]byte{byte((uidLen >> 8) & 0xFF)})
|
||||
z.Write([]byte{byte(uidLen & 0xFF)})
|
||||
z.Write(uid)
|
||||
|
||||
sm2P256 := util.NewP256Sm2()
|
||||
|
||||
z.Write(b.bigIntToByte(sm2P256.A))
|
||||
z.Write(b.bigIntToByte(sm2P256.B))
|
||||
z.Write(b.bigIntToByte(sm2P256.Gx))
|
||||
z.Write(b.bigIntToByte(sm2P256.Gy))
|
||||
|
||||
z.Write(x.Bytes())
|
||||
z.Write(y.Bytes())
|
||||
return z.Sum(nil)
|
||||
}
|
||||
|
||||
func (b *BaseSdk) GetE(z []byte, data []byte) *big.Int {
|
||||
e := util.New()
|
||||
e.Write(z)
|
||||
e.Write(data)
|
||||
return new(big.Int).SetBytes(e.Sum(nil)[:32])
|
||||
}
|
||||
|
||||
func (b *BaseSdk) uint32ToBytes(x uint32) []byte {
|
||||
var buf = make([]byte, 4)
|
||||
binary.BigEndian.PutUint32(buf, x)
|
||||
return buf
|
||||
}
|
||||
|
||||
func (b *BaseSdk) sm3hash(sources ...[]byte) ([]byte, error) {
|
||||
bytes, err := util.JoinBytes(sources...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
md := make([]byte, 32)
|
||||
h := util.New()
|
||||
h.Write(bytes)
|
||||
h.Sum(md[:0])
|
||||
return md, nil
|
||||
}
|
||||
|
||||
func (b *BaseSdk) bigIntToByte(n *big.Int) []byte {
|
||||
byteArray := n.Bytes()
|
||||
|
||||
// If the bytes is not a multiple of 32, pad with zero bytes.
|
||||
byteArrLen := len(byteArray)
|
||||
KeyBytes := 32
|
||||
if byteArrLen == KeyBytes {
|
||||
return byteArray
|
||||
}
|
||||
byteArray = append(make([]byte, KeyBytes-byteArrLen), byteArray...)
|
||||
|
||||
// If the most significant byte's most significant bit is set,
|
||||
// prepend a 0 byte to the slice to avoid being interpreted as a negative number.
|
||||
if (byteArray[0] & 0x80) != 0 {
|
||||
byteArray = append([]byte{0}, byteArray...)
|
||||
}
|
||||
return byteArray
|
||||
}
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
package sdk
|
||||
|
||||
import (
|
||||
"PaymentCenter/app/third/paymentService/psbc/internal/gmutil/sm2/util"
|
||||
"crypto/elliptic"
|
||||
"encoding/binary"
|
||||
"math/big"
|
||||
)
|
||||
|
||||
// CmbLifeSdk 招商银行生活服务
|
||||
type CmbLifeSdk struct {
|
||||
BaseSdk
|
||||
}
|
||||
|
||||
func NewCmbLifeSdk() SDK {
|
||||
return &CmbLifeSdk{}
|
||||
}
|
||||
|
||||
func (c *CmbLifeSdk) Kdf(cur elliptic.Curve, x *big.Int, y *big.Int, c2 []byte) error {
|
||||
bufSize := 4
|
||||
digest := util.New()
|
||||
if bufSize < digest.Size() {
|
||||
bufSize = digest.Size()
|
||||
}
|
||||
buf := make([]byte, bufSize)
|
||||
|
||||
encDataLen := len(c2)
|
||||
c1xBytes := c.bigIntToByte(x)
|
||||
c1yBytes := c.bigIntToByte(y)
|
||||
off := 0
|
||||
ct := uint32(0)
|
||||
for off < encDataLen {
|
||||
digest.Reset()
|
||||
digest.Write(c1xBytes)
|
||||
digest.Write(c1yBytes)
|
||||
ct++
|
||||
binary.BigEndian.PutUint32(buf, ct)
|
||||
digest.Write(buf[:4])
|
||||
tmp := digest.Sum(nil)
|
||||
copy(buf[:bufSize], tmp[:bufSize])
|
||||
|
||||
xorLen := encDataLen - off
|
||||
if xorLen > digest.Size() {
|
||||
xorLen = digest.Size()
|
||||
}
|
||||
xor(c2[off:], buf, xorLen)
|
||||
off += xorLen
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func xor(data []byte, kdfOut []byte, dRemaining int) {
|
||||
for i := 0; i < dRemaining; i++ {
|
||||
data[i] ^= kdfOut[i]
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
package sdk
|
||||
|
||||
import (
|
||||
"crypto/elliptic"
|
||||
"math/big"
|
||||
)
|
||||
|
||||
type SDK interface {
|
||||
Kdf(c elliptic.Curve, x, y *big.Int, c2 []byte) error
|
||||
CalculateHash(x *big.Int, c2 []byte, y *big.Int) []byte
|
||||
GetZ(x *big.Int, y *big.Int, uid []byte) []byte
|
||||
GetE(z []byte, data []byte) *big.Int
|
||||
|
||||
uint32ToBytes(x uint32) []byte
|
||||
sm3hash(sources ...[]byte) ([]byte, error)
|
||||
bigIntToByte(n *big.Int) []byte
|
||||
}
|
||||
|
|
@ -0,0 +1,91 @@
|
|||
package sdk
|
||||
|
||||
import (
|
||||
"PaymentCenter/app/third/paymentService/psbc/internal/gmutil/sm2/util"
|
||||
"crypto/elliptic"
|
||||
"encoding/binary"
|
||||
"math/big"
|
||||
)
|
||||
|
||||
// ZbSdk 众邦
|
||||
type ZbSdk struct {
|
||||
BaseSdk
|
||||
}
|
||||
|
||||
func NewZbSdk() SDK {
|
||||
return &ZbSdk{}
|
||||
}
|
||||
|
||||
func (zb *ZbSdk) Kdf(c elliptic.Curve, x, y *big.Int, c2 []byte) error {
|
||||
data := elliptic.Marshal(c, x, y)
|
||||
ct := uint32(1)
|
||||
length := len(c2)
|
||||
end := (length + 31) / 32
|
||||
result := make([]byte, 0)
|
||||
for i := 1; i <= end; i++ {
|
||||
bytes, err := zb.sm3hash(data, zb.uint32ToBytes(ct))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
result = append(result, bytes...)
|
||||
ct++
|
||||
}
|
||||
last, err := zb.sm3hash(data, zb.uint32ToBytes(ct))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if length%32 == 0 {
|
||||
result = append(result, last...)
|
||||
} else {
|
||||
result = append(result, last[:length%32]...)
|
||||
}
|
||||
for i := 0; i < length; i++ {
|
||||
c2[i] ^= result[i]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (zb *ZbSdk) CalculateHash(x *big.Int, c2 []byte, y *big.Int) []byte {
|
||||
digest := util.New()
|
||||
digest.Write(zb.bigIntToByte(x))
|
||||
digest.Write(c2)
|
||||
digest.Write(zb.bigIntToByte(y))
|
||||
result := digest.Sum(nil)[:32]
|
||||
return result
|
||||
}
|
||||
|
||||
func (zb *ZbSdk) GetZ(x *big.Int, y *big.Int, uid []byte) []byte {
|
||||
z := util.New()
|
||||
uidLen := len(uid) * 8
|
||||
z.Write([]byte{byte((uidLen >> 8) & 0xFF)})
|
||||
z.Write([]byte{byte(uidLen & 0xFF)})
|
||||
z.Write(uid)
|
||||
|
||||
sm2P256 := util.NewP256Sm2()
|
||||
|
||||
z.Write(zb.bigIntToByte(sm2P256.A))
|
||||
z.Write(zb.bigIntToByte(sm2P256.B))
|
||||
z.Write(zb.bigIntToByte(sm2P256.Gx))
|
||||
z.Write(zb.bigIntToByte(sm2P256.Gy))
|
||||
|
||||
z.Write(x.Bytes())
|
||||
z.Write(y.Bytes())
|
||||
return z.Sum(nil)
|
||||
}
|
||||
|
||||
func (zb *ZbSdk) bigIntToByte(n *big.Int) []byte {
|
||||
byteArray := n.Bytes()
|
||||
|
||||
// If the most significant byte's most significant bit is set,
|
||||
// prepend a 0 byte to the slice to avoid being interpreted as a negative number.
|
||||
if (byteArray[0] & 0x80) != 0 {
|
||||
byteArray = append([]byte{0}, byteArray...)
|
||||
}
|
||||
return byteArray
|
||||
}
|
||||
|
||||
func (zb *ZbSdk) uint32ToBytes(x uint32) []byte {
|
||||
var buf = make([]byte, 4)
|
||||
binary.LittleEndian.PutUint32(buf, x)
|
||||
return buf
|
||||
}
|
||||
|
|
@ -0,0 +1,427 @@
|
|||
package sm2
|
||||
|
||||
import (
|
||||
"PaymentCenter/app/third/paymentService/psbc/internal/gmutil/sm2/model"
|
||||
"PaymentCenter/app/third/paymentService/psbc/internal/gmutil/sm2/sdk"
|
||||
"PaymentCenter/app/third/paymentService/psbc/internal/gmutil/sm2/util"
|
||||
"bytes"
|
||||
|
||||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
"encoding/asn1"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/big"
|
||||
)
|
||||
|
||||
type Sm2 struct {
|
||||
publicKey *model.PublicKey
|
||||
privateKey *model.PrivateKey
|
||||
signature model.Signature
|
||||
sdk sdk.SDK
|
||||
cipherType model.CipherType
|
||||
c3Len int
|
||||
uid []byte
|
||||
data []byte
|
||||
err []error
|
||||
toData []byte
|
||||
}
|
||||
|
||||
func NewSm2() *Sm2 {
|
||||
return &Sm2{
|
||||
sdk: sdk.NewBaseSdk(),
|
||||
c3Len: 32,
|
||||
uid: model.DefaultUid,
|
||||
cipherType: model.C1C2C3,
|
||||
err: make([]error, 0),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Sm2) Encrypt() *Sm2 {
|
||||
if err := s.encryptErrHandler(); err != nil {
|
||||
return s
|
||||
}
|
||||
c2 := make([]byte, len(s.data))
|
||||
copy(c2, s.data)
|
||||
var c1 []byte
|
||||
var kx, ky *big.Int
|
||||
for {
|
||||
k, err := rand.Int(rand.Reader, s.publicKey.Params().N)
|
||||
if err != nil {
|
||||
return s.SetError(fmt.Errorf("rand error: %v", err))
|
||||
}
|
||||
c1x, c1y := s.publicKey.Curve.ScalarBaseMult(k.Bytes())
|
||||
c1 = elliptic.Marshal(s.publicKey.Curve, c1x, c1y)
|
||||
kx, ky = s.publicKey.Curve.ScalarMult(s.publicKey.X, s.publicKey.Y, k.Bytes())
|
||||
|
||||
err = s.sdk.Kdf(s.publicKey, kx, ky, c2)
|
||||
if err != nil {
|
||||
return s.SetError(fmt.Errorf("kdf error: %v", err))
|
||||
}
|
||||
if s.encrypted(c2, s.data) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
c3 := s.sdk.CalculateHash(kx, s.data, ky)
|
||||
|
||||
c1Len := len(c1)
|
||||
c2Len := len(c2)
|
||||
c3Len := len(c3)
|
||||
s.toData = make([]byte, c1Len+c2Len+c3Len)
|
||||
if s.cipherType == model.C1C2C3 {
|
||||
copy(s.toData[:c1Len], c1)
|
||||
copy(s.toData[c1Len:c1Len+c2Len], c2)
|
||||
copy(s.toData[c1Len+c2Len:], c3)
|
||||
} else if s.cipherType == model.C1C3C2 {
|
||||
copy(s.toData[:c1Len], c1)
|
||||
copy(s.toData[c1Len:c1Len+c3Len], c3)
|
||||
copy(s.toData[c1Len+c3Len:], c2)
|
||||
} else {
|
||||
return s.SetError(fmt.Errorf("cipher type not support"))
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *Sm2) Decrypt() *Sm2 {
|
||||
if err := s.decryptErrHandler(); err != nil {
|
||||
return s
|
||||
}
|
||||
c1Len := 65
|
||||
C1Byte := make([]byte, c1Len)
|
||||
copy(C1Byte, s.data[:c1Len])
|
||||
x, y := elliptic.Unmarshal(s.privateKey.Curve, C1Byte)
|
||||
dBC1X, dBC1Y := s.privateKey.Curve.ScalarMult(x, y, s.privateKey.D.Bytes())
|
||||
|
||||
c2Len := len(s.data) - c1Len - s.c3Len
|
||||
c2 := make([]byte, c2Len)
|
||||
c3 := make([]byte, s.c3Len)
|
||||
if s.cipherType == model.C1C2C3 {
|
||||
copy(c2, s.data[c1Len:c1Len+c2Len])
|
||||
copy(c3, s.data[c1Len+c2Len:])
|
||||
} else if s.cipherType == model.C1C3C2 {
|
||||
copy(c3, s.data[c1Len:c1Len+s.c3Len])
|
||||
copy(c2, s.data[c1Len+s.c3Len:])
|
||||
} else {
|
||||
return s.SetError(fmt.Errorf("cipher type not support"))
|
||||
}
|
||||
|
||||
err := s.sdk.Kdf(s.privateKey.Curve, dBC1X, dBC1Y, c2)
|
||||
if err != nil {
|
||||
return s.SetError(fmt.Errorf("kdf error: %v", err))
|
||||
}
|
||||
|
||||
u := s.sdk.CalculateHash(dBC1X, c2, dBC1Y)
|
||||
if bytes.Compare(u, c3) == 0 {
|
||||
s.toData = c2
|
||||
return s
|
||||
} else {
|
||||
return s.SetError(fmt.Errorf("decrypt error"))
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Sm2) Verify() *Sm2 {
|
||||
if err := s.encryptErrHandler(); err != nil {
|
||||
return s
|
||||
}
|
||||
c := s.publicKey.Curve
|
||||
N := c.Params().N
|
||||
if s.signature.R.Cmp(model.One) < 0 || s.signature.S.Cmp(model.One) < 0 {
|
||||
s.toData = model.VerifyFalse
|
||||
return s
|
||||
}
|
||||
if s.signature.R.Cmp(N) >= 0 || s.signature.S.Cmp(N) >= 0 {
|
||||
s.toData = model.VerifyFalse
|
||||
return s
|
||||
}
|
||||
z := s.sdk.GetZ(s.publicKey.X, s.publicKey.Y, s.uid)
|
||||
e := s.sdk.GetE(z, s.data)
|
||||
t := new(big.Int).Add(s.signature.R, s.signature.S)
|
||||
t.Mod(t, N)
|
||||
if t.Sign() == 0 {
|
||||
s.toData = model.VerifyFalse
|
||||
return s
|
||||
}
|
||||
var x *big.Int
|
||||
x1, y1 := c.ScalarBaseMult(s.signature.S.Bytes())
|
||||
x2, y2 := c.ScalarMult(s.publicKey.X, s.publicKey.Y, t.Bytes())
|
||||
x, _ = c.Add(x1, y1, x2, y2)
|
||||
|
||||
x.Add(x, e)
|
||||
x.Mod(x, N)
|
||||
if x.Cmp(s.signature.R) == 0 {
|
||||
s.toData = model.VerifyTrue
|
||||
} else {
|
||||
s.toData = model.VerifyFalse
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *Sm2) Sign() *Sm2 {
|
||||
if err := s.signErrHandler(); err != nil {
|
||||
return s
|
||||
}
|
||||
z := s.sdk.GetZ(s.privateKey.PublicKey.X, s.privateKey.PublicKey.Y, s.uid)
|
||||
e := s.sdk.GetE(z, s.data)
|
||||
|
||||
c := s.privateKey.PublicKey.Curve
|
||||
N := c.Params().N
|
||||
if N.Sign() == 0 {
|
||||
return s.SetError(fmt.Errorf("invalid curve order"))
|
||||
}
|
||||
var k, r, sb *big.Int
|
||||
var err error
|
||||
for {
|
||||
for {
|
||||
k, err = s.randFieldElement(c, rand.Reader)
|
||||
if err != nil {
|
||||
return s.SetError(fmt.Errorf("randFieldElement: %+v", err))
|
||||
}
|
||||
r, _ = s.privateKey.Curve.ScalarBaseMult(k.Bytes())
|
||||
r.Add(r, e)
|
||||
r.Mod(r, N)
|
||||
if r.Sign() != 0 {
|
||||
if t := new(big.Int).Add(r, k); t.Cmp(N) != 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
rD := new(big.Int).Mul(s.privateKey.D, r)
|
||||
sb = new(big.Int).Sub(k, rD)
|
||||
d1 := new(big.Int).Add(s.privateKey.D, model.One)
|
||||
d1Inv := new(big.Int).ModInverse(d1, N)
|
||||
sb.Mul(sb, d1Inv)
|
||||
sb.Mod(sb, N)
|
||||
if sb.Sign() != 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
s.signature = model.Signature{R: r, S: sb}
|
||||
si, err := asn1.Marshal(s.signature)
|
||||
if err != nil {
|
||||
return s.SetError(fmt.Errorf("asn1.Marshal: %+v", err))
|
||||
}
|
||||
s.toData = si
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *Sm2) randFieldElement(c elliptic.Curve, random io.Reader) (k *big.Int, err error) {
|
||||
params := c.Params()
|
||||
b := make([]byte, params.BitSize/8+8)
|
||||
_, err = io.ReadFull(random, b)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
k = new(big.Int).SetBytes(b)
|
||||
n := new(big.Int).Sub(params.N, model.One)
|
||||
k.Mod(k, n)
|
||||
k.Add(k, model.One)
|
||||
return
|
||||
}
|
||||
|
||||
func (s *Sm2) encrypted(encData []byte, in []byte) bool {
|
||||
encDataLen := len(encData)
|
||||
for i := 0; i != encDataLen; i++ {
|
||||
if encData[i] != in[i] {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (s *Sm2) SetCipherType(cipherType model.CipherType) *Sm2 {
|
||||
s.cipherType = cipherType
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *Sm2) SetHexPublicKey(hexStr string) *Sm2 {
|
||||
d, err := hex.DecodeString(hexStr)
|
||||
if err != nil {
|
||||
return s.SetError(fmt.Errorf("publicKey is not hex string: %s", err.Error()))
|
||||
}
|
||||
s.publicKey, err = util.HexToPublicKey(d)
|
||||
if err != nil {
|
||||
return s.SetError(fmt.Errorf("parse publicKey err: %+v", err))
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *Sm2) SetHexPrivateKey(hexStr string) *Sm2 {
|
||||
d, err := hex.DecodeString(hexStr)
|
||||
if err != nil {
|
||||
return s.SetError(fmt.Errorf("privateKey is not hex string: %s", err.Error()))
|
||||
}
|
||||
s.privateKey, err = util.HexToPrivateKey(d)
|
||||
if err != nil {
|
||||
return s.SetError(fmt.Errorf("parse privateKey err: %+v", err))
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *Sm2) SetPemPublicKey(pemBytes []byte) *Sm2 {
|
||||
block, _ := pem.Decode(pemBytes)
|
||||
if block == nil || block.Type != "PUBLIC KEY" {
|
||||
return s.SetError(fmt.Errorf("publicKey is not pem string"))
|
||||
}
|
||||
var err error
|
||||
s.publicKey, err = util.ParsePublicKey(block.Bytes)
|
||||
if err != nil {
|
||||
return s.SetError(fmt.Errorf("parse publicKey err: %+v", err))
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *Sm2) SetPemPrivateKey(pemBytes []byte, pwd []byte) *Sm2 {
|
||||
block, _ := pem.Decode(pemBytes)
|
||||
if block == nil {
|
||||
return s.SetError(fmt.Errorf("privateKey is not pem string"))
|
||||
}
|
||||
var err error
|
||||
s.privateKey, err = util.ParsePrivateKey(block.Bytes, pwd)
|
||||
if err != nil {
|
||||
return s.SetError(fmt.Errorf("parse privateKey err: %+v", err))
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *Sm2) SetPublicKey(publicKey *model.PublicKey) *Sm2 {
|
||||
s.publicKey = publicKey
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *Sm2) SetPrivateKey(privateKey *model.PrivateKey) *Sm2 {
|
||||
s.privateKey = privateKey
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *Sm2) SetHexSignature(hexStr string) *Sm2 {
|
||||
sign, err := hex.DecodeString(hexStr)
|
||||
if err != nil {
|
||||
return s.SetError(fmt.Errorf("signature is not hex string: %s", err.Error()))
|
||||
}
|
||||
_, err = asn1.Unmarshal(sign, &s.signature)
|
||||
if err != nil {
|
||||
return s.SetError(fmt.Errorf("signature is not asn1: %s", err.Error()))
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *Sm2) SetBase64Signature(base64Str string) *Sm2 {
|
||||
sign, err := base64.StdEncoding.DecodeString(base64Str)
|
||||
if err != nil {
|
||||
return s.SetError(fmt.Errorf("signature is not base64 string: %s", err.Error()))
|
||||
}
|
||||
_, err = asn1.Unmarshal(sign, &s.signature)
|
||||
if err != nil {
|
||||
return s.SetError(fmt.Errorf("signature is not asn1: %s", err.Error()))
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *Sm2) SetHexSignatureData(hexStr string) *Sm2 {
|
||||
sign, err := hex.DecodeString(hexStr)
|
||||
if err != nil {
|
||||
return s.SetError(fmt.Errorf("signature is not hex string: %s", err.Error()))
|
||||
}
|
||||
_, err = asn1.Unmarshal(sign, &s.signature)
|
||||
if err != nil {
|
||||
return s.SetError(fmt.Errorf("signature is not asn1: %s", err.Error()))
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *Sm2) SetSignature(signature model.Signature) *Sm2 {
|
||||
s.signature = signature
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *Sm2) SetSdk(sdk sdk.SDK) *Sm2 {
|
||||
s.sdk = sdk
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *Sm2) SetC3Len(c3Len int) *Sm2 {
|
||||
s.c3Len = c3Len
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *Sm2) SetUid(uid []byte) *Sm2 {
|
||||
s.uid = uid
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *Sm2) SetBase64StringData(base64String string) *Sm2 {
|
||||
data, err := base64.StdEncoding.DecodeString(base64String)
|
||||
if err != nil {
|
||||
return s.SetError(fmt.Errorf("data is not base64 string: %s", err.Error()))
|
||||
}
|
||||
s.data = data
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *Sm2) SetStringData(str string) *Sm2 {
|
||||
s.data = []byte(str)
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *Sm2) SetHexData(hexStr string) *Sm2 {
|
||||
data, err := hex.DecodeString(hexStr)
|
||||
if err != nil {
|
||||
return s.SetError(fmt.Errorf("data is not hex string: %s", err.Error()))
|
||||
}
|
||||
s.data = data
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *Sm2) SetData(data []byte) *Sm2 {
|
||||
s.data = data
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *Sm2) ToBytes() ([]byte, error) {
|
||||
if err := s.errHandle(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return s.toData, nil
|
||||
}
|
||||
|
||||
func (s *Sm2) ToString() (string, error) {
|
||||
if err := s.errHandle(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(s.toData), nil
|
||||
}
|
||||
|
||||
func (s *Sm2) ToBase64String() (string, error) {
|
||||
if err := s.errHandle(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return base64.StdEncoding.EncodeToString(s.toData), nil
|
||||
}
|
||||
|
||||
func (s *Sm2) ToHexString() (string, error) {
|
||||
if err := s.errHandle(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return hex.EncodeToString(s.toData), nil
|
||||
}
|
||||
|
||||
func (s *Sm2) ToBool() (bool, error) {
|
||||
if err := s.errHandle(); err != nil {
|
||||
return false, err
|
||||
}
|
||||
if bytes.Equal(s.toData, model.VerifyTrue) {
|
||||
return true, nil
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (s *Sm2) ToSignature() (*model.Signature, error) {
|
||||
if err := s.errHandle(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &s.signature, nil
|
||||
}
|
||||
|
|
@ -0,0 +1,134 @@
|
|||
package sm2
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"qteam/app/utils/gmutil/sm2/model"
|
||||
"qteam/app/utils/gmutil/sm2/sdk"
|
||||
"qteam/app/utils/gmutil/sm2/util"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var (
|
||||
pubHexKey = "0447fe9ed13aac6200c92b893ad1289a98437c8404e64b1d2f7c755698a8b8e8acb35c1db2bedc5213c930bdfc10efb0e12269cf6a06877679f114fe5ae9dd4469"
|
||||
priHexKey = "9450c673cf801164435b9c164ac1404e87997245bc6f323fde22015875a03f6e"
|
||||
enStr = "BI2O20YuamIpOpXH/RJDtB9gWIpNZPjFbTpbvX45lG8mcma7Cab1yRpE3rcM33oJ8xJ3mbbIvXf/1N507i97eXYQSbLzOBcl/8PyaB4dQ/Ub7QQncN+Npuif4Qp6s11tobdTVOFlz9S9i0VC"
|
||||
)
|
||||
|
||||
func TestSm2_Encrypt(t *testing.T) {
|
||||
var bytes = []byte{94, 256 - 26, 34, 256 - 44, 256 - 90, 256 - 13, 35, 58, 119, 87, 76, 256 - 67, 43, 256 - 39, 122, 101}
|
||||
encrypt, err := NewSm2().
|
||||
SetHexPublicKey(pubHexKey).
|
||||
SetData(bytes).
|
||||
SetSdk(sdk.NewCmbLifeSdk()).
|
||||
SetCipherType(model.C1C3C2).
|
||||
Encrypt().
|
||||
ToHexString()
|
||||
if err != nil {
|
||||
t.Error("sm2 encrypt error:", err)
|
||||
return
|
||||
}
|
||||
t.Log("sm2 encrypt result:", encrypt)
|
||||
}
|
||||
|
||||
func TestSm2_Decrypt(t *testing.T) {
|
||||
//var data = []byte{12, 75, 256 - 22, 115, 121, 256 - 89, 256 - 43, 13, 108, 36, 256 - 35, 256 - 45, 256 - 47, 3, 256 - 74, 126}
|
||||
decrypt, err := NewSm2().
|
||||
SetHexPrivateKey("140c5c68da1829b79d8e4629a8b9548bd694ccc7061fbacb1079aed0e5ac33fa").
|
||||
SetHexData("04504fa0c628cfee8c4ca69fa10df0b8f75fe546a50738befc5e8e638f508fe29a88953b82e16b781e447939b69e9ea6f73b57d8555e7e22b45a424e4d2df553a776940870bd16ae807ac66685df8fe20ff2f701220dccc9ece41d8d8d0476b719c2dddf12ec").
|
||||
SetSdk(sdk.NewCmbLifeSdk()).
|
||||
SetCipherType(model.C1C3C2).
|
||||
Decrypt().
|
||||
ToBytes()
|
||||
if err != nil {
|
||||
t.Error("sm2 decrypt error:", err)
|
||||
return
|
||||
}
|
||||
t.Log("sm2 decrypt result:", decrypt)
|
||||
}
|
||||
|
||||
func TestSm2_Sign(t *testing.T) {
|
||||
sign, err := NewSm2().
|
||||
SetUid([]byte("")).
|
||||
SetHexPrivateKey("140c5c68da1829b79d8e4629a8b9548bd694ccc7061fbacb1079aed0e5ac33fa").
|
||||
SetStringData("hello").
|
||||
Sign().
|
||||
ToBytes()
|
||||
fmt.Println(base64.StdEncoding.EncodeToString(sign))
|
||||
if err != nil {
|
||||
t.Error("sm2 sign error:", err)
|
||||
return
|
||||
}
|
||||
t.Log("sm2 sign result:", sign)
|
||||
}
|
||||
|
||||
func TestSm2_Verify(t *testing.T) {
|
||||
verify, err := NewSm2().
|
||||
SetUid([]byte("")).
|
||||
SetBase64StringData("MEQCIEx1cXGEs35tBAGtVONn/8K9ZKp7CTVl8fIMYk8N08/iAiA9NuJv2CvAfy768A+i3ira8tDa46VaZX7h7NhmJbKs8Q==").
|
||||
//SetSdk(sdk.NewZbSdk()).
|
||||
SetHexPublicKey("0447fe9ed13aac6200c92b893ad1289a98437c8404e64b1d2f7c755698a8b8e8acb35c1db2bedc5213c930bdfc10efb0e12269cf6a06877679f114fe5ae9dd4469").
|
||||
SetStringData("hello").
|
||||
Verify().
|
||||
ToBool()
|
||||
if err != nil {
|
||||
t.Error("sm2 verify error:", err)
|
||||
return
|
||||
}
|
||||
t.Log("sm2 verify result:", verify)
|
||||
}
|
||||
|
||||
func TestSm2_SetPemPrivateKey(t *testing.T) {
|
||||
priPem := `-----BEGIN PRIVATE KEY-----
|
||||
MIGHAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBG0wawIBAQQgilIj1dWX+977jcQO
|
||||
oHDQq6XtbWaazcZdJiHjXpAhKD6hRANCAASbGZLLgc4PZ3axqRolPDRAWFEZmzbm
|
||||
6ZwrOaDXYUCxg2NVGa0vFxvJ3NMwQsYqkceV7/8hnQSrHs/XkgqLKgr+
|
||||
-----END PRIVATE KEY-----`
|
||||
enStr = "BNCI99FErQ6n1w5UujcpFgPk2DNBVsM3M3SYpj1yhybC4kw6+jurrQ3OWCeFK/7Tuaicku6wb2ZCpMiQmUpstgZSHOCZjik+x3DesUeJ4CnX9o826PQuEz2xXoiP/8+n5sSwbY7zh7sdMrSD"
|
||||
encrypt, err := NewSm2().
|
||||
SetPemPrivateKey([]byte(priPem), nil).
|
||||
SetBase64StringData(enStr).
|
||||
SetSdk(sdk.NewCmbLifeSdk()).
|
||||
SetCipherType(model.C1C3C2).
|
||||
Decrypt().
|
||||
ToString()
|
||||
if err != nil {
|
||||
t.Fatalf("sm2 decrypt error: %+v", err)
|
||||
}
|
||||
t.Log("sm2 decrypt result:", encrypt)
|
||||
}
|
||||
|
||||
func TestSm2_SetPemPublicKey(t *testing.T) {
|
||||
pemPubKey := `-----BEGIN PUBLIC KEY-----
|
||||
MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAEmxmSy4HOD2d2sakaJTw0QFhRGZs2
|
||||
5umcKzmg12FAsYNjVRmtLxcbydzTMELGKpHHle//IZ0Eqx7P15IKiyoK/g==
|
||||
-----END PUBLIC KEY-----`
|
||||
encrypt, err := NewSm2().
|
||||
SetPemPublicKey([]byte(pemPubKey)).
|
||||
SetStringData("hello world").
|
||||
SetSdk(sdk.NewCmbLifeSdk()).
|
||||
SetCipherType(model.C1C3C2).
|
||||
Encrypt().
|
||||
ToBase64String()
|
||||
if err != nil {
|
||||
t.Fatalf("sm2 encrypt error: %+v", err)
|
||||
}
|
||||
t.Log("sm2 encrypt result:", encrypt)
|
||||
}
|
||||
|
||||
func Test_Util(t *testing.T) {
|
||||
// todo 有点问题
|
||||
encrypt := NewSm2().SetHexPublicKey(pubHexKey).SetHexPrivateKey(priHexKey)
|
||||
pem, err := util.PublicKeyToPem(encrypt.publicKey)
|
||||
if err != nil {
|
||||
t.Fatalf("sm2 encrypt error: %+v", err)
|
||||
}
|
||||
s, err := encrypt.SetPemPublicKey(pem).SetStringData("hello world").Encrypt().ToBase64String()
|
||||
t.Log(s, err)
|
||||
t.Log(string(pem))
|
||||
privateKeyToPem, err := util.PrivateKeyToPem(encrypt.privateKey, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("sm2 encrypt error: %+v", err)
|
||||
}
|
||||
t.Log(string(privateKeyToPem))
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,329 @@
|
|||
package util
|
||||
|
||||
import (
|
||||
"PaymentCenter/app/third/paymentService/psbc/internal/gmutil/sm2/model"
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/elliptic"
|
||||
"crypto/hmac"
|
||||
"crypto/md5"
|
||||
"crypto/rand"
|
||||
"crypto/sha1"
|
||||
"crypto/sha256"
|
||||
"crypto/sha512"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/asn1"
|
||||
"fmt"
|
||||
"hash"
|
||||
"math/big"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
/*
|
||||
* reference to RFC5959 and RFC2898
|
||||
*/
|
||||
|
||||
var (
|
||||
oidPBES2 = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 5, 13} // id-PBES2(PBES2)
|
||||
oidPBKDF2 = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 5, 12} // id-PBKDF2
|
||||
|
||||
oidAES128CBC = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 1, 2}
|
||||
oidAES256CBC = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 1, 42}
|
||||
|
||||
oidKEYMD5 = asn1.ObjectIdentifier{1, 2, 840, 113549, 2, 5}
|
||||
oidKEYSHA1 = asn1.ObjectIdentifier{1, 2, 840, 113549, 2, 7}
|
||||
oidKEYSHA256 = asn1.ObjectIdentifier{1, 2, 840, 113549, 2, 9}
|
||||
oidKEYSHA512 = asn1.ObjectIdentifier{1, 2, 840, 113549, 2, 11}
|
||||
|
||||
oidSM2 = asn1.ObjectIdentifier{1, 2, 840, 10045, 2, 1}
|
||||
)
|
||||
|
||||
type Sm2PrivateKey struct {
|
||||
Version int
|
||||
PrivateKey []byte
|
||||
NamedCurveOID asn1.ObjectIdentifier `asn1:"optional,explicit,tag:0"`
|
||||
PublicKey asn1.BitString `asn1:"optional,explicit,tag:1"`
|
||||
}
|
||||
|
||||
type pkcs8 struct {
|
||||
Version int
|
||||
Algo pkix.AlgorithmIdentifier
|
||||
PrivateKey []byte
|
||||
}
|
||||
|
||||
// EncryptedPrivateKeyInfo reference to https://www.rfc-editor.org/rfc/rfc5958.txt
|
||||
type EncryptedPrivateKeyInfo struct {
|
||||
EncryptionAlgorithm Pbes2Algorithms
|
||||
EncryptedData []byte
|
||||
}
|
||||
|
||||
// Pbes2Algorithms reference to https://www.ietf.org/rfc/rfc2898.txt
|
||||
type Pbes2Algorithms struct {
|
||||
IdPBES2 asn1.ObjectIdentifier
|
||||
Pbes2Params Pbes2Params
|
||||
}
|
||||
|
||||
// Pbes2Params reference to https://www.ietf.org/rfc/rfc2898.txt
|
||||
type Pbes2Params struct {
|
||||
KeyDerivationFunc Pbes2KDfs // PBES2-KDFs
|
||||
EncryptionScheme Pbes2Encs // PBES2-Encs
|
||||
}
|
||||
|
||||
// Pbes2KDfs reference to https://www.ietf.org/rfc/rfc2898.txt
|
||||
type Pbes2KDfs struct {
|
||||
IdPBKDF2 asn1.ObjectIdentifier
|
||||
Pkdf2Params Pkdf2Params
|
||||
}
|
||||
type Pbes2Encs struct {
|
||||
EncryAlgo asn1.ObjectIdentifier
|
||||
IV []byte
|
||||
}
|
||||
|
||||
// Pkdf2Params reference to https://www.ietf.org/rfc/rfc2898.txt
|
||||
type Pkdf2Params struct {
|
||||
Salt []byte
|
||||
IterationCount int
|
||||
Prf pkix.AlgorithmIdentifier
|
||||
}
|
||||
|
||||
func ParsePrivateKey(bytes []byte, pwd []byte) (*model.PrivateKey, error) {
|
||||
var priKey Sm2PrivateKey
|
||||
var err error
|
||||
if pwd == nil {
|
||||
priKey, err = ParsePKCS8UnEncryptedPrivateKey(bytes)
|
||||
} else {
|
||||
priKey, err = ParsePKCS8EncryptedPrivateKey(bytes, pwd)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parse private key err: %s", err.Error())
|
||||
}
|
||||
curve := NewP256Sm2()
|
||||
k := new(big.Int).SetBytes(priKey.PrivateKey)
|
||||
curveOrder := curve.Params().N
|
||||
if k.Cmp(curveOrder) >= 0 {
|
||||
return nil, fmt.Errorf("invalid elliptic curve private key value")
|
||||
}
|
||||
privateKey := make([]byte, (curveOrder.BitLen()+7)/8)
|
||||
for len(priKey.PrivateKey) > len(privateKey) {
|
||||
if priKey.PrivateKey[0] != 0 {
|
||||
return nil, fmt.Errorf("invalid private key")
|
||||
}
|
||||
priKey.PrivateKey = priKey.PrivateKey[1:]
|
||||
}
|
||||
copy(privateKey[len(privateKey)-len(priKey.PrivateKey):], priKey.PrivateKey)
|
||||
x, y := curve.ScalarBaseMult(privateKey)
|
||||
return &model.PrivateKey{
|
||||
PublicKey: &model.PublicKey{
|
||||
Curve: curve,
|
||||
X: x,
|
||||
Y: y,
|
||||
},
|
||||
D: k,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func ParsePKCS8UnEncryptedPrivateKey(bytes []byte) (Sm2PrivateKey, error) {
|
||||
var pk pkcs8
|
||||
var priKey Sm2PrivateKey
|
||||
|
||||
if _, err := asn1.Unmarshal(bytes, &pk); err != nil {
|
||||
return priKey, err
|
||||
}
|
||||
if !reflect.DeepEqual(pk.Algo.Algorithm, oidSM2) {
|
||||
return priKey, fmt.Errorf("not sm2 elliptic curve")
|
||||
}
|
||||
|
||||
if _, err := asn1.Unmarshal(pk.PrivateKey, &priKey); err != nil {
|
||||
return priKey, fmt.Errorf("privateKey is not sm2 private key: %s", err.Error())
|
||||
}
|
||||
return priKey, nil
|
||||
}
|
||||
|
||||
func ParsePKCS8EncryptedPrivateKey(bytes, pwd []byte) (Sm2PrivateKey, error) {
|
||||
var keyInfo EncryptedPrivateKeyInfo
|
||||
var priKey Sm2PrivateKey
|
||||
_, err := asn1.Unmarshal(bytes, &keyInfo)
|
||||
if err != nil {
|
||||
return priKey, fmt.Errorf("privateKey is not sm2 encrypted private key: %s", err.Error())
|
||||
}
|
||||
if !reflect.DeepEqual(keyInfo.EncryptionAlgorithm.IdPBES2, oidPBES2) {
|
||||
return priKey, fmt.Errorf("x509: only support PBES2")
|
||||
}
|
||||
encryptionScheme := keyInfo.EncryptionAlgorithm.Pbes2Params.EncryptionScheme
|
||||
keyDerivationFunc := keyInfo.EncryptionAlgorithm.Pbes2Params.KeyDerivationFunc
|
||||
if !reflect.DeepEqual(keyDerivationFunc.IdPBKDF2, oidPBKDF2) {
|
||||
return priKey, fmt.Errorf("x509: only support PBKDF2")
|
||||
}
|
||||
pkdf2Params := keyDerivationFunc.Pkdf2Params
|
||||
if !reflect.DeepEqual(encryptionScheme.EncryAlgo, oidAES128CBC) &&
|
||||
!reflect.DeepEqual(encryptionScheme.EncryAlgo, oidAES256CBC) {
|
||||
return priKey, fmt.Errorf("x509: only support AES")
|
||||
}
|
||||
iv := encryptionScheme.IV
|
||||
salt := pkdf2Params.Salt
|
||||
iter := pkdf2Params.IterationCount
|
||||
encryptedKey := keyInfo.EncryptedData
|
||||
var key []byte
|
||||
switch {
|
||||
case pkdf2Params.Prf.Algorithm.Equal(oidKEYMD5):
|
||||
key = pbkdf(pwd, salt, iter, 32, md5.New)
|
||||
break
|
||||
case pkdf2Params.Prf.Algorithm.Equal(oidKEYSHA1):
|
||||
key = pbkdf(pwd, salt, iter, 32, sha1.New)
|
||||
break
|
||||
case pkdf2Params.Prf.Algorithm.Equal(oidKEYSHA256):
|
||||
key = pbkdf(pwd, salt, iter, 32, sha256.New)
|
||||
break
|
||||
case pkdf2Params.Prf.Algorithm.Equal(oidKEYSHA512):
|
||||
key = pbkdf(pwd, salt, iter, 32, sha512.New)
|
||||
break
|
||||
default:
|
||||
return priKey, fmt.Errorf("x509: unknown hash algorithm")
|
||||
}
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
return priKey, err
|
||||
}
|
||||
mode := cipher.NewCBCDecrypter(block, iv)
|
||||
mode.CryptBlocks(encryptedKey, encryptedKey)
|
||||
return ParsePKCS8UnEncryptedPrivateKey(encryptedKey)
|
||||
}
|
||||
|
||||
// copy from crypto/pbkdf2.go
|
||||
func pbkdf(password, salt []byte, iter, keyLen int, h func() hash.Hash) []byte {
|
||||
prf := hmac.New(h, password)
|
||||
hashLen := prf.Size()
|
||||
numBlocks := (keyLen + hashLen - 1) / hashLen
|
||||
|
||||
var buf [4]byte
|
||||
dk := make([]byte, 0, numBlocks*hashLen)
|
||||
U := make([]byte, hashLen)
|
||||
for block := 1; block <= numBlocks; block++ {
|
||||
// N.B.: || means concatenation, ^ means XOR
|
||||
// for each block T_i = U_1 ^ U_2 ^ ... ^ U_iter
|
||||
// U_1 = PRF(password, salt || uint(i))
|
||||
prf.Reset()
|
||||
prf.Write(salt)
|
||||
buf[0] = byte(block >> 24)
|
||||
buf[1] = byte(block >> 16)
|
||||
buf[2] = byte(block >> 8)
|
||||
buf[3] = byte(block)
|
||||
prf.Write(buf[:4])
|
||||
dk = prf.Sum(dk)
|
||||
T := dk[len(dk)-hashLen:]
|
||||
copy(U, T)
|
||||
|
||||
// U_n = PRF(password, U_(n-1))
|
||||
for n := 2; n <= iter; n++ {
|
||||
prf.Reset()
|
||||
prf.Write(U)
|
||||
U = U[:0]
|
||||
U = prf.Sum(U)
|
||||
for x := range U {
|
||||
T[x] ^= U[x]
|
||||
}
|
||||
}
|
||||
}
|
||||
return dk[:keyLen]
|
||||
}
|
||||
|
||||
func MarshalSm2PrivateKey(key *model.PrivateKey, pwd []byte) ([]byte, error) {
|
||||
if pwd == nil {
|
||||
return MarshalSm2UnEncryptedPrivateKey(key)
|
||||
}
|
||||
return MarshalSm2EncryptedPrivateKey(key, pwd)
|
||||
}
|
||||
|
||||
func MarshalSm2EncryptedPrivateKey(priKey *model.PrivateKey, pwd []byte) ([]byte, error) {
|
||||
der, err := MarshalSm2UnEncryptedPrivateKey(priKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
iter := 2048
|
||||
salt := make([]byte, 8)
|
||||
iv := make([]byte, 16)
|
||||
rand.Reader.Read(salt)
|
||||
rand.Reader.Read(iv)
|
||||
key := pbkdf(pwd, salt, iter, 32, sha1.New) // 默认是SHA1
|
||||
padding := aes.BlockSize - len(der)%aes.BlockSize
|
||||
if padding > 0 {
|
||||
n := len(der)
|
||||
der = append(der, make([]byte, padding)...)
|
||||
for i := 0; i < padding; i++ {
|
||||
der[n+i] = byte(padding)
|
||||
}
|
||||
}
|
||||
encryptedKey := make([]byte, len(der))
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mode := cipher.NewCBCEncrypter(block, iv)
|
||||
mode.CryptBlocks(encryptedKey, der)
|
||||
var algorithmIdentifier pkix.AlgorithmIdentifier
|
||||
algorithmIdentifier.Algorithm = oidKEYSHA1
|
||||
algorithmIdentifier.Parameters.Tag = 5
|
||||
algorithmIdentifier.Parameters.IsCompound = false
|
||||
algorithmIdentifier.Parameters.FullBytes = []byte{5, 0}
|
||||
keyDerivationFunc := Pbes2KDfs{
|
||||
oidPBKDF2,
|
||||
Pkdf2Params{
|
||||
salt,
|
||||
iter,
|
||||
algorithmIdentifier,
|
||||
},
|
||||
}
|
||||
encryptionScheme := Pbes2Encs{
|
||||
oidAES256CBC,
|
||||
iv,
|
||||
}
|
||||
pbes2Algorithms := Pbes2Algorithms{
|
||||
oidPBES2,
|
||||
Pbes2Params{
|
||||
keyDerivationFunc,
|
||||
encryptionScheme,
|
||||
},
|
||||
}
|
||||
encryptedPkey := EncryptedPrivateKeyInfo{
|
||||
pbes2Algorithms,
|
||||
encryptedKey,
|
||||
}
|
||||
return asn1.Marshal(encryptedPkey)
|
||||
}
|
||||
|
||||
func MarshalSm2UnEncryptedPrivateKey(key *model.PrivateKey) ([]byte, error) {
|
||||
var r pkcs8
|
||||
var pri Sm2PrivateKey
|
||||
var algo pkix.AlgorithmIdentifier
|
||||
|
||||
algo.Algorithm = oidSM2
|
||||
algo.Parameters.Class = 0
|
||||
algo.Parameters.Tag = 6
|
||||
algo.Parameters.IsCompound = false
|
||||
algo.Parameters.FullBytes = []byte{6, 8, 42, 129, 28, 207, 85, 1, 130, 45} // asn1.Marshal(asn1.ObjectIdentifier{1, 2, 156, 10197, 1, 301})
|
||||
pri.Version = 1
|
||||
pri.NamedCurveOID = oidNamedCurveP256SM2
|
||||
pri.PublicKey = asn1.BitString{Bytes: elliptic.Marshal(key.Curve, key.X, key.Y)}
|
||||
pri.PrivateKey = key.D.Bytes()
|
||||
r.Version = 0
|
||||
r.Algo = algo
|
||||
r.PrivateKey, _ = asn1.Marshal(pri)
|
||||
return asn1.Marshal(r)
|
||||
}
|
||||
|
||||
func MarshalSm2PublicKey(key *model.PublicKey) ([]byte, error) {
|
||||
var r PKIXPublicKey
|
||||
var algo pkix.AlgorithmIdentifier
|
||||
|
||||
if key.Curve.Params() != NewP256Sm2().Params() {
|
||||
return nil, fmt.Errorf("x509: unsupported elliptic curve")
|
||||
}
|
||||
algo.Algorithm = oidSM2
|
||||
algo.Parameters.Class = 0
|
||||
algo.Parameters.Tag = 6
|
||||
algo.Parameters.IsCompound = false
|
||||
algo.Parameters.FullBytes = []byte{6, 8, 42, 129, 28, 207, 85, 1, 130, 45} // asn1.Marshal(asn1.ObjectIdentifier{1, 2, 156, 10197, 1, 301})
|
||||
r.Algo = algo
|
||||
r.BitString = asn1.BitString{Bytes: elliptic.Marshal(key.Curve, key.X, key.Y)}
|
||||
return asn1.Marshal(r)
|
||||
}
|
||||
|
|
@ -0,0 +1,245 @@
|
|||
package util
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"hash"
|
||||
)
|
||||
|
||||
type SM3 struct {
|
||||
digest [8]uint32 // digest represents the partial evaluation of V
|
||||
length uint64 // length of the message
|
||||
unHandleMsg []byte // uint8 //
|
||||
}
|
||||
|
||||
func (sm3 *SM3) ff0(x, y, z uint32) uint32 { return x ^ y ^ z }
|
||||
|
||||
func (sm3 *SM3) ff1(x, y, z uint32) uint32 { return (x & y) | (x & z) | (y & z) }
|
||||
|
||||
func (sm3 *SM3) gg0(x, y, z uint32) uint32 { return x ^ y ^ z }
|
||||
|
||||
func (sm3 *SM3) gg1(x, y, z uint32) uint32 { return (x & y) | (^x & z) }
|
||||
|
||||
func (sm3 *SM3) p0(x uint32) uint32 { return x ^ sm3.leftRotate(x, 9) ^ sm3.leftRotate(x, 17) }
|
||||
|
||||
func (sm3 *SM3) p1(x uint32) uint32 { return x ^ sm3.leftRotate(x, 15) ^ sm3.leftRotate(x, 23) }
|
||||
|
||||
func (sm3 *SM3) leftRotate(x uint32, i uint32) uint32 { return x<<(i%32) | x>>(32-i%32) }
|
||||
|
||||
func (sm3 *SM3) pad() []byte {
|
||||
msg := sm3.unHandleMsg
|
||||
msg = append(msg, 0x80) // Append '1'
|
||||
blockSize := 64 // Append until the resulting message length (in bits) is congruent to 448 (mod 512)
|
||||
for len(msg)%blockSize != 56 {
|
||||
msg = append(msg, 0x00)
|
||||
}
|
||||
// append message length
|
||||
msg = append(msg, uint8(sm3.length>>56&0xff))
|
||||
msg = append(msg, uint8(sm3.length>>48&0xff))
|
||||
msg = append(msg, uint8(sm3.length>>40&0xff))
|
||||
msg = append(msg, uint8(sm3.length>>32&0xff))
|
||||
msg = append(msg, uint8(sm3.length>>24&0xff))
|
||||
msg = append(msg, uint8(sm3.length>>16&0xff))
|
||||
msg = append(msg, uint8(sm3.length>>8&0xff))
|
||||
msg = append(msg, uint8(sm3.length>>0&0xff))
|
||||
|
||||
if len(msg)%64 != 0 {
|
||||
panic("------SM3 Pad: error msgLen =")
|
||||
}
|
||||
return msg
|
||||
}
|
||||
|
||||
func (sm3 *SM3) update(msg []byte) {
|
||||
var w [68]uint32
|
||||
var w1 [64]uint32
|
||||
|
||||
a, b, c, d, e, f, g, h := sm3.digest[0], sm3.digest[1], sm3.digest[2], sm3.digest[3], sm3.digest[4], sm3.digest[5], sm3.digest[6], sm3.digest[7]
|
||||
for len(msg) >= 64 {
|
||||
for i := 0; i < 16; i++ {
|
||||
w[i] = binary.BigEndian.Uint32(msg[4*i : 4*(i+1)])
|
||||
}
|
||||
for i := 16; i < 68; i++ {
|
||||
w[i] = sm3.p1(w[i-16]^w[i-9]^sm3.leftRotate(w[i-3], 15)) ^ sm3.leftRotate(w[i-13], 7) ^ w[i-6]
|
||||
}
|
||||
for i := 0; i < 64; i++ {
|
||||
w1[i] = w[i] ^ w[i+4]
|
||||
}
|
||||
A, B, C, D, E, F, G, H := a, b, c, d, e, f, g, h
|
||||
for i := 0; i < 16; i++ {
|
||||
SS1 := sm3.leftRotate(sm3.leftRotate(A, 12)+E+sm3.leftRotate(0x79cc4519, uint32(i)), 7)
|
||||
SS2 := SS1 ^ sm3.leftRotate(A, 12)
|
||||
TT1 := sm3.ff0(A, B, C) + D + SS2 + w1[i]
|
||||
TT2 := sm3.gg0(E, F, G) + H + SS1 + w[i]
|
||||
D = C
|
||||
C = sm3.leftRotate(B, 9)
|
||||
B = A
|
||||
A = TT1
|
||||
H = G
|
||||
G = sm3.leftRotate(F, 19)
|
||||
F = E
|
||||
E = sm3.p0(TT2)
|
||||
}
|
||||
for i := 16; i < 64; i++ {
|
||||
SS1 := sm3.leftRotate(sm3.leftRotate(A, 12)+E+sm3.leftRotate(0x7a879d8a, uint32(i)), 7)
|
||||
SS2 := SS1 ^ sm3.leftRotate(A, 12)
|
||||
TT1 := sm3.ff1(A, B, C) + D + SS2 + w1[i]
|
||||
TT2 := sm3.gg1(E, F, G) + H + SS1 + w[i]
|
||||
D = C
|
||||
C = sm3.leftRotate(B, 9)
|
||||
B = A
|
||||
A = TT1
|
||||
H = G
|
||||
G = sm3.leftRotate(F, 19)
|
||||
F = E
|
||||
E = sm3.p0(TT2)
|
||||
}
|
||||
a ^= A
|
||||
b ^= B
|
||||
c ^= C
|
||||
d ^= D
|
||||
e ^= E
|
||||
f ^= F
|
||||
g ^= G
|
||||
h ^= H
|
||||
msg = msg[64:]
|
||||
}
|
||||
sm3.digest[0], sm3.digest[1], sm3.digest[2], sm3.digest[3], sm3.digest[4], sm3.digest[5], sm3.digest[6], sm3.digest[7] = a, b, c, d, e, f, g, h
|
||||
}
|
||||
func (sm3 *SM3) update2(msg []byte) [8]uint32 {
|
||||
var w [68]uint32
|
||||
var w1 [64]uint32
|
||||
|
||||
a, b, c, d, e, f, g, h := sm3.digest[0], sm3.digest[1], sm3.digest[2], sm3.digest[3], sm3.digest[4], sm3.digest[5], sm3.digest[6], sm3.digest[7]
|
||||
for len(msg) >= 64 {
|
||||
for i := 0; i < 16; i++ {
|
||||
w[i] = binary.BigEndian.Uint32(msg[4*i : 4*(i+1)])
|
||||
}
|
||||
for i := 16; i < 68; i++ {
|
||||
w[i] = sm3.p1(w[i-16]^w[i-9]^sm3.leftRotate(w[i-3], 15)) ^ sm3.leftRotate(w[i-13], 7) ^ w[i-6]
|
||||
}
|
||||
for i := 0; i < 64; i++ {
|
||||
w1[i] = w[i] ^ w[i+4]
|
||||
}
|
||||
A, B, C, D, E, F, G, H := a, b, c, d, e, f, g, h
|
||||
for i := 0; i < 16; i++ {
|
||||
SS1 := sm3.leftRotate(sm3.leftRotate(A, 12)+E+sm3.leftRotate(0x79cc4519, uint32(i)), 7)
|
||||
SS2 := SS1 ^ sm3.leftRotate(A, 12)
|
||||
TT1 := sm3.ff0(A, B, C) + D + SS2 + w1[i]
|
||||
TT2 := sm3.gg0(E, F, G) + H + SS1 + w[i]
|
||||
D = C
|
||||
C = sm3.leftRotate(B, 9)
|
||||
B = A
|
||||
A = TT1
|
||||
H = G
|
||||
G = sm3.leftRotate(F, 19)
|
||||
F = E
|
||||
E = sm3.p0(TT2)
|
||||
}
|
||||
for i := 16; i < 64; i++ {
|
||||
SS1 := sm3.leftRotate(sm3.leftRotate(A, 12)+E+sm3.leftRotate(0x7a879d8a, uint32(i)), 7)
|
||||
SS2 := SS1 ^ sm3.leftRotate(A, 12)
|
||||
TT1 := sm3.ff1(A, B, C) + D + SS2 + w1[i]
|
||||
TT2 := sm3.gg1(E, F, G) + H + SS1 + w[i]
|
||||
D = C
|
||||
C = sm3.leftRotate(B, 9)
|
||||
B = A
|
||||
A = TT1
|
||||
H = G
|
||||
G = sm3.leftRotate(F, 19)
|
||||
F = E
|
||||
E = sm3.p0(TT2)
|
||||
}
|
||||
a ^= A
|
||||
b ^= B
|
||||
c ^= C
|
||||
d ^= D
|
||||
e ^= E
|
||||
f ^= F
|
||||
g ^= G
|
||||
h ^= H
|
||||
msg = msg[64:]
|
||||
}
|
||||
var digest [8]uint32
|
||||
digest[0], digest[1], digest[2], digest[3], digest[4], digest[5], digest[6], digest[7] = a, b, c, d, e, f, g, h
|
||||
return digest
|
||||
}
|
||||
|
||||
// New 创建哈希计算实例
|
||||
func New() hash.Hash {
|
||||
var sm3 SM3
|
||||
|
||||
sm3.Reset()
|
||||
return &sm3
|
||||
}
|
||||
|
||||
// BlockSize returns the hash's underlying block size.
|
||||
// The Write method must be able to accept any amount
|
||||
// of data, but it may operate more efficiently if all writes
|
||||
// are a multiple of the block size.
|
||||
func (sm3 *SM3) BlockSize() int { return 64 }
|
||||
|
||||
// Size returns the number of bytes Sum will return.
|
||||
func (sm3 *SM3) Size() int { return 32 }
|
||||
|
||||
// Reset clears the internal state by zeroing bytes in the state buffer.
|
||||
// This can be skipped for a newly-created hash state; the default zero-allocated state is correct.
|
||||
func (sm3 *SM3) Reset() {
|
||||
// Reset digest
|
||||
sm3.digest[0] = 0x7380166f
|
||||
sm3.digest[1] = 0x4914b2b9
|
||||
sm3.digest[2] = 0x172442d7
|
||||
sm3.digest[3] = 0xda8a0600
|
||||
sm3.digest[4] = 0xa96f30bc
|
||||
sm3.digest[5] = 0x163138aa
|
||||
sm3.digest[6] = 0xe38dee4d
|
||||
sm3.digest[7] = 0xb0fb0e4e
|
||||
|
||||
sm3.length = 0 // Reset numberic states
|
||||
sm3.unHandleMsg = []byte{}
|
||||
}
|
||||
|
||||
// Write (via the embedded io.Writer interface) adds more data to the running hash.
|
||||
// It never returns an error.
|
||||
func (sm3 *SM3) Write(p []byte) (int, error) {
|
||||
toWrite := len(p)
|
||||
sm3.length += uint64(len(p) * 8)
|
||||
msg := append(sm3.unHandleMsg, p...)
|
||||
nblocks := len(msg) / sm3.BlockSize()
|
||||
sm3.update(msg)
|
||||
// Update unHandleMsg
|
||||
sm3.unHandleMsg = msg[nblocks*sm3.BlockSize():]
|
||||
|
||||
return toWrite, nil
|
||||
}
|
||||
|
||||
// Sum 返回SM3哈希算法摘要值
|
||||
// Sum appends the current hash to b and returns the resulting slice.
|
||||
// It does not change the underlying hash state.
|
||||
func (sm3 *SM3) Sum(in []byte) []byte {
|
||||
_, _ = sm3.Write(in)
|
||||
msg := sm3.pad()
|
||||
//Finalize
|
||||
digest := sm3.update2(msg)
|
||||
|
||||
// save hash to in
|
||||
needed := sm3.Size()
|
||||
if cap(in)-len(in) < needed {
|
||||
newIn := make([]byte, len(in), len(in)+needed)
|
||||
copy(newIn, in)
|
||||
in = newIn
|
||||
}
|
||||
out := in[len(in) : len(in)+needed]
|
||||
for i := 0; i < 8; i++ {
|
||||
binary.BigEndian.PutUint32(out[i*4:], digest[i])
|
||||
}
|
||||
return out
|
||||
|
||||
}
|
||||
|
||||
// Sm3Sum 返回SM3哈希算法摘要值
|
||||
func Sm3Sum(data []byte) []byte {
|
||||
var sm3 SM3
|
||||
|
||||
sm3.Reset()
|
||||
_, _ = sm3.Write(data)
|
||||
return sm3.Sum(nil)
|
||||
}
|
||||
|
|
@ -0,0 +1,138 @@
|
|||
package util
|
||||
|
||||
import (
|
||||
"PaymentCenter/app/third/paymentService/psbc/internal/gmutil/sm2/model"
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"math/big"
|
||||
)
|
||||
|
||||
func JoinBytes(params ...[]byte) ([]byte, error) {
|
||||
var buffer bytes.Buffer
|
||||
for i := 0; i < len(params); i++ {
|
||||
_, err := buffer.Write(params[i])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return buffer.Bytes(), nil
|
||||
}
|
||||
|
||||
func HexToPrivateKey(d []byte) (*model.PrivateKey, error) {
|
||||
k := new(big.Int).SetBytes(d)
|
||||
c := NewP256Sm2()
|
||||
params := c.Params()
|
||||
n := new(big.Int).Sub(params.N, model.One)
|
||||
if k.Cmp(n) >= 0 {
|
||||
return nil, fmt.Errorf("privateKey is overflow")
|
||||
}
|
||||
pri := &model.PrivateKey{
|
||||
PublicKey: &model.PublicKey{},
|
||||
D: nil,
|
||||
}
|
||||
pri.PublicKey.Curve = c
|
||||
pri.D = k
|
||||
pri.PublicKey.X, pri.PublicKey.Y = c.ScalarBaseMult(k.Bytes())
|
||||
return pri, nil
|
||||
}
|
||||
|
||||
func HexToPublicKey(d []byte) (*model.PublicKey, error) {
|
||||
if len(d) == 65 && d[0] == byte(0x04) {
|
||||
d = d[1:]
|
||||
}
|
||||
if len(d) != 64 {
|
||||
return nil, fmt.Errorf("publicKey is not 64 bytes: %d", len(d))
|
||||
}
|
||||
pub := new(model.PublicKey)
|
||||
pub.Curve = NewP256Sm2()
|
||||
pub.X = new(big.Int).SetBytes(d[:32])
|
||||
pub.Y = new(big.Int).SetBytes(d[32:])
|
||||
return pub, nil
|
||||
}
|
||||
|
||||
func PrivateKeyToPem(key *model.PrivateKey, pwd []byte) ([]byte, error) {
|
||||
var block *pem.Block
|
||||
der, err := MarshalSm2PrivateKey(key, pwd) //Convert private key to DER format
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if pwd != nil {
|
||||
block = &pem.Block{
|
||||
Type: "ENCRYPTED PRIVATE KEY",
|
||||
Bytes: der,
|
||||
}
|
||||
} else {
|
||||
block = &pem.Block{
|
||||
Type: "PRIVATE KEY",
|
||||
Bytes: der,
|
||||
}
|
||||
}
|
||||
certPem := pem.EncodeToMemory(block)
|
||||
return certPem, nil
|
||||
}
|
||||
|
||||
func PublicKeyToPem(key *model.PublicKey) ([]byte, error) {
|
||||
der, err := MarshalSm2PublicKey(key) //Convert publick key to DER format
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
block := &pem.Block{
|
||||
Type: "PUBLIC KEY",
|
||||
Bytes: der,
|
||||
}
|
||||
certPem := pem.EncodeToMemory(block)
|
||||
return certPem, nil
|
||||
}
|
||||
|
||||
func PrivateKeyToHex(key *model.PrivateKey) string {
|
||||
return key.D.Text(16)
|
||||
}
|
||||
|
||||
func PublicKeyToHex(key *model.PublicKey) string {
|
||||
x := key.X.Bytes()
|
||||
y := key.Y.Bytes()
|
||||
if n := len(x); n < 32 {
|
||||
x = append(zeroByteSlice()[:32-n], x...)
|
||||
}
|
||||
if n := len(y); n < 32 {
|
||||
y = append(zeroByteSlice()[:32-n], y...)
|
||||
}
|
||||
var c []byte
|
||||
c = append(c, x...)
|
||||
c = append(c, y...)
|
||||
c = append([]byte{0x04}, c...)
|
||||
return hex.EncodeToString(c)
|
||||
}
|
||||
|
||||
// 32byte
|
||||
func zeroByteSlice() []byte {
|
||||
return []byte{
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
}
|
||||
}
|
||||
|
||||
func HexToSignature(hexStr string) (s model.Signature, err error) {
|
||||
signData, err := hex.DecodeString(hexStr)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
rBy := make([]byte, 33)
|
||||
copy(rBy[1:], signData[:32])
|
||||
rBy[0] = 0x00
|
||||
s.R = new(big.Int).SetBytes(rBy)
|
||||
|
||||
sBy := make([]byte, 33)
|
||||
copy(sBy[1:], signData[32:64])
|
||||
sBy[0] = 0x00
|
||||
s.S = new(big.Int).SetBytes(sBy)
|
||||
return
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
package util
|
||||
|
||||
import (
|
||||
"PaymentCenter/app/third/paymentService/psbc/internal/gmutil/sm2/model"
|
||||
"crypto/elliptic"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/asn1"
|
||||
"fmt"
|
||||
|
||||
"reflect"
|
||||
)
|
||||
|
||||
var (
|
||||
oidNamedCurveP256SM2 = asn1.ObjectIdentifier{1, 2, 156, 10197, 1, 301} // I get the SM2 ID through parsing the pem file generated by gmssl
|
||||
)
|
||||
|
||||
// PKIXPublicKey reflects a PKIX public key structure. See SubjectPublicKeyInfo
|
||||
// in RFC 3280.
|
||||
type PKIXPublicKey struct {
|
||||
Algo pkix.AlgorithmIdentifier
|
||||
BitString asn1.BitString
|
||||
}
|
||||
|
||||
func ParsePublicKey(bytes []byte) (*model.PublicKey, error) {
|
||||
var pk PKIXPublicKey
|
||||
if _, err := asn1.Unmarshal(bytes, &pk); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !reflect.DeepEqual(pk.Algo.Algorithm, oidSM2) {
|
||||
return nil, fmt.Errorf("not sm2 elliptic curve")
|
||||
}
|
||||
curve := NewP256Sm2()
|
||||
x, y := elliptic.Unmarshal(curve, pk.BitString.Bytes)
|
||||
return &model.PublicKey{
|
||||
Curve: curve,
|
||||
X: x,
|
||||
Y: y,
|
||||
}, nil
|
||||
}
|
||||
|
|
@ -0,0 +1,378 @@
|
|||
package sm4
|
||||
|
||||
import (
|
||||
"crypto/cipher"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"math/bits"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
const (
|
||||
BlockSize = 16
|
||||
KeySize = 16
|
||||
)
|
||||
|
||||
var sBox = [256]byte{
|
||||
0xd6, 0x90, 0xe9, 0xfe, 0xcc, 0xe1, 0x3d, 0xb7,
|
||||
0x16, 0xb6, 0x14, 0xc2, 0x28, 0xfb, 0x2c, 0x05,
|
||||
0x2b, 0x67, 0x9a, 0x76, 0x2a, 0xbe, 0x04, 0xc3,
|
||||
0xaa, 0x44, 0x13, 0x26, 0x49, 0x86, 0x06, 0x99,
|
||||
0x9c, 0x42, 0x50, 0xf4, 0x91, 0xef, 0x98, 0x7a,
|
||||
0x33, 0x54, 0x0b, 0x43, 0xed, 0xcf, 0xac, 0x62,
|
||||
0xe4, 0xb3, 0x1c, 0xa9, 0xc9, 0x08, 0xe8, 0x95,
|
||||
0x80, 0xdf, 0x94, 0xfa, 0x75, 0x8f, 0x3f, 0xa6,
|
||||
0x47, 0x07, 0xa7, 0xfc, 0xf3, 0x73, 0x17, 0xba,
|
||||
0x83, 0x59, 0x3c, 0x19, 0xe6, 0x85, 0x4f, 0xa8,
|
||||
0x68, 0x6b, 0x81, 0xb2, 0x71, 0x64, 0xda, 0x8b,
|
||||
0xf8, 0xeb, 0x0f, 0x4b, 0x70, 0x56, 0x9d, 0x35,
|
||||
0x1e, 0x24, 0x0e, 0x5e, 0x63, 0x58, 0xd1, 0xa2,
|
||||
0x25, 0x22, 0x7c, 0x3b, 0x01, 0x21, 0x78, 0x87,
|
||||
0xd4, 0x00, 0x46, 0x57, 0x9f, 0xd3, 0x27, 0x52,
|
||||
0x4c, 0x36, 0x02, 0xe7, 0xa0, 0xc4, 0xc8, 0x9e,
|
||||
0xea, 0xbf, 0x8a, 0xd2, 0x40, 0xc7, 0x38, 0xb5,
|
||||
0xa3, 0xf7, 0xf2, 0xce, 0xf9, 0x61, 0x15, 0xa1,
|
||||
0xe0, 0xae, 0x5d, 0xa4, 0x9b, 0x34, 0x1a, 0x55,
|
||||
0xad, 0x93, 0x32, 0x30, 0xf5, 0x8c, 0xb1, 0xe3,
|
||||
0x1d, 0xf6, 0xe2, 0x2e, 0x82, 0x66, 0xca, 0x60,
|
||||
0xc0, 0x29, 0x23, 0xab, 0x0d, 0x53, 0x4e, 0x6f,
|
||||
0xd5, 0xdb, 0x37, 0x45, 0xde, 0xfd, 0x8e, 0x2f,
|
||||
0x03, 0xff, 0x6a, 0x72, 0x6d, 0x6c, 0x5b, 0x51,
|
||||
0x8d, 0x1b, 0xaf, 0x92, 0xbb, 0xdd, 0xbc, 0x7f,
|
||||
0x11, 0xd9, 0x5c, 0x41, 0x1f, 0x10, 0x5a, 0xd8,
|
||||
0x0a, 0xc1, 0x31, 0x88, 0xa5, 0xcd, 0x7b, 0xbd,
|
||||
0x2d, 0x74, 0xd0, 0x12, 0xb8, 0xe5, 0xb4, 0xb0,
|
||||
0x89, 0x69, 0x97, 0x4a, 0x0c, 0x96, 0x77, 0x7e,
|
||||
0x65, 0xb9, 0xf1, 0x09, 0xc5, 0x6e, 0xc6, 0x84,
|
||||
0x18, 0xf0, 0x7d, 0xec, 0x3a, 0xdc, 0x4d, 0x20,
|
||||
0x79, 0xee, 0x5f, 0x3e, 0xd7, 0xcb, 0x39, 0x48,
|
||||
}
|
||||
|
||||
var cK = [32]uint32{
|
||||
0x00070e15, 0x1c232a31, 0x383f464d, 0x545b6269,
|
||||
0x70777e85, 0x8c939aa1, 0xa8afb6bd, 0xc4cbd2d9,
|
||||
0xe0e7eef5, 0xfc030a11, 0x181f262d, 0x343b4249,
|
||||
0x50575e65, 0x6c737a81, 0x888f969d, 0xa4abb2b9,
|
||||
0xc0c7ced5, 0xdce3eaf1, 0xf8ff060d, 0x141b2229,
|
||||
0x30373e45, 0x4c535a61, 0x686f767d, 0x848b9299,
|
||||
0xa0a7aeb5, 0xbcc3cad1, 0xd8dfe6ed, 0xf4fb0209,
|
||||
0x10171e25, 0x2c333a41, 0x484f565d, 0x646b7279,
|
||||
}
|
||||
|
||||
var fK = [4]uint32{
|
||||
0xa3b1bac6, 0x56aa3350, 0x677d9197, 0xb27022dc,
|
||||
}
|
||||
|
||||
type KeySizeError int
|
||||
|
||||
func (k KeySizeError) Error() string {
|
||||
return "sm4: invalid key size " + strconv.Itoa(int(k))
|
||||
}
|
||||
|
||||
type sm4Cipher struct {
|
||||
enc []uint32
|
||||
dec []uint32
|
||||
}
|
||||
|
||||
func NewCipher(key []byte) (cipher.Block, error) {
|
||||
n := len(key)
|
||||
if n != KeySize {
|
||||
return nil, KeySizeError(n)
|
||||
}
|
||||
c := new(sm4Cipher)
|
||||
c.enc = expandKey(key, true)
|
||||
c.dec = expandKey(key, false)
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func (c *sm4Cipher) BlockSize() int {
|
||||
return BlockSize
|
||||
}
|
||||
|
||||
func (c *sm4Cipher) Encrypt(dst, src []byte) {
|
||||
if len(src) < BlockSize {
|
||||
panic("sm4: input not full block")
|
||||
}
|
||||
if len(dst) < BlockSize {
|
||||
panic("sm4: output not full block")
|
||||
}
|
||||
processBlock(c.enc, src, dst)
|
||||
}
|
||||
|
||||
func (c *sm4Cipher) Decrypt(dst, src []byte) {
|
||||
if len(src) < BlockSize {
|
||||
panic("sm4: input not full block")
|
||||
}
|
||||
if len(dst) < BlockSize {
|
||||
panic("sm4: output not full block")
|
||||
}
|
||||
processBlock(c.dec, src, dst)
|
||||
}
|
||||
|
||||
func expandKey(key []byte, forEnc bool) []uint32 {
|
||||
var mK [4]uint32
|
||||
mK[0] = binary.BigEndian.Uint32(key[0:4])
|
||||
mK[1] = binary.BigEndian.Uint32(key[4:8])
|
||||
mK[2] = binary.BigEndian.Uint32(key[8:12])
|
||||
mK[3] = binary.BigEndian.Uint32(key[12:16])
|
||||
|
||||
var x [5]uint32
|
||||
x[0] = mK[0] ^ fK[0]
|
||||
x[1] = mK[1] ^ fK[1]
|
||||
x[2] = mK[2] ^ fK[2]
|
||||
x[3] = mK[3] ^ fK[3]
|
||||
|
||||
var rk [32]uint32
|
||||
if forEnc {
|
||||
for i := 0; i < 32; i++ {
|
||||
x[(i+4)%5] = encRound(x[i%5], x[(i+1)%5], x[(i+2)%5], x[(i+3)%5], x[(i+4)%5], rk[:], i)
|
||||
}
|
||||
} else {
|
||||
for i := 0; i < 32; i++ {
|
||||
x[(i+4)%5] = decRound(x[i%5], x[(i+1)%5], x[(i+2)%5], x[(i+3)%5], x[(i+4)%5], rk[:], i)
|
||||
}
|
||||
}
|
||||
return rk[:]
|
||||
}
|
||||
|
||||
func tau(a uint32) uint32 {
|
||||
var aArr [4]byte
|
||||
var bArr [4]byte
|
||||
binary.BigEndian.PutUint32(aArr[:], a)
|
||||
bArr[0] = sBox[aArr[0]]
|
||||
bArr[1] = sBox[aArr[1]]
|
||||
bArr[2] = sBox[aArr[2]]
|
||||
bArr[3] = sBox[aArr[3]]
|
||||
return binary.BigEndian.Uint32(bArr[:])
|
||||
}
|
||||
|
||||
func lAp(b uint32) uint32 {
|
||||
return b ^ bits.RotateLeft32(b, 13) ^ bits.RotateLeft32(b, 23)
|
||||
}
|
||||
|
||||
func tAp(z uint32) uint32 {
|
||||
return lAp(tau(z))
|
||||
}
|
||||
|
||||
func encRound(x0 uint32, x1 uint32, x2 uint32, x3 uint32, x4 uint32, rk []uint32, i int) uint32 {
|
||||
x4 = x0 ^ tAp(x1^x2^x3^cK[i])
|
||||
rk[i] = x4
|
||||
return x4
|
||||
}
|
||||
|
||||
func decRound(x0 uint32, x1 uint32, x2 uint32, x3 uint32, x4 uint32, rk []uint32, i int) uint32 {
|
||||
x4 = x0 ^ tAp(x1^x2^x3^cK[i])
|
||||
rk[31-i] = x4
|
||||
return x4
|
||||
}
|
||||
|
||||
func processBlock(rk []uint32, in []byte, out []byte) {
|
||||
var x [BlockSize / 4]uint32
|
||||
x[0] = binary.BigEndian.Uint32(in[0:4])
|
||||
x[1] = binary.BigEndian.Uint32(in[4:8])
|
||||
x[2] = binary.BigEndian.Uint32(in[8:12])
|
||||
x[3] = binary.BigEndian.Uint32(in[12:16])
|
||||
|
||||
for i := 0; i < 32; i += 4 {
|
||||
x[0] = f0(x[:], rk[i])
|
||||
x[1] = f1(x[:], rk[i+1])
|
||||
x[2] = f2(x[:], rk[i+2])
|
||||
x[3] = f3(x[:], rk[i+3])
|
||||
}
|
||||
r(x[:])
|
||||
|
||||
binary.BigEndian.PutUint32(out[0:4], x[0])
|
||||
binary.BigEndian.PutUint32(out[4:8], x[1])
|
||||
binary.BigEndian.PutUint32(out[8:12], x[2])
|
||||
binary.BigEndian.PutUint32(out[12:16], x[3])
|
||||
}
|
||||
|
||||
func l(b uint32) uint32 {
|
||||
return b ^ bits.RotateLeft32(b, 2) ^ bits.RotateLeft32(b, 10) ^
|
||||
bits.RotateLeft32(b, 18) ^ bits.RotateLeft32(b, 24)
|
||||
}
|
||||
|
||||
func t(z uint32) uint32 {
|
||||
return l(tau(z))
|
||||
}
|
||||
|
||||
func r(a []uint32) {
|
||||
a[0] = a[0] ^ a[3]
|
||||
a[3] = a[0] ^ a[3]
|
||||
a[0] = a[0] ^ a[3]
|
||||
a[1] = a[1] ^ a[2]
|
||||
a[2] = a[1] ^ a[2]
|
||||
a[1] = a[1] ^ a[2]
|
||||
}
|
||||
|
||||
func f0(x []uint32, rk uint32) uint32 {
|
||||
return x[0] ^ t(x[1]^x[2]^x[3]^rk)
|
||||
}
|
||||
|
||||
func f1(x []uint32, rk uint32) uint32 {
|
||||
return x[1] ^ t(x[2]^x[3]^x[0]^rk)
|
||||
}
|
||||
|
||||
func f2(x []uint32, rk uint32) uint32 {
|
||||
return x[2] ^ t(x[3]^x[0]^x[1]^rk)
|
||||
}
|
||||
|
||||
func f3(x []uint32, rk uint32) uint32 {
|
||||
return x[3] ^ t(x[0]^x[1]^x[2]^rk)
|
||||
}
|
||||
|
||||
func xor(in, iv []byte) (out []byte) {
|
||||
if len(in) != len(iv) {
|
||||
return nil
|
||||
}
|
||||
|
||||
out = make([]byte, len(in))
|
||||
for i := 0; i < len(in); i++ {
|
||||
out[i] = in[i] ^ iv[i]
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// ECBEncrypt 输入的plainText长度必须是BlockSize(16)的整数倍,也就是调用该方法前调用方需先加好padding
|
||||
func ECBEncrypt(key, plainText []byte) (cipherText []byte, err error) {
|
||||
plainTextLen := len(plainText)
|
||||
if plainTextLen%BlockSize != 0 {
|
||||
return nil, errors.New("input not full blocks")
|
||||
}
|
||||
|
||||
c, err := NewCipher(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cipherText = make([]byte, plainTextLen)
|
||||
for i := 0; i < plainTextLen; i += BlockSize {
|
||||
c.Encrypt(cipherText[i:i+BlockSize], plainText[i:i+BlockSize])
|
||||
}
|
||||
return cipherText, nil
|
||||
}
|
||||
|
||||
// ECBDecrypt 输出的plainText是加padding的明文,调用方需要自己去padding
|
||||
func ECBDecrypt(key, cipherText []byte) (plainText []byte, err error) {
|
||||
cipherTextLen := len(cipherText)
|
||||
if cipherTextLen%BlockSize != 0 {
|
||||
return nil, errors.New("input not full blocks")
|
||||
}
|
||||
|
||||
c, err := NewCipher(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
plainText = make([]byte, cipherTextLen)
|
||||
for i := 0; i < cipherTextLen; i += BlockSize {
|
||||
c.Decrypt(plainText[i:i+BlockSize], cipherText[i:i+BlockSize])
|
||||
}
|
||||
return plainText, nil
|
||||
}
|
||||
|
||||
// CBCEncrypt 输入的plainText长度必须是BlockSize(16)的整数倍,也就是调用该方法前调用方需先加好padding
|
||||
func CBCEncrypt(key, iv, plainText []byte) (cipherText []byte, err error) {
|
||||
plainTextLen := len(plainText)
|
||||
if plainTextLen%BlockSize != 0 {
|
||||
return nil, errors.New("input not full blocks")
|
||||
}
|
||||
|
||||
c, err := NewCipher(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
encrypter := cipher.NewCBCEncrypter(c, iv)
|
||||
cipherText = make([]byte, plainTextLen)
|
||||
encrypter.CryptBlocks(cipherText, plainText)
|
||||
return cipherText, nil
|
||||
}
|
||||
|
||||
// CBCDecrypt 输出的plainText是加padding的明文,调用方需要自己去padding
|
||||
func CBCDecrypt(key, iv, cipherText []byte) (plainText []byte, err error) {
|
||||
cipherTextLen := len(cipherText)
|
||||
if cipherTextLen%BlockSize != 0 {
|
||||
return nil, errors.New("input not full blocks")
|
||||
}
|
||||
|
||||
c, err := NewCipher(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
decrypter := cipher.NewCBCDecrypter(c, iv)
|
||||
plainText = make([]byte, len(cipherText))
|
||||
decrypter.CryptBlocks(plainText, cipherText)
|
||||
return plainText, nil
|
||||
}
|
||||
|
||||
// CFBEncrypt 输入的plainText长度必须是BlockSize(16)的整数倍,也就是调用该方法前调用方需先加好padding
|
||||
func CFBEncrypt(key, iv, plainText []byte) (cipherText []byte, err error) {
|
||||
plainTextLen := len(plainText)
|
||||
if plainTextLen%BlockSize != 0 {
|
||||
return nil, errors.New("input not full blocks")
|
||||
}
|
||||
|
||||
c, err := NewCipher(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cipherText = make([]byte, plainTextLen)
|
||||
copy(cipherText, plainText)
|
||||
cipher.NewCFBEncrypter(c, iv).XORKeyStream(cipherText, cipherText)
|
||||
return plainText, nil
|
||||
}
|
||||
|
||||
// CFBDecrypt 输出的plainText是加padding的明文,调用方需要自己去padding
|
||||
// https://blog.csdn.net/zy_strive_2012/article/details/102520356
|
||||
// https://blog.csdn.net/sinat_23338865/article/details/72869841
|
||||
func CFBDecrypt(key, iv, cipherText []byte) (plainText []byte, err error) {
|
||||
cipherTextLen := len(cipherText)
|
||||
if cipherTextLen%BlockSize != 0 {
|
||||
return nil, errors.New("input not full blocks")
|
||||
}
|
||||
|
||||
c, err := NewCipher(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
plainText = make([]byte, cipherTextLen)
|
||||
copy(plainText, cipherText)
|
||||
cipher.NewCFBDecrypter(c, iv).XORKeyStream(plainText, plainText)
|
||||
return plainText, nil
|
||||
}
|
||||
|
||||
// OFBEncrypt 输入反馈模式(Input feedback, OFB)
|
||||
func OFBEncrypt(key, iv, plainText []byte) (cipherText []byte, err error) {
|
||||
plainTextLen := len(plainText)
|
||||
if plainTextLen%BlockSize != 0 {
|
||||
return nil, errors.New("input not full blocks")
|
||||
}
|
||||
|
||||
c, err := NewCipher(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cipherText = make([]byte, plainTextLen)
|
||||
copy(cipherText, plainText)
|
||||
cipher.NewOFB(c, iv).XORKeyStream(cipherText, cipherText)
|
||||
return plainText, nil
|
||||
}
|
||||
|
||||
// OFBDecrypt 输出反馈模式(Output feedback, OFB)
|
||||
func OFBDecrypt(key, iv, cipherText []byte) (plainText []byte, err error) {
|
||||
cipherTextLen := len(cipherText)
|
||||
if cipherTextLen%BlockSize != 0 {
|
||||
return nil, errors.New("input not full blocks")
|
||||
}
|
||||
|
||||
c, err := NewCipher(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
plainText = make([]byte, cipherTextLen)
|
||||
copy(plainText, cipherText)
|
||||
cipher.NewOFB(c, iv).XORKeyStream(plainText, plainText)
|
||||
return plainText, nil
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
package sm4
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestECBEecrypt(t *testing.T) {
|
||||
decode := "hello"
|
||||
//if err != nil {
|
||||
// t.Fatalf("decode error: %v", err)
|
||||
//}
|
||||
key := []byte{87, 29, 256 - 6, 256 - 55, 256 - 87, 46, 256 - 74, 256 - 54, 32, 29, 15, 86, 18, 256 - 56, 256 - 55, 72}
|
||||
//iv := []byte{34, 244, 188, 11, 120, 236, 119, 58, 191, 210, 3, 95, 85, 72, 172, 249}
|
||||
plainText, err := ECBEncrypt(key, PKCS5Padding([]byte(decode), 16))
|
||||
fmt.Println(string(PKCS5UnPadding(plainText)))
|
||||
if err != nil {
|
||||
t.Fatalf("ecb decrypt error: %v", err)
|
||||
}
|
||||
t.Log("ecb decrypt result:", string(PKCS5UnPadding(plainText)))
|
||||
}
|
||||
|
||||
func TestECBDecrypt(t *testing.T) {
|
||||
decode, err := base64.StdEncoding.DecodeString("dLXNaTFed24oFyQHcEiQLNOiF0PaoMjxo9iB0mL5bsQ9aeCM3+s3YqK9EnsbjHfep73gW/FphzMIQ51yOXzbxDhDZzAZWI/EgC8HT90Jr2OQVChC30nj+4TOAvlwld9M/2jn6lg4n/SDJUNUhUNPMw==")
|
||||
if err != nil {
|
||||
t.Fatalf("decode error: %v", err)
|
||||
}
|
||||
key := []byte{118, 58, 56, 11, 256 - 76, 81, 256 - 113, 256 - 29, 256 - 112, 256 - 63, 86, 16, 256 - 58, 256 - 54, 256 - 19, 58}
|
||||
//iv := []byte{34, 244, 188, 11, 120, 236, 119, 58, 191, 210, 3, 95, 85, 72, 172, 249}
|
||||
plainText, err := ECBDecrypt(key, decode)
|
||||
fmt.Println(string(PKCS5UnPadding(plainText)))
|
||||
if err != nil {
|
||||
t.Fatalf("ecb decrypt error: %v", err)
|
||||
}
|
||||
t.Log("ecb decrypt result:", string(PKCS5UnPadding(plainText)))
|
||||
}
|
||||
|
||||
func TestCFBEncrypt(t *testing.T) {
|
||||
key := []byte{16, 101, 63, 34, 97, 41, 62, 49, 225, 208, 57, 189, 50, 158, 31, 100}
|
||||
iv := []byte{34, 244, 188, 11, 120, 236, 119, 58, 191, 210, 3, 95, 85, 72, 172, 249}
|
||||
decode, err := base64.StdEncoding.DecodeString("XO9I6k9h2zk/dHSK+zo3Dg==")
|
||||
if err != nil {
|
||||
t.Fatalf("decode error: %v", err)
|
||||
}
|
||||
bytes, err := OFBDecrypt(key, iv, decode)
|
||||
if err != nil {
|
||||
t.Fatalf("ecb decrypt error: %v", err)
|
||||
}
|
||||
t.Log("ecb decrypt result:", string(PKCS5UnPadding(bytes)))
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
package sm4
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func PKCS5Padding(src []byte, blockSize int) []byte {
|
||||
padding := blockSize - len(src)%blockSize
|
||||
padBytes := bytes.Repeat([]byte{byte(padding)}, padding)
|
||||
return append(src, padBytes...)
|
||||
}
|
||||
|
||||
func PKCS5UnPadding(src []byte) []byte {
|
||||
length := len(src)
|
||||
unPadding := int(src[length-1])
|
||||
return src[:(length - unPadding)]
|
||||
}
|
||||
|
||||
func PKCS7Padding(src []byte) []byte {
|
||||
padding := BlockSize - len(src)%BlockSize
|
||||
padBytes := bytes.Repeat([]byte{byte(padding)}, padding)
|
||||
return append(src, padBytes...)
|
||||
}
|
||||
|
||||
func PKCS7UnPadding(src []byte) ([]byte, error) {
|
||||
length := len(src)
|
||||
unPadding := int(src[length-1])
|
||||
if unPadding > BlockSize || unPadding == 0 {
|
||||
return nil, fmt.Errorf("invalid pkcs7 padding (unPadding > BlockSize || unPadding == 0)")
|
||||
}
|
||||
pad := src[len(src)-unPadding:]
|
||||
for i := 0; i < unPadding; i++ {
|
||||
if pad[i] != byte(unPadding) {
|
||||
return nil, fmt.Errorf("invalid pkcs7 padding (pad[i] != unPadding)")
|
||||
}
|
||||
}
|
||||
return src[:(length - unPadding)], nil
|
||||
}
|
||||
|
|
@ -0,0 +1,139 @@
|
|||
package sm2
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"github.com/tjfoc/gmsm/sm2"
|
||||
"math/big"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// 生成公钥、私钥
|
||||
func GenerateSM2Key() (PublicKey string, PrivateKey string, err error) {
|
||||
// 生成私钥、公钥
|
||||
privKey, err := sm2.GenerateKey(rand.Reader)
|
||||
if err != nil {
|
||||
fmt.Println("生成密钥对失败:", err)
|
||||
return "", "", err
|
||||
}
|
||||
return PublicKeyToString(&privKey.PublicKey), PrivateKeyToString(privKey), nil
|
||||
}
|
||||
|
||||
// PublicKeyToString 公钥sm2.PublicKey转字符串(与java中org.bouncycastle.crypto生成的公私钥完全互通使用)
|
||||
func PublicKeyToString(publicKey *sm2.PublicKey) string {
|
||||
xBytes := publicKey.X.Bytes()
|
||||
yBytes := publicKey.Y.Bytes()
|
||||
|
||||
// 确保坐标字节切片长度相同
|
||||
byteLen := len(xBytes)
|
||||
if len(yBytes) > byteLen {
|
||||
byteLen = len(yBytes)
|
||||
}
|
||||
|
||||
// 为坐标补齐前导零
|
||||
xBytes = append(make([]byte, byteLen-len(xBytes)), xBytes...)
|
||||
yBytes = append(make([]byte, byteLen-len(yBytes)), yBytes...)
|
||||
|
||||
// 添加 "04" 前缀
|
||||
publicKeyBytes := append([]byte{0x04}, append(xBytes, yBytes...)...)
|
||||
|
||||
return strings.ToUpper(hex.EncodeToString(publicKeyBytes))
|
||||
}
|
||||
|
||||
// PrivateKeyToString 私钥sm2.PrivateKey 转字符串(与java中org.bouncycastle.crypto生成的公私钥完全互通使用)
|
||||
func PrivateKeyToString(privateKey *sm2.PrivateKey) string {
|
||||
return strings.ToUpper(hex.EncodeToString(privateKey.D.Bytes()))
|
||||
}
|
||||
|
||||
func encryptLoc(publicKeyStr, data string) (string, error) {
|
||||
publicKeyObj, err := StringToPublicKey(publicKeyStr)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
decrypt, err := sm2.Encrypt(publicKeyObj, []byte(data), rand.Reader, sm2.C1C2C3)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
resultStr := hex.EncodeToString(decrypt)
|
||||
return resultStr, nil
|
||||
}
|
||||
|
||||
func decryptLoc(publicKeyStr, privateKeyStr, cipherText string) (string, error) {
|
||||
publicKeyObj, err := StringToPublicKey(publicKeyStr)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
privateKeyObj, err := StringToPrivateKey(privateKeyStr, publicKeyObj)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
decodeString, err := hex.DecodeString(cipherText)
|
||||
decrypt, err := sm2.Decrypt(privateKeyObj, decodeString, sm2.C1C2C3)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
resultStr := string(decrypt)
|
||||
fmt.Println("解密后的字符串:", resultStr)
|
||||
return resultStr, nil
|
||||
}
|
||||
|
||||
// StringToPrivateKey 私钥还原为 sm2.PrivateKey对象(与java中org.bouncycastle.crypto生成的公私钥完全互通使用)
|
||||
func StringToPrivateKey(privateKeyStr string, publicKey *sm2.PublicKey) (*sm2.PrivateKey, error) {
|
||||
privateKeyBytes, err := hex.DecodeString(privateKeyStr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 将字节切片转换为大整数
|
||||
d := new(big.Int).SetBytes(privateKeyBytes)
|
||||
|
||||
// 创建 sm2.PrivateKey 对象
|
||||
privateKey := &sm2.PrivateKey{
|
||||
PublicKey: *publicKey,
|
||||
D: d,
|
||||
}
|
||||
|
||||
return privateKey, nil
|
||||
}
|
||||
|
||||
// StringToPublicKey 公钥字符串还原为 sm2.PublicKey 对象(与java中org.bouncycastle.crypto生成的公私钥完全互通使用)
|
||||
func StringToPublicKey(publicKeyStr string) (*sm2.PublicKey, error) {
|
||||
publicKeyBytes, err := hex.DecodeString(publicKeyStr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 提取 x 和 y 坐标字节切片
|
||||
curve := sm2.P256Sm2().Params()
|
||||
byteLen := (curve.BitSize + 7) / 8
|
||||
xBytes := publicKeyBytes[1 : byteLen+1]
|
||||
yBytes := publicKeyBytes[byteLen+1 : 2*byteLen+1]
|
||||
|
||||
// 将字节切片转换为大整数
|
||||
x := new(big.Int).SetBytes(xBytes)
|
||||
y := new(big.Int).SetBytes(yBytes)
|
||||
|
||||
// 创建 sm2.PublicKey 对象
|
||||
publicKey := &sm2.PublicKey{
|
||||
Curve: curve,
|
||||
X: x,
|
||||
Y: y,
|
||||
}
|
||||
|
||||
return publicKey, nil
|
||||
}
|
||||
|
||||
// 验证签名
|
||||
func VerSm2Sig(pub *sm2.PublicKey, msg []byte, sign []byte) bool {
|
||||
isok := pub.Verify(msg, sign)
|
||||
return isok
|
||||
}
|
||||
|
||||
func SignSm2(privateKey *sm2.PrivateKey, msg []byte) ([]byte, error) {
|
||||
sign, err := privateKey.Sign(rand.Reader, msg, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return sign, nil
|
||||
}
|
||||
|
|
@ -10,6 +10,10 @@ import (
|
|||
|
||||
// CreatePaymentLinkWithBackUrl 创建支付链接(带 fromId 判断)
|
||||
func (c *Client) CreatePaymentLinkWithBackUrl(req PaymentLinkRequest) (*PaymentLinkResponse, error) {
|
||||
returnUrl := c.cfg.ReturnUrl
|
||||
if req.BackUrl != "" {
|
||||
returnUrl = req.BackUrl
|
||||
}
|
||||
|
||||
hasQuery := len(c.cfg.PayUrl) > 0 && strings.Contains(c.cfg.PayUrl, "?")
|
||||
|
||||
|
|
@ -38,10 +42,7 @@ func (c *Client) CreatePaymentLinkWithBackUrl(req PaymentLinkRequest) (*PaymentL
|
|||
if c.cfg.PayUrl != "" {
|
||||
payUrl = c.cfg.PayUrl
|
||||
}
|
||||
returnUrl := c.cfg.ReturnUrl
|
||||
if req.BackUrl != "" {
|
||||
returnUrl = req.BackUrl
|
||||
}
|
||||
|
||||
// https://static.mobile-bank.psbc.com/static/back/jump.html/?pageId=50000000&h5Type=9079& tysdPayParams=密文&tysdShopid=XXX & tysdEncryptKey =XXX& returnUrl =XXX
|
||||
if hasQuery {
|
||||
payUrl = fmt.Sprintf("%s&tysdPayParams=%s&tysdShopid=%s&tysdEncryptKey=%s&returnUrl=%s",
|
||||
|
|
|
|||
|
|
@ -6,24 +6,24 @@ import (
|
|||
|
||||
// Config 支付配置
|
||||
type Config struct {
|
||||
MerchantId string
|
||||
MchtNo string
|
||||
AppID string
|
||||
SopPublicKey string
|
||||
PrivateKey string
|
||||
Pubkey string
|
||||
BankKey string
|
||||
Sha string
|
||||
ReturnUrl string // 支付返回地址
|
||||
SuccessUrl string // 支付成功地址
|
||||
NotifyUrl string
|
||||
LoginHost string
|
||||
OrderHost string
|
||||
FileHost string
|
||||
ShopId string
|
||||
Psbcmcc string // 三方服务商标识,如 LSXD、JBZ
|
||||
PrivateKeyCallback string // 邮储响应解密的私钥
|
||||
PayUrl string // 支付地址
|
||||
MerchantId string `json:"merchant_id"` // 商户ID
|
||||
MchtNo string `json:"mcht_no"` // 商户号
|
||||
AppID string `json:"app_id"` // 应用ID
|
||||
SopPublicKey string `json:"sop_public_key"` // SOP公钥
|
||||
PrivateKey string `json:"private_key"` // 商户私钥 手机银行
|
||||
PrivateKeyCallback string `json:"private_key_callback"` // 邮储响应解密的私钥
|
||||
Pubkey string `json:"pubkey"` // 商户公钥 手机银行
|
||||
BankKey string `json:"bank_key"` // 手机银行公钥
|
||||
Sha string `json:"sha"` // SHA密钥
|
||||
ReturnUrl string `json:"return_url"` // 支付返回地址
|
||||
SuccessUrl string `json:"success_url"` // 支付成功地址
|
||||
NotifyUrl string `json:"notify_url"` // 回调通知地址
|
||||
LoginHost string `json:"login_host"` // 登录服务地址
|
||||
OrderHost string `json:"order_host"` // 订单服务地址
|
||||
FileHost string `json:"file_host"` // 文件服务地址
|
||||
ShopId string `json:"shop_id"` // 店铺ID
|
||||
Psbcmcc string `json:"psbcmcc"` // 三方服务商标识
|
||||
PayUrl string `json:"pay_url"` // 支付地址
|
||||
}
|
||||
|
||||
// PaymentLinkRequest 生成支付链接请求
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ type PsbcPay struct {
|
|||
PrivateKey string `json:"private_key"` // 商户私钥
|
||||
PrivateKeyCallback string `json:"private_key_callback"` // 邮储响应解密的私钥
|
||||
Pubkey string `json:"pubkey"` // 商户公钥
|
||||
BankKey string `json:"bank_key"` // 银行公钥
|
||||
BankKey string `json:"bank_key"` // 手机银行公钥
|
||||
Sha string `json:"sha"` // SHA密钥
|
||||
ReturnUrl string `json:"return_url"` // 支付返回地址
|
||||
SuccessUrl string `json:"success_url"` // 支付成功地址
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package paymentService
|
||||
|
||||
import (
|
||||
payment "PaymentCenter/app/third/paymentService/psbc"
|
||||
"PaymentCenter/config"
|
||||
"context"
|
||||
"encoding/json"
|
||||
|
|
@ -82,6 +83,7 @@ func TestPsbcPay(t *testing.T) {
|
|||
// return
|
||||
//}
|
||||
|
||||
//{"sha": "463726ztx68n79e3g27", "app_id": "1204022501096787968001", "pubkey": "0454dcb911feb9a892c520f37ebaa11f8c6a552187ac7e57ad0a22356035fc1f7fb09d840def9fa90ee2cd0b0efdb976a597de798e22b81a09684b3d466148e3ea", "mcht_no": "100510102303326", "psbcmcc": "", "shop_id": "LSXD0001", "bank_key": "04E842C70157584DE6229FFE56A2CCABDBCFA01A7C5EF24B254638EFB650C9EE196B64788F09777F376F921B038A5BBFF2AFEBA0B81E63EB40DFCDFD1B46819BE1", "file_host": "", "login_host": "https://open.psbc.com/gateway/biz/crecard/", "notify_url": "https://pay.cdlsxd.cn/pay/front/api/v1/notify/psbc/89351417415", "order_host": "https://open.psbc.com/gateway/biz/unionpay/", "return_url": "https://market.86698.cn/hmOrderList", "merchant_id": "lansexiongdi666", "private_key": "00dbdc5f54de98d2281bec34f87f23905610e17af651eae9c16bab68f312b5f2a9", "success_url": "https://market.86698.cn/hmOrderList", "show_title_bar": "true", "sop_public_key": "04A3C235C15070E127679628FE024E6C77FFCB1840B4EFBE09D19CBE0EE69BEA231912943984D34C03989771E503DFBB4ECB186F4BBC27764109E63C2875005C81", "private_key_callback": "7FE05FEB81673ABF0AC4F9EEB99FB03BFE7BE432CA474CB9AAD8E302CAF00766"}
|
||||
data := `{
|
||||
"sha": "463726ztx68n79e3g27",
|
||||
"app_id": "1204022501096787968001",
|
||||
|
|
@ -118,16 +120,16 @@ func TestPsbcPay(t *testing.T) {
|
|||
Psbc: psbc,
|
||||
ReturnUrl: psbc.ReturnUrl,
|
||||
}
|
||||
////支付
|
||||
//orderResult := PaymentService(c, request)
|
||||
//t.Log(orderResult)
|
||||
//
|
||||
//rsp := payment.PaymentLinkResponse{}
|
||||
//err = json.Unmarshal([]byte(orderResult.Result), &rsp)
|
||||
//if err != nil {
|
||||
// t.Error(err)
|
||||
//}
|
||||
//t.Log(rsp)
|
||||
//支付
|
||||
orderResult := PaymentService(c, request)
|
||||
t.Log(orderResult)
|
||||
|
||||
rsp := payment.PaymentLinkResponse{}
|
||||
err = json.Unmarshal([]byte(orderResult.Result), &rsp)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
t.Log(rsp)
|
||||
|
||||
// 查询订单
|
||||
qreq := PayOrderQueryRequest{
|
||||
|
|
|
|||
Loading…
Reference in New Issue