feat:邮储支付fix

This commit is contained in:
wolter 2026-08-20 17:38:35 +08:00
parent 6df638f471
commit 4219e20d30
23 changed files with 3553 additions and 63 deletions

View File

@ -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 的 Sm2SignUserID 传 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 的 Sm2SignUserID 传 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 解密银行响应

View File

@ -0,0 +1,2 @@
# gmutil
蓝色兄弟 国密工具仓库

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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]
}
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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)))
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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",

View File

@ -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 生成支付链接请求

View File

@ -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"` // 支付成功地址

View File

@ -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{