feat:邮储支付fix
This commit is contained in:
parent
6df638f471
commit
4219e20d30
|
|
@ -1,6 +1,10 @@
|
||||||
package payment
|
package payment
|
||||||
|
|
||||||
import (
|
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"
|
"bytes"
|
||||||
"crypto/hmac"
|
"crypto/hmac"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
|
|
@ -19,7 +23,6 @@ import (
|
||||||
|
|
||||||
"PaymentCenter/app/third/paymentService/psbc/internal/sm2"
|
"PaymentCenter/app/third/paymentService/psbc/internal/sm2"
|
||||||
psbcutil "PaymentCenter/app/third/paymentService/psbc/internal/util"
|
psbcutil "PaymentCenter/app/third/paymentService/psbc/internal/util"
|
||||||
"github.com/ZZMarquis/gm/sm4"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Client 支付客户端
|
// Client 支付客户端
|
||||||
|
|
@ -111,53 +114,98 @@ func RandomNumber(n int) string {
|
||||||
return string(result)
|
return string(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
// EncryptMobile 手机银行支付参数加密
|
//// EncryptMobile 手机银行支付参数加密
|
||||||
// 返回: tysdPayParams(base64), tysdEncryptKey(base64)
|
//// 返回: tysdPayParams(base64), tysdEncryptKey(base64)
|
||||||
// 使用 YouChuKoffee 加密包(psbc/internal/sm2 + psbc/internal/util)
|
//// 使用 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) {
|
func (c *Client) EncryptMobile(inputJson string, signStr string) (string, string, error) {
|
||||||
defer func() {
|
defer func() error {
|
||||||
if err := recover(); err != nil {
|
if err := recover(); err != nil {
|
||||||
fmt.Println("加密失败", err)
|
return errors.New("加密失败")
|
||||||
|
} else {
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
sm4Key := psbcutil.GenerateSM4Key()
|
sm4Key := psbcutil.GenerateSM4Key()
|
||||||
|
|
||||||
// SM2 加密 SM4 密钥(使用银行公钥,使用 YouChuKoffee 的 Sm2Encrypt)
|
encryptKeyBytes, err := sm22.NewSm2().
|
||||||
bankPubKey, err := sm2.ReadPublicKeyFromHex(c.cfg.BankKey)
|
SetHexPublicKey(c.cfg.BankKey).
|
||||||
|
SetData(sm4Key).
|
||||||
|
SetSdk(sdk.NewCmbLifeSdk()).
|
||||||
|
SetCipherType(model.C1C3C2).
|
||||||
|
Encrypt().
|
||||||
|
ToBytes()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", "", fmt.Errorf("读取银行公钥失败: %v", err)
|
return "", "", errors.New("加密sm2key失败")
|
||||||
}
|
|
||||||
encryptKeyBytes, err := psbcutil.Sm2Encrypt(bankPubKey, sm4Key)
|
|
||||||
if err != nil {
|
|
||||||
return "", "", fmt.Errorf("sm2加密失败: %v", err)
|
|
||||||
}
|
}
|
||||||
encryptKey := hex.EncodeToString(encryptKeyBytes)
|
encryptKey := hex.EncodeToString(encryptKeyBytes)
|
||||||
if len(encryptKey) > 2 && encryptKey[0:2] == "04" {
|
if encryptKey[0:2] == "04" {
|
||||||
encryptKeyBytes = encryptKeyBytes[1:]
|
encryptKeyBytes = encryptKeyBytes[1:]
|
||||||
}
|
}
|
||||||
|
pub, err := sm2.StringToPublicKey(c.cfg.Pubkey)
|
||||||
// SM2 签名(使用 YouChuKoffee 的 Sm2Sign,UserID 传 nil,默认值 1234567812345678)
|
|
||||||
merchantPrivKey, err := sm2.ReadPrivateKeyFromHex(c.cfg.PrivateKey)
|
|
||||||
if err != nil {
|
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 {
|
if err != nil {
|
||||||
return "", "", fmt.Errorf("签名失败: %v", err)
|
return "", "", errors.New("读取私钥失败")
|
||||||
}
|
}
|
||||||
sig := encodeBase64(rsToBytes(r, s))
|
rs, err := sm2.SignSm2(pri, []byte(signStr))
|
||||||
|
if err != nil {
|
||||||
// 拼接参数并 SM4 ECB 加密
|
return "", "", errors.New("签名失败")
|
||||||
// 对齐 YouChuKoffee: sm43.ECBEncrypt(sm4Key, sm43.PKCS5Padding([]byte(param), 16))
|
}
|
||||||
// sm4ECBEncrypt 内部已处理 padding,调用方不需要再 pad
|
var sig = base64.StdEncoding.EncodeToString(rs)
|
||||||
param := fmt.Sprintf("%s&sign=%s", inputJson, sig)
|
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 {
|
if err != nil {
|
||||||
return "", "", fmt.Errorf("sm4加密失败: %v", err)
|
return "", "", errors.New("加密失败")
|
||||||
}
|
}
|
||||||
|
return base64.StdEncoding.EncodeToString(tmp), base64.StdEncoding.EncodeToString([]byte(encryptKeyBytes)), nil
|
||||||
return encodeBase64(tmp), encodeBase64(encryptKeyBytes), nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DecryptResponse 解密银行响应
|
// 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 判断)
|
// CreatePaymentLinkWithBackUrl 创建支付链接(带 fromId 判断)
|
||||||
func (c *Client) CreatePaymentLinkWithBackUrl(req PaymentLinkRequest) (*PaymentLinkResponse, error) {
|
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, "?")
|
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 != "" {
|
if c.cfg.PayUrl != "" {
|
||||||
payUrl = 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
|
// https://static.mobile-bank.psbc.com/static/back/jump.html/?pageId=50000000&h5Type=9079& tysdPayParams=密文&tysdShopid=XXX & tysdEncryptKey =XXX& returnUrl =XXX
|
||||||
if hasQuery {
|
if hasQuery {
|
||||||
payUrl = fmt.Sprintf("%s&tysdPayParams=%s&tysdShopid=%s&tysdEncryptKey=%s&returnUrl=%s",
|
payUrl = fmt.Sprintf("%s&tysdPayParams=%s&tysdShopid=%s&tysdEncryptKey=%s&returnUrl=%s",
|
||||||
|
|
|
||||||
|
|
@ -6,24 +6,24 @@ import (
|
||||||
|
|
||||||
// Config 支付配置
|
// Config 支付配置
|
||||||
type Config struct {
|
type Config struct {
|
||||||
MerchantId string
|
MerchantId string `json:"merchant_id"` // 商户ID
|
||||||
MchtNo string
|
MchtNo string `json:"mcht_no"` // 商户号
|
||||||
AppID string
|
AppID string `json:"app_id"` // 应用ID
|
||||||
SopPublicKey string
|
SopPublicKey string `json:"sop_public_key"` // SOP公钥
|
||||||
PrivateKey string
|
PrivateKey string `json:"private_key"` // 商户私钥 手机银行
|
||||||
Pubkey string
|
PrivateKeyCallback string `json:"private_key_callback"` // 邮储响应解密的私钥
|
||||||
BankKey string
|
Pubkey string `json:"pubkey"` // 商户公钥 手机银行
|
||||||
Sha string
|
BankKey string `json:"bank_key"` // 手机银行公钥
|
||||||
ReturnUrl string // 支付返回地址
|
Sha string `json:"sha"` // SHA密钥
|
||||||
SuccessUrl string // 支付成功地址
|
ReturnUrl string `json:"return_url"` // 支付返回地址
|
||||||
NotifyUrl string
|
SuccessUrl string `json:"success_url"` // 支付成功地址
|
||||||
LoginHost string
|
NotifyUrl string `json:"notify_url"` // 回调通知地址
|
||||||
OrderHost string
|
LoginHost string `json:"login_host"` // 登录服务地址
|
||||||
FileHost string
|
OrderHost string `json:"order_host"` // 订单服务地址
|
||||||
ShopId string
|
FileHost string `json:"file_host"` // 文件服务地址
|
||||||
Psbcmcc string // 三方服务商标识,如 LSXD、JBZ
|
ShopId string `json:"shop_id"` // 店铺ID
|
||||||
PrivateKeyCallback string // 邮储响应解密的私钥
|
Psbcmcc string `json:"psbcmcc"` // 三方服务商标识
|
||||||
PayUrl string // 支付地址
|
PayUrl string `json:"pay_url"` // 支付地址
|
||||||
}
|
}
|
||||||
|
|
||||||
// PaymentLinkRequest 生成支付链接请求
|
// PaymentLinkRequest 生成支付链接请求
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ type PsbcPay struct {
|
||||||
PrivateKey string `json:"private_key"` // 商户私钥
|
PrivateKey string `json:"private_key"` // 商户私钥
|
||||||
PrivateKeyCallback string `json:"private_key_callback"` // 邮储响应解密的私钥
|
PrivateKeyCallback string `json:"private_key_callback"` // 邮储响应解密的私钥
|
||||||
Pubkey string `json:"pubkey"` // 商户公钥
|
Pubkey string `json:"pubkey"` // 商户公钥
|
||||||
BankKey string `json:"bank_key"` // 银行公钥
|
BankKey string `json:"bank_key"` // 手机银行公钥
|
||||||
Sha string `json:"sha"` // SHA密钥
|
Sha string `json:"sha"` // SHA密钥
|
||||||
ReturnUrl string `json:"return_url"` // 支付返回地址
|
ReturnUrl string `json:"return_url"` // 支付返回地址
|
||||||
SuccessUrl string `json:"success_url"` // 支付成功地址
|
SuccessUrl string `json:"success_url"` // 支付成功地址
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package paymentService
|
package paymentService
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
payment "PaymentCenter/app/third/paymentService/psbc"
|
||||||
"PaymentCenter/config"
|
"PaymentCenter/config"
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
|
@ -82,6 +83,7 @@ func TestPsbcPay(t *testing.T) {
|
||||||
// return
|
// 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 := `{
|
data := `{
|
||||||
"sha": "463726ztx68n79e3g27",
|
"sha": "463726ztx68n79e3g27",
|
||||||
"app_id": "1204022501096787968001",
|
"app_id": "1204022501096787968001",
|
||||||
|
|
@ -118,16 +120,16 @@ func TestPsbcPay(t *testing.T) {
|
||||||
Psbc: psbc,
|
Psbc: psbc,
|
||||||
ReturnUrl: psbc.ReturnUrl,
|
ReturnUrl: psbc.ReturnUrl,
|
||||||
}
|
}
|
||||||
////支付
|
//支付
|
||||||
//orderResult := PaymentService(c, request)
|
orderResult := PaymentService(c, request)
|
||||||
//t.Log(orderResult)
|
t.Log(orderResult)
|
||||||
//
|
|
||||||
//rsp := payment.PaymentLinkResponse{}
|
rsp := payment.PaymentLinkResponse{}
|
||||||
//err = json.Unmarshal([]byte(orderResult.Result), &rsp)
|
err = json.Unmarshal([]byte(orderResult.Result), &rsp)
|
||||||
//if err != nil {
|
if err != nil {
|
||||||
// t.Error(err)
|
t.Error(err)
|
||||||
//}
|
}
|
||||||
//t.Log(rsp)
|
t.Log(rsp)
|
||||||
|
|
||||||
// 查询订单
|
// 查询订单
|
||||||
qreq := PayOrderQueryRequest{
|
qreq := PayOrderQueryRequest{
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue