<feat>新增rsa,sm2,sm4加解密以及测试用例
This commit is contained in:
parent
4be80f228e
commit
dd3255e220
|
@ -0,0 +1,110 @@
|
||||||
|
package rsa
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/rand"
|
||||||
|
"crypto/rsa"
|
||||||
|
"crypto/sha256"
|
||||||
|
"crypto/x509"
|
||||||
|
"encoding/base64"
|
||||||
|
"encoding/pem"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
// parseRSAPublicKeyFromPEM 解析PEM编码的RSA公钥
|
||||||
|
func parseRSAPublicKeyFromPEM(pemData []byte) (*rsa.PublicKey, error) {
|
||||||
|
block, _ := pem.Decode(pemData)
|
||||||
|
if block == nil || block.Type != "PUBLIC KEY" {
|
||||||
|
return nil, fmt.Errorf("failed to parse PEM block containing the RSA public key")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub, err := x509.ParsePKIXPublicKey(block.Bytes)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch pub := pub.(type) {
|
||||||
|
case *rsa.PublicKey:
|
||||||
|
return pub, nil
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("unknown public key type in PKIX wrapping")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// encrypt 使用RSA公钥加密数据
|
||||||
|
func Encrypt(publicKeyPEM string, plaintext []byte) ([]byte, error) {
|
||||||
|
// 将PEM编码的公钥转换为[]byte
|
||||||
|
pemData := []byte(publicKeyPEM)
|
||||||
|
|
||||||
|
// 解析PEM数据以获取公钥
|
||||||
|
pubKey, err := parseRSAPublicKeyFromPEM(pemData)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建用于加密的随机填充
|
||||||
|
label := []byte("") // OAEP标签,对于某些情况可能是非空的
|
||||||
|
ciphertext, err := rsa.EncryptOAEP(sha256.New(), rand.Reader, pubKey, plaintext, label)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return ciphertext, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// parseRSAPrivateKeyFromPEM 解析PEM编码的RSA私钥
|
||||||
|
func parseRSAPrivateKeyFromPEM(pemData []byte) (*rsa.PrivateKey, error) {
|
||||||
|
block, _ := pem.Decode(pemData)
|
||||||
|
if block == nil || block.Type != "RSA PRIVATE KEY" {
|
||||||
|
return nil, fmt.Errorf("failed to parse PEM block containing the RSA private key")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 尝试使用PKCS#1 v1.5
|
||||||
|
priv, err := x509.ParsePKCS1PrivateKey(block.Bytes)
|
||||||
|
if err != nil {
|
||||||
|
// 如果失败,尝试使用PKCS#8
|
||||||
|
privInterface, err := x509.ParsePKCS8PrivateKey(block.Bytes)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch k := privInterface.(type) {
|
||||||
|
case *rsa.PrivateKey:
|
||||||
|
priv = k
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("unknown private key type in PKCS#8 wrapping")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return priv, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// decrypt 使用RSA私钥解密数据
|
||||||
|
func Decrypt(privateKeyPEM string, encryptedDataBase64 string) ([]byte, error) {
|
||||||
|
// 将PEM编码的私钥转换为[]byte
|
||||||
|
pemData := []byte(privateKeyPEM)
|
||||||
|
|
||||||
|
// 解析PEM数据以获取私钥
|
||||||
|
privKey, err := parseRSAPrivateKeyFromPEM(pemData)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将Base64编码的加密数据解码为字节切片
|
||||||
|
encryptedData, err := base64.StdEncoding.DecodeString(encryptedDataBase64)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据你的加密方式选择合适的解密函数
|
||||||
|
// 这里假设使用的是OAEP填充和SHA-256哈希函数
|
||||||
|
label := []byte("") // OAEP标签,对于某些情况可能是非空的
|
||||||
|
decrypted, err := rsa.DecryptOAEP(sha256.New(), rand.Reader, privKey, encryptedData, label)
|
||||||
|
if err != nil {
|
||||||
|
// 如果失败,可以尝试使用PKCS#1 v1.5填充
|
||||||
|
decrypted, err = rsa.DecryptPKCS1v15(rand.Reader, privKey, encryptedData)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return decrypted, nil
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
package rsa
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/base64"
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
PRI = "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCmjK6SPkrP03ssex5Dxn4KZeVm9rQoJMslru13GNgoGKJAq13xwUGl6lpGlhzM9IMzg0ldOO2a0SQPPjc0fLrDjIgHPfIT6H1hDGkZdPaF4D0OfiHGzlLwXq7FyyyGc2JXILsniMBXcCxNFhbW0jAaJyYrBJb3q84a5y5AtK3IC+eDV6Bj2J4HlQVGKgW9u2ic6Jxl23sacXY6iifi+KEuoXNCJrmYlgRWTaQovLmTCLkErkzxzG9DFRDWGoz25LthDPqcCSUmWEbJ+obwIGB4r2WCbFXvaeVBQORlyVRyNUvYMItjHBQIKinDWZ6y8KzA0YKOoxEfr0KfE8Uk4PQBAgMBAAECggEABTAX0PzelN4uyvTT0sMi/R0YRKPgepP40vtBsNvF10E7Lp4ClAupHpYFSrJq178xu1/2dVBXEGM9hw8GUQd7RCjuD3cFwcp/EKU+Zy6uQ38iZRTskEDa3bC+q3EXzuFXDxqOfIhai262UTlkATw0sjUwJRdkbMxoeWHkSNuH7UBVddxFL8Bq1DKaPzRCqQ8zlkMZHy8Xbf2b8rFoi1oPBoPjHyxCo33zcnSg5xntIoA5pkD6x4z5cAnU55aBoYUiRv7jmG+MVp1jpDvAmJLfUayVZNakgX1r74bMPsl9kpA7dVdgOlWrIkbJE1plVXXswBb8QKN0/Yx2vv/YASSi0QKBgQDaO9BkRjvht/lrsQEur1wXf5ITnsVWsqlUhYQKGHihzOj7e0rGO9QICM4eQZH9ssHfxEXhmEoFdkaqo3Fo47NI+yinpWm+KruwrRFkCGejlKZ4bhn9zWPb8L1qJbN4UD1c5jUNk1B0EEdnLRFg0/O7xm602bGilvY5x2nf0v95+QKBgQDDXyiiGNV7GO4h8OQYJwq0IqenPyIanRgYI3rw//tg147mhWcxT6ms6dMUh9nEXEFali2J1En+aVvx1Xn47CuGrRmZOLaGkw9ESFA/4ngYdea+xgttbKMXm0QwIwvATq2jxxrYEKmnr/+EUUWzIWioM1zQffAhVlkLFVnImquMSQKBgDe7qNfC/A4ELwWqubOTg0BZCxRJqvoePJJiWrs9Tql7rFB1Rz5jDx5SKVmew0r4OP0Nog8gFl9YumlfvlncNPBBfDt8SgoP3ckcGeHjJ5ymHPGKpMaliogj7ivKnw/t5g3wmMHzyksp0SJvZw3Ec22UGrfDFNOCHDXbUJWhzC75AoGBALbM6rAAnH65LNcFFeajYRh69HNAVyCfrFOpnvawDPzntAVs/MjeyNvJTH8BPXjE+UFREvrLbxBkdGsqWx3VnEQ+4pzCu8XfA4HYR33+4G/CoUwO8dJIu7DyzjJcGDqvYzjCqxNPQ+5qdqHPiW+56rq2lDlgHLaUnGwKZh+U2L5BAoGAeogtSQbnZaLQofSGcUOol2fyG24NU1JK3My+N1ypkSpD+y1KiFQeM5kg7UcJB6LBKZ/lRCKcjEMaxMyj57ETMkbRVKBLvsIL5QYolJLIHYqBul0AeFJ4K51SKK2Xk5rFvyuJKkJBux26WodtCXTnEzP1KRZGlSxJeN/V1yXjSEU="
|
||||||
|
|
||||||
|
PUB = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApoyukj5Kz9N7LHseQ8Z+CmXlZva0KCTLJa7tdxjYKBiiQKtd8cFBpepaRpYczPSDM4NJXTjtmtEkDz43NHy6w4yIBz3yE+h9YQxpGXT2heA9Dn4hxs5S8F6uxcsshnNiVyC7J4jAV3AsTRYW1tIwGicmKwSW96vOGucuQLStyAvng1egY9ieB5UFRioFvbtonOicZdt7GnF2Ooon4vihLqFzQia5mJYEVk2kKLy5kwi5BK5M8cxvQxUQ1hqM9uS7YQz6nAklJlhGyfqG8CBgeK9lgmxV72nlQUDkZclUcjVL2DCLYxwUCCopw1mesvCswNGCjqMRH69CnxPFJOD0AQIDAQAB"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestRsaEncrypt(t *testing.T) {
|
||||||
|
fmt.Printf("%s\n", encrypt())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRsaDecrypt(t *testing.T) {
|
||||||
|
data := encrypt()
|
||||||
|
privateKeyPEM := `-----BEGIN RSA PRIVATE KEY-----
|
||||||
|
` + PRI + `
|
||||||
|
-----END RSA PRIVATE KEY-----`
|
||||||
|
res, err := Decrypt(privateKeyPEM, data)
|
||||||
|
fmt.Println(string(res), err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func encrypt() string {
|
||||||
|
data := "{\"name\":\"张三\",\"sex\":1,\"is_human\":true}"
|
||||||
|
dataJson := []byte(data)
|
||||||
|
pub := `-----BEGIN PUBLIC KEY-----
|
||||||
|
` + PUB + `
|
||||||
|
-----END PUBLIC KEY-----`
|
||||||
|
en, err := Encrypt(pub, dataJson)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return base64.StdEncoding.EncodeToString(en)
|
||||||
|
}
|
|
@ -1,7 +1,6 @@
|
||||||
package sm2
|
package sm2
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"PaymentCenter/config"
|
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
|
@ -16,12 +15,21 @@ func GenerateSM2Key() (PublicKey string, PrivateKey string, err error) {
|
||||||
// 生成私钥、公钥
|
// 生成私钥、公钥
|
||||||
privKey, err := sm2.GenerateKey(rand.Reader)
|
privKey, err := sm2.GenerateKey(rand.Reader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("生成密钥对失败:", err)
|
|
||||||
return "", "", err
|
return "", "", err
|
||||||
}
|
}
|
||||||
return PublicKeyToString(&privKey.PublicKey), PrivateKeyToString(privKey), nil
|
return PublicKeyToString(&privKey.PublicKey), PrivateKeyToString(privKey), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GenerateKey 生成密钥对
|
||||||
|
func GenerateKey() (string, string) {
|
||||||
|
pri, _ := sm2.GenerateKey(rand.Reader)
|
||||||
|
hexPri := pri.D.Text(16)
|
||||||
|
// 获取公钥
|
||||||
|
publicKeyHex := PublicKeyToString(&pri.PublicKey)
|
||||||
|
return strings.ToUpper(hexPri), publicKeyHex
|
||||||
|
}
|
||||||
|
|
||||||
// PublicKeyToString 公钥sm2.PublicKey转字符串(与java中org.bouncycastle.crypto生成的公私钥完全互通使用)
|
// PublicKeyToString 公钥sm2.PublicKey转字符串(与java中org.bouncycastle.crypto生成的公私钥完全互通使用)
|
||||||
func PublicKeyToString(publicKey *sm2.PublicKey) string {
|
func PublicKeyToString(publicKey *sm2.PublicKey) string {
|
||||||
xBytes := publicKey.X.Bytes()
|
xBytes := publicKey.X.Bytes()
|
||||||
|
@ -48,27 +56,27 @@ func PrivateKeyToString(privateKey *sm2.PrivateKey) string {
|
||||||
return strings.ToUpper(hex.EncodeToString(privateKey.D.Bytes()))
|
return strings.ToUpper(hex.EncodeToString(privateKey.D.Bytes()))
|
||||||
}
|
}
|
||||||
|
|
||||||
func SM2Decrypt(cipherText string) (string, error) {
|
func SM2Decrypt(cipherText, publicKey string, privateKey string) (string, error) {
|
||||||
if cipherText == "" {
|
if cipherText == "" {
|
||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
decodedBytes, err := base64.StdEncoding.DecodeString(cipherText)
|
decodedBytes, err := base64.StdEncoding.DecodeString(cipherText)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("解码错误:", err)
|
|
||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
decrypt, err := decryptLoc(config.GetConf().Sm2.PublicKey, config.GetConf().Sm2.PrivateKey, string(decodedBytes))
|
decrypt, err := decryptLoc(publicKey, privateKey, string(decodedBytes))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
return decrypt, nil
|
return decrypt, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func SM2Encrypt(cipherText string) (string, error) {
|
func SM2Encrypt(cipherText string, privateKey string) (string, error) {
|
||||||
if cipherText == "" {
|
if cipherText == "" {
|
||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
decrypt, err := encryptLoc(config.GetConf().Sm2.PublicKey, cipherText)
|
decrypt, err := encryptLoc(privateKey, cipherText)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
@ -78,11 +86,11 @@ func SM2Encrypt(cipherText string) (string, error) {
|
||||||
func encryptLoc(publicKeyStr, data string) (string, error) {
|
func encryptLoc(publicKeyStr, data string) (string, error) {
|
||||||
publicKeyObj, err := StringToPublicKey(publicKeyStr)
|
publicKeyObj, err := StringToPublicKey(publicKeyStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
return "", err
|
||||||
}
|
}
|
||||||
decrypt, err := sm2.Encrypt(publicKeyObj, []byte(data), rand.Reader, sm2.C1C2C3)
|
decrypt, err := sm2.Encrypt(publicKeyObj, []byte(data), rand.Reader, sm2.C1C2C3)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
return "", err
|
||||||
}
|
}
|
||||||
resultStr := hex.EncodeToString(decrypt)
|
resultStr := hex.EncodeToString(decrypt)
|
||||||
return base64.StdEncoding.EncodeToString([]byte(resultStr)), nil
|
return base64.StdEncoding.EncodeToString([]byte(resultStr)), nil
|
||||||
|
@ -103,7 +111,6 @@ func decryptLoc(publicKeyStr, privateKeyStr, cipherText string) (string, error)
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
}
|
}
|
||||||
resultStr := string(decrypt)
|
resultStr := string(decrypt)
|
||||||
fmt.Println("解密后的字符串:", resultStr)
|
|
||||||
return resultStr, nil
|
return resultStr, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
package sm2
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
SELF_PRI = "EA7CB6F907A96264D6763F8C46AB96B476538D2ABC880A459E10BE5A1C30013D"
|
||||||
|
|
||||||
|
SELF_PUB = "04363DF574D4FE34EE58FB8A3F7CB08E6CA5EBB3B7335CBAE10A2900551F6450AB3AD25DBC0A76EFA9E6D44D2C51E3027483F7BFD09996457888BAFD1AF673817F"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestGenerateSM2KeyPair(t *testing.T) {
|
||||||
|
// Generate a new SM2 key pair
|
||||||
|
privateKey, publicKey := GenerateKey()
|
||||||
|
|
||||||
|
// Print the private and public keys
|
||||||
|
fmt.Printf("Private Key: %s\n", privateKey)
|
||||||
|
fmt.Printf("Public Key: %s", publicKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSM2Encrypt(t *testing.T) {
|
||||||
|
t.Log(encrypt())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSM2Decrypt(t *testing.T) {
|
||||||
|
en := encrypt()
|
||||||
|
decrypt, err := SM2Decrypt(en, SELF_PUB, SELF_PRI)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
t.Log(decrypt)
|
||||||
|
}
|
||||||
|
|
||||||
|
func encrypt() string {
|
||||||
|
data := "{\"name\":\"张三\",\"sex\":1,\"is_human\":true}"
|
||||||
|
en, err := SM2Encrypt(data, SELF_PUB)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return en
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,2 @@
|
||||||
|
* 来源于 github.com/tjfoc/gmsm
|
||||||
|
* 修改适配 邮储对接
|
|
@ -0,0 +1,219 @@
|
||||||
|
package sm2
|
||||||
|
|
||||||
|
// reference to ecdsa
|
||||||
|
import (
|
||||||
|
"crypto"
|
||||||
|
"crypto/elliptic"
|
||||||
|
"crypto/rand"
|
||||||
|
"encoding/asn1"
|
||||||
|
"errors"
|
||||||
|
"github.com/tjfoc/gmsm/sm3"
|
||||||
|
"io"
|
||||||
|
"math/big"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
default_uid = []byte{0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38}
|
||||||
|
)
|
||||||
|
|
||||||
|
type PublicKey struct {
|
||||||
|
elliptic.Curve
|
||||||
|
X, Y *big.Int
|
||||||
|
}
|
||||||
|
|
||||||
|
type PrivateKey struct {
|
||||||
|
PublicKey
|
||||||
|
D *big.Int
|
||||||
|
}
|
||||||
|
|
||||||
|
type sm2Signature struct {
|
||||||
|
R, S *big.Int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (priv *PrivateKey) Public() crypto.PublicKey {
|
||||||
|
return &priv.PublicKey
|
||||||
|
}
|
||||||
|
|
||||||
|
var errZeroParam = errors.New("zero parameter")
|
||||||
|
var one = new(big.Int).SetInt64(1)
|
||||||
|
var two = new(big.Int).SetInt64(2)
|
||||||
|
|
||||||
|
func (priv *PrivateKey) Sign(random io.Reader, msg []byte, signer crypto.SignerOpts) ([]byte, error) {
|
||||||
|
r, s, err := Sm2Sign(priv, msg, nil, random)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return asn1.Marshal(sm2Signature{r, s})
|
||||||
|
}
|
||||||
|
|
||||||
|
func Sm2Sign(priv *PrivateKey, msg, uid []byte, random io.Reader) (r, s *big.Int, err error) {
|
||||||
|
digest, err := priv.PublicKey.Sm3Digest(msg, uid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
e := new(big.Int).SetBytes(digest)
|
||||||
|
c := priv.PublicKey.Curve
|
||||||
|
N := c.Params().N
|
||||||
|
if N.Sign() == 0 {
|
||||||
|
return nil, nil, errZeroParam
|
||||||
|
}
|
||||||
|
var k *big.Int
|
||||||
|
for { // 调整算法细节以实现SM2
|
||||||
|
for {
|
||||||
|
k, err = randFieldElement(c, random)
|
||||||
|
if err != nil {
|
||||||
|
r = nil
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r, _ = priv.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(priv.D, r)
|
||||||
|
s = new(big.Int).Sub(k, rD)
|
||||||
|
d1 := new(big.Int).Add(priv.D, one)
|
||||||
|
d1Inv := new(big.Int).ModInverse(d1, N)
|
||||||
|
s.Mul(s, d1Inv)
|
||||||
|
s.Mod(s, N)
|
||||||
|
if s.Sign() != 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pub *PublicKey) Sm3Digest(msg, uid []byte) ([]byte, error) {
|
||||||
|
if len(uid) == 0 {
|
||||||
|
uid = default_uid
|
||||||
|
}
|
||||||
|
|
||||||
|
za, err := getZ(pub, uid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
e, err := msgHash(za, msg)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.Bytes(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func Sm2Verify(pub *PublicKey, msg, uid []byte, r, s *big.Int) bool {
|
||||||
|
c := pub.Curve
|
||||||
|
N := c.Params().N
|
||||||
|
one := new(big.Int).SetInt64(1)
|
||||||
|
if r.Cmp(one) < 0 || s.Cmp(one) < 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if r.Cmp(N) >= 0 || s.Cmp(N) >= 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if len(uid) == 0 {
|
||||||
|
uid = default_uid
|
||||||
|
}
|
||||||
|
za, err := getZ(pub, uid)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
e, err := msgHash(za, msg)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
t := new(big.Int).Add(r, s)
|
||||||
|
t.Mod(t, N)
|
||||||
|
if t.Sign() == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
var x *big.Int
|
||||||
|
x1, y1 := c.ScalarBaseMult(s.Bytes())
|
||||||
|
x2, y2 := c.ScalarMult(pub.X, pub.Y, t.Bytes())
|
||||||
|
x, _ = c.Add(x1, y1, x2, y2)
|
||||||
|
|
||||||
|
x.Add(x, e)
|
||||||
|
x.Mod(x, N)
|
||||||
|
return x.Cmp(r) == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func msgHash(za, msg []byte) (*big.Int, error) {
|
||||||
|
e := sm3.New()
|
||||||
|
e.Write(za)
|
||||||
|
e.Write(msg)
|
||||||
|
return new(big.Int).SetBytes(e.Sum(nil)[:32]), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func 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 getZ(pub *PublicKey, uid []byte) ([]byte, error) {
|
||||||
|
z := sm3.New()
|
||||||
|
uidLen := len(uid) * 8
|
||||||
|
entla := []byte{byte(uidLen >> 8), byte(uidLen & 255)}
|
||||||
|
z.Write(entla)
|
||||||
|
z.Write(uid)
|
||||||
|
|
||||||
|
// a 先写死,原来的没有暴露
|
||||||
|
z.Write(bigIntToByte(sm2P256ToBig(&sm2P256.a)))
|
||||||
|
z.Write(bigIntToByte(sm2P256.B))
|
||||||
|
z.Write(bigIntToByte(sm2P256.Gx))
|
||||||
|
z.Write(bigIntToByte(sm2P256.Gy))
|
||||||
|
|
||||||
|
z.Write(bigIntToByte(pub.X))
|
||||||
|
z.Write(bigIntToByte(pub.Y))
|
||||||
|
return z.Sum(nil), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func randFieldElement(c elliptic.Curve, random io.Reader) (k *big.Int, err error) {
|
||||||
|
if random == nil {
|
||||||
|
random = rand.Reader //If there is no external trusted random source,please use rand.Reader to instead of it.
|
||||||
|
}
|
||||||
|
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, one)
|
||||||
|
k.Mod(k, n)
|
||||||
|
k.Add(k, one)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func GenerateKey(random io.Reader) (*PrivateKey, error) {
|
||||||
|
c := P256Sm2()
|
||||||
|
if random == nil {
|
||||||
|
random = rand.Reader //If there is no external trusted random source,please use rand.Reader to instead of it.
|
||||||
|
}
|
||||||
|
params := c.Params()
|
||||||
|
b := make([]byte, params.BitSize/8+8)
|
||||||
|
_, err := io.ReadFull(random, b)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
k := new(big.Int).SetBytes(b)
|
||||||
|
n := new(big.Int).Sub(params.N, two)
|
||||||
|
k.Mod(k, n)
|
||||||
|
k.Add(k, one)
|
||||||
|
priv := new(PrivateKey)
|
||||||
|
priv.PublicKey.Curve = c
|
||||||
|
priv.D = k
|
||||||
|
priv.PublicKey.X, priv.PublicKey.Y = c.ScalarBaseMult(k.Bytes())
|
||||||
|
|
||||||
|
return priv, nil
|
||||||
|
}
|
|
@ -0,0 +1,45 @@
|
||||||
|
package sm2
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/hex"
|
||||||
|
"errors"
|
||||||
|
"math/big"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ReadPrivateKeyFromHex(Dhex string) (*PrivateKey, error) {
|
||||||
|
c := P256Sm2()
|
||||||
|
d, err := hex.DecodeString(Dhex)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
k := new(big.Int).SetBytes(d)
|
||||||
|
params := c.Params()
|
||||||
|
one := new(big.Int).SetInt64(1)
|
||||||
|
n := new(big.Int).Sub(params.N, one)
|
||||||
|
if k.Cmp(n) >= 0 {
|
||||||
|
return nil, errors.New("privateKey's D is overflow.")
|
||||||
|
}
|
||||||
|
priv := new(PrivateKey)
|
||||||
|
priv.PublicKey.Curve = c
|
||||||
|
priv.D = k
|
||||||
|
priv.PublicKey.X, priv.PublicKey.Y = c.ScalarBaseMult(k.Bytes())
|
||||||
|
return priv, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ReadPublicKeyFromHex(Qhex string) (*PublicKey, error) {
|
||||||
|
q, err := hex.DecodeString(Qhex)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(q) == 65 && q[0] == byte(0x04) {
|
||||||
|
q = q[1:]
|
||||||
|
}
|
||||||
|
if len(q) != 64 {
|
||||||
|
return nil, errors.New("publicKey is not uncompressed.")
|
||||||
|
}
|
||||||
|
pub := new(PublicKey)
|
||||||
|
pub.Curve = P256Sm2()
|
||||||
|
pub.X = new(big.Int).SetBytes(q[:32])
|
||||||
|
pub.Y = new(big.Int).SetBytes(q[32:])
|
||||||
|
return pub, nil
|
||||||
|
}
|
|
@ -0,0 +1,163 @@
|
||||||
|
package util
|
||||||
|
|
||||||
|
import (
|
||||||
|
"PaymentCenter/app/utils/encrypt/sm4/internal/sm2"
|
||||||
|
"bytes"
|
||||||
|
"crypto/elliptic"
|
||||||
|
"crypto/rand"
|
||||||
|
"errors"
|
||||||
|
zzsm2 "github.com/ZZMarquis/gm/sm2"
|
||||||
|
"github.com/tjfoc/gmsm/sm3"
|
||||||
|
"github.com/tjfoc/gmsm/x509"
|
||||||
|
"math/big"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Sm2Decrypt(privateKey *sm2.PrivateKey, encryptData []byte) ([]byte, error) {
|
||||||
|
C1Byte := make([]byte, 65)
|
||||||
|
copy(C1Byte, encryptData[:65])
|
||||||
|
x, y := elliptic.Unmarshal(privateKey.Curve, C1Byte)
|
||||||
|
dBC1X, dBC1Y := privateKey.Curve.ScalarMult(x, y, bigIntToByte(privateKey.D))
|
||||||
|
dBC1Bytes := elliptic.Marshal(privateKey.Curve, dBC1X, dBC1Y)
|
||||||
|
|
||||||
|
kLen := len(encryptData) - 65 - 32
|
||||||
|
t, err := kdf(dBC1Bytes, kLen)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
M := make([]byte, kLen)
|
||||||
|
for i := 0; i < kLen; i++ {
|
||||||
|
M[i] = encryptData[65+i] ^ t[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
C3 := make([]byte, 32)
|
||||||
|
copy(C3, encryptData[len(encryptData)-32:])
|
||||||
|
u := calculateHash(dBC1X, M, dBC1Y)
|
||||||
|
|
||||||
|
if bytes.Compare(u, C3) == 0 {
|
||||||
|
return M, nil
|
||||||
|
} else {
|
||||||
|
return nil, errors.New("解密失败")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Sm2Encrypt(publicKey *sm2.PublicKey, m []byte) ([]byte, error) {
|
||||||
|
kLen := len(m)
|
||||||
|
var C1, t []byte
|
||||||
|
var err error
|
||||||
|
var kx, ky *big.Int
|
||||||
|
for {
|
||||||
|
k, _ := rand.Int(rand.Reader, publicKey.Params().N)
|
||||||
|
C1x, C1y := zzsm2.GetSm2P256V1().ScalarBaseMult(bigIntToByte(k))
|
||||||
|
// C1x, C1y := sm2.P256Sm2().ScalarBaseMult(bigIntToByte(k))
|
||||||
|
C1 = elliptic.Marshal(publicKey.Curve, C1x, C1y)
|
||||||
|
|
||||||
|
kx, ky = publicKey.ScalarMult(publicKey.X, publicKey.Y, bigIntToByte(k))
|
||||||
|
kpbBytes := elliptic.Marshal(publicKey, kx, ky)
|
||||||
|
t, err = kdf(kpbBytes, kLen)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if !isAllZero(t) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
C2 := make([]byte, kLen)
|
||||||
|
for i := 0; i < kLen; i++ {
|
||||||
|
C2[i] = m[i] ^ t[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
C3 := calculateHash(kx, m, ky)
|
||||||
|
|
||||||
|
r := make([]byte, 0, len(C1)+len(C2)+len(C3))
|
||||||
|
r = append(r, C1...)
|
||||||
|
r = append(r, C2...)
|
||||||
|
r = append(r, C3...)
|
||||||
|
return r, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func isAllZero(m []byte) bool {
|
||||||
|
for i := 0; i < len(m); i++ {
|
||||||
|
if m[i] != 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func calculateHash(x *big.Int, M []byte, y *big.Int) []byte {
|
||||||
|
digest := sm3.New()
|
||||||
|
digest.Write(bigIntToByte(x))
|
||||||
|
digest.Write(M)
|
||||||
|
digest.Write(bigIntToByte(y))
|
||||||
|
result := digest.Sum(nil)[:32]
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func 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 kdf(Z []byte, klen int) ([]byte, error) {
|
||||||
|
ct := 1
|
||||||
|
end := (klen + 31) / 32
|
||||||
|
result := make([]byte, 0)
|
||||||
|
for i := 1; i <= end; i++ {
|
||||||
|
b, err := sm3hash(Z, toByteArray(ct))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result = append(result, b...)
|
||||||
|
ct++
|
||||||
|
}
|
||||||
|
last, err := sm3hash(Z, toByteArray(ct))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if klen%32 == 0 {
|
||||||
|
result = append(result, last...)
|
||||||
|
} else {
|
||||||
|
result = append(result, last[:klen%32]...)
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func sm3hash(sources ...[]byte) ([]byte, error) {
|
||||||
|
b, err := joinBytes(sources...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
md := make([]byte, 32)
|
||||||
|
h := x509.SM3.New()
|
||||||
|
h.Write(b)
|
||||||
|
h.Sum(md[:0])
|
||||||
|
return md, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
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 toByteArray(i int) []byte {
|
||||||
|
byteArray := []byte{
|
||||||
|
byte(i >> 24),
|
||||||
|
byte((i & 16777215) >> 16),
|
||||||
|
byte((i & 65535) >> 8),
|
||||||
|
byte(i & 255),
|
||||||
|
}
|
||||||
|
return byteArray
|
||||||
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
package util
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/md5"
|
||||||
|
"crypto/rand"
|
||||||
|
"encoding/hex"
|
||||||
|
"math/big"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GenerateSM4Key() []byte {
|
||||||
|
str := "qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM1234567890"
|
||||||
|
buffer := make([]byte, 16)
|
||||||
|
for i := 0; i < 16; i++ {
|
||||||
|
nextInt, _ := rand.Int(rand.Reader, big.NewInt(int64(len(str))))
|
||||||
|
buffer[i] = str[nextInt.Int64()]
|
||||||
|
}
|
||||||
|
return buffer
|
||||||
|
}
|
||||||
|
|
||||||
|
func GenAccessToken(token string) string {
|
||||||
|
if token != "" {
|
||||||
|
return token
|
||||||
|
}
|
||||||
|
now := time.Now()
|
||||||
|
return strings.ToUpper(Md5Hash(now.Format("2006A01B02CD15E04F05"), ""))
|
||||||
|
}
|
||||||
|
|
||||||
|
func Md5Hash(password, salt string) string {
|
||||||
|
m := md5.New()
|
||||||
|
m.Write([]byte(salt + password))
|
||||||
|
return hex.EncodeToString(m.Sum(nil))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSM4IV 获取SM4的IV
|
||||||
|
func GetSM4IV() []byte {
|
||||||
|
return []byte("UISwD9fW6cFh9SNS")
|
||||||
|
}
|
||||||
|
|
||||||
|
func Padding(input []byte, mode int) []byte {
|
||||||
|
if input == nil {
|
||||||
|
return nil
|
||||||
|
} else {
|
||||||
|
var ret []byte
|
||||||
|
if mode == 1 {
|
||||||
|
p := 16 - len(input)%16
|
||||||
|
ret = make([]byte, len(input)+p)
|
||||||
|
copy(ret, input)
|
||||||
|
|
||||||
|
for i := 0; i < p; i++ {
|
||||||
|
ret[len(input)+i] = byte(p)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
p := input[len(input)-1]
|
||||||
|
ret = make([]byte, len(input)-int(p))
|
||||||
|
copy(ret, input[:len(input)-int(p)])
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,203 @@
|
||||||
|
package sm4
|
||||||
|
|
||||||
|
import (
|
||||||
|
"PaymentCenter/app/utils/encrypt/sm4/internal/sm2"
|
||||||
|
"PaymentCenter/app/utils/encrypt/sm4/internal/util"
|
||||||
|
"crypto/rand"
|
||||||
|
"encoding/base64"
|
||||||
|
"encoding/hex"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"github.com/ZZMarquis/gm/sm4"
|
||||||
|
"math/big"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func checkInData(reqData map[string]string, key string) (string, error) {
|
||||||
|
data, ok := reqData[key]
|
||||||
|
if !ok {
|
||||||
|
return "", errors.New("请求数据中不存在" + key)
|
||||||
|
}
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func Sm4Decrypt(merchantId, privateKey, sopPublicKey, respJson string, isRequest bool) (string, error) {
|
||||||
|
var reqData map[string]string
|
||||||
|
err := json.Unmarshal([]byte(respJson), &reqData)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
keys := [4]string{}
|
||||||
|
if isRequest {
|
||||||
|
keys = [4]string{"request", "signature", "encryptKey", "accessToken"}
|
||||||
|
} else {
|
||||||
|
keys = [4]string{"response", "signature", "encryptKey", "accessToken"}
|
||||||
|
}
|
||||||
|
var inEncryptKey, inAccessToken, inData, inSignature string
|
||||||
|
|
||||||
|
for i := 0; i < 4; i++ {
|
||||||
|
data, err := checkInData(reqData, keys[i])
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
switch keys[i] {
|
||||||
|
case "request", "response":
|
||||||
|
inData = data
|
||||||
|
case "signature":
|
||||||
|
inSignature = data
|
||||||
|
case "encryptKey":
|
||||||
|
inEncryptKey = data
|
||||||
|
case "accessToken":
|
||||||
|
inAccessToken = data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
checked := verify(fmt.Sprintf("%s%s%s", inData, inEncryptKey, inAccessToken), inSignature, sopPublicKey, merchantId)
|
||||||
|
if !checked {
|
||||||
|
return "", errors.New("签名验证失败")
|
||||||
|
}
|
||||||
|
|
||||||
|
priKey, err := sm2.ReadPrivateKeyFromHex(privateKey)
|
||||||
|
if err != nil {
|
||||||
|
return "", errors.New("读取私钥失败")
|
||||||
|
}
|
||||||
|
hexEncryptKey, err := hex.DecodeString(inEncryptKey)
|
||||||
|
if err != nil {
|
||||||
|
return "", errors.New("解密sm4key失败")
|
||||||
|
}
|
||||||
|
sm4Key, err := util.Sm2Decrypt(priKey, hexEncryptKey)
|
||||||
|
|
||||||
|
request, _ := base64.StdEncoding.DecodeString(inData)
|
||||||
|
|
||||||
|
encryptedSm4Key, err := sm4.CBCDecrypt(sm4Key, util.GetSM4IV(), request)
|
||||||
|
|
||||||
|
return string(util.Padding(encryptedSm4Key, 0)), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func Sm4Encrypt(merchantId, privateKey, sopPublicKey, inputJson, token string, isRequest bool) (string, error) {
|
||||||
|
sm4Key := util.GenerateSM4Key()
|
||||||
|
iv := util.GetSM4IV()
|
||||||
|
tmp, err := sm4.CBCEncrypt(sm4Key, iv, util.Padding([]byte(inputJson), 1))
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
responseMsg := base64.StdEncoding.EncodeToString(tmp)
|
||||||
|
responseMsg = addNewline(responseMsg)
|
||||||
|
|
||||||
|
pubKey, err := sm2.ReadPublicKeyFromHex(sopPublicKey)
|
||||||
|
if err != nil {
|
||||||
|
return "", errors.New("读取私钥失败")
|
||||||
|
}
|
||||||
|
encryptKeyBytes, err := util.Sm2Encrypt(pubKey, sm4Key)
|
||||||
|
encryptKey := strings.ToUpper(hex.EncodeToString(encryptKeyBytes))
|
||||||
|
|
||||||
|
accessToken := util.GenAccessToken(token)
|
||||||
|
signContent := fmt.Sprintf("%s%s%s", responseMsg, encryptKey, accessToken)
|
||||||
|
signature, err := sign(merchantId, privateKey, signContent)
|
||||||
|
|
||||||
|
var reqData map[string]string
|
||||||
|
|
||||||
|
if isRequest {
|
||||||
|
reqData = map[string]string{
|
||||||
|
"request": responseMsg,
|
||||||
|
"signature": signature,
|
||||||
|
"encryptKey": encryptKey,
|
||||||
|
"accessToken": accessToken,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
reqData = map[string]string{
|
||||||
|
"response": responseMsg,
|
||||||
|
"signature": signature,
|
||||||
|
"encryptKey": encryptKey,
|
||||||
|
"accessToken": accessToken,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
jsonStr, err := json.Marshal(reqData)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return string(jsonStr), err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GenerateKey 生成密钥对
|
||||||
|
func GenerateKey() (string, string) {
|
||||||
|
pri, _ := sm2.GenerateKey(rand.Reader)
|
||||||
|
hexPri := pri.D.Text(16)
|
||||||
|
// 获取公钥
|
||||||
|
publicKeyHex := publicKeyToString(&pri.PublicKey)
|
||||||
|
return strings.ToUpper(hexPri), publicKeyHex
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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))
|
||||||
|
}
|
||||||
|
|
||||||
|
func addNewline(str string) string {
|
||||||
|
lineLength := 76
|
||||||
|
var result strings.Builder
|
||||||
|
for i := 0; i < len(str); i++ {
|
||||||
|
if i > 0 && i%lineLength == 0 {
|
||||||
|
result.WriteString("\r\n")
|
||||||
|
}
|
||||||
|
result.WriteByte(str[i])
|
||||||
|
}
|
||||||
|
return result.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func sign(merchantId string, privateKeyHex string, signContent string) (string, error) {
|
||||||
|
privateKey, err := sm2.ReadPrivateKeyFromHex(privateKeyHex)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
r, s, err := sm2.Sm2Sign(privateKey, []byte(signContent), []byte(merchantId), rand.Reader)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return rSToSign(r, s), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func verify(content string, signature string, publicKeyStr string, merchantId string) bool {
|
||||||
|
pubKey, err := sm2.ReadPublicKeyFromHex(publicKeyStr)
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Sprintf("pubKeyBytes sm2 ReadPublicKeyFromHex err: %v", err))
|
||||||
|
}
|
||||||
|
r, s := signToRS(signature)
|
||||||
|
return sm2.Sm2Verify(pubKey, []byte(content), []byte(merchantId), r, s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func signToRS(signStr string) (*big.Int, *big.Int) {
|
||||||
|
signSub := strings.Split(signStr, "#")
|
||||||
|
if len(signSub) != 2 {
|
||||||
|
panic(fmt.Sprintf("err rs: %x", signSub))
|
||||||
|
}
|
||||||
|
r, _ := new(big.Int).SetString(signSub[0], 16)
|
||||||
|
s, _ := new(big.Int).SetString(signSub[1], 16)
|
||||||
|
return r, s
|
||||||
|
}
|
||||||
|
|
||||||
|
func rSToSign(r *big.Int, s *big.Int) string {
|
||||||
|
rStr := r.Text(16)
|
||||||
|
sStr := s.Text(16)
|
||||||
|
return fmt.Sprintf("%s#%s", rStr, sStr)
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
package sm4
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
SELF_PRI = "EA7CB6F907A96264D6763F8C46AB96B476538D2ABC880A459E10BE5A1C30013D"
|
||||||
|
|
||||||
|
SELF_PUB = "04363DF574D4FE34EE58FB8A3F7CB08E6CA5EBB3B7335CBAE10A2900551F6450AB3AD25DBC0A76EFA9E6D44D2C51E3027483F7BFD09996457888BAFD1AF673817F"
|
||||||
|
|
||||||
|
PARTY_PRI = "EEB0A34DE1F05154E4B96E50BFC1F8B9750EEAE799F5708C7AFBABB9AFCFA1BF"
|
||||||
|
|
||||||
|
PARTY_PUB = "0420425DF33945C9D5596A33ED60ABEEFD0165C27BA7D6C95D37344E9223149FEAF4C10CEACD7EC88E8DD1E0BDEA71FD09BE2077A1BDC61BC45587B7CC3613F85A"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestGenerateKey(t *testing.T) {
|
||||||
|
hexPri, publicKeyHex := GenerateKey()
|
||||||
|
fmt.Println(hexPri, publicKeyHex)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSM4Encrypt(t *testing.T) {
|
||||||
|
t.Log(encrypt())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSM4Decrypt(t *testing.T) {
|
||||||
|
uid, en := encrypt()
|
||||||
|
decrypt, err := Sm4Decrypt(uid, SELF_PRI, PARTY_PUB, en, true)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
t.Log(decrypt)
|
||||||
|
}
|
||||||
|
|
||||||
|
func encrypt() (string, string) {
|
||||||
|
uid := "1234567890"
|
||||||
|
data := "{\"name\":\"张三\",\"sex\":1,\"is_human\":true}"
|
||||||
|
en, err := Sm4Encrypt(uid, PARTY_PRI, SELF_PUB, data, "", true)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return uid, en
|
||||||
|
}
|
4
go.mod
4
go.mod
|
@ -6,6 +6,7 @@ require (
|
||||||
gitee.com/chengdu_blue_brothers/openapi-go-sdk v0.0.2
|
gitee.com/chengdu_blue_brothers/openapi-go-sdk v0.0.2
|
||||||
github.com/BurntSushi/toml v0.4.1
|
github.com/BurntSushi/toml v0.4.1
|
||||||
github.com/Shopify/sarama v1.19.0
|
github.com/Shopify/sarama v1.19.0
|
||||||
|
github.com/ZZMarquis/gm v1.3.2
|
||||||
github.com/ahmetb/go-linq/v3 v3.2.0
|
github.com/ahmetb/go-linq/v3 v3.2.0
|
||||||
github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible
|
github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible
|
||||||
github.com/forgoer/openssl v1.6.0
|
github.com/forgoer/openssl v1.6.0
|
||||||
|
@ -22,6 +23,7 @@ require (
|
||||||
github.com/qit-team/snow-core v0.1.28
|
github.com/qit-team/snow-core v0.1.28
|
||||||
github.com/qit-team/work v0.3.11
|
github.com/qit-team/work v0.3.11
|
||||||
github.com/robfig/cron v1.2.0
|
github.com/robfig/cron v1.2.0
|
||||||
|
github.com/spf13/cobra v1.2.1
|
||||||
github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271
|
github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271
|
||||||
github.com/swaggo/gin-swagger v1.3.3
|
github.com/swaggo/gin-swagger v1.3.3
|
||||||
github.com/swaggo/swag v1.7.9
|
github.com/swaggo/swag v1.7.9
|
||||||
|
@ -70,6 +72,7 @@ require (
|
||||||
github.com/google/uuid v1.3.0 // indirect
|
github.com/google/uuid v1.3.0 // indirect
|
||||||
github.com/hetiansu5/accesslog v1.0.0 // indirect
|
github.com/hetiansu5/accesslog v1.0.0 // indirect
|
||||||
github.com/hetiansu5/cores v1.0.0 // indirect
|
github.com/hetiansu5/cores v1.0.0 // indirect
|
||||||
|
github.com/inconshreveable/mousetrap v1.0.0 // indirect
|
||||||
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af // indirect
|
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af // indirect
|
||||||
github.com/josharian/intern v1.0.0 // indirect
|
github.com/josharian/intern v1.0.0 // indirect
|
||||||
github.com/json-iterator/go v1.1.12 // indirect
|
github.com/json-iterator/go v1.1.12 // indirect
|
||||||
|
@ -92,6 +95,7 @@ require (
|
||||||
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a // indirect
|
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a // indirect
|
||||||
github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5 // indirect
|
github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5 // indirect
|
||||||
github.com/sirupsen/logrus v1.8.1 // indirect
|
github.com/sirupsen/logrus v1.8.1 // indirect
|
||||||
|
github.com/spf13/pflag v1.0.5 // indirect
|
||||||
github.com/syndtr/goleveldb v1.0.0 // indirect
|
github.com/syndtr/goleveldb v1.0.0 // indirect
|
||||||
github.com/tidwall/gjson v1.12.1 // indirect
|
github.com/tidwall/gjson v1.12.1 // indirect
|
||||||
github.com/tidwall/match v1.1.1 // indirect
|
github.com/tidwall/match v1.1.1 // indirect
|
||||||
|
|
5
go.sum
5
go.sum
|
@ -58,6 +58,8 @@ github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWX
|
||||||
github.com/Shopify/toxiproxy v2.1.4+incompatible h1:TKdv8HiTLgE5wdJuEML90aBgNWsokNbMijUGhmcoBJc=
|
github.com/Shopify/toxiproxy v2.1.4+incompatible h1:TKdv8HiTLgE5wdJuEML90aBgNWsokNbMijUGhmcoBJc=
|
||||||
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
|
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
|
||||||
github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g=
|
github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g=
|
||||||
|
github.com/ZZMarquis/gm v1.3.2 h1:lFtpzg5zeeVMZ/gKi0gtYcKLBEo9XTqsZDHDz6s3Gow=
|
||||||
|
github.com/ZZMarquis/gm v1.3.2/go.mod h1:wWbjZYgruQVd7Bb8UkSN8ujU931kx2XUW6nZLCiDE0Q=
|
||||||
github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c=
|
github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c=
|
||||||
github.com/agiledragon/gomonkey/v2 v2.3.1 h1:k+UnUY0EMNYUFUAQVETGY9uUTxjMdnUkP0ARyJS1zzs=
|
github.com/agiledragon/gomonkey/v2 v2.3.1 h1:k+UnUY0EMNYUFUAQVETGY9uUTxjMdnUkP0ARyJS1zzs=
|
||||||
github.com/agiledragon/gomonkey/v2 v2.3.1/go.mod h1:ap1AmDzcVOAz1YpeJ3TCzIgstoaWLA6jbbgxfB4w2iY=
|
github.com/agiledragon/gomonkey/v2 v2.3.1/go.mod h1:ap1AmDzcVOAz1YpeJ3TCzIgstoaWLA6jbbgxfB4w2iY=
|
||||||
|
@ -368,6 +370,7 @@ github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpO
|
||||||
github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg=
|
github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg=
|
||||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||||
|
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
|
||||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||||
github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo=
|
github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo=
|
||||||
github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo=
|
github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo=
|
||||||
|
@ -671,9 +674,11 @@ github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJ
|
||||||
github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
|
github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
|
||||||
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||||
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
|
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
|
||||||
|
github.com/spf13/cobra v1.2.1 h1:+KmjbUw1hriSNMF55oPrkZcb27aECyrj8V2ytv7kWDw=
|
||||||
github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk=
|
github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk=
|
||||||
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
|
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
|
||||||
github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||||
|
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||||
github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns=
|
github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns=
|
||||||
github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
|
github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
|
||||||
|
|
Loading…
Reference in New Issue