From 5b2b5d0ba09ebd2d3e34879078b78b76fe75e99f Mon Sep 17 00:00:00 2001 From: "qiyunfanbo126.com" <815699> Date: Mon, 24 Mar 2025 20:25:53 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=8A=A0=E5=AF=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cmd/server/main.go | 2 +- go.mod | 2 + go.sum | 5 +- internal/conf/conf.pb.go | 24 +- internal/data/mixrepoimpl/cmb.go | 50 +- .../pkg/cmb/encrypt/encrypt_way/aes/aes.go | 101 ++ .../cmb/encrypt/encrypt_way/aes/aes_test.go | 34 + .../pkg/cmb/encrypt/encrypt_way/rsa/rsa.go | 162 +++ .../cmb/encrypt/encrypt_way/rsa/rsa_test.go | 63 + .../pkg/cmb/encrypt/encrypt_way/sm2/sm2.go | 167 +++ .../cmb/encrypt/encrypt_way/sm2/sm2_test.go | 68 + .../encrypt_way/sm4/internal/sm2/p256.go | 1157 +++++++++++++++++ .../encrypt_way/sm4/internal/sm2/sm2.go | 219 ++++ .../encrypt_way/sm4/internal/sm2/utils.go | 45 + .../encrypt_way/sm4/internal/util/sm2x.go | 163 +++ .../encrypt_way/sm4/internal/util/smutil.go | 62 + .../pkg/cmb/encrypt/encrypt_way/sm4/sm.go | 203 +++ .../cmb/encrypt/encrypt_way/sm4/sm4_test.go | 48 + internal/pkg/cmb/encrypt/errcode/errcode.go | 15 + internal/pkg/cmb/encrypt/pojo/const.go | 8 + .../pkg/cmb/encrypt/random_str/encrypt.go | 34 + .../cmb/encrypt/random_str/encrypt_test.go | 15 + internal/pkg/cmb/encrypt/sm2.go | 44 + internal/pkg/cmb/encrypt/sm2sm3.go | 132 ++ internal/pkg/cmb/encrypt/sm3.go | 36 + internal/pkg/cmb/encrypt/sm4.go | 43 + internal/pkg/cmb/encrypt/types.go | 39 + internal/pkg/cmb/sign.go | 136 ++ internal/pkg/cmb/sm2.go | 1 + internal/pkg/cmb/sm2/sm2_test.go | 46 + internal/pkg/cmb/sm2_test.go | 40 + internal/server/http.go | 2 + third_party/swagger_ui/openapi.yaml | 20 +- 33 files changed, 3145 insertions(+), 41 deletions(-) create mode 100644 internal/pkg/cmb/encrypt/encrypt_way/aes/aes.go create mode 100644 internal/pkg/cmb/encrypt/encrypt_way/aes/aes_test.go create mode 100644 internal/pkg/cmb/encrypt/encrypt_way/rsa/rsa.go create mode 100644 internal/pkg/cmb/encrypt/encrypt_way/rsa/rsa_test.go create mode 100644 internal/pkg/cmb/encrypt/encrypt_way/sm2/sm2.go create mode 100644 internal/pkg/cmb/encrypt/encrypt_way/sm2/sm2_test.go create mode 100644 internal/pkg/cmb/encrypt/encrypt_way/sm4/internal/sm2/p256.go create mode 100644 internal/pkg/cmb/encrypt/encrypt_way/sm4/internal/sm2/sm2.go create mode 100644 internal/pkg/cmb/encrypt/encrypt_way/sm4/internal/sm2/utils.go create mode 100644 internal/pkg/cmb/encrypt/encrypt_way/sm4/internal/util/sm2x.go create mode 100644 internal/pkg/cmb/encrypt/encrypt_way/sm4/internal/util/smutil.go create mode 100644 internal/pkg/cmb/encrypt/encrypt_way/sm4/sm.go create mode 100644 internal/pkg/cmb/encrypt/encrypt_way/sm4/sm4_test.go create mode 100644 internal/pkg/cmb/encrypt/errcode/errcode.go create mode 100644 internal/pkg/cmb/encrypt/pojo/const.go create mode 100644 internal/pkg/cmb/encrypt/random_str/encrypt.go create mode 100644 internal/pkg/cmb/encrypt/random_str/encrypt_test.go create mode 100644 internal/pkg/cmb/encrypt/sm2.go create mode 100644 internal/pkg/cmb/encrypt/sm2sm3.go create mode 100644 internal/pkg/cmb/encrypt/sm3.go create mode 100644 internal/pkg/cmb/encrypt/sm4.go create mode 100644 internal/pkg/cmb/encrypt/types.go create mode 100644 internal/pkg/cmb/sign.go diff --git a/cmd/server/main.go b/cmd/server/main.go index cd00baf..362c44b 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -46,7 +46,7 @@ const ( func init() { flag.StringVar(&nacosIp, "nacosIp", "120.55.12.245", "nacos ip address") flag.IntVar(&nacosPort, "nacosPort", 8848, "nacos port") - flag.StringVar(&nacosSpace, "nacosSpace", "voucher", "nacos space") + flag.StringVar(&nacosSpace, "nacosSpace", "voucher-test", "nacos space") flag.StringVar(&nacosUsername, "nacosUsername", "nacos", "nacos passowrd") flag.StringVar(&nacosPassword, "nacosPassword", "LsxdNacos@2025", "nacos passowrd") flag.Parse() diff --git a/go.mod b/go.mod index 6b19700..cfddba6 100644 --- a/go.mod +++ b/go.mod @@ -3,12 +3,14 @@ module voucher go 1.22.2 require ( + gitea.cdlsxd.cn/self-tools/l_crypt v1.0.0 github.com/ZZMarquis/gm v1.3.2 github.com/aliyunmq/mq-http-go-sdk v1.0.3 github.com/apache/rocketmq-client-go/v2 v2.1.2 github.com/brianvoe/gofakeit/v6 v6.28.0 github.com/bwmarrin/snowflake v0.3.0 github.com/duke-git/lancet/v2 v2.2.8 + github.com/emmansun/gmsm v0.29.8 github.com/envoyproxy/protoc-gen-validate v1.0.4 github.com/go-kratos/kratos/contrib/config/nacos/v2 v2.0.0-20241105072421-f8b97f675b32 github.com/go-kratos/kratos/v2 v2.8.2 diff --git a/go.sum b/go.sum index 26e6c8d..81ebe16 100644 --- a/go.sum +++ b/go.sum @@ -1,6 +1,8 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= +gitea.cdlsxd.cn/self-tools/l_crypt v1.0.0 h1:U0SBdxgrWNmbzPjEMuAtA51GeQ8PpRoZgN+SNoyqrQM= +gitea.cdlsxd.cn/self-tools/l_crypt v1.0.0/go.mod h1:Q7sEfyYLXGZ7i97HBJ7OaYLYyc4f9scUJK9Ev3ZGyDM= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v1.1.0 h1:ksErzDEI1khOiGPgpwuI7x2ebx/uXQNw7xJpn9Eq1+I= github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= @@ -46,6 +48,8 @@ github.com/duke-git/lancet/v2 v2.2.8 h1:wlruXhliDe4zls1e2cYmz4qLc+WtcvrpcCnk1VJd github.com/duke-git/lancet/v2 v2.2.8/go.mod h1:zGa2R4xswg6EG9I6WnyubDbFO/+A/RROxIbXcwryTsc= github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg= github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= +github.com/emmansun/gmsm v0.29.8 h1:py9RwKHe4sIxjgD9mtWSIF5bmspP7IXvQ70Rx8x22Ow= +github.com/emmansun/gmsm v0.29.8/go.mod h1:7UTFG3GmF8yxyZVB4HgpdeU0JoergL/i2OMGm5w02RA= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= @@ -129,7 +133,6 @@ github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/subcommands v1.2.0 h1:vWQspBTo2nEqTUFita5/KeEWlUL8kQObDFbub/EN9oE= github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= diff --git a/internal/conf/conf.pb.go b/internal/conf/conf.pb.go index f400113..1c47679 100644 --- a/internal/conf/conf.pb.go +++ b/internal/conf/conf.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.34.2 -// protoc v4.24.3 +// protoc-gen-go v1.31.0 +// protoc v3.12.4 // source: conf/conf.proto package conf @@ -1429,7 +1429,7 @@ func file_conf_conf_proto_rawDescGZIP() []byte { } var file_conf_conf_proto_msgTypes = make([]protoimpl.MessageInfo, 17) -var file_conf_conf_proto_goTypes = []any{ +var file_conf_conf_proto_goTypes = []interface{}{ (*Bootstrap)(nil), // 0: voucher.config.Bootstrap (*Server)(nil), // 1: voucher.config.Server (*Data)(nil), // 2: voucher.config.Data @@ -1484,7 +1484,7 @@ func file_conf_conf_proto_init() { return } if !protoimpl.UnsafeEnabled { - file_conf_conf_proto_msgTypes[0].Exporter = func(v any, i int) any { + file_conf_conf_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Bootstrap); i { case 0: return &v.state @@ -1496,7 +1496,7 @@ func file_conf_conf_proto_init() { return nil } } - file_conf_conf_proto_msgTypes[1].Exporter = func(v any, i int) any { + file_conf_conf_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Server); i { case 0: return &v.state @@ -1508,7 +1508,7 @@ func file_conf_conf_proto_init() { return nil } } - file_conf_conf_proto_msgTypes[2].Exporter = func(v any, i int) any { + file_conf_conf_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Data); i { case 0: return &v.state @@ -1520,7 +1520,7 @@ func file_conf_conf_proto_init() { return nil } } - file_conf_conf_proto_msgTypes[3].Exporter = func(v any, i int) any { + file_conf_conf_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*RocketMQ); i { case 0: return &v.state @@ -1532,7 +1532,7 @@ func file_conf_conf_proto_init() { return nil } } - file_conf_conf_proto_msgTypes[4].Exporter = func(v any, i int) any { + file_conf_conf_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*EventMap); i { case 0: return &v.state @@ -1544,7 +1544,7 @@ func file_conf_conf_proto_init() { return nil } } - file_conf_conf_proto_msgTypes[5].Exporter = func(v any, i int) any { + file_conf_conf_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Wechat); i { case 0: return &v.state @@ -1556,7 +1556,7 @@ func file_conf_conf_proto_init() { return nil } } - file_conf_conf_proto_msgTypes[6].Exporter = func(v any, i int) any { + file_conf_conf_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Cmb); i { case 0: return &v.state @@ -1568,7 +1568,7 @@ func file_conf_conf_proto_init() { return nil } } - file_conf_conf_proto_msgTypes[7].Exporter = func(v any, i int) any { + file_conf_conf_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*WechatNotifyMQ); i { case 0: return &v.state @@ -1580,7 +1580,7 @@ func file_conf_conf_proto_init() { return nil } } - file_conf_conf_proto_msgTypes[8].Exporter = func(v any, i int) any { + file_conf_conf_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Alarm); i { case 0: return &v.state diff --git a/internal/data/mixrepoimpl/cmb.go b/internal/data/mixrepoimpl/cmb.go index cc7a8b4..4e86e39 100644 --- a/internal/data/mixrepoimpl/cmb.go +++ b/internal/data/mixrepoimpl/cmb.go @@ -49,7 +49,7 @@ func (c *CmbMixRepoImpl) recordBody(ctx context.Context) { func (s *CmbMixRepoImpl) OrderVerify(ctx context.Context, req *v1.CmbRequest) (*v1.CmbOrderRequest, error) { - bizStr, err := s.Verify(ctx, req) + bizStr, err := s.VerifyNew(ctx, req) if err != nil { return nil, err2.ErrorCmbVerifyFail(err.Error()) } @@ -73,7 +73,7 @@ func (s *CmbMixRepoImpl) OrderVerify(ctx context.Context, req *v1.CmbRequest) (* func (s *CmbMixRepoImpl) QueryVerify(ctx context.Context, req *v1.CmbRequest) (*v1.CmbQueryRequest, error) { - bizStr, err := s.Verify(ctx, req) + bizStr, err := s.VerifyNew(ctx, req) if err != nil { return nil, err2.ErrorCmbVerifyFail(err.Error()) } @@ -97,7 +97,7 @@ func (s *CmbMixRepoImpl) QueryVerify(ctx context.Context, req *v1.CmbRequest) (* func (s *CmbMixRepoImpl) ProductQueryVerify(ctx context.Context, req *v1.CmbRequest) (*v1.CmbQueryProductRequest, error) { - bizStr, err := s.Verify(ctx, req) + bizStr, err := s.VerifyNew(ctx, req) if err != nil { return nil, err } @@ -140,9 +140,32 @@ func (s *CmbMixRepoImpl) Verify(_ context.Context, req *v1.CmbRequest) (string, return bizStr, nil } +func (s *CmbMixRepoImpl) VerifyNew(_ context.Context, req *v1.CmbRequest) (string, error) { + + str := cmb.SortStructStr(req) + + //b, err := cmb.Verify(s.bc.Cmb.CmbSm2Puk, str, req.Sign) + b, err := cmb.VerifyBody(str, req.Sign, s.bc.Cmb.CmbSm2Puk) + if err != nil { + return "", err2.ErrorCmbVerifyFail(err.Error()) + } + + if !b { + return "", err2.ErrorCmbVerifyFail("签名验证失败") + } + + bizStr, err := cmb.DecryptBody(&cmb.Decrypts{req.EncryptBody, s.bc.Cmb.CmbSm2Pik}) + if err != nil { + return "", err2.ErrorCmbBizContentDecryptFail(err.Error()) + } + + return string(bizStr), nil +} + func (s *CmbMixRepoImpl) GetRequest(_ context.Context, reqBo *bo.CmbRequestBo) (*v1.CmbRequest, error) { - encryptBody, err := cmb.Encrypt(s.bc.Cmb.CmbSm2Puk, reqBo.BizContent) + //encryptBody, err := cmb.Encrypt(s.bc.Cmb.CmbSm2Puk, reqBo.BizContent) + encryptBody, err := cmb.EncryptBody(&cmb.Encrypts{SoaPubKey: s.bc.Cmb.CmbSm2Puk, JsonParam: reqBo.BizContent}) if err != nil { return nil, err } @@ -160,7 +183,7 @@ func (s *CmbMixRepoImpl) GetRequest(_ context.Context, reqBo *bo.CmbRequestBo) ( str := fmt.Sprintf("%s?%s", reqBo.FuncName, cmb.SortStructStr(req)) - sing, err := cmb.Sign(s.bc.Cmb.Sm2Prk, str) + sing, err := cmb.Sign(s.bc.Cmb.CmbSm2Pik, str) if err != nil { return nil, err } @@ -180,7 +203,8 @@ func (s *CmbMixRepoImpl) GetMockRequest(_ context.Context, bizContent string) (* return nil, errors.New("mock cmb sm2 pik is empty") } - encryptBody, err := cmb.Encrypt(s.bc.Cmb.Sm2Puk, bizContent) + //encryptBody, err := cmb.Encrypt(s.bc.Cmb.Sm2Puk, bizContent) + encryptBody, err := cmb.EncryptBody(&cmb.Encrypts{SoaPubKey: s.bc.Cmb.CmbSm2Puk, JsonParam: bizContent}) if err != nil { return nil, err } @@ -196,7 +220,7 @@ func (s *CmbMixRepoImpl) GetMockRequest(_ context.Context, bizContent string) (* Sign: "", } - sign, err := cmb.Sign(s.bc.Cmb.CmbSm2Pik, cmb.SortStructStr(req)) + sign, err := cmb.SignBody(cmb.SortStructStr(req), s.bc.Cmb.CmbSm2Pik) if err != nil { return nil, err } @@ -210,7 +234,8 @@ func (s *CmbMixRepoImpl) VerifyResponse(_ context.Context, req *v1.CmbReply) err str := cmb.SortStructStr(req) - b, err := cmb.Verify(s.bc.Cmb.CmbSm2Puk, str, req.Sign) + //b, err := cmb.Verify(s.bc.Cmb.CmbSm2Puk, str, req.Sign) + b, err := cmb.VerifyBody(str, req.Sign, s.bc.Cmb.CmbSm2Puk) if err != nil { return err } @@ -235,14 +260,14 @@ func (s *CmbMixRepoImpl) GetResponse(_ context.Context, reqBo *bo.CmbResponseBo) } if len(reqBo.BizContent) > 0 { - encryptBody, err := cmb.Encrypt(s.bc.Cmb.CmbSm2Puk, reqBo.BizContent) + encryptBody, err := cmb.EncryptBody(&cmb.Encrypts{SoaPubKey: s.bc.Cmb.CmbSm2Puk, JsonParam: reqBo.BizContent}) if err != nil { return nil, err } reply.EncryptBody = encryptBody } - sign, err := cmb.Sign(s.bc.Cmb.Sm2Prk, cmb.SortStructStr(reply)) + sign, err := cmb.SignBody(cmb.SortStructStr(reply), s.bc.Cmb.Sm2Prk) if err != nil { return nil, err } @@ -295,6 +320,7 @@ func (s *CmbMixRepoImpl) Decrypt(_ context.Context, encryptBody string) (string, if len(s.bc.Cmb.CmbSm2Pik) == 0 { return "", errors.New("mock CmbSm2Pik is empty") } - - return cmb.Decrypt(s.bc.Cmb.CmbSm2Pik, encryptBody) + rs, err := cmb.DecryptBody(&cmb.Decrypts{EncryptBody: encryptBody, PrivateKey: s.bc.Cmb.CmbSm2Pik}) + return string(rs), err + //return cmb.Decrypt(s.bc.Cmb.CmbSm2Pik, encryptBody) } diff --git a/internal/pkg/cmb/encrypt/encrypt_way/aes/aes.go b/internal/pkg/cmb/encrypt/encrypt_way/aes/aes.go new file mode 100644 index 0000000..402130f --- /dev/null +++ b/internal/pkg/cmb/encrypt/encrypt_way/aes/aes.go @@ -0,0 +1,101 @@ +package aes + +import ( + "bytes" + "crypto/aes" + "crypto/cipher" + "crypto/rand" + "fmt" + "io" + "math/big" +) + +const ( + TestKey = "ROK0nAaxcsI0KRCy8VJgLlnlfjWYAOHk" +) + +// 加密函数 +func Encrypt(plaintext, key []byte) ([]byte, error) { + block, err := aes.NewCipher(key) + if err != nil { + return nil, err + } + + // 加密后的数据会比原文长,因为需要添加一些填充字节 + // PKCS#7填充 + plaintext = pkcs7Padding(plaintext, block.BlockSize()) + + // 创建一个cipher.BlockMode,这里使用CBC模式 + // 需要一个iv(初始化向量),它的长度和Block的块大小相同 + ciphertext := make([]byte, aes.BlockSize+len(plaintext)) + iv := ciphertext[:aes.BlockSize] + if _, err := io.ReadFull(rand.Reader, iv); err != nil { + return nil, err + } + + mode := cipher.NewCBCEncrypter(block, iv) + mode.CryptBlocks(ciphertext[aes.BlockSize:], plaintext) + + // 返回的密文包括iv和加密后的数据 + return ciphertext, nil +} + +// 解密函数 +func Decrypt(ciphertext, key []byte) ([]byte, error) { + block, err := aes.NewCipher(key) + if err != nil { + return nil, err + } + + if len(ciphertext) < aes.BlockSize { + return nil, fmt.Errorf("ciphertext too short") + } + + // 提取iv + iv := ciphertext[:aes.BlockSize] + ciphertext = ciphertext[aes.BlockSize:] + + // 创建一个cipher.BlockMode + mode := cipher.NewCBCDecrypter(block, iv) + + // 解密 + mode.CryptBlocks(ciphertext, ciphertext) + + // 去除PKCS#7填充 + plaintext, err := pkcs7Unpadding(ciphertext, block.BlockSize()) + if err != nil { + return nil, err + } + + return plaintext, nil +} + +// PKCS#7填充 +func pkcs7Padding(ciphertext []byte, blockSize int) []byte { + padding := blockSize - len(ciphertext)%blockSize + padtext := bytes.Repeat([]byte{byte(padding)}, padding) + return append(ciphertext, padtext...) +} + +// 去除PKCS#7填充 +func pkcs7Unpadding(ciphertext []byte, blockSize int) ([]byte, error) { + length := len(ciphertext) + unpadding := int(ciphertext[length-1]) + if unpadding > blockSize || unpadding == 0 { + return nil, fmt.Errorf("invalid padding") + } + return ciphertext[:(length - unpadding)], nil +} + +func GenerateRandomStringCrypto(length int) (string, error) { + const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" + var bytes = make([]byte, length) + for i := range bytes { + num, err := rand.Int(rand.Reader, big.NewInt(int64(len(charset)))) + if err != nil { + return "", err + } + bytes[i] = charset[num.Int64()] + } + return string(bytes), nil +} diff --git a/internal/pkg/cmb/encrypt/encrypt_way/aes/aes_test.go b/internal/pkg/cmb/encrypt/encrypt_way/aes/aes_test.go new file mode 100644 index 0000000..c9e4ef3 --- /dev/null +++ b/internal/pkg/cmb/encrypt/encrypt_way/aes/aes_test.go @@ -0,0 +1,34 @@ +package aes + +import ( + "fmt" + "testing" +) + +func TestCreateKey(t *testing.T) { + key, _ := GenerateRandomStringCrypto(32) + fmt.Printf(key) +} + +func TestAesEncrypt(t *testing.T) { + + fmt.Printf("%s\n", encrypt()) +} + +func TestAesDecrypt(t *testing.T) { + data := "dk9trGQn2kZyE0rmfYglxwNmr7gc0DGFWvnPDVpLHfzwPiaWKkr+ZffKu0wj9/DQurIgjrQZIW8uV5/e+jxzBE6+5YZuKcT9+5xZSv6ieiXB7WUrKKnjxX/bHEaWgfoa0eDqEBhGth+mgql7qWFZLmuXpoKuAc0FPhdHTiynAttqjNMU4rMeXq52yJLuXrKHGlavhd9DETNDrhPFzyIAw7XjoMfGtBIFkXyDK5X+AKGkRvMJ8KfXR3lk9sSzTyGKRK/S" + + res, err := Decrypt([]byte(data), []byte(TestKey)) + fmt.Println(string(res), err) +} + +func encrypt() string { + data := "{\"pay_channel_id\":8935141660703064070,\"out_trade_no\":\"asdadasdas\",\"order_type\":1,\"amount\":1,\"desc\":\"abc\",\"ext_json\":\"\",\"app_id\":5476377146882523138,\"timestamp\":53612533412643}{\"pay_channel_id\":8935141660703064070,\"out_trade_no\":\"asdadasdas\",\"order_type\":1,\"amount\":1,\"desc\":\"abc\",\"ext_json\":\"\",\"app_id\":5476377146882523138,\"timestamp\":53612533412643}{\"pay_channel_id\":8935141660703064070,\"out_trade_no\":\"asdadasdas\",\"order_type\":1,\"amount\":1,\"desc\":\"abc\",\"ext_json\":\"\",\"app_id\":5476377146882523138,\"timestamp\":53612533412643}{\"pay_channel_id\":8935141660703064070,\"out_trade_no\":\"asdadasdas\",\"order_type\":1,\"amount\":1,\"desc\":\"abc\",\"ext_json\":\"\",\"app_id\":5476377146882523138,\"timestamp\":53612533412643}{\"pay_channel_id\":8935141660703064070,\"out_trade_no\":\"asdadasdas\",\"order_type\":1,\"amount\":1,\"desc\":\"abc\",\"ext_json\":\"\",\"app_id\":5476377146882523138,\"timestamp\":53612533412643}{\"pay_channel_id\":8935141660703064070,\"out_trade_no\":\"asdadasdas\",\"order_type\":1,\"amount\":1,\"desc\":\"abc\",\"ext_json\":\"\",\"app_id\":5476377146882523138,\"timestamp\":53612533412643}{\"pay_channel_id\":8935141660703064070,\"out_trade_no\":\"asdadasdas\",\"order_type\":1,\"amount\":1,\"desc\":\"abc\",\"ext_json\":\"\",\"app_id\":5476377146882523138,\"timestamp\":53612533412643}{\"pay_channel_id\":8935141660703064070,\"out_trade_no\":\"asdadasdas\",\"order_type\":1,\"amount\":1,\"desc\":\"abc\",\"ext_json\":\"\",\"app_id\":5476377146882523138,\"timestamp\":53612533412643}" + + en, err := Encrypt([]byte(data), []byte(TestKey)) + if err != nil { + panic(err) + } + + return string(en) +} diff --git a/internal/pkg/cmb/encrypt/encrypt_way/rsa/rsa.go b/internal/pkg/cmb/encrypt/encrypt_way/rsa/rsa.go new file mode 100644 index 0000000..c5f958f --- /dev/null +++ b/internal/pkg/cmb/encrypt/encrypt_way/rsa/rsa.go @@ -0,0 +1,162 @@ +package rsa + +import ( + "crypto/rand" + "crypto/rsa" + "crypto/sha256" + "crypto/x509" + "encoding/base64" + "encoding/pem" + "fmt" + "strings" +) + +// 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 string) ([]byte, error) { + var encryptedData []byte + // 将PEM编码的公钥转换为[]byte + pemData := []byte(publicKeyPEM) + + // 解析PEM数据以获取公钥 + pubKey, err := parseRSAPublicKeyFromPEM(pemData) + if err != nil { + return nil, err + } + hash := sha256.New() + maxBlockSize := pubKey.Size() - 2*hash.Size() - 2 + // 创建用于加密的随机填充 + label := []byte("") // OAEP标签,对于某些情况可能是非空的 + for len(plaintext) > 0 { + blockSize := maxBlockSize + if len(plaintext) < maxBlockSize { + blockSize = len(plaintext) + } + block := plaintext[:blockSize] + encryptedBlock, err := rsa.EncryptOAEP(hash, rand.Reader, pubKey, []byte(block), label) + if err != nil { + return nil, err + } + encryptedData = append(encryptedData, encryptedBlock...) + plaintext = plaintext[blockSize:] + } + return encryptedData, 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) { + var decryptedData []byte + // 将PEM编码的私钥转换为[]byte + pemData := []byte(privateKeyPEM) + // 解析PEM数据以获取私钥 + privKey, err := parseRSAPrivateKeyFromPEM(pemData) + if err != nil { + return nil, err + } + + keySize := privKey.PublicKey.Size() + label := []byte("") // OAEP标签,对于某些情况可能是非空的 + hash := sha256.New() + // 将Base64编码的加密数据解码为字节切片 + encryptedData, err := base64.StdEncoding.DecodeString(encryptedDataBase64) + if err != nil { + return nil, err + } + for len(encryptedData) > 0 { + block := encryptedData[:keySize] + // 这里假设使用的是OAEP填充和SHA-256哈希函数 + decryptedBlock, err := rsa.DecryptOAEP(hash, rand.Reader, privKey, block, label) + if err != nil { + //// 如果失败,可以尝试使用PKCS#1 v1.5填充 + decryptedBlock, err = rsa.DecryptPKCS1v15(rand.Reader, privKey, encryptedData) + if err != nil { + return nil, err + } + } + decryptedData = append(decryptedData, decryptedBlock...) + encryptedData = encryptedData[keySize:] + } + return decryptedData, nil +} + +// 生成密钥对 +func GenerateKey() (string, string, error) { + // 生成私钥 + privateKey, err := rsa.GenerateKey(rand.Reader, 2048) + if err != nil { + return "", "", err + } + // 导出私钥PKCS#1格式 + privKey := x509.MarshalPKCS1PrivateKey(privateKey) + // 将私钥转换为PEM编码 + var privBlock = &pem.Block{ + Type: "RSA PRIVATE KEY", + Bytes: privKey, + } + privPem := pem.EncodeToMemory(privBlock) + // 导出公钥 + pubKey := &privateKey.PublicKey + derPkix, err := x509.MarshalPKIXPublicKey(pubKey) + if err != nil { + return "", "", err + } + // 将公钥转换为PEM编码 + var pubBlock = &pem.Block{ + Type: "PUBLIC KEY", + Bytes: derPkix, + } + pubPem := pem.EncodeToMemory(pubBlock) + pri := strings.Replace(string(privPem), "-----BEGIN RSA PRIVATE KEY-----\n", "", -1) + pri = strings.Replace(pri, "\n-----END RSA PRIVATE KEY-----\n", "", -1) + pri = strings.Replace(pri, "\n", "", -1) + pub := strings.Replace(string(pubPem), "-----BEGIN PUBLIC KEY-----\n", "", -1) + pub = strings.Replace(pub, "\n-----END PUBLIC KEY-----\n", "", -1) + pub = strings.Replace(pub, "\n", "", -1) + return pub, pri, nil +} diff --git a/internal/pkg/cmb/encrypt/encrypt_way/rsa/rsa_test.go b/internal/pkg/cmb/encrypt/encrypt_way/rsa/rsa_test.go new file mode 100644 index 0000000..c489424 --- /dev/null +++ b/internal/pkg/cmb/encrypt/encrypt_way/rsa/rsa_test.go @@ -0,0 +1,63 @@ +package rsa + +import ( + "encoding/base64" + "fmt" + "physicalGoods/pkg/encrypt/encrypt_way/aes" + "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 := "pPnAPy7v2SY9Fu0LFcQH8UBA6VQ2FCfSg3nRZdMXS7mWjBwlacKHuFnh9UhobL7mxnmMyZPP100bpjCg2kvcfOpOp3ci85p+OYWINt4Fh3qgEOTG5FUyziaagGLm882t/I36KsDTVvbMZvC5sg4gZ9JQ5yAR+nuJfr0IxI0se/iD5luV1rms1kZHggd30iXdZtbkbX7xJ4xtnIiJmZU7kL+Xmvv1rDdPLxbol65QfnM1me1IHkXJapqSBnhEEmFQyBx31vp1ccNjkza8ZWbvTPCngc1k4kvlm6lKfwsG4hMuSdXUzveDm+Oo8StAKnyVoerJ202n7Vfx1XhehineQT0TPD7bO0HCEsDXXYEWwvcax8VdzYvHk7qSbH6e154qCr4LgDRSHKwAAExinTrzxx2rtSimieBLaEpDL2v5ch45HnhjRhWTRmM61W1g6sdHaVX1mQxaXvrT4v+h+f4TbIV4r4qeGJ6rXG+yKRoYseLzyGgystoOny9P0UH15W8rWPytV2eioWT7i3Cglg04BWP9mst67LQXeFH4CA6CkwVV2w9nCHrzxX2ouYSQELUEkTlIMry2AlkZubUnupGJLmLLUyZj7pM/6cLjyAgm02/gRc4wwf7JBBq/ipmKXpkhHXWLtQDWJEZTT+ug2v9EXy5dgPNPe8ZI0MILAeipjIc=" + privateKeyPEM := `-----BEGIN RSA PRIVATE KEY----- +` + PRI + ` +-----END RSA PRIVATE KEY-----` + res, err := Decrypt(privateKeyPEM, data) + fmt.Println(string(res), err) +} + +func encrypt() string { + data := "{\"pay_channel_id\":8935141660703064070,\"out_trade_no\":\"refundOutTreadNo001\",\"amount\":1,\"desc\":\"退款\",\"ext_json\":\"\",\"app_id\":5476377146882523138,\"timestamp\":53612533412643,\"refund_out_trade_no\":\"asdadasdas\"}" + pub := `-----BEGIN PUBLIC KEY----- +` + PUB + ` +-----END PUBLIC KEY-----` + en, err := Encrypt(pub, data) + if err != nil { + panic(err) + } + + return base64.StdEncoding.EncodeToString(en) +} + +func encryptWithAes() string { + data := "{\"pay_channel_id\":8935141660703064070,\"out_trade_no\":\"refundOutTreadNo001\",\"amount\":1,\"desc\":\"退款\",\"ext_json\":\"\",\"app_id\":5476377146882523138,\"timestamp\":53612533412643,\"refund_out_trade_no\":\"asdadasdas\"}" + aes.Encrypt([]byte(data), []byte(aes.TestKey)) + + dataJson := base64.StdEncoding.EncodeToString([]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) +} + +// 测试生成密钥对 +func TestGenerateRSAKey(t *testing.T) { + pub, pri, _ := GenerateKey() + + fmt.Println("pub:", pub, "\n", "pri:", pri) +} diff --git a/internal/pkg/cmb/encrypt/encrypt_way/sm2/sm2.go b/internal/pkg/cmb/encrypt/encrypt_way/sm2/sm2.go new file mode 100644 index 0000000..6f9d745 --- /dev/null +++ b/internal/pkg/cmb/encrypt/encrypt_way/sm2/sm2.go @@ -0,0 +1,167 @@ +package sm2 + +import ( + "crypto/rand" + "encoding/base64" + "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 { + + return "", "", err + } + 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生成的公私钥完全互通使用) +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 SM2Decrypt(cipherText, publicKey string, privateKey string) (string, error) { + if cipherText == "" { + return "", nil + } + decodedBytes, err := base64.StdEncoding.DecodeString(cipherText) + if err != nil { + + return "", nil + } + decrypt, err := decryptLoc(publicKey, privateKey, string(decodedBytes)) + if err != nil { + return "", err + } + return decrypt, nil +} + +func SM2Encrypt(cipherText string, privateKey string) (string, error) { + if cipherText == "" { + return "", nil + } + decrypt, err := encryptLoc(privateKey, cipherText) + if err != nil { + return "", err + } + return decrypt, nil +} + +func encryptLoc(publicKeyStr, data string) (string, error) { + publicKeyObj, err := StringToPublicKey(publicKeyStr) + if err != nil { + return "", err + } + decrypt, err := sm2.Encrypt(publicKeyObj, []byte(data), rand.Reader, sm2.C1C2C3) + if err != nil { + return "", err + } + resultStr := hex.EncodeToString(decrypt) + return base64.StdEncoding.EncodeToString([]byte(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) + 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 +} diff --git a/internal/pkg/cmb/encrypt/encrypt_way/sm2/sm2_test.go b/internal/pkg/cmb/encrypt/encrypt_way/sm2/sm2_test.go new file mode 100644 index 0000000..b21b431 --- /dev/null +++ b/internal/pkg/cmb/encrypt/encrypt_way/sm2/sm2_test.go @@ -0,0 +1,68 @@ +package sm2 + +import ( + "fmt" + "testing" +) + +const ( + SELF_PRI = "cde43bc462e2ffad2d6fda08e975bee59d673c33591fcbf1aa181d4cb9d89314" + + SELF_PUB = "04B5A21130C6BCE5B161C33B182D4E9E84F366C28660F515AC1DB3278E2B55C5CB62765A56144049997D6AE5F75D70750EA1C621D3D9599558E8847B55A90856B2" + + SOA_PUB = "0416445bc16cbf42e47002ad9fe7c7af67d902b48be1eb69b98f6a006b0918630e1127f5f2fff83b2ecb30fc7fd72c34c33f37c7c355dffde3589f66800f0036ca" +) + +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\n", publicKey) + + data := "{\"name\":\"张三\",\"sex\":1,\"is_human\":true}" + en, err := SM2Encrypt(data, publicKey) + if err != nil { + panic(err) + } + + decrypt, err := SM2Decrypt(en, publicKey, privateKey) + if err != nil { + panic(err) + } + t.Log(decrypt) + +} + +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 TestSM2Decrypt2(t *testing.T) { + en := "BOZcpvnFxHrqyzqpq6w3aiTv0KZ5VvLMQnT9sZDxBpMY2hjOrDmwiRau+5QB6iV8ghNZZQKivzUU3I6sfIBSqvRtmtK8nGepQsqi+OCq3uNyMnzWOXkW2Ft9kbt4n4AusCeLLJJGTwS0cmoURiWpdrpr+sNk5wW3+crw9Yo4Xv5UIhyFYtYS8vyEb57Z|YNtjSKBan8/cAxfTgirq7EqLxSdFkEpht/BDp2wW56BCg+4eTmUZo7/YDtUe2MIoAJpSRoI8RwqzrZ3B1V5rOxGopycEwZ/nrrcUkGN6pNE=" + decrypt, err := SM2Decrypt(en, SELF_PUB, SELF_PRI) + if err != nil { + panic(err) + } + t.Log(decrypt) +} + +func encrypt() string { + data := "funmallGetOrderList.json?aid=AppFunmallTestSM&cmbKeyAlias=CO_PUB_KEY_SM2&date=20241106105348&encryptBody=TURRNU5HWXpPV015WXpNMU1HRTVNMlV4TkRnNE1XTTNPVGhsWlRjMk1qUXhNamhoWkRVeU5UQmtPVFEyWVRjMk56VXpNemt3TkdVeE5XVTVObUUxTmpFNU1XWXdPVFJpT1RoaFlURmhNemMzTWpNMVlqTTVaRGd3WmpZNFl6ZzVZVE15TUdKaFpESXdaVEJsWlRnNE1qTTBNelZrWlRBNE5tVTVNR0poTWpZeE5qUmhOakprWm1ZeFpHRTBaV0UyTmpJNU1ESmlObUUwTWpGa056UTRZVGhtTkRkbE4yUTJNek15TVRVellUSXlOREV5WWpKaE9HRTBNVEUwWXpoaFltVTROalpoTVdZM00yRmlNall4WW1abVptRXpNakExTmpVMU0yWmpZamN4WVRBellqVXdZakl3TXpabU4ySTVNR1V3WlRCbFl6VmpNVE0wTURFelkyTXpaRGd4TVdZeU9HTXhOemszTVRrM1pqVmpZell6TjJVeFltUTFOakEzTnpsbE5tVTROemxoWlRsaE0yUTRNREUxWVdGbU5qWTJORFJrT0ROalptVTJaamsy|lGeghQQEGiVwd0oINhKJDvEIhI6Qbvh41G5x9CseXApghhHGJ98TOd2B8UUCo6uJ4bvmDhl6lMhq1Uy2FvZfkF1WQ8cG2H2EwDLUtsF7CEY=&keyAlias=SM2_CMBLIFE&mid=MerchFunmallTestSM&random=ziy1gctmame68wz4hdr3xc0vmvmhnf35" + + en, err := SM2Encrypt(data, SELF_PUB) + if err != nil { + panic(err) + } + return en +} diff --git a/internal/pkg/cmb/encrypt/encrypt_way/sm4/internal/sm2/p256.go b/internal/pkg/cmb/encrypt/encrypt_way/sm4/internal/sm2/p256.go new file mode 100644 index 0000000..1ad2712 --- /dev/null +++ b/internal/pkg/cmb/encrypt/encrypt_way/sm4/internal/sm2/p256.go @@ -0,0 +1,1157 @@ +/* +Copyright Suzhou Tongji Fintech Research Institute 2017 All Rights Reserved. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package sm2 + +import ( + "crypto/elliptic" + "math/big" + "sync" +) + +type sm2P256Curve struct { + RInverse *big.Int + *elliptic.CurveParams + a, b, gx, gy sm2P256FieldElement +} + +var initonce sync.Once +var sm2P256 sm2P256Curve + +type sm2P256FieldElement [9]uint32 +type sm2P256LargeFieldElement [17]uint64 + +const ( + bottom28Bits = 0xFFFFFFF + bottom29Bits = 0x1FFFFFFF +) + +func initP256Sm2() { + sm2P256.CurveParams = &elliptic.CurveParams{Name: "SM2-P-256"} // sm2 + A, _ := new(big.Int).SetString("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC", 16) + //SM2椭 椭 圆 曲 线 公 钥 密 码 算 法 推 荐 曲 线 参 数 + sm2P256.P, _ = new(big.Int).SetString("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF", 16) + sm2P256.N, _ = new(big.Int).SetString("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123", 16) + sm2P256.B, _ = new(big.Int).SetString("28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93", 16) + sm2P256.Gx, _ = new(big.Int).SetString("32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7", 16) + sm2P256.Gy, _ = new(big.Int).SetString("BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0", 16) + sm2P256.RInverse, _ = new(big.Int).SetString("7ffffffd80000002fffffffe000000017ffffffe800000037ffffffc80000002", 16) + sm2P256.BitSize = 256 + sm2P256FromBig(&sm2P256.a, A) + sm2P256FromBig(&sm2P256.gx, sm2P256.Gx) + sm2P256FromBig(&sm2P256.gy, sm2P256.Gy) + sm2P256FromBig(&sm2P256.b, sm2P256.B) +} + +func P256Sm2() elliptic.Curve { + initonce.Do(initP256Sm2) + return sm2P256 +} + +func (curve sm2P256Curve) Params() *elliptic.CurveParams { + return sm2P256.CurveParams +} + +// y^2 = x^3 + ax + b +func (curve sm2P256Curve) IsOnCurve(X, Y *big.Int) bool { + var a, x, y, y2, x3 sm2P256FieldElement + + sm2P256FromBig(&x, X) + sm2P256FromBig(&y, Y) + + sm2P256Square(&x3, &x) // x3 = x ^ 2 + sm2P256Mul(&x3, &x3, &x) // x3 = x ^ 2 * x + sm2P256Mul(&a, &curve.a, &x) // a = a * x + sm2P256Add(&x3, &x3, &a) + sm2P256Add(&x3, &x3, &curve.b) + + sm2P256Square(&y2, &y) // y2 = y ^ 2 + return sm2P256ToBig(&x3).Cmp(sm2P256ToBig(&y2)) == 0 +} + +func zForAffine(x, y *big.Int) *big.Int { + z := new(big.Int) + if x.Sign() != 0 || y.Sign() != 0 { + z.SetInt64(1) + } + return z +} + +func (curve sm2P256Curve) Add(x1, y1, x2, y2 *big.Int) (*big.Int, *big.Int) { + var X1, Y1, Z1, X2, Y2, Z2, X3, Y3, Z3 sm2P256FieldElement + + z1 := zForAffine(x1, y1) + z2 := zForAffine(x2, y2) + sm2P256FromBig(&X1, x1) + sm2P256FromBig(&Y1, y1) + sm2P256FromBig(&Z1, z1) + sm2P256FromBig(&X2, x2) + sm2P256FromBig(&Y2, y2) + sm2P256FromBig(&Z2, z2) + sm2P256PointAdd(&X1, &Y1, &Z1, &X2, &Y2, &Z2, &X3, &Y3, &Z3) + return sm2P256ToAffine(&X3, &Y3, &Z3) +} + +func (curve sm2P256Curve) Double(x1, y1 *big.Int) (*big.Int, *big.Int) { + var X1, Y1, Z1 sm2P256FieldElement + + z1 := zForAffine(x1, y1) + sm2P256FromBig(&X1, x1) + sm2P256FromBig(&Y1, y1) + sm2P256FromBig(&Z1, z1) + sm2P256PointDouble(&X1, &Y1, &Z1, &X1, &Y1, &Z1) + return sm2P256ToAffine(&X1, &Y1, &Z1) +} + +func (curve sm2P256Curve) ScalarMult(x1, y1 *big.Int, k []byte) (*big.Int, *big.Int) { + var X, Y, Z, X1, Y1 sm2P256FieldElement + sm2P256FromBig(&X1, x1) + sm2P256FromBig(&Y1, y1) + scalar := sm2GenrateWNaf(k) + scalarReversed := WNafReversed(scalar) + sm2P256ScalarMult(&X, &Y, &Z, &X1, &Y1, scalarReversed) + return sm2P256ToAffine(&X, &Y, &Z) +} + +func (curve sm2P256Curve) ScalarBaseMult(k []byte) (*big.Int, *big.Int) { + var scalarReversed [32]byte + var X, Y, Z sm2P256FieldElement + + sm2P256GetScalar(&scalarReversed, k) + sm2P256ScalarBaseMult(&X, &Y, &Z, &scalarReversed) + return sm2P256ToAffine(&X, &Y, &Z) +} + +var sm2P256Precomputed = [9 * 2 * 15 * 2]uint32{ + 0x830053d, 0x328990f, 0x6c04fe1, 0xc0f72e5, 0x1e19f3c, 0x666b093, 0x175a87b, 0xec38276, 0x222cf4b, + 0x185a1bba, 0x354e593, 0x1295fac1, 0xf2bc469, 0x47c60fa, 0xc19b8a9, 0xf63533e, 0x903ae6b, 0xc79acba, + 0x15b061a4, 0x33e020b, 0xdffb34b, 0xfcf2c8, 0x16582e08, 0x262f203, 0xfb34381, 0xa55452, 0x604f0ff, + 0x41f1f90, 0xd64ced2, 0xee377bf, 0x75f05f0, 0x189467ae, 0xe2244e, 0x1e7700e8, 0x3fbc464, 0x9612d2e, + 0x1341b3b8, 0xee84e23, 0x1edfa5b4, 0x14e6030, 0x19e87be9, 0x92f533c, 0x1665d96c, 0x226653e, 0xa238d3e, + 0xf5c62c, 0x95bb7a, 0x1f0e5a41, 0x28789c3, 0x1f251d23, 0x8726609, 0xe918910, 0x8096848, 0xf63d028, + 0x152296a1, 0x9f561a8, 0x14d376fb, 0x898788a, 0x61a95fb, 0xa59466d, 0x159a003d, 0x1ad1698, 0x93cca08, + 0x1b314662, 0x706e006, 0x11ce1e30, 0x97b710, 0x172fbc0d, 0x8f50158, 0x11c7ffe7, 0xd182cce, 0xc6ad9e8, + 0x12ea31b2, 0xc4e4f38, 0x175b0d96, 0xec06337, 0x75a9c12, 0xb001fdf, 0x93e82f5, 0x34607de, 0xb8035ed, + 0x17f97924, 0x75cf9e6, 0xdceaedd, 0x2529924, 0x1a10c5ff, 0xb1a54dc, 0x19464d8, 0x2d1997, 0xde6a110, + 0x1e276ee5, 0x95c510c, 0x1aca7c7a, 0xfe48aca, 0x121ad4d9, 0xe4132c6, 0x8239b9d, 0x40ea9cd, 0x816c7b, + 0x632d7a4, 0xa679813, 0x5911fcf, 0x82b0f7c, 0x57b0ad5, 0xbef65, 0xd541365, 0x7f9921f, 0xc62e7a, + 0x3f4b32d, 0x58e50e1, 0x6427aed, 0xdcdda67, 0xe8c2d3e, 0x6aa54a4, 0x18df4c35, 0x49a6a8e, 0x3cd3d0c, + 0xd7adf2, 0xcbca97, 0x1bda5f2d, 0x3258579, 0x606b1e6, 0x6fc1b5b, 0x1ac27317, 0x503ca16, 0xa677435, + 0x57bc73, 0x3992a42, 0xbab987b, 0xfab25eb, 0x128912a4, 0x90a1dc4, 0x1402d591, 0x9ffbcfc, 0xaa48856, + 0x7a7c2dc, 0xcefd08a, 0x1b29bda6, 0xa785641, 0x16462d8c, 0x76241b7, 0x79b6c3b, 0x204ae18, 0xf41212b, + 0x1f567a4d, 0xd6ce6db, 0xedf1784, 0x111df34, 0x85d7955, 0x55fc189, 0x1b7ae265, 0xf9281ac, 0xded7740, + 0xf19468b, 0x83763bb, 0x8ff7234, 0x3da7df8, 0x9590ac3, 0xdc96f2a, 0x16e44896, 0x7931009, 0x99d5acc, + 0x10f7b842, 0xaef5e84, 0xc0310d7, 0xdebac2c, 0x2a7b137, 0x4342344, 0x19633649, 0x3a10624, 0x4b4cb56, + 0x1d809c59, 0xac007f, 0x1f0f4bcd, 0xa1ab06e, 0xc5042cf, 0x82c0c77, 0x76c7563, 0x22c30f3, 0x3bf1568, + 0x7a895be, 0xfcca554, 0x12e90e4c, 0x7b4ab5f, 0x13aeb76b, 0x5887e2c, 0x1d7fe1e3, 0x908c8e3, 0x95800ee, + 0xb36bd54, 0xf08905d, 0x4e73ae8, 0xf5a7e48, 0xa67cb0, 0x50e1067, 0x1b944a0a, 0xf29c83a, 0xb23cfb9, + 0xbe1db1, 0x54de6e8, 0xd4707f2, 0x8ebcc2d, 0x2c77056, 0x1568ce4, 0x15fcc849, 0x4069712, 0xe2ed85f, + 0x2c5ff09, 0x42a6929, 0x628e7ea, 0xbd5b355, 0xaf0bd79, 0xaa03699, 0xdb99816, 0x4379cef, 0x81d57b, + 0x11237f01, 0xe2a820b, 0xfd53b95, 0x6beb5ee, 0x1aeb790c, 0xe470d53, 0x2c2cfee, 0x1c1d8d8, 0xa520fc4, + 0x1518e034, 0xa584dd4, 0x29e572b, 0xd4594fc, 0x141a8f6f, 0x8dfccf3, 0x5d20ba3, 0x2eb60c3, 0x9f16eb0, + 0x11cec356, 0xf039f84, 0x1b0990c1, 0xc91e526, 0x10b65bae, 0xf0616e8, 0x173fa3ff, 0xec8ccf9, 0xbe32790, + 0x11da3e79, 0xe2f35c7, 0x908875c, 0xdacf7bd, 0x538c165, 0x8d1487f, 0x7c31aed, 0x21af228, 0x7e1689d, + 0xdfc23ca, 0x24f15dc, 0x25ef3c4, 0x35248cd, 0x99a0f43, 0xa4b6ecc, 0xd066b3, 0x2481152, 0x37a7688, + 0x15a444b6, 0xb62300c, 0x4b841b, 0xa655e79, 0xd53226d, 0xbeb348a, 0x127f3c2, 0xb989247, 0x71a277d, + 0x19e9dfcb, 0xb8f92d0, 0xe2d226c, 0x390a8b0, 0x183cc462, 0x7bd8167, 0x1f32a552, 0x5e02db4, 0xa146ee9, + 0x1a003957, 0x1c95f61, 0x1eeec155, 0x26f811f, 0xf9596ba, 0x3082bfb, 0x96df083, 0x3e3a289, 0x7e2d8be, + 0x157a63e0, 0x99b8941, 0x1da7d345, 0xcc6cd0, 0x10beed9a, 0x48e83c0, 0x13aa2e25, 0x7cad710, 0x4029988, + 0x13dfa9dd, 0xb94f884, 0x1f4adfef, 0xb88543, 0x16f5f8dc, 0xa6a67f4, 0x14e274e2, 0x5e56cf4, 0x2f24ef, + 0x1e9ef967, 0xfe09bad, 0xfe079b3, 0xcc0ae9e, 0xb3edf6d, 0x3e961bc, 0x130d7831, 0x31043d6, 0xba986f9, + 0x1d28055, 0x65240ca, 0x4971fa3, 0x81b17f8, 0x11ec34a5, 0x8366ddc, 0x1471809, 0xfa5f1c6, 0xc911e15, + 0x8849491, 0xcf4c2e2, 0x14471b91, 0x39f75be, 0x445c21e, 0xf1585e9, 0x72cc11f, 0x4c79f0c, 0xe5522e1, + 0x1874c1ee, 0x4444211, 0x7914884, 0x3d1b133, 0x25ba3c, 0x4194f65, 0x1c0457ef, 0xac4899d, 0xe1fa66c, + 0x130a7918, 0x9b8d312, 0x4b1c5c8, 0x61ccac3, 0x18c8aa6f, 0xe93cb0a, 0xdccb12c, 0xde10825, 0x969737d, + 0xf58c0c3, 0x7cee6a9, 0xc2c329a, 0xc7f9ed9, 0x107b3981, 0x696a40e, 0x152847ff, 0x4d88754, 0xb141f47, + 0x5a16ffe, 0x3a7870a, 0x18667659, 0x3b72b03, 0xb1c9435, 0x9285394, 0xa00005a, 0x37506c, 0x2edc0bb, + 0x19afe392, 0xeb39cac, 0x177ef286, 0xdf87197, 0x19f844ed, 0x31fe8, 0x15f9bfd, 0x80dbec, 0x342e96e, + 0x497aced, 0xe88e909, 0x1f5fa9ba, 0x530a6ee, 0x1ef4e3f1, 0x69ffd12, 0x583006d, 0x2ecc9b1, 0x362db70, + 0x18c7bdc5, 0xf4bb3c5, 0x1c90b957, 0xf067c09, 0x9768f2b, 0xf73566a, 0x1939a900, 0x198c38a, 0x202a2a1, + 0x4bbf5a6, 0x4e265bc, 0x1f44b6e7, 0x185ca49, 0xa39e81b, 0x24aff5b, 0x4acc9c2, 0x638bdd3, 0xb65b2a8, + 0x6def8be, 0xb94537a, 0x10b81dee, 0xe00ec55, 0x2f2cdf7, 0xc20622d, 0x2d20f36, 0xe03c8c9, 0x898ea76, + 0x8e3921b, 0x8905bff, 0x1e94b6c8, 0xee7ad86, 0x154797f2, 0xa620863, 0x3fbd0d9, 0x1f3caab, 0x30c24bd, + 0x19d3892f, 0x59c17a2, 0x1ab4b0ae, 0xf8714ee, 0x90c4098, 0xa9c800d, 0x1910236b, 0xea808d3, 0x9ae2f31, + 0x1a15ad64, 0xa48c8d1, 0x184635a4, 0xb725ef1, 0x11921dcc, 0x3f866df, 0x16c27568, 0xbdf580a, 0xb08f55c, + 0x186ee1c, 0xb1627fa, 0x34e82f6, 0x933837e, 0xf311be5, 0xfedb03b, 0x167f72cd, 0xa5469c0, 0x9c82531, + 0xb92a24b, 0x14fdc8b, 0x141980d1, 0xbdc3a49, 0x7e02bb1, 0xaf4e6dd, 0x106d99e1, 0xd4616fc, 0x93c2717, + 0x1c0a0507, 0xc6d5fed, 0x9a03d8b, 0xa1d22b0, 0x127853e3, 0xc4ac6b8, 0x1a048cf7, 0x9afb72c, 0x65d485d, + 0x72d5998, 0xe9fa744, 0xe49e82c, 0x253cf80, 0x5f777ce, 0xa3799a5, 0x17270cbb, 0xc1d1ef0, 0xdf74977, + 0x114cb859, 0xfa8e037, 0xb8f3fe5, 0xc734cc6, 0x70d3d61, 0xeadac62, 0x12093dd0, 0x9add67d, 0x87200d6, + 0x175bcbb, 0xb29b49f, 0x1806b79c, 0x12fb61f, 0x170b3a10, 0x3aaf1cf, 0xa224085, 0x79d26af, 0x97759e2, + 0x92e19f1, 0xb32714d, 0x1f00d9f1, 0xc728619, 0x9e6f627, 0xe745e24, 0x18ea4ace, 0xfc60a41, 0x125f5b2, + 0xc3cf512, 0x39ed486, 0xf4d15fa, 0xf9167fd, 0x1c1f5dd5, 0xc21a53e, 0x1897930, 0x957a112, 0x21059a0, + 0x1f9e3ddc, 0xa4dfced, 0x8427f6f, 0x726fbe7, 0x1ea658f8, 0x2fdcd4c, 0x17e9b66f, 0xb2e7c2e, 0x39923bf, + 0x1bae104, 0x3973ce5, 0xc6f264c, 0x3511b84, 0x124195d7, 0x11996bd, 0x20be23d, 0xdc437c4, 0x4b4f16b, + 0x11902a0, 0x6c29cc9, 0x1d5ffbe6, 0xdb0b4c7, 0x10144c14, 0x2f2b719, 0x301189, 0x2343336, 0xa0bf2ac, +} + +func sm2P256GetScalar(b *[32]byte, a []byte) { + var scalarBytes []byte + + n := new(big.Int).SetBytes(a) + if n.Cmp(sm2P256.N) >= 0 { + n.Mod(n, sm2P256.N) + scalarBytes = n.Bytes() + } else { + scalarBytes = a + } + for i, v := range scalarBytes { + b[len(scalarBytes)-(1+i)] = v + } +} + +func sm2P256PointAddMixed(xOut, yOut, zOut, x1, y1, z1, x2, y2 *sm2P256FieldElement) { + var z1z1, z1z1z1, s2, u2, h, i, j, r, rr, v, tmp sm2P256FieldElement + + sm2P256Square(&z1z1, z1) + sm2P256Add(&tmp, z1, z1) + + sm2P256Mul(&u2, x2, &z1z1) + sm2P256Mul(&z1z1z1, z1, &z1z1) + sm2P256Mul(&s2, y2, &z1z1z1) + sm2P256Sub(&h, &u2, x1) + sm2P256Add(&i, &h, &h) + sm2P256Square(&i, &i) + sm2P256Mul(&j, &h, &i) + sm2P256Sub(&r, &s2, y1) + sm2P256Add(&r, &r, &r) + sm2P256Mul(&v, x1, &i) + + sm2P256Mul(zOut, &tmp, &h) + sm2P256Square(&rr, &r) + sm2P256Sub(xOut, &rr, &j) + sm2P256Sub(xOut, xOut, &v) + sm2P256Sub(xOut, xOut, &v) + + sm2P256Sub(&tmp, &v, xOut) + sm2P256Mul(yOut, &tmp, &r) + sm2P256Mul(&tmp, y1, &j) + sm2P256Sub(yOut, yOut, &tmp) + sm2P256Sub(yOut, yOut, &tmp) +} + +// sm2P256CopyConditional sets out=in if mask = 0xffffffff in constant time. +// +// On entry: mask is either 0 or 0xffffffff. +func sm2P256CopyConditional(out, in *sm2P256FieldElement, mask uint32) { + for i := 0; i < 9; i++ { + tmp := mask & (in[i] ^ out[i]) + out[i] ^= tmp + } +} + +// sm2P256SelectAffinePoint sets {out_x,out_y} to the index'th entry of table. +// On entry: index < 16, table[0] must be zero. +func sm2P256SelectAffinePoint(xOut, yOut *sm2P256FieldElement, table []uint32, index uint32) { + for i := range xOut { + xOut[i] = 0 + } + for i := range yOut { + yOut[i] = 0 + } + + for i := uint32(1); i < 16; i++ { + mask := i ^ index + mask |= mask >> 2 + mask |= mask >> 1 + mask &= 1 + mask-- + for j := range xOut { + xOut[j] |= table[0] & mask + table = table[1:] + } + for j := range yOut { + yOut[j] |= table[0] & mask + table = table[1:] + } + } +} + +// sm2P256SelectJacobianPoint sets {out_x,out_y,out_z} to the index'th entry of +// table. +// On entry: index < 16, table[0] must be zero. +func sm2P256SelectJacobianPoint(xOut, yOut, zOut *sm2P256FieldElement, table *[16][3]sm2P256FieldElement, index uint32) { + for i := range xOut { + xOut[i] = 0 + } + for i := range yOut { + yOut[i] = 0 + } + for i := range zOut { + zOut[i] = 0 + } + + // The implicit value at index 0 is all zero. We don't need to perform that + // iteration of the loop because we already set out_* to zero. + for i := uint32(1); i < 16; i++ { + mask := i ^ index + mask |= mask >> 2 + mask |= mask >> 1 + mask &= 1 + mask-- + for j := range xOut { + xOut[j] |= table[i][0][j] & mask + } + for j := range yOut { + yOut[j] |= table[i][1][j] & mask + } + for j := range zOut { + zOut[j] |= table[i][2][j] & mask + } + } +} + +// sm2P256GetBit returns the bit'th bit of scalar. +func sm2P256GetBit(scalar *[32]uint8, bit uint) uint32 { + return uint32(((scalar[bit>>3]) >> (bit & 7)) & 1) +} + +// sm2P256ScalarBaseMult sets {xOut,yOut,zOut} = scalar*G where scalar is a +// little-endian number. Note that the value of scalar must be less than the +// order of the group. +func sm2P256ScalarBaseMult(xOut, yOut, zOut *sm2P256FieldElement, scalar *[32]uint8) { + nIsInfinityMask := ^uint32(0) + var px, py, tx, ty, tz sm2P256FieldElement + var pIsNoninfiniteMask, mask, tableOffset uint32 + + for i := range xOut { + xOut[i] = 0 + } + for i := range yOut { + yOut[i] = 0 + } + for i := range zOut { + zOut[i] = 0 + } + + // The loop adds bits at positions 0, 64, 128 and 192, followed by + // positions 32,96,160 and 224 and does this 32 times. + for i := uint(0); i < 32; i++ { + if i != 0 { + sm2P256PointDouble(xOut, yOut, zOut, xOut, yOut, zOut) + } + tableOffset = 0 + for j := uint(0); j <= 32; j += 32 { + bit0 := sm2P256GetBit(scalar, 31-i+j) + bit1 := sm2P256GetBit(scalar, 95-i+j) + bit2 := sm2P256GetBit(scalar, 159-i+j) + bit3 := sm2P256GetBit(scalar, 223-i+j) + index := bit0 | (bit1 << 1) | (bit2 << 2) | (bit3 << 3) + + sm2P256SelectAffinePoint(&px, &py, sm2P256Precomputed[tableOffset:], index) + tableOffset += 30 * 9 + + // Since scalar is less than the order of the group, we know that + // {xOut,yOut,zOut} != {px,py,1}, unless both are zero, which we handle + // below. + sm2P256PointAddMixed(&tx, &ty, &tz, xOut, yOut, zOut, &px, &py) + // The result of pointAddMixed is incorrect if {xOut,yOut,zOut} is zero + // (a.k.a. the point at infinity). We handle that situation by + // copying the point from the table. + sm2P256CopyConditional(xOut, &px, nIsInfinityMask) + sm2P256CopyConditional(yOut, &py, nIsInfinityMask) + sm2P256CopyConditional(zOut, &sm2P256Factor[1], nIsInfinityMask) + + // Equally, the result is also wrong if the point from the table is + // zero, which happens when the index is zero. We handle that by + // only copying from {tx,ty,tz} to {xOut,yOut,zOut} if index != 0. + pIsNoninfiniteMask = nonZeroToAllOnes(index) + mask = pIsNoninfiniteMask & ^nIsInfinityMask + sm2P256CopyConditional(xOut, &tx, mask) + sm2P256CopyConditional(yOut, &ty, mask) + sm2P256CopyConditional(zOut, &tz, mask) + // If p was not zero, then n is now non-zero. + nIsInfinityMask &^= pIsNoninfiniteMask + } + } +} + +func sm2P256PointToAffine(xOut, yOut, x, y, z *sm2P256FieldElement) { + var zInv, zInvSq sm2P256FieldElement + + zz := sm2P256ToBig(z) + zz.ModInverse(zz, sm2P256.P) + sm2P256FromBig(&zInv, zz) + + sm2P256Square(&zInvSq, &zInv) + sm2P256Mul(xOut, x, &zInvSq) + sm2P256Mul(&zInv, &zInv, &zInvSq) + sm2P256Mul(yOut, y, &zInv) +} + +func sm2P256ToAffine(x, y, z *sm2P256FieldElement) (xOut, yOut *big.Int) { + var xx, yy sm2P256FieldElement + + sm2P256PointToAffine(&xx, &yy, x, y, z) + return sm2P256ToBig(&xx), sm2P256ToBig(&yy) +} + +var sm2P256Factor = []sm2P256FieldElement{ + sm2P256FieldElement{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, + sm2P256FieldElement{0x2, 0x0, 0x1FFFFF00, 0x7FF, 0x0, 0x0, 0x0, 0x2000000, 0x0}, + sm2P256FieldElement{0x4, 0x0, 0x1FFFFE00, 0xFFF, 0x0, 0x0, 0x0, 0x4000000, 0x0}, + sm2P256FieldElement{0x6, 0x0, 0x1FFFFD00, 0x17FF, 0x0, 0x0, 0x0, 0x6000000, 0x0}, + sm2P256FieldElement{0x8, 0x0, 0x1FFFFC00, 0x1FFF, 0x0, 0x0, 0x0, 0x8000000, 0x0}, + sm2P256FieldElement{0xA, 0x0, 0x1FFFFB00, 0x27FF, 0x0, 0x0, 0x0, 0xA000000, 0x0}, + sm2P256FieldElement{0xC, 0x0, 0x1FFFFA00, 0x2FFF, 0x0, 0x0, 0x0, 0xC000000, 0x0}, + sm2P256FieldElement{0xE, 0x0, 0x1FFFF900, 0x37FF, 0x0, 0x0, 0x0, 0xE000000, 0x0}, + sm2P256FieldElement{0x10, 0x0, 0x1FFFF800, 0x3FFF, 0x0, 0x0, 0x0, 0x0, 0x01}, +} + +func sm2P256Scalar(b *sm2P256FieldElement, a int) { + sm2P256Mul(b, b, &sm2P256Factor[a]) +} + +// (x3, y3, z3) = (x1, y1, z1) + (x2, y2, z2) +func sm2P256PointAdd(x1, y1, z1, x2, y2, z2, x3, y3, z3 *sm2P256FieldElement) { + var u1, u2, z22, z12, z23, z13, s1, s2, h, h2, r, r2, tm sm2P256FieldElement + + if sm2P256ToBig(z1).Sign() == 0 { + sm2P256Dup(x3, x2) + sm2P256Dup(y3, y2) + sm2P256Dup(z3, z2) + return + } + + if sm2P256ToBig(z2).Sign() == 0 { + sm2P256Dup(x3, x1) + sm2P256Dup(y3, y1) + sm2P256Dup(z3, z1) + return + } + + sm2P256Square(&z12, z1) // z12 = z1 ^ 2 + sm2P256Square(&z22, z2) // z22 = z2 ^ 2 + + sm2P256Mul(&z13, &z12, z1) // z13 = z1 ^ 3 + sm2P256Mul(&z23, &z22, z2) // z23 = z2 ^ 3 + + sm2P256Mul(&u1, x1, &z22) // u1 = x1 * z2 ^ 2 + sm2P256Mul(&u2, x2, &z12) // u2 = x2 * z1 ^ 2 + + sm2P256Mul(&s1, y1, &z23) // s1 = y1 * z2 ^ 3 + sm2P256Mul(&s2, y2, &z13) // s2 = y2 * z1 ^ 3 + + if sm2P256ToBig(&u1).Cmp(sm2P256ToBig(&u2)) == 0 && + sm2P256ToBig(&s1).Cmp(sm2P256ToBig(&s2)) == 0 { + sm2P256PointDouble(x1, y1, z1, x1, y1, z1) + } + + sm2P256Sub(&h, &u2, &u1) // h = u2 - u1 + sm2P256Sub(&r, &s2, &s1) // r = s2 - s1 + + sm2P256Square(&r2, &r) // r2 = r ^ 2 + sm2P256Square(&h2, &h) // h2 = h ^ 2 + + sm2P256Mul(&tm, &h2, &h) // tm = h ^ 3 + sm2P256Sub(x3, &r2, &tm) + sm2P256Mul(&tm, &u1, &h2) + sm2P256Scalar(&tm, 2) // tm = 2 * (u1 * h ^ 2) + sm2P256Sub(x3, x3, &tm) // x3 = r ^ 2 - h ^ 3 - 2 * u1 * h ^ 2 + + sm2P256Mul(&tm, &u1, &h2) // tm = u1 * h ^ 2 + sm2P256Sub(&tm, &tm, x3) // tm = u1 * h ^ 2 - x3 + sm2P256Mul(y3, &r, &tm) + sm2P256Mul(&tm, &h2, &h) // tm = h ^ 3 + sm2P256Mul(&tm, &tm, &s1) // tm = s1 * h ^ 3 + sm2P256Sub(y3, y3, &tm) // y3 = r * (u1 * h ^ 2 - x3) - s1 * h ^ 3 + + sm2P256Mul(z3, z1, z2) + sm2P256Mul(z3, z3, &h) // z3 = z1 * z3 * h +} + +// (x3, y3, z3) = (x1, y1, z1)- (x2, y2, z2) +func sm2P256PointSub(x1, y1, z1, x2, y2, z2, x3, y3, z3 *sm2P256FieldElement) { + var u1, u2, z22, z12, z23, z13, s1, s2, h, h2, r, r2, tm sm2P256FieldElement + y := sm2P256ToBig(y2) + zero := new(big.Int).SetInt64(0) + y.Sub(zero, y) + sm2P256FromBig(y2, y) + + if sm2P256ToBig(z1).Sign() == 0 { + sm2P256Dup(x3, x2) + sm2P256Dup(y3, y2) + sm2P256Dup(z3, z2) + return + } + + if sm2P256ToBig(z2).Sign() == 0 { + sm2P256Dup(x3, x1) + sm2P256Dup(y3, y1) + sm2P256Dup(z3, z1) + return + } + + sm2P256Square(&z12, z1) // z12 = z1 ^ 2 + sm2P256Square(&z22, z2) // z22 = z2 ^ 2 + + sm2P256Mul(&z13, &z12, z1) // z13 = z1 ^ 3 + sm2P256Mul(&z23, &z22, z2) // z23 = z2 ^ 3 + + sm2P256Mul(&u1, x1, &z22) // u1 = x1 * z2 ^ 2 + sm2P256Mul(&u2, x2, &z12) // u2 = x2 * z1 ^ 2 + + sm2P256Mul(&s1, y1, &z23) // s1 = y1 * z2 ^ 3 + sm2P256Mul(&s2, y2, &z13) // s2 = y2 * z1 ^ 3 + + if sm2P256ToBig(&u1).Cmp(sm2P256ToBig(&u2)) == 0 && + sm2P256ToBig(&s1).Cmp(sm2P256ToBig(&s2)) == 0 { + sm2P256PointDouble(x1, y1, z1, x1, y1, z1) + } + + sm2P256Sub(&h, &u2, &u1) // h = u2 - u1 + sm2P256Sub(&r, &s2, &s1) // r = s2 - s1 + + sm2P256Square(&r2, &r) // r2 = r ^ 2 + sm2P256Square(&h2, &h) // h2 = h ^ 2 + + sm2P256Mul(&tm, &h2, &h) // tm = h ^ 3 + sm2P256Sub(x3, &r2, &tm) + sm2P256Mul(&tm, &u1, &h2) + sm2P256Scalar(&tm, 2) // tm = 2 * (u1 * h ^ 2) + sm2P256Sub(x3, x3, &tm) // x3 = r ^ 2 - h ^ 3 - 2 * u1 * h ^ 2 + + sm2P256Mul(&tm, &u1, &h2) // tm = u1 * h ^ 2 + sm2P256Sub(&tm, &tm, x3) // tm = u1 * h ^ 2 - x3 + sm2P256Mul(y3, &r, &tm) + sm2P256Mul(&tm, &h2, &h) // tm = h ^ 3 + sm2P256Mul(&tm, &tm, &s1) // tm = s1 * h ^ 3 + sm2P256Sub(y3, y3, &tm) // y3 = r * (u1 * h ^ 2 - x3) - s1 * h ^ 3 + + sm2P256Mul(z3, z1, z2) + sm2P256Mul(z3, z3, &h) // z3 = z1 * z3 * h +} + +func sm2P256PointDouble(x3, y3, z3, x, y, z *sm2P256FieldElement) { + var s, m, m2, x2, y2, z2, z4, y4, az4 sm2P256FieldElement + + sm2P256Square(&x2, x) // x2 = x ^ 2 + sm2P256Square(&y2, y) // y2 = y ^ 2 + sm2P256Square(&z2, z) // z2 = z ^ 2 + + sm2P256Square(&z4, z) // z4 = z ^ 2 + sm2P256Mul(&z4, &z4, z) // z4 = z ^ 3 + sm2P256Mul(&z4, &z4, z) // z4 = z ^ 4 + + sm2P256Square(&y4, y) // y4 = y ^ 2 + sm2P256Mul(&y4, &y4, y) // y4 = y ^ 3 + sm2P256Mul(&y4, &y4, y) // y4 = y ^ 4 + sm2P256Scalar(&y4, 8) // y4 = 8 * y ^ 4 + + sm2P256Mul(&s, x, &y2) + sm2P256Scalar(&s, 4) // s = 4 * x * y ^ 2 + + sm2P256Dup(&m, &x2) + sm2P256Scalar(&m, 3) + sm2P256Mul(&az4, &sm2P256.a, &z4) + sm2P256Add(&m, &m, &az4) // m = 3 * x ^ 2 + a * z ^ 4 + + sm2P256Square(&m2, &m) // m2 = m ^ 2 + + sm2P256Add(z3, y, z) + sm2P256Square(z3, z3) + sm2P256Sub(z3, z3, &z2) + sm2P256Sub(z3, z3, &y2) // z' = (y + z) ^2 - z ^ 2 - y ^ 2 + + sm2P256Sub(x3, &m2, &s) + sm2P256Sub(x3, x3, &s) // x' = m2 - 2 * s + + sm2P256Sub(y3, &s, x3) + sm2P256Mul(y3, y3, &m) + sm2P256Sub(y3, y3, &y4) // y' = m * (s - x') - 8 * y ^ 4 +} + +// p256Zero31 is 0 mod p. +var sm2P256Zero31 = sm2P256FieldElement{0x7FFFFFF8, 0x3FFFFFFC, 0x800003FC, 0x3FFFDFFC, 0x7FFFFFFC, 0x3FFFFFFC, 0x7FFFFFFC, 0x37FFFFFC, 0x7FFFFFFC} + +// c = a + b +func sm2P256Add(c, a, b *sm2P256FieldElement) { + carry := uint32(0) + for i := 0; ; i++ { + c[i] = a[i] + b[i] + c[i] += carry + carry = c[i] >> 29 + c[i] &= bottom29Bits + i++ + if i == 9 { + break + } + c[i] = a[i] + b[i] + c[i] += carry + carry = c[i] >> 28 + c[i] &= bottom28Bits + } + sm2P256ReduceCarry(c, carry) +} + +// c = a - b +func sm2P256Sub(c, a, b *sm2P256FieldElement) { + var carry uint32 + + for i := 0; ; i++ { + c[i] = a[i] - b[i] + c[i] += sm2P256Zero31[i] + c[i] += carry + carry = c[i] >> 29 + c[i] &= bottom29Bits + i++ + if i == 9 { + break + } + c[i] = a[i] - b[i] + c[i] += sm2P256Zero31[i] + c[i] += carry + carry = c[i] >> 28 + c[i] &= bottom28Bits + } + sm2P256ReduceCarry(c, carry) +} + +// c = a * b +func sm2P256Mul(c, a, b *sm2P256FieldElement) { + var tmp sm2P256LargeFieldElement + + tmp[0] = uint64(a[0]) * uint64(b[0]) + tmp[1] = uint64(a[0])*(uint64(b[1])<<0) + + uint64(a[1])*(uint64(b[0])<<0) + tmp[2] = uint64(a[0])*(uint64(b[2])<<0) + + uint64(a[1])*(uint64(b[1])<<1) + + uint64(a[2])*(uint64(b[0])<<0) + tmp[3] = uint64(a[0])*(uint64(b[3])<<0) + + uint64(a[1])*(uint64(b[2])<<0) + + uint64(a[2])*(uint64(b[1])<<0) + + uint64(a[3])*(uint64(b[0])<<0) + tmp[4] = uint64(a[0])*(uint64(b[4])<<0) + + uint64(a[1])*(uint64(b[3])<<1) + + uint64(a[2])*(uint64(b[2])<<0) + + uint64(a[3])*(uint64(b[1])<<1) + + uint64(a[4])*(uint64(b[0])<<0) + tmp[5] = uint64(a[0])*(uint64(b[5])<<0) + + uint64(a[1])*(uint64(b[4])<<0) + + uint64(a[2])*(uint64(b[3])<<0) + + uint64(a[3])*(uint64(b[2])<<0) + + uint64(a[4])*(uint64(b[1])<<0) + + uint64(a[5])*(uint64(b[0])<<0) + tmp[6] = uint64(a[0])*(uint64(b[6])<<0) + + uint64(a[1])*(uint64(b[5])<<1) + + uint64(a[2])*(uint64(b[4])<<0) + + uint64(a[3])*(uint64(b[3])<<1) + + uint64(a[4])*(uint64(b[2])<<0) + + uint64(a[5])*(uint64(b[1])<<1) + + uint64(a[6])*(uint64(b[0])<<0) + tmp[7] = uint64(a[0])*(uint64(b[7])<<0) + + uint64(a[1])*(uint64(b[6])<<0) + + uint64(a[2])*(uint64(b[5])<<0) + + uint64(a[3])*(uint64(b[4])<<0) + + uint64(a[4])*(uint64(b[3])<<0) + + uint64(a[5])*(uint64(b[2])<<0) + + uint64(a[6])*(uint64(b[1])<<0) + + uint64(a[7])*(uint64(b[0])<<0) + // tmp[8] has the greatest value but doesn't overflow. See logic in + // p256Square. + tmp[8] = uint64(a[0])*(uint64(b[8])<<0) + + uint64(a[1])*(uint64(b[7])<<1) + + uint64(a[2])*(uint64(b[6])<<0) + + uint64(a[3])*(uint64(b[5])<<1) + + uint64(a[4])*(uint64(b[4])<<0) + + uint64(a[5])*(uint64(b[3])<<1) + + uint64(a[6])*(uint64(b[2])<<0) + + uint64(a[7])*(uint64(b[1])<<1) + + uint64(a[8])*(uint64(b[0])<<0) + tmp[9] = uint64(a[1])*(uint64(b[8])<<0) + + uint64(a[2])*(uint64(b[7])<<0) + + uint64(a[3])*(uint64(b[6])<<0) + + uint64(a[4])*(uint64(b[5])<<0) + + uint64(a[5])*(uint64(b[4])<<0) + + uint64(a[6])*(uint64(b[3])<<0) + + uint64(a[7])*(uint64(b[2])<<0) + + uint64(a[8])*(uint64(b[1])<<0) + tmp[10] = uint64(a[2])*(uint64(b[8])<<0) + + uint64(a[3])*(uint64(b[7])<<1) + + uint64(a[4])*(uint64(b[6])<<0) + + uint64(a[5])*(uint64(b[5])<<1) + + uint64(a[6])*(uint64(b[4])<<0) + + uint64(a[7])*(uint64(b[3])<<1) + + uint64(a[8])*(uint64(b[2])<<0) + tmp[11] = uint64(a[3])*(uint64(b[8])<<0) + + uint64(a[4])*(uint64(b[7])<<0) + + uint64(a[5])*(uint64(b[6])<<0) + + uint64(a[6])*(uint64(b[5])<<0) + + uint64(a[7])*(uint64(b[4])<<0) + + uint64(a[8])*(uint64(b[3])<<0) + tmp[12] = uint64(a[4])*(uint64(b[8])<<0) + + uint64(a[5])*(uint64(b[7])<<1) + + uint64(a[6])*(uint64(b[6])<<0) + + uint64(a[7])*(uint64(b[5])<<1) + + uint64(a[8])*(uint64(b[4])<<0) + tmp[13] = uint64(a[5])*(uint64(b[8])<<0) + + uint64(a[6])*(uint64(b[7])<<0) + + uint64(a[7])*(uint64(b[6])<<0) + + uint64(a[8])*(uint64(b[5])<<0) + tmp[14] = uint64(a[6])*(uint64(b[8])<<0) + + uint64(a[7])*(uint64(b[7])<<1) + + uint64(a[8])*(uint64(b[6])<<0) + tmp[15] = uint64(a[7])*(uint64(b[8])<<0) + + uint64(a[8])*(uint64(b[7])<<0) + tmp[16] = uint64(a[8]) * (uint64(b[8]) << 0) + sm2P256ReduceDegree(c, &tmp) +} + +// b = a * a +func sm2P256Square(b, a *sm2P256FieldElement) { + var tmp sm2P256LargeFieldElement + + tmp[0] = uint64(a[0]) * uint64(a[0]) + tmp[1] = uint64(a[0]) * (uint64(a[1]) << 1) + tmp[2] = uint64(a[0])*(uint64(a[2])<<1) + + uint64(a[1])*(uint64(a[1])<<1) + tmp[3] = uint64(a[0])*(uint64(a[3])<<1) + + uint64(a[1])*(uint64(a[2])<<1) + tmp[4] = uint64(a[0])*(uint64(a[4])<<1) + + uint64(a[1])*(uint64(a[3])<<2) + + uint64(a[2])*uint64(a[2]) + tmp[5] = uint64(a[0])*(uint64(a[5])<<1) + + uint64(a[1])*(uint64(a[4])<<1) + + uint64(a[2])*(uint64(a[3])<<1) + tmp[6] = uint64(a[0])*(uint64(a[6])<<1) + + uint64(a[1])*(uint64(a[5])<<2) + + uint64(a[2])*(uint64(a[4])<<1) + + uint64(a[3])*(uint64(a[3])<<1) + tmp[7] = uint64(a[0])*(uint64(a[7])<<1) + + uint64(a[1])*(uint64(a[6])<<1) + + uint64(a[2])*(uint64(a[5])<<1) + + uint64(a[3])*(uint64(a[4])<<1) + // tmp[8] has the greatest value of 2**61 + 2**60 + 2**61 + 2**60 + 2**60, + // which is < 2**64 as required. + tmp[8] = uint64(a[0])*(uint64(a[8])<<1) + + uint64(a[1])*(uint64(a[7])<<2) + + uint64(a[2])*(uint64(a[6])<<1) + + uint64(a[3])*(uint64(a[5])<<2) + + uint64(a[4])*uint64(a[4]) + tmp[9] = uint64(a[1])*(uint64(a[8])<<1) + + uint64(a[2])*(uint64(a[7])<<1) + + uint64(a[3])*(uint64(a[6])<<1) + + uint64(a[4])*(uint64(a[5])<<1) + tmp[10] = uint64(a[2])*(uint64(a[8])<<1) + + uint64(a[3])*(uint64(a[7])<<2) + + uint64(a[4])*(uint64(a[6])<<1) + + uint64(a[5])*(uint64(a[5])<<1) + tmp[11] = uint64(a[3])*(uint64(a[8])<<1) + + uint64(a[4])*(uint64(a[7])<<1) + + uint64(a[5])*(uint64(a[6])<<1) + tmp[12] = uint64(a[4])*(uint64(a[8])<<1) + + uint64(a[5])*(uint64(a[7])<<2) + + uint64(a[6])*uint64(a[6]) + tmp[13] = uint64(a[5])*(uint64(a[8])<<1) + + uint64(a[6])*(uint64(a[7])<<1) + tmp[14] = uint64(a[6])*(uint64(a[8])<<1) + + uint64(a[7])*(uint64(a[7])<<1) + tmp[15] = uint64(a[7]) * (uint64(a[8]) << 1) + tmp[16] = uint64(a[8]) * uint64(a[8]) + sm2P256ReduceDegree(b, &tmp) +} + +// nonZeroToAllOnes returns: +// +// 0xffffffff for 0 < x <= 2**31 +// 0 for x == 0 or x > 2**31. +func nonZeroToAllOnes(x uint32) uint32 { + return ((x - 1) >> 31) - 1 +} + +var sm2P256Carry = [8 * 9]uint32{ + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x2, 0x0, 0x1FFFFF00, 0x7FF, 0x0, 0x0, 0x0, 0x2000000, 0x0, + 0x4, 0x0, 0x1FFFFE00, 0xFFF, 0x0, 0x0, 0x0, 0x4000000, 0x0, + 0x6, 0x0, 0x1FFFFD00, 0x17FF, 0x0, 0x0, 0x0, 0x6000000, 0x0, + 0x8, 0x0, 0x1FFFFC00, 0x1FFF, 0x0, 0x0, 0x0, 0x8000000, 0x0, + 0xA, 0x0, 0x1FFFFB00, 0x27FF, 0x0, 0x0, 0x0, 0xA000000, 0x0, + 0xC, 0x0, 0x1FFFFA00, 0x2FFF, 0x0, 0x0, 0x0, 0xC000000, 0x0, + 0xE, 0x0, 0x1FFFF900, 0x37FF, 0x0, 0x0, 0x0, 0xE000000, 0x0, +} + +// carry < 2 ^ 3 +func sm2P256ReduceCarry(a *sm2P256FieldElement, carry uint32) { + a[0] += sm2P256Carry[carry*9+0] + a[2] += sm2P256Carry[carry*9+2] + a[3] += sm2P256Carry[carry*9+3] + a[7] += sm2P256Carry[carry*9+7] +} + +func sm2P256ReduceDegree(a *sm2P256FieldElement, b *sm2P256LargeFieldElement) { + var tmp [18]uint32 + var carry, x, xMask uint32 + + // tmp + // 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 ... + // 29 | 28 | 29 | 28 | 29 | 28 | 29 | 28 | 29 | 28 | 29 ... + tmp[0] = uint32(b[0]) & bottom29Bits + tmp[1] = uint32(b[0]) >> 29 + tmp[1] |= (uint32(b[0]>>32) << 3) & bottom28Bits + tmp[1] += uint32(b[1]) & bottom28Bits + carry = tmp[1] >> 28 + tmp[1] &= bottom28Bits + for i := 2; i < 17; i++ { + tmp[i] = (uint32(b[i-2] >> 32)) >> 25 + tmp[i] += (uint32(b[i-1])) >> 28 + tmp[i] += (uint32(b[i-1]>>32) << 4) & bottom29Bits + tmp[i] += uint32(b[i]) & bottom29Bits + tmp[i] += carry + carry = tmp[i] >> 29 + tmp[i] &= bottom29Bits + + i++ + if i == 17 { + break + } + tmp[i] = uint32(b[i-2]>>32) >> 25 + tmp[i] += uint32(b[i-1]) >> 29 + tmp[i] += ((uint32(b[i-1] >> 32)) << 3) & bottom28Bits + tmp[i] += uint32(b[i]) & bottom28Bits + tmp[i] += carry + carry = tmp[i] >> 28 + tmp[i] &= bottom28Bits + } + tmp[17] = uint32(b[15]>>32) >> 25 + tmp[17] += uint32(b[16]) >> 29 + tmp[17] += uint32(b[16]>>32) << 3 + tmp[17] += carry + + for i := 0; ; i += 2 { + + tmp[i+1] += tmp[i] >> 29 + x = tmp[i] & bottom29Bits + tmp[i] = 0 + if x > 0 { + set4 := uint32(0) + set7 := uint32(0) + xMask = nonZeroToAllOnes(x) + tmp[i+2] += (x << 7) & bottom29Bits + tmp[i+3] += x >> 22 + if tmp[i+3] < 0x10000000 { + set4 = 1 + tmp[i+3] += 0x10000000 & xMask + tmp[i+3] -= (x << 10) & bottom28Bits + } else { + tmp[i+3] -= (x << 10) & bottom28Bits + } + if tmp[i+4] < 0x20000000 { + tmp[i+4] += 0x20000000 & xMask + tmp[i+4] -= set4 // 借位 + tmp[i+4] -= x >> 18 + if tmp[i+5] < 0x10000000 { + tmp[i+5] += 0x10000000 & xMask + tmp[i+5] -= 1 // 借位 + if tmp[i+6] < 0x20000000 { + set7 = 1 + tmp[i+6] += 0x20000000 & xMask + tmp[i+6] -= 1 // 借位 + } else { + tmp[i+6] -= 1 // 借位 + } + } else { + tmp[i+5] -= 1 + } + } else { + tmp[i+4] -= set4 // 借位 + tmp[i+4] -= x >> 18 + } + if tmp[i+7] < 0x10000000 { + tmp[i+7] += 0x10000000 & xMask + tmp[i+7] -= set7 + tmp[i+7] -= (x << 24) & bottom28Bits + tmp[i+8] += (x << 28) & bottom29Bits + if tmp[i+8] < 0x20000000 { + tmp[i+8] += 0x20000000 & xMask + tmp[i+8] -= 1 + tmp[i+8] -= x >> 4 + tmp[i+9] += ((x >> 1) - 1) & xMask + } else { + tmp[i+8] -= 1 + tmp[i+8] -= x >> 4 + tmp[i+9] += (x >> 1) & xMask + } + } else { + tmp[i+7] -= set7 // 借位 + tmp[i+7] -= (x << 24) & bottom28Bits + tmp[i+8] += (x << 28) & bottom29Bits + if tmp[i+8] < 0x20000000 { + tmp[i+8] += 0x20000000 & xMask + tmp[i+8] -= x >> 4 + tmp[i+9] += ((x >> 1) - 1) & xMask + } else { + tmp[i+8] -= x >> 4 + tmp[i+9] += (x >> 1) & xMask + } + } + + } + + if i+1 == 9 { + break + } + + tmp[i+2] += tmp[i+1] >> 28 + x = tmp[i+1] & bottom28Bits + tmp[i+1] = 0 + if x > 0 { + set5 := uint32(0) + set8 := uint32(0) + set9 := uint32(0) + xMask = nonZeroToAllOnes(x) + tmp[i+3] += (x << 7) & bottom28Bits + tmp[i+4] += x >> 21 + if tmp[i+4] < 0x20000000 { + set5 = 1 + tmp[i+4] += 0x20000000 & xMask + tmp[i+4] -= (x << 11) & bottom29Bits + } else { + tmp[i+4] -= (x << 11) & bottom29Bits + } + if tmp[i+5] < 0x10000000 { + tmp[i+5] += 0x10000000 & xMask + tmp[i+5] -= set5 // 借位 + tmp[i+5] -= x >> 18 + if tmp[i+6] < 0x20000000 { + tmp[i+6] += 0x20000000 & xMask + tmp[i+6] -= 1 // 借位 + if tmp[i+7] < 0x10000000 { + set8 = 1 + tmp[i+7] += 0x10000000 & xMask + tmp[i+7] -= 1 // 借位 + } else { + tmp[i+7] -= 1 // 借位 + } + } else { + tmp[i+6] -= 1 // 借位 + } + } else { + tmp[i+5] -= set5 // 借位 + tmp[i+5] -= x >> 18 + } + if tmp[i+8] < 0x20000000 { + set9 = 1 + tmp[i+8] += 0x20000000 & xMask + tmp[i+8] -= set8 + tmp[i+8] -= (x << 25) & bottom29Bits + } else { + tmp[i+8] -= set8 + tmp[i+8] -= (x << 25) & bottom29Bits + } + if tmp[i+9] < 0x10000000 { + tmp[i+9] += 0x10000000 & xMask + tmp[i+9] -= set9 // 借位 + tmp[i+9] -= x >> 4 + tmp[i+10] += (x - 1) & xMask + } else { + tmp[i+9] -= set9 // 借位 + tmp[i+9] -= x >> 4 + tmp[i+10] += x & xMask + } + } + } + + carry = uint32(0) + for i := 0; i < 8; i++ { + a[i] = tmp[i+9] + a[i] += carry + a[i] += (tmp[i+10] << 28) & bottom29Bits + carry = a[i] >> 29 + a[i] &= bottom29Bits + + i++ + a[i] = tmp[i+9] >> 1 + a[i] += carry + carry = a[i] >> 28 + a[i] &= bottom28Bits + } + a[8] = tmp[17] + a[8] += carry + carry = a[8] >> 29 + a[8] &= bottom29Bits + sm2P256ReduceCarry(a, carry) +} + +// b = a +func sm2P256Dup(b, a *sm2P256FieldElement) { + *b = *a +} + +// X = a * R mod P +func sm2P256FromBig(X *sm2P256FieldElement, a *big.Int) { + x := new(big.Int).Lsh(a, 257) + x.Mod(x, sm2P256.P) + for i := 0; i < 9; i++ { + if bits := x.Bits(); len(bits) > 0 { + X[i] = uint32(bits[0]) & bottom29Bits + } else { + X[i] = 0 + } + x.Rsh(x, 29) + i++ + if i == 9 { + break + } + if bits := x.Bits(); len(bits) > 0 { + X[i] = uint32(bits[0]) & bottom28Bits + } else { + X[i] = 0 + } + x.Rsh(x, 28) + } +} + +// X = r * R mod P +// r = X * R' mod P +func sm2P256ToBig(X *sm2P256FieldElement) *big.Int { + r, tm := new(big.Int), new(big.Int) + r.SetInt64(int64(X[8])) + for i := 7; i >= 0; i-- { + if (i & 1) == 0 { + r.Lsh(r, 29) + } else { + r.Lsh(r, 28) + } + tm.SetInt64(int64(X[i])) + r.Add(r, tm) + } + r.Mul(r, sm2P256.RInverse) + r.Mod(r, sm2P256.P) + return r +} +func WNafReversed(wnaf []int8) []int8 { + wnafRev := make([]int8, len(wnaf), len(wnaf)) + for i, v := range wnaf { + wnafRev[len(wnaf)-(1+i)] = v + } + return wnafRev +} +func sm2GenrateWNaf(b []byte) []int8 { + n := new(big.Int).SetBytes(b) + var k *big.Int + if n.Cmp(sm2P256.N) >= 0 { + n.Mod(n, sm2P256.N) + k = n + } else { + k = n + } + wnaf := make([]int8, k.BitLen()+1, k.BitLen()+1) + if k.Sign() == 0 { + return wnaf + } + var width, pow2, sign int + width, pow2, sign = 4, 16, 8 + var mask int64 = 15 + var carry bool + var length, pos int + for pos <= k.BitLen() { + if k.Bit(pos) == boolToUint(carry) { + pos++ + continue + } + k.Rsh(k, uint(pos)) + var digit int + digit = int(k.Int64() & mask) + if carry { + digit++ + } + carry = (digit & sign) != 0 + if carry { + digit -= pow2 + } + length += pos + wnaf[length] = int8(digit) + pos = int(width) + } + if len(wnaf) > length+1 { + t := make([]int8, length+1, length+1) + copy(t, wnaf[0:length+1]) + wnaf = t + } + return wnaf +} +func boolToUint(b bool) uint { + if b { + return 1 + } + return 0 +} +func abs(a int8) uint32 { + if a < 0 { + return uint32(-a) + } + return uint32(a) +} + +func sm2P256ScalarMult(xOut, yOut, zOut, x, y *sm2P256FieldElement, scalar []int8) { + var precomp [16][3]sm2P256FieldElement + var px, py, pz, tx, ty, tz sm2P256FieldElement + var nIsInfinityMask, index, pIsNoninfiniteMask, mask uint32 + + // We precompute 0,1,2,... times {x,y}. + precomp[1][0] = *x + precomp[1][1] = *y + precomp[1][2] = sm2P256Factor[1] + + for i := 2; i < 8; i += 2 { + sm2P256PointDouble(&precomp[i][0], &precomp[i][1], &precomp[i][2], &precomp[i/2][0], &precomp[i/2][1], &precomp[i/2][2]) + sm2P256PointAddMixed(&precomp[i+1][0], &precomp[i+1][1], &precomp[i+1][2], &precomp[i][0], &precomp[i][1], &precomp[i][2], x, y) + } + + for i := range xOut { + xOut[i] = 0 + } + for i := range yOut { + yOut[i] = 0 + } + for i := range zOut { + zOut[i] = 0 + } + nIsInfinityMask = ^uint32(0) + var zeroes int16 + for i := 0; i < len(scalar); i++ { + if scalar[i] == 0 { + zeroes++ + continue + } + if zeroes > 0 { + for ; zeroes > 0; zeroes-- { + sm2P256PointDouble(xOut, yOut, zOut, xOut, yOut, zOut) + } + } + index = abs(scalar[i]) + sm2P256PointDouble(xOut, yOut, zOut, xOut, yOut, zOut) + sm2P256SelectJacobianPoint(&px, &py, &pz, &precomp, index) + if scalar[i] > 0 { + sm2P256PointAdd(xOut, yOut, zOut, &px, &py, &pz, &tx, &ty, &tz) + } else { + sm2P256PointSub(xOut, yOut, zOut, &px, &py, &pz, &tx, &ty, &tz) + } + sm2P256CopyConditional(xOut, &px, nIsInfinityMask) + sm2P256CopyConditional(yOut, &py, nIsInfinityMask) + sm2P256CopyConditional(zOut, &pz, nIsInfinityMask) + pIsNoninfiniteMask = nonZeroToAllOnes(index) + mask = pIsNoninfiniteMask & ^nIsInfinityMask + sm2P256CopyConditional(xOut, &tx, mask) + sm2P256CopyConditional(yOut, &ty, mask) + sm2P256CopyConditional(zOut, &tz, mask) + nIsInfinityMask &^= pIsNoninfiniteMask + } + if zeroes > 0 { + for ; zeroes > 0; zeroes-- { + sm2P256PointDouble(xOut, yOut, zOut, xOut, yOut, zOut) + } + } +} diff --git a/internal/pkg/cmb/encrypt/encrypt_way/sm4/internal/sm2/sm2.go b/internal/pkg/cmb/encrypt/encrypt_way/sm4/internal/sm2/sm2.go new file mode 100644 index 0000000..32d907e --- /dev/null +++ b/internal/pkg/cmb/encrypt/encrypt_way/sm4/internal/sm2/sm2.go @@ -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 +} diff --git a/internal/pkg/cmb/encrypt/encrypt_way/sm4/internal/sm2/utils.go b/internal/pkg/cmb/encrypt/encrypt_way/sm4/internal/sm2/utils.go new file mode 100644 index 0000000..6b09718 --- /dev/null +++ b/internal/pkg/cmb/encrypt/encrypt_way/sm4/internal/sm2/utils.go @@ -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 +} diff --git a/internal/pkg/cmb/encrypt/encrypt_way/sm4/internal/util/sm2x.go b/internal/pkg/cmb/encrypt/encrypt_way/sm4/internal/util/sm2x.go new file mode 100644 index 0000000..b012f1f --- /dev/null +++ b/internal/pkg/cmb/encrypt/encrypt_way/sm4/internal/util/sm2x.go @@ -0,0 +1,163 @@ +package util + +import ( + "bytes" + "crypto/elliptic" + "crypto/rand" + "errors" + zzsm2 "github.com/ZZMarquis/gm/sm2" + "github.com/tjfoc/gmsm/sm3" + "github.com/tjfoc/gmsm/x509" + "math/big" + "voucher/internal/pkg/cmb/encrypt/encrypt_way/sm4/internal/sm2" +) + +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 +} diff --git a/internal/pkg/cmb/encrypt/encrypt_way/sm4/internal/util/smutil.go b/internal/pkg/cmb/encrypt/encrypt_way/sm4/internal/util/smutil.go new file mode 100644 index 0000000..f0773ff --- /dev/null +++ b/internal/pkg/cmb/encrypt/encrypt_way/sm4/internal/util/smutil.go @@ -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 + } +} diff --git a/internal/pkg/cmb/encrypt/encrypt_way/sm4/sm.go b/internal/pkg/cmb/encrypt/encrypt_way/sm4/sm.go new file mode 100644 index 0000000..f2655ce --- /dev/null +++ b/internal/pkg/cmb/encrypt/encrypt_way/sm4/sm.go @@ -0,0 +1,203 @@ +package sm4 + +import ( + "crypto/rand" + "encoding/base64" + "encoding/hex" + "encoding/json" + "errors" + "fmt" + "github.com/ZZMarquis/gm/sm4" + "math/big" + "strings" + "voucher/internal/pkg/cmb/encrypt/encrypt_way/sm4/internal/sm2" + "voucher/internal/pkg/cmb/encrypt/encrypt_way/sm4/internal/util" +) + +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) +} diff --git a/internal/pkg/cmb/encrypt/encrypt_way/sm4/sm4_test.go b/internal/pkg/cmb/encrypt/encrypt_way/sm4/sm4_test.go new file mode 100644 index 0000000..987fad0 --- /dev/null +++ b/internal/pkg/cmb/encrypt/encrypt_way/sm4/sm4_test.go @@ -0,0 +1,48 @@ +package sm4 + +import ( + "fmt" + "strconv" + "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() + //uid := "1729382256910270475" + //en := "{\"accessToken\":\"77F59F157466F309E703F43CFDCFFECF\",\"encryptKey\":\"04237241E4A465C18645985B3C1DAE987B5DDF1C077AA27D677C843C52E833A24711C63F2512D1A4C37E85A5C9CEAC94156C97460CB5E8966CAD2A0C2596A64ED69CF3306D031C4AADAA73D165FB7EEC34E5AAF532A301169847560329F7F1E40E9FD09EB191976BB49ABFE611E05158EF\",\"request\":\"mkuquQ1RB2AtZYzBtWtLPJ3MMULWj7I5RmK3dKENYVW8OgB//I/+MAD/XnjxYYJlRWM8uL/rWL9o\\r\\n0L7W9fSBvOXWwz8reiwcAF/JZ5dnacZtVe0NPujDfeVIJp+9ua7hxQcegcEsIRS9CQqtF/rJN7M9\\r\\nxxCLSzEiJY8bIdRLBsfmB0uVIE2144s2tH7Q8R2fSOVbiSTH1PW3Ye0kkyCcBw==\",\"signature\":\"ed99a2ce827a4d443e2639ccfb78865e913854e2d61d1746dafb640e19cbb4f8#3793b1cac082d9e1cdfc2b7b8387a8c29e44b2f3fb35b352d02f1b2c9321e0a7\"}" + decrypt, err := Sm4Decrypt(uid, SELF_PRI, PARTY_PUB, en, true) + if err != nil { + panic(err) + } + t.Log(decrypt) +} + +func encrypt() (string, string) { + uid := strconv.FormatInt(int64(5476377146882523149), 10) + data := "{\"pay_channel_id\":1729382256910270476,\"out_trade_no\":\"asdadasdas\",\"order_type\":1,\"amount\":1,\"desc\":\"abc\",\"ext_json\":\"\",\"app_id\":5476377146882523149,\"timestamp\":1723096731}" + en, err := Sm4Encrypt(uid, PARTY_PRI, SELF_PUB, data, "", true) + if err != nil { + panic(err) + } + return uid, en +} diff --git a/internal/pkg/cmb/encrypt/errcode/errcode.go b/internal/pkg/cmb/encrypt/errcode/errcode.go new file mode 100644 index 0000000..76a55fa --- /dev/null +++ b/internal/pkg/cmb/encrypt/errcode/errcode.go @@ -0,0 +1,15 @@ +package errcode + +type EncryptErr struct { + Message string +} + +func (e *EncryptErr) Error() string { + return e.Message +} + +var ( + AppKeyNotFound = &EncryptErr{Message: "资源未找到"} + AppEncryptFail = &EncryptErr{Message: "加密失败"} + AppDecryptFail = &EncryptErr{Message: "解密失败"} +) diff --git a/internal/pkg/cmb/encrypt/pojo/const.go b/internal/pkg/cmb/encrypt/pojo/const.go new file mode 100644 index 0000000..39b38da --- /dev/null +++ b/internal/pkg/cmb/encrypt/pojo/const.go @@ -0,0 +1,8 @@ +package pojo + +const ( + RSA = 1 + SM2 = 2 + SM3 = 4 + SM4 = 3 +) diff --git a/internal/pkg/cmb/encrypt/random_str/encrypt.go b/internal/pkg/cmb/encrypt/random_str/encrypt.go new file mode 100644 index 0000000..4ef00a2 --- /dev/null +++ b/internal/pkg/cmb/encrypt/random_str/encrypt.go @@ -0,0 +1,34 @@ +package encrypt + +import ( + "math/rand" + "unsafe" +) + +const lettersString = "0123456789abcdefghijkmnpqrstuvwxyz" + +/* +16位码,前15位随机字符串,最后一位通过前15位字符串计算校验生成 +*/ + +func LotteryEncryptEncode(number int) string { + b := make([]byte, number) + var sum byte + for i := 0; i < number-1; i++ { + b[i] = lettersString[rand.Int63()%int64(len(lettersString))] + sum += b[i] + } + b[number-1] = lettersString[sum%byte(len(lettersString))] + return *(*string)(unsafe.Pointer(&b)) +} + +func LotteryEncryptDecode(str string) bool { + var sum byte + for i := 0; i < len(str)-1; i++ { + sum += str[i] + } + if lettersString[sum%byte(len(lettersString))] != str[len(str)-1] { + return false + } + return true +} diff --git a/internal/pkg/cmb/encrypt/random_str/encrypt_test.go b/internal/pkg/cmb/encrypt/random_str/encrypt_test.go new file mode 100644 index 0000000..794ad23 --- /dev/null +++ b/internal/pkg/cmb/encrypt/random_str/encrypt_test.go @@ -0,0 +1,15 @@ +package encrypt + +import "testing" + +func TestLotteryEncryptEncode(t *testing.T) { + code := LotteryEncryptEncode(16) + t.Log(code) +} + +func TestLotteryEncryptDecode(t *testing.T) { + code := LotteryEncryptEncode(16) + t.Log(code) + result := LotteryEncryptDecode(code) + t.Log(result) +} diff --git a/internal/pkg/cmb/encrypt/sm2.go b/internal/pkg/cmb/encrypt/sm2.go new file mode 100644 index 0000000..518c207 --- /dev/null +++ b/internal/pkg/cmb/encrypt/sm2.go @@ -0,0 +1,44 @@ +package encrypt + +import ( + "voucher/internal/pkg/cmb/encrypt/encrypt_way/sm2" + "voucher/internal/pkg/cmb/encrypt/errcode" +) + +func NewSm2(app *AppEncrypt) ApiCrypt { + return &SM2{ + App: app, + } +} + +func (r *SM2) Encrypt(data string) (encryptData []byte, err error) { + + if r.App.PrivateKey == "" { + return nil, errcode.AppKeyNotFound + } + + encryptDataString, err := sm2.SM2Encrypt(data, r.App.PrivateKey) + if err != nil { + return nil, errcode.AppEncryptFail + } + encryptData = []byte(encryptDataString) + return +} + +func (r *SM2) Decrypt(encryptData string) (decryptData []byte, err error) { + defer func() { + if e := recover(); e != nil { + err = errcode.AppDecryptFail + } + }() + if r.App.PrivateKey == "" || r.App.PublicKey == "" { + return nil, errcode.AppKeyNotFound + } + + decryptDataString, err := sm2.SM2Decrypt(encryptData, r.App.PublicKey, r.App.PrivateKey) + if err != nil { + return nil, errcode.AppDecryptFail + } + decryptData = []byte(decryptDataString) + return +} diff --git a/internal/pkg/cmb/encrypt/sm2sm3.go b/internal/pkg/cmb/encrypt/sm2sm3.go new file mode 100644 index 0000000..4acd61d --- /dev/null +++ b/internal/pkg/cmb/encrypt/sm2sm3.go @@ -0,0 +1,132 @@ +package encrypt + +import ( + "crypto/ecdsa" + "encoding/base64" + "encoding/hex" + "encoding/pem" + "fmt" + "github.com/emmansun/gmsm/sm2" + "github.com/emmansun/gmsm/smx509" +) + +type KeyType string + +const ( + Raw KeyType = "raw" + Hex = "hex" + Base64 = "base64" + Pem = "pem" +) + +const publicPemFormat = `-----BEGIN PUBLIC KEY----- +%s +-----END PUBLIC KEY-----` + +const privatePemFormat = `-----BEGIN PRIVATE KEY----- +%s +-----END PRIVATE KEY-----` + +func ParsePublicKey(key string, kt KeyType) (*ecdsa.PublicKey, error) { + if len(key) == 0 { + return nil, nil + } + + switch kt { + case Raw: + return sm2.NewPublicKey([]byte(key)) + case Hex: + pubBytes, err := hex.DecodeString(key) + if err != nil { + return nil, err + } + return sm2.NewPublicKey(pubBytes) + case Base64: + pubBytes, err := base64.StdEncoding.DecodeString(key) + if err != nil { + return nil, err + } + return sm2.NewPublicKey(pubBytes) + case Pem: + pubPEM := fmt.Sprintf(publicPemFormat, key) + block, _ := pem.Decode([]byte(pubPEM)) + if block == nil { + return nil, fmt.Errorf("failed to parse PEM block containing the public key") + } + + pub, err := smx509.ParsePKIXPublicKey(block.Bytes) + if err != nil { + return nil, err + } + + if !sm2.IsSM2PublicKey(pub) { + return nil, fmt.Errorf("not a SM2 public key") + } + + if key, ok := pub.(*ecdsa.PublicKey); ok { + return key, nil + } + + return nil, fmt.Errorf("not a valid SM2 public key") + default: + return nil, nil + } +} + +func ParsePrivateKey(key string, kt KeyType) (*sm2.PrivateKey, error) { + if len(key) == 0 { + return nil, nil + } + + switch kt { + case Raw: + return sm2.NewPrivateKey([]byte(key)) + case Hex: + priBytes, err := hex.DecodeString(key) + if err != nil { + return nil, err + } + return sm2.NewPrivateKey(priBytes) + case Base64: + priBytes, err := base64.StdEncoding.DecodeString(key) + if err != nil { + return nil, err + } + return sm2.NewPrivateKey(priBytes) + case Pem: + priPEM := fmt.Sprintf(privatePemFormat, key) + block, _ := pem.Decode([]byte(priPEM)) + if block == nil { + return nil, fmt.Errorf("failed to parse PEM block containing the private key") + } + + pri, err := smx509.ParsePKCS8PrivateKey(block.Bytes) + if err != nil { + return nil, err + } + + if pk, ok := pri.(*sm2.PrivateKey); ok { + return pk, nil + } + return nil, fmt.Errorf("not a valid SM2 private key") + default: + return nil, fmt.Errorf("unsupported key type") + } +} + +func PriToPub(priKey string) (string, error) { + priBytes, err := hex.DecodeString(priKey) + if err != nil { + return "", err + } + priObj, err := sm2.NewPrivateKey(priBytes) + if err != nil { + return "", err + } + + pubBytes, err := smx509.MarshalPKIXPublicKey(&priObj.PublicKey) + if err != nil { + return "", err + } + return hex.EncodeToString(pubBytes), nil +} diff --git a/internal/pkg/cmb/encrypt/sm3.go b/internal/pkg/cmb/encrypt/sm3.go new file mode 100644 index 0000000..adbf1fe --- /dev/null +++ b/internal/pkg/cmb/encrypt/sm3.go @@ -0,0 +1,36 @@ +package encrypt + +import ( + "crypto/rand" + em2 "github.com/emmansun/gmsm/sm2" +) + +// SM3WithSM2Sign SM3WithSM2签名 Hex ToUpper +func SM3WithSM2Sign(key string, data string) ([]byte, error) { + //掌上生活文档是错误的,实际只需要对data进行本身进行签名,而不需要对data的sm3摘要进行签名 + //hashed := sm3.Sm3Sum([]byte(data)) + // 获取私钥 + + //hashed := em3.Sum([]byte(data)) + // 获取私钥 + privateKey, err := ParsePrivateKey(key, Hex) + if err != nil { + return nil, err + } + + signed, err := privateKey.Sign(rand.Reader, []byte(data), em2.DefaultSM2SignerOpts) + return signed, nil +} + +func Sm2Sm3VerySign(data, sign string, pubKey string) (bool, error) { + // 计算hash值 + //hashed := em3.Sum([]byte(data)) + // 获取公钥 + publicKey, err := ParsePublicKey(pubKey, Hex) + if err != nil { + return false, err + } + // 验证签名 + ok := em2.VerifyASN1WithSM2(publicKey, nil, []byte(data), []byte(sign)) + return ok, nil +} diff --git a/internal/pkg/cmb/encrypt/sm4.go b/internal/pkg/cmb/encrypt/sm4.go new file mode 100644 index 0000000..13f1f4a --- /dev/null +++ b/internal/pkg/cmb/encrypt/sm4.go @@ -0,0 +1,43 @@ +package encrypt + +import ( + "voucher/internal/pkg/cmb/encrypt/encrypt_way/sm4" + "voucher/internal/pkg/cmb/encrypt/errcode" +) + +func NewSm4(app *AppEncrypt) ApiCrypt { + return &SM4{ + App: app, + } +} + +func (r *SM4) Encrypt(data string) (encryptData []byte, err error) { + if r.App.MerchantPublicKey == "" || r.App.PrivateKey == "" { + return nil, errcode.AppKeyNotFound + } + encryptDataString, err := sm4.Sm4Encrypt(r.App.UniKEY, r.App.PrivateKey, r.App.MerchantPublicKey, data, "", true) + if err != nil { + return nil, errcode.AppEncryptFail + } + encryptData = []byte(encryptDataString) + return +} + +func (r *SM4) Decrypt(encryptData string) (decryptData []byte, err error) { + defer func() { + if e := recover(); e != nil { + err = errcode.AppDecryptFail + } + }() + if r.App.PrivateKey == "" || r.App.MerchantPublicKey == "" { + return nil, errcode.AppKeyNotFound + } + + decryptDataString, err := sm4.Sm4Decrypt(r.App.UniKEY, r.App.PrivateKey, r.App.MerchantPublicKey, encryptData, true) + if err != nil { + return nil, errcode.AppDecryptFail + } + decryptData = []byte(decryptDataString) + return + +} diff --git a/internal/pkg/cmb/encrypt/types.go b/internal/pkg/cmb/encrypt/types.go new file mode 100644 index 0000000..521b4c8 --- /dev/null +++ b/internal/pkg/cmb/encrypt/types.go @@ -0,0 +1,39 @@ +package encrypt + +import ( + "voucher/internal/pkg/cmb/encrypt/pojo" +) + +type ( + ApiCrypt interface { + Encrypt(data string) (encryptData []byte, err error) + Decrypt(encryptData string) (decryptData []byte, err error) + } + + Rsa struct { + App *AppEncrypt + } + + SM2 struct { + App *AppEncrypt + } + + SM4 struct { + App *AppEncrypt + } + + AppEncrypt struct { + UniKEY string + MerchantPublicKey string + PublicKey string + PrivateKey string + } +) + +var ApiCryptMap = map[int32]func(en *AppEncrypt) ApiCrypt{ + //pojo.RSA: NewRsa, + pojo.SM2: NewSm2, + pojo.SM4: NewSm4, +} + +const CryptNotError = 0 diff --git a/internal/pkg/cmb/sign.go b/internal/pkg/cmb/sign.go new file mode 100644 index 0000000..e206c54 --- /dev/null +++ b/internal/pkg/cmb/sign.go @@ -0,0 +1,136 @@ +package cmb + +import ( + "crypto/cipher" + "crypto/rand" + "encoding/base64" + "fmt" + "github.com/ZZMarquis/gm/util" + tsm2 "github.com/tjfoc/gmsm/sm2" + "github.com/tjfoc/gmsm/sm4" + "github.com/tjfoc/gmsm/x509" + "strings" + "voucher/internal/pkg/cmb/encrypt" +) + +const messageSeparator = byte(0x7C) + +type Decrypts struct { + EncryptBody string + PrivateKey string +} + +type Encrypts struct { + JsonParam string + SoaPubKey string +} + +func EncryptBody(encrypts *Encrypts) (string, error) { + + paddedPlaintext := util.PKCS5Padding([]byte(encrypts.JsonParam), sm4.BlockSize) + //随机生成对称密钥RandomKey和偏移向量RandomIV + randomKey := make([]byte, sm4.BlockSize) + randomIV := make([]byte, sm4.BlockSize) + if _, err := rand.Read(randomKey); err != nil { + return "", fmt.Errorf("生成randomKey失败:%v", err) + } + if _, err := rand.Read(randomIV); err != nil { + return "", fmt.Errorf("生成randomIV失败: %v", err) + } + // 使用对称密钥对报文进行加密,并对结果进行Base64编码 + //对称加密算法为SM4/CBC/PKCS5Padding,密钥长度为16字节,明文长度不做要求,IV长度为16字节。 + block, err := sm4.NewCipher(randomKey) + if err != nil { + return "", fmt.Errorf("IV加密失败: %v", err) + } + ciphertext := make([]byte, len(paddedPlaintext)) + if len(paddedPlaintext)%sm4.BlockSize != 0 { + return "", fmt.Errorf("加密格式错误:%v", err) + } + mode := cipher.NewCBCEncrypter(block, randomIV) + mode.CryptBlocks(ciphertext, paddedPlaintext) + //ciphertext, err := sm4.Sm4Cbc(randomKey, randomIV, util.PKCS5Padding([]byte(encrypts.JsonParam), sm4.BlockSize)) + + ciphertextBase64 := base64.StdEncoding.EncodeToString(ciphertext) + + //使用掌上生活的SM2算法公钥对“RandomKey|RandomIV”进行base64之后加密,并对结果进行Base64编码 + //非对称加密算法为SM2,公钥长度为65字节,私钥长度为32字节。 + keyAndIV := AssemblingByteArray(randomKey, randomIV) + keyAndIVBase64 := base64.StdEncoding.EncodeToString(keyAndIV) + pubk, err := x509.ReadPublicKeyFromHex(encrypts.SoaPubKey) + if err != nil { + return "", fmt.Errorf("解析公钥失败: %v", err) + } + sm2EncryptKeyAndIV, err := tsm2.Encrypt(pubk, []byte(keyAndIVBase64), rand.Reader, tsm2.C1C3C2) + if err != nil { + return "", fmt.Errorf("RandomKey|RandomIV加密失败: %v", err) + } + sm2EncryptKeyAndIVBase64 := base64.StdEncoding.EncodeToString(sm2EncryptKeyAndIV) + + //将加密后的对称密钥以及加密后的报文进行拼接,使用“ | ”进行分割。 + encryptedBody := fmt.Sprintf("%s|%s", sm2EncryptKeyAndIVBase64, ciphertextBase64) + return encryptedBody, nil +} + +func DecryptBody(decrypts *Decrypts) ([]byte, error) { + var ( + EncryptSlice []string + ) + EncryptSlice = strings.Split(decrypts.EncryptBody, "|") + if len(EncryptSlice) != 2 { + return nil, fmt.Errorf("解密失败: 格式错误") + } + sm2EncryptKeyAndIV, err := base64.StdEncoding.DecodeString(EncryptSlice[0]) + if err != nil { + return nil, fmt.Errorf("解密失败:向量格式错误: %v", err) + } + ciphertext, err := base64.StdEncoding.DecodeString(EncryptSlice[1]) + if err != nil { + return nil, fmt.Errorf("解密失败:内容格式错误: %v", err) + } + prik, err := x509.ReadPrivateKeyFromHex(decrypts.PrivateKey) + if err != nil { + return nil, fmt.Errorf("解密失败:密钥错误: %v", err) + } + keyAndIv, err := tsm2.Decrypt(prik, sm2EncryptKeyAndIV, tsm2.C1C3C2) + if err != nil { + return nil, fmt.Errorf("解密失败: %v", err) + } + key, iv, err := Base64DecodeAndSplit(string(keyAndIv)) + if err != nil { + return nil, fmt.Errorf("解密失败:解密后向量格式错误: %v", err) + } + block, err := sm4.NewCipher(key) + if err != nil { + return nil, fmt.Errorf("IV加密失败: %v", err) + } + paddedPlaintext := make([]byte, len(ciphertext)) + mode := cipher.NewCBCDecrypter(block, iv) + mode.CryptBlocks(paddedPlaintext, ciphertext) + res := util.PKCS5UnPadding(paddedPlaintext) + return res, err +} +func VerifyBody(crypt string, signDataBase64 string, pubKey string) (bool, error) { + signByte, _ := base64.StdEncoding.DecodeString(signDataBase64) + return encrypt.Sm2Sm3VerySign(crypt, string(signByte), pubKey) +} + +func SignBody(sign string, privateKey string) (string, error) { + //签名 + signData, err := encrypt.SM3WithSM2Sign(privateKey, sign) + return base64.StdEncoding.EncodeToString(signData), err +} + +func Base64DecodeAndSplit(encoded string) ([]byte, []byte, error) { + // 解码 Base64 字符串 + decodedBytes, err := base64.StdEncoding.DecodeString(encoded) + if err != nil { + return nil, nil, err + } + + // 拆分字节切片 + firstParam := decodedBytes[:sm4.BlockSize] + secondParam := decodedBytes[sm4.BlockSize+1:] // +1 以跳过分隔符本身 + + return firstParam, secondParam, nil +} diff --git a/internal/pkg/cmb/sm2.go b/internal/pkg/cmb/sm2.go index f25bef3..7605bb9 100644 --- a/internal/pkg/cmb/sm2.go +++ b/internal/pkg/cmb/sm2.go @@ -62,6 +62,7 @@ func Encrypt(sopPublicKey, input string) (string, error) { if err != nil { return "", err } + fmt.Println(base64.StdEncoding.EncodeToString([]byte(kvTmp))) return fmt.Sprintf("%s|%s", base64.StdEncoding.EncodeToString([]byte(kvTmp)), base64.StdEncoding.EncodeToString(encryptedBody)), nil } diff --git a/internal/pkg/cmb/sm2/sm2_test.go b/internal/pkg/cmb/sm2/sm2_test.go index 5fc9b5c..d0248ee 100644 --- a/internal/pkg/cmb/sm2/sm2_test.go +++ b/internal/pkg/cmb/sm2/sm2_test.go @@ -1,7 +1,9 @@ package sm2 import ( + "fmt" "testing" + "time" "voucher/internal/pkg/cmb/sm2/model" "voucher/internal/pkg/cmb/sm2/sdk" "voucher/internal/pkg/cmb/sm2/util" @@ -13,6 +15,50 @@ var ( enStr = "BI2O20YuamIpOpXH/RJDtB9gWIpNZPjFbTpbvX45lG8mcma7Cab1yRpE3rcM33oJ8xJ3mbbIvXf/1N507i97eXYQSbLzOBcl/8PyaB4dQ/Ub7QQncN+Npuif4Qp6s11tobdTVOFlz9S9i0VC" ) +func BenchmarkSm2_Encrypt(b *testing.B) { + for j := 0; j < 1000; j++ { + for i := 0; i < 300; i++ { + go func() { + _, err := NewSm2(). + SetHexPublicKey(pubHexKey). + SetStringData(`{"name":"zhangxx","phoneNo":"137xxxxxxxx"}`). + SetSdk(sdk.NewCmbLifeSdk()). + SetCipherType(model.C1C3C2). + Encrypt(). + ToBase64String() + if err != nil { + //("sm2 encrypt error:", err) + return + } + }() + } + time.Sleep(1 * time.Second) + } + + select {} +} + +func BenchmarkSm2_Decrypt(b *testing.B) { + s, err := util.HexToSignature("abd5a608aad610840bd387263c81f8813e7ab4b121cd69f0d69ac4736cc29978d44c47d9bbf497c712e067c320d3e6b8ef70063da284cc957440e36733f0ff81") + if err != nil { + //fmt.Println("hex to signature error: %v", err) + } + + _, err = NewSm2(). + SetUid([]byte("opv22s05zaezfccc")). + SetSignature(model.Signature(s)). + SetHexPublicKey("04c443e81459725ae9979ce44ce8c0e1a45fdf6e884c2fc1e615db02909698b7fdd81fab5404060e2ab849b9e1529397ee4c45ae0d768aebf48d943f953320f78e"). + SetStringData("apiCode=conductor.cashier.queryTransStatus&appId=bolz18v22s05zaezfccc×tamp=2022070417330581653&version=1.0.0"). + Verify(). + ToBool() + if err != nil { + fmt.Println("sm2 verify error:", err) + return + } + + //t.Log("sm2 verify result:", verify) +} + func TestSm2_Encrypt(t *testing.T) { encrypt, err := NewSm2(). SetHexPublicKey(pubHexKey). diff --git a/internal/pkg/cmb/sm2_test.go b/internal/pkg/cmb/sm2_test.go index 0944e0c..0b072ff 100644 --- a/internal/pkg/cmb/sm2_test.go +++ b/internal/pkg/cmb/sm2_test.go @@ -2,6 +2,8 @@ package cmb import ( "encoding/json" + "fmt" + _ "gitea.cdlsxd.cn/self-tools/l_crypt" "testing" v1 "voucher/api/v1" ) @@ -166,3 +168,41 @@ func TestGenerateSm2KeyAndEncryptDecrypt(t *testing.T) { } t.Log(aa) } + +func TestZhEncryptVerify(t *testing.T) { + pukKey := "04838f74275e6f4f2373d4e6e974ac790c10ab6f9c17e273cf0c84848c6838979c158315932e36f0b9444442f145e4671b1ee5d43d5d63913a70d4d0d52cc3c0d6" + + content := "accessToken.json?aid=9dad6d3900ec3ffabd80e46522a10ead&cmbKeyAlias=SM2_CMBLIFE&date=20250305115032&encryptBody=BHeko/ZYFzQOJn6Q3y46X1AjNz8Nh5fq1FfMuWebh+TangLnlK5iFqePCst4rjG/FKJInijiKO2Qq18sJULlMEEgri05s+bHHDKM+Y+73crAbCnIhHbZxUjt8A0cq2rKjzkl8bxW33dU18uuiTEAmsAvKvmZgE6zJ1eDyjFWefHEIFJaKCNY2cTQOInt|8UYFZFTkx0DovPhaWCbdBkAqbgGmegT14F5gwXLJ6G1uWdYNvX+i5QWAYUGtd8u9&keyAlias=CO_PUB_KEY_SM2&mid=f806c259d86e3b9aa956c98d475b6af7&random=286d97b1d8ed4bbf822b004470c92ae8" + signDataBase64 := "MEUCIAg1zxnKG+X8t/hlwEoyL/T33iKgle09S6bfb3eZh/FqAiEAxtK5TdGAo+JpK7JmL15tT4nlQyrUzC14flu0Tq+9Svo=" + + ok, err := VerifyBody(content, signDataBase64, pukKey) + fmt.Println(ok, err) +} +func TestZhEncryptDecrypt(t *testing.T) { + priKey := "f6a8d2f412e289686aba6a0f33cad1a64367d0ba012046ee0fbbefd3ffd675bd" + + //content := "BAdcIauIjNx3LsrplpJiZoljE4hCiGHra6ulhgG1qL0tKcAeenX+Z9VaHfXLSdkji1fYBpdZiiI35R0vFtnXPXJCJdHsGbfbae+PzNznYQS3KM8/90Y/FIWzSoszfUiF6fAuv8I6v9kQuqHUTidHeHyICDoyvJ0nhbNyUyg85bAKd6TmkVX1MgXLQ81m|5KfR/5UkpVBEQv1dx+iJbojOykNRuDV8Gsy3QOIlRI+cZvafRRPUUG6eeixnPMumhOvyZwsSG/OBeg0U/lSlAepg12tXWcQ601wjgyLaKN1iMvb1DCtfnJFAm8EWAc2SLH3NQuyhxGe/jgCXvj0wGphh4vBUzm8la8i8Aij0BI5lfgU5OzglkKDln6zHN3vBHDqOurEh18eU6z1bfvNnDpzdwEcygcEIH/6lGiqVnGH+C2+QpcKeCnj5qKGFiuSC" + //content := "BDUuuPClIlUKDJdpHtNBIU6u5JTetrVG53AfKDSrhah9Q0QZWAj3K5pZF8G/HFtzj/KvbrHfP/gnHri0L7L91HaKYYc1vqy/q8Z69v7MEiIWL2LeLOsc2b0cHmnt7Qey5aZzYVbZJJNhus2gvhahGwOPpPL50JFC8IqAlU4+E/kUBgx+RgzAIkLLs8Se|k1WOt2Eb+xkxSobw/1DaLblguznhnsk1ga87sfqrrPATRuTyszzdVrRtCUuUHRKJ+vQwlZAR1ypkBC1vPMdt8zccI/CeNof+4Ap23enbQwTJQ4KRvij4kbJd6ycY97B+vHnI+oSnwfmjK0EWNUeRrCr2Uau7yxmzlFwJHprbgPZpHVuUjAzMIXNixOfxSTdc9dL+j3/tR7+yookvd9W3hNm96XZFPTheI0FqUKkbKWUUcVs4lC1/yEgjwXFcD4NM" + content := "BDqANzEC9vq82FTu9wR89Ou/8o2J2vD7yeoExb1Uxl2PSA9EsvI7YQNGSkSdxoloqRBn4vIrA8Uh+FmWtJ9wbFEEtbC+Epj8qHWN8S+lH9JEnvJhPhEtMgmHeuGDtvzHMACvc7KoBmJ/6XZIoEyLeRgkJnCTVVxnD78KMJ4eXzj7C2ErkISJ5r3qcL9t|cPw/uy87PW74aeU1RwGwUsYXZlXYkG0m+BoO/3qT4rLSIWsHvBN76yQJlTk89aa9VALdtwcU7H0q7ivCLZ9uflB6YFkg5QRQoj1b2AFFU4TPkpgAdCBAKs5+6z9cwDn+QQyuamKAnp1wJfMj7Ksa3HxLwCxTh/w2dF6LuruLFWZstMK1g9ID7tVTPqc05VNmktmNhc97BYuIH66xa0ZFgr+0i/3hFMx0hNTOau5UWFM6v4Lb1iM/v9ggM5ZvAheUspfgvRUhpD2TZvgyneWxqg==" + + //decryptStr, err := Decrypt(priKey, content) + //if err != nil { + // t.Log(err) + // return + //} + //签名 + rs, err := DecryptBody(&Decrypts{content, priKey}) + + fmt.Println(rs, err) +} + +func TestZhEncryptEncrypt(t *testing.T) { + pukKey := "04a702106cf530dc981e44cd515b394747cfd6bb059247696b188b25281ea4278fe7c6e34a83680110eec71becd31f5db14abc671e5d8e67ce7ca3c6b3adc86674" + content := `{"name":"zhangxx","phoneNo":"137xxxxxxxx"}` + xx, err := Encrypt(pukKey, content) + t.Log(xx, err) + //签名 + rs, err := EncryptBody(&Encrypts{content, pukKey}) + + fmt.Println(rs, err) +} diff --git a/internal/server/http.go b/internal/server/http.go index a499c19..44d72df 100644 --- a/internal/server/http.go +++ b/internal/server/http.go @@ -11,6 +11,7 @@ import ( "github.com/go-kratos/kratos/v2/middleware/recovery" "github.com/go-kratos/kratos/v2/middleware/validate" "github.com/go-kratos/kratos/v2/transport/http" + "github.com/go-kratos/kratos/v2/transport/http/pprof" "github.com/gorilla/handlers" http2 "net/http" v1 "voucher/api/v1" @@ -28,6 +29,7 @@ func NewHTTPServer( ) *http.Server { //构建 server srv := buildHTTPServer(c, accessLogger, log) + srv.Handle("/debug/pprof/", pprof.NewHandler()) srv.Route("/").GET("ping", func(ctx http.Context) error { return ctx.String(http2.StatusOK, "pong") diff --git a/third_party/swagger_ui/openapi.yaml b/third_party/swagger_ui/openapi.yaml index eb8440b..dcbcf7d 100644 --- a/third_party/swagger_ui/openapi.yaml +++ b/third_party/swagger_ui/openapi.yaml @@ -157,9 +157,7 @@ components: properties: transactionId: type: string - description: |- - 业务参数 - 唯一流水号,需支持14天内幂等 + description: "业务参数\r\n 唯一流水号,需支持14天内幂等" activityId: type: string description: 外部合作方权益批次号 @@ -183,25 +181,19 @@ components: properties: activityId: type: string - description: |- - 业务参数 - 外部合作方权益批次号 + description: "业务参数\r\n 外部合作方权益批次号" api.v1.CmbQueryRequest: type: object properties: codeNo: type: string - description: |- - 业务参数 - 外部合作方权益批次号 + description: "业务参数\r\n 外部合作方权益批次号" api.v1.CmbReply: type: object properties: respCode: type: string - description: |- - 响应公共参数 - 接口调用返回码,1000 成功,1001 失败 + description: "响应公共参数\r\n 接口调用返回码,1000 成功,1001 失败" respMsg: type: string description: 返回话术,失败信息落此字段 @@ -225,9 +217,7 @@ components: properties: mid: type: string - description: |- - 请求公共参数 - 合作方唯一ID,32位定长 + description: "请求公共参数\r\n 合作方唯一ID,32位定长" aid: type: string description: 应用唯一ID,32位定长