cmb
This commit is contained in:
parent
a6c258fd29
commit
eecda8daab
3
go.mod
3
go.mod
|
|
@ -3,6 +3,8 @@ module voucher
|
|||
go 1.22.2
|
||||
|
||||
require (
|
||||
codeup.aliyun.com/lsxd/backend_deveoper/gmutil v1.0.2
|
||||
github.com/ZZMarquis/gm v1.3.2
|
||||
github.com/apache/rocketmq-client-go/v2 v2.1.2
|
||||
github.com/brianvoe/gofakeit/v6 v6.28.0
|
||||
github.com/duke-git/lancet/v2 v2.2.8
|
||||
|
|
@ -16,6 +18,7 @@ require (
|
|||
github.com/nacos-group/nacos-sdk-go v1.1.4
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/redis/go-redis/v9 v9.1.0
|
||||
github.com/tjfoc/gmsm v1.4.1
|
||||
github.com/wechatpay-apiv3/wechatpay-go v0.2.20
|
||||
go.opentelemetry.io/otel v1.28.0
|
||||
go.opentelemetry.io/otel/exporters/jaeger v1.17.0
|
||||
|
|
|
|||
43
go.sum
43
go.sum
|
|
@ -1,8 +1,13 @@
|
|||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
codeup.aliyun.com/lsxd/backend_deveoper/gmutil v1.0.2 h1:sw+r1d2JkKbGD8Fj4t5KcdbM2paP0a95AkBCTkMp7ug=
|
||||
codeup.aliyun.com/lsxd/backend_deveoper/gmutil v1.0.2/go.mod h1:WhIG/nkg4pO3u3Hx69fdjI0gvUGU4iVH1SCaKFii51I=
|
||||
dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
|
||||
dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
|
||||
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=
|
||||
github.com/ZZMarquis/gm v1.3.2 h1:lFtpzg5zeeVMZ/gKi0gtYcKLBEo9XTqsZDHDz6s3Gow=
|
||||
github.com/ZZMarquis/gm v1.3.2/go.mod h1:wWbjZYgruQVd7Bb8UkSN8ujU931kx2XUW6nZLCiDE0Q=
|
||||
github.com/agiledragon/gomonkey v2.0.2+incompatible h1:eXKi9/piiC3cjJD1658mEE2o3NjkJ5vDLgYjCQu0Xlw=
|
||||
github.com/agiledragon/gomonkey v2.0.2+incompatible/go.mod h1:2NGfXu1a80LLr2cmWXGBDaHEjb1idR6+FVlX5T3D9hw=
|
||||
github.com/aliyun/alibaba-cloud-sdk-go v1.61.18 h1:zOVTBdCKFd9JbCKz9/nt+FovbjPFmb7mUnp8nH9fQBA=
|
||||
|
|
@ -17,6 +22,7 @@ github.com/bsm/gomega v1.26.0 h1:LhQm+AFcgV2M0WyKroMASzAzCAJVpAxQXv4SaI9a69Y=
|
|||
github.com/bsm/gomega v1.26.0/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=
|
||||
github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs=
|
||||
github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
|
||||
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
|
|
@ -25,6 +31,8 @@ github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5P
|
|||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/clbanning/mxj v1.8.5-0.20200714211355-ff02cfb8ea28 h1:LdXxtjzvZYhhUaonAaAKArG3pyC67kGL3YY+6hGG8G4=
|
||||
github.com/clbanning/mxj v1.8.5-0.20200714211355-ff02cfb8ea28/go.mod h1:BVjHeAH+rl9rs6f+QIpeRl0tfu10SXn1pUSa5PVGJng=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
|
|
@ -35,6 +43,9 @@ 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/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=
|
||||
github.com/envoyproxy/protoc-gen-validate v1.0.4 h1:gVPz/FMfvh57HdSJQyvBtF00j8JU4zdyUgIUNhlgg0A=
|
||||
github.com/envoyproxy/protoc-gen-validate v1.0.4/go.mod h1:qys6tmnRsYrQqIhm2bvKZH4Blx/1gTIZ2UKVY1M+Yew=
|
||||
github.com/fatih/color v1.12.0 h1:mRhaKNwANqRgUBGKmnI5ZxEk7QXmjQeCcuYFMX2bfcc=
|
||||
|
|
@ -79,9 +90,13 @@ github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg78
|
|||
github.com/gogf/gf v1.16.9 h1:Q803UmmRo59+Ws08sMVFOcd8oNpkSWL9vS33hlo/Cyk=
|
||||
github.com/gogf/gf v1.16.9/go.mod h1:8Q/kw05nlVRp+4vv7XASBsMe9L1tsVKiGoeP2AHnlkk=
|
||||
github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.3.1 h1:qGJ6qTW+x6xX/my+8YUVl4WNpX9B7+/l2tRsHGZ7f2s=
|
||||
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||
|
|
@ -186,6 +201,7 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
|
|||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g=
|
||||
github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/redis/go-redis/v9 v9.1.0 h1:137FnGdk+EQdCbye1FW+qOEcY5S+SpY9T0NiuqvtfMY=
|
||||
github.com/redis/go-redis/v9 v9.1.0/go.mod h1:urWj3He21Dj5k4TK1y59xH8Uj6ATueP8AH1cY3lZl4c=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
|
|
@ -221,6 +237,8 @@ github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
|
|||
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
|
||||
github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
|
||||
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
||||
github.com/tjfoc/gmsm v1.4.1 h1:aMe1GlZb+0bLjn+cKTPEvvn9oUEBlJitaZiiBwsbgho=
|
||||
github.com/tjfoc/gmsm v1.4.1/go.mod h1:j4INPkHWMrhJb38G+J6W4Tw0AbuN8Thu3PbdVYhVcTE=
|
||||
github.com/wechatpay-apiv3/wechatpay-go v0.2.20 h1:gS8oFn1bHGnyapR2Zb4aqTV6l4kJWgbtqjCq6k1L9DQ=
|
||||
github.com/wechatpay-apiv3/wechatpay-go v0.2.20/go.mod h1:A254AUBVB6R+EqQFo3yTgeh7HtyqRRtN2w9hQSOrd4Q=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
|
|
@ -253,13 +271,18 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
|
|||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
|
||||
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
|
||||
golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
|
||||
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20221208152030-732eee02a75a h1:4iLhBPcpqFmylhnkbY3W0ONLUYYkDAW9xMFLfxgsvCw=
|
||||
golang.org/x/exp v0.0.0-20221208152030-732eee02a75a/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20241112194109-818c5a804067 h1:adDmSQyFTCiv19j015EGKJBoaa7ElV0Q1Wovb/4G7NA=
|
||||
golang.org/x/lint v0.0.0-20241112194109-818c5a804067/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
|
|
@ -272,11 +295,15 @@ golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
|||
golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4=
|
||||
golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
|
||||
|
|
@ -288,7 +315,9 @@ golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
|
|||
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
|
||||
golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0=
|
||||
golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
|
|
@ -297,6 +326,7 @@ golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
|||
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
|
||||
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
|
|
@ -340,9 +370,12 @@ golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
|||
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
|
||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
|
|
@ -359,10 +392,18 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
|
|||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094 h1:0+ozOGcrp+Y8Aq8TLNN2Aliibms5LEzsq99ZZmAGYm0=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094/go.mod h1:fJ/e3If/Q67Mj99hin0hMhiNyCRmt6BQ2aWIJshUSJw=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 h1:BwIjyKYGsK9dMCBOorzRri8MQwmi7mT9rGHsCEinZkA=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY=
|
||||
google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
|
|
@ -402,6 +443,8 @@ gorm.io/driver/mysql v1.5.7/go.mod h1:sEtPWMiqiN1N1cMXoXmBbd8C6/l+TESwriotuRRpkD
|
|||
gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
|
||||
gorm.io/gorm v1.25.12 h1:I0u8i2hWQItBq1WfE0o2+WuL9+8L21K9e2HHSTE/0f8=
|
||||
gorm.io/gorm v1.25.12/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
stathat.com/c/consistent v1.0.0 h1:ezyc51EGcRPJUxfHGSgJjWzJdj3NiMU9pNfLNGiXV0c=
|
||||
|
|
|
|||
|
|
@ -0,0 +1,150 @@
|
|||
package cmb
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"github.com/ZZMarquis/gm/sm4"
|
||||
"github.com/tjfoc/gmsm/sm2"
|
||||
"strings"
|
||||
sm22 "voucher/internal/pkg/cmb/sm2"
|
||||
"voucher/internal/pkg/cmb/sm2/model"
|
||||
"voucher/internal/pkg/cmb/sm2/sdk"
|
||||
)
|
||||
|
||||
// GenerateSm2Key 生成密钥对
|
||||
func GenerateSm2Key() (string, string) {
|
||||
pri, _ := sm2.GenerateKey(rand.Reader)
|
||||
hexPri := pri.D.Text(16)
|
||||
// 获取公钥
|
||||
publicKeyHex := publicKeyToString(&pri.PublicKey)
|
||||
return 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 hex.EncodeToString(publicKeyBytes)
|
||||
}
|
||||
|
||||
func encrypt(sopPublicKey, inputJson string) (string, error) {
|
||||
data, _ := base64.StdEncoding.DecodeString(inputJson)
|
||||
|
||||
sm4Key := GenerateSM4Key()
|
||||
iv := GetSM4IV()
|
||||
encryptedBody, err := sm4.CBCEncrypt(sm4Key, iv, Padding(data, 1))
|
||||
|
||||
keyAndIv := AssemblingByteArray(sm4Key, iv)
|
||||
|
||||
kvTmp, err := sm22.NewSm2().
|
||||
SetHexPublicKey(sopPublicKey).
|
||||
SetData([]byte(base64.StdEncoding.EncodeToString(keyAndIv))).
|
||||
SetSdk(sdk.NewCmbLifeSdk()).
|
||||
SetCipherType(model.C1C3C2).
|
||||
Encrypt().
|
||||
ToString()
|
||||
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%s|%s", base64.StdEncoding.EncodeToString([]byte(kvTmp)), base64.StdEncoding.EncodeToString(encryptedBody)), nil
|
||||
}
|
||||
|
||||
func decrypt(privateKey, inputJson string) (string, error) {
|
||||
data, err := base64.StdEncoding.DecodeString(inputJson)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
tmpDataArr := strings.Split(string(data), "|")
|
||||
if len(tmpDataArr) != 2 {
|
||||
return "", fmt.Errorf("数据格式错误")
|
||||
}
|
||||
|
||||
keyAndIvStr := tmpDataArr[0]
|
||||
encryptedBody := tmpDataArr[1]
|
||||
|
||||
kvBase64Tmp, err := sm22.NewSm2().SetHexPrivateKey(privateKey).
|
||||
SetBase64StringData(keyAndIvStr).
|
||||
SetSdk(sdk.NewCmbLifeSdk()).
|
||||
SetCipherType(model.C1C3C2).
|
||||
Decrypt().
|
||||
ToString()
|
||||
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
kvTmp, err := base64.StdEncoding.DecodeString(kvBase64Tmp)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
kvArr := strings.Split(string(kvTmp), "|")
|
||||
if len(tmpDataArr) != 2 {
|
||||
return "", fmt.Errorf("数据格式错误!")
|
||||
}
|
||||
plainKey := []byte(kvArr[0])
|
||||
plainIv := []byte(kvArr[1])
|
||||
|
||||
data2, err := base64.StdEncoding.DecodeString(encryptedBody)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
plainText, err := sm4.CBCDecrypt(plainKey, plainIv, data2)
|
||||
|
||||
return string(Padding(plainText, 0)), nil
|
||||
}
|
||||
|
||||
func sign(privateKey, inputJson string) (string, error) {
|
||||
data, _ := base64.StdEncoding.DecodeString(inputJson)
|
||||
|
||||
signData, err := sm22.NewSm2().
|
||||
SetHexPrivateKey(privateKey).
|
||||
SetData(data).
|
||||
Sign().
|
||||
ToString()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return base64.StdEncoding.EncodeToString([]byte(signData)), nil
|
||||
}
|
||||
|
||||
func verify(publicKey, inputJson, sign string) (bool, error) {
|
||||
data, _ := base64.StdEncoding.DecodeString(inputJson)
|
||||
|
||||
ok, err := sm22.NewSm2().
|
||||
SetHexPublicKey(publicKey).
|
||||
SetData(data).
|
||||
SetBase64Signature(sign).
|
||||
Verify().
|
||||
ToBool()
|
||||
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if !ok {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
package sm2
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func (s *Sm2) SetError(err error) *Sm2 {
|
||||
s.err = append(s.err, err)
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *Sm2) encryptErrHandler() error {
|
||||
if len(s.data) == 0 {
|
||||
s.SetError(fmt.Errorf("data is empty"))
|
||||
}
|
||||
if s.publicKey == nil {
|
||||
s.SetError(fmt.Errorf("publicKey is nil"))
|
||||
}
|
||||
return s.errHandle()
|
||||
}
|
||||
|
||||
func (s *Sm2) decryptErrHandler() error {
|
||||
if len(s.data) == 0 {
|
||||
s.SetError(fmt.Errorf("data is empty"))
|
||||
}
|
||||
if s.privateKey == nil {
|
||||
s.SetError(fmt.Errorf("privateKey is nil"))
|
||||
}
|
||||
return s.errHandle()
|
||||
}
|
||||
|
||||
func (s *Sm2) verifyErrHandler() error {
|
||||
if len(s.data) == 0 {
|
||||
s.SetError(fmt.Errorf("data is empty"))
|
||||
}
|
||||
if s.publicKey == nil {
|
||||
s.SetError(fmt.Errorf("publicKey is nil"))
|
||||
}
|
||||
return s.errHandle()
|
||||
}
|
||||
|
||||
func (s *Sm2) signErrHandler() error {
|
||||
if len(s.data) == 0 {
|
||||
s.SetError(fmt.Errorf("data is empty"))
|
||||
}
|
||||
if s.privateKey == nil {
|
||||
s.SetError(fmt.Errorf("privateKey is nil"))
|
||||
}
|
||||
return s.errHandle()
|
||||
}
|
||||
|
||||
func (s *Sm2) errHandle() error {
|
||||
if len(s.err) > 0 {
|
||||
errStr := ""
|
||||
for _, e := range s.err {
|
||||
errStr += e.Error() + "\n"
|
||||
}
|
||||
return fmt.Errorf(errStr)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
package model
|
||||
|
||||
import (
|
||||
"crypto/elliptic"
|
||||
"math/big"
|
||||
)
|
||||
|
||||
var (
|
||||
One = new(big.Int).SetInt64(1)
|
||||
DefaultUid = []byte{0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38}
|
||||
VerifyFalse = []byte{0x30}
|
||||
VerifyTrue = []byte{0x31}
|
||||
)
|
||||
|
||||
type CipherType int32
|
||||
|
||||
const (
|
||||
C1C2C3 CipherType = 1
|
||||
C1C3C2 CipherType = 2
|
||||
)
|
||||
|
||||
type PublicKey struct {
|
||||
elliptic.Curve
|
||||
X, Y *big.Int
|
||||
}
|
||||
|
||||
type PrivateKey struct {
|
||||
*PublicKey
|
||||
D *big.Int
|
||||
}
|
||||
|
||||
type Signature struct {
|
||||
R, S *big.Int
|
||||
}
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
package sdk
|
||||
|
||||
import (
|
||||
"crypto/elliptic"
|
||||
"encoding/binary"
|
||||
"math/big"
|
||||
"voucher/internal/pkg/cmb/sm2/util"
|
||||
)
|
||||
|
||||
type BaseSdk struct {
|
||||
}
|
||||
|
||||
func NewBaseSdk() SDK {
|
||||
return &BaseSdk{}
|
||||
}
|
||||
|
||||
func (b *BaseSdk) Kdf(c elliptic.Curve, x, y *big.Int, c2 []byte) error {
|
||||
data := elliptic.Marshal(c, x, y)
|
||||
ct := uint32(1)
|
||||
length := len(c2)
|
||||
end := (length + 31) / 32
|
||||
result := make([]byte, 0)
|
||||
for i := 1; i <= end; i++ {
|
||||
bytes, err := b.sm3hash(data, b.uint32ToBytes(ct))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
result = append(result, bytes...)
|
||||
ct++
|
||||
}
|
||||
last, err := b.sm3hash(data, b.uint32ToBytes(ct))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if length%32 == 0 {
|
||||
result = append(result, last...)
|
||||
} else {
|
||||
result = append(result, last[:length%32]...)
|
||||
}
|
||||
for i := 0; i < length; i++ {
|
||||
c2[i] ^= result[i]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *BaseSdk) CalculateHash(x *big.Int, c2 []byte, y *big.Int) []byte {
|
||||
digest := util.New()
|
||||
digest.Write(util.BigIntToByte(x))
|
||||
digest.Write(c2)
|
||||
digest.Write(util.BigIntToByte(y))
|
||||
result := digest.Sum(nil)[:32]
|
||||
return result
|
||||
}
|
||||
|
||||
func (b *BaseSdk) GetZ(x *big.Int, y *big.Int, uid []byte) []byte {
|
||||
z := util.New()
|
||||
uidLen := len(uid) * 8
|
||||
z.Write([]byte{byte((uidLen >> 8) & 0xFF)})
|
||||
z.Write([]byte{byte(uidLen & 0xFF)})
|
||||
z.Write(uid)
|
||||
|
||||
sm2P256 := util.NewP256Sm2()
|
||||
|
||||
z.Write(util.BigIntToByte(sm2P256.A))
|
||||
z.Write(util.BigIntToByte(sm2P256.B))
|
||||
z.Write(util.BigIntToByte(sm2P256.Gx))
|
||||
z.Write(util.BigIntToByte(sm2P256.Gy))
|
||||
|
||||
z.Write(x.Bytes())
|
||||
z.Write(y.Bytes())
|
||||
return z.Sum(nil)
|
||||
}
|
||||
|
||||
func (b *BaseSdk) GetE(z []byte, data []byte) *big.Int {
|
||||
e := util.New()
|
||||
e.Write(z)
|
||||
e.Write(data)
|
||||
return new(big.Int).SetBytes(e.Sum(nil)[:32])
|
||||
}
|
||||
|
||||
func (b *BaseSdk) uint32ToBytes(x uint32) []byte {
|
||||
var buf = make([]byte, 4)
|
||||
binary.BigEndian.PutUint32(buf, x)
|
||||
return buf
|
||||
}
|
||||
|
||||
func (b *BaseSdk) sm3hash(sources ...[]byte) ([]byte, error) {
|
||||
bytes, err := util.JoinBytes(sources...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
md := make([]byte, 32)
|
||||
h := util.New()
|
||||
h.Write(bytes)
|
||||
h.Sum(md[:0])
|
||||
return md, nil
|
||||
}
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
package sdk
|
||||
|
||||
import (
|
||||
"crypto/elliptic"
|
||||
"encoding/binary"
|
||||
"math/big"
|
||||
"voucher/internal/pkg/cmb/sm2/util"
|
||||
)
|
||||
|
||||
// CmbLifeSdk 招商银行生活服务
|
||||
type CmbLifeSdk struct {
|
||||
BaseSdk
|
||||
}
|
||||
|
||||
func NewCmbLifeSdk() SDK {
|
||||
return &CmbLifeSdk{}
|
||||
}
|
||||
|
||||
func (c *CmbLifeSdk) Kdf(cur elliptic.Curve, x *big.Int, y *big.Int, c2 []byte) error {
|
||||
bufSize := 4
|
||||
digest := util.New()
|
||||
if bufSize < digest.Size() {
|
||||
bufSize = digest.Size()
|
||||
}
|
||||
buf := make([]byte, bufSize)
|
||||
|
||||
encDataLen := len(c2)
|
||||
c1xBytes := util.BigIntToByte(x)
|
||||
c1yBytes := util.BigIntToByte(y)
|
||||
off := 0
|
||||
ct := uint32(0)
|
||||
for off < encDataLen {
|
||||
digest.Reset()
|
||||
digest.Write(c1xBytes)
|
||||
digest.Write(c1yBytes)
|
||||
ct++
|
||||
binary.BigEndian.PutUint32(buf, ct)
|
||||
digest.Write(buf[:4])
|
||||
tmp := digest.Sum(nil)
|
||||
copy(buf[:bufSize], tmp[:bufSize])
|
||||
|
||||
xorLen := encDataLen - off
|
||||
if xorLen > digest.Size() {
|
||||
xorLen = digest.Size()
|
||||
}
|
||||
xor(c2[off:], buf, xorLen)
|
||||
off += xorLen
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func xor(data []byte, kdfOut []byte, dRemaining int) {
|
||||
for i := 0; i < dRemaining; i++ {
|
||||
data[i] ^= kdfOut[i]
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
package sdk
|
||||
|
||||
import (
|
||||
"crypto/elliptic"
|
||||
"math/big"
|
||||
)
|
||||
|
||||
type SDK interface {
|
||||
Kdf(c elliptic.Curve, x, y *big.Int, c2 []byte) error
|
||||
CalculateHash(x *big.Int, c2 []byte, y *big.Int) []byte
|
||||
GetZ(x *big.Int, y *big.Int, uid []byte) []byte
|
||||
GetE(z []byte, data []byte) *big.Int
|
||||
|
||||
uint32ToBytes(x uint32) []byte
|
||||
sm3hash(sources ...[]byte) ([]byte, error)
|
||||
}
|
||||
|
|
@ -0,0 +1,399 @@
|
|||
package sm2
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
"encoding/asn1"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/big"
|
||||
"voucher/internal/pkg/cmb/sm2/model"
|
||||
"voucher/internal/pkg/cmb/sm2/sdk"
|
||||
"voucher/internal/pkg/cmb/sm2/util"
|
||||
)
|
||||
|
||||
type Sm2 struct {
|
||||
publicKey *model.PublicKey
|
||||
privateKey *model.PrivateKey
|
||||
signature model.Signature
|
||||
sdk sdk.SDK
|
||||
cipherType model.CipherType
|
||||
c3Len int
|
||||
uid []byte
|
||||
data []byte
|
||||
err []error
|
||||
toData []byte
|
||||
}
|
||||
|
||||
func NewSm2() *Sm2 {
|
||||
return &Sm2{
|
||||
sdk: sdk.NewBaseSdk(),
|
||||
c3Len: 32,
|
||||
uid: model.DefaultUid,
|
||||
cipherType: model.C1C2C3,
|
||||
err: make([]error, 0),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Sm2) Encrypt() *Sm2 {
|
||||
if err := s.encryptErrHandler(); err != nil {
|
||||
return s
|
||||
}
|
||||
c2 := make([]byte, len(s.data))
|
||||
copy(c2, s.data)
|
||||
var c1 []byte
|
||||
var kx, ky *big.Int
|
||||
for {
|
||||
k, err := rand.Int(rand.Reader, s.publicKey.Params().N)
|
||||
if err != nil {
|
||||
return s.SetError(fmt.Errorf("rand error: %v", err))
|
||||
}
|
||||
c1x, c1y := s.publicKey.Curve.ScalarBaseMult(k.Bytes())
|
||||
c1 = elliptic.Marshal(s.publicKey.Curve, c1x, c1y)
|
||||
kx, ky = s.publicKey.Curve.ScalarMult(s.publicKey.X, s.publicKey.Y, k.Bytes())
|
||||
|
||||
err = s.sdk.Kdf(s.publicKey, kx, ky, c2)
|
||||
if err != nil {
|
||||
return s.SetError(fmt.Errorf("kdf error: %v", err))
|
||||
}
|
||||
if s.encrypted(c2, s.data) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
c3 := s.sdk.CalculateHash(kx, s.data, ky)
|
||||
|
||||
c1Len := len(c1)
|
||||
c2Len := len(c2)
|
||||
c3Len := len(c3)
|
||||
s.toData = make([]byte, c1Len+c2Len+c3Len)
|
||||
if s.cipherType == model.C1C2C3 {
|
||||
copy(s.toData[:c1Len], c1)
|
||||
copy(s.toData[c1Len:c1Len+c2Len], c2)
|
||||
copy(s.toData[c1Len+c2Len:], c3)
|
||||
} else if s.cipherType == model.C1C3C2 {
|
||||
copy(s.toData[:c1Len], c1)
|
||||
copy(s.toData[c1Len:c1Len+c3Len], c3)
|
||||
copy(s.toData[c1Len+c3Len:], c2)
|
||||
} else {
|
||||
return s.SetError(fmt.Errorf("cipher type not support"))
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *Sm2) Decrypt() *Sm2 {
|
||||
if err := s.decryptErrHandler(); err != nil {
|
||||
return s
|
||||
}
|
||||
c1Len := 65
|
||||
C1Byte := make([]byte, c1Len)
|
||||
copy(C1Byte, s.data[:c1Len])
|
||||
x, y := elliptic.Unmarshal(s.privateKey.Curve, C1Byte)
|
||||
dBC1X, dBC1Y := s.privateKey.Curve.ScalarMult(x, y, s.privateKey.D.Bytes())
|
||||
|
||||
c2Len := len(s.data) - c1Len - s.c3Len
|
||||
c2 := make([]byte, c2Len)
|
||||
c3 := make([]byte, s.c3Len)
|
||||
if s.cipherType == model.C1C2C3 {
|
||||
copy(c2, s.data[c1Len:c1Len+c2Len])
|
||||
copy(c3, s.data[c1Len+c2Len:])
|
||||
} else if s.cipherType == model.C1C3C2 {
|
||||
copy(c3, s.data[c1Len:c1Len+s.c3Len])
|
||||
copy(c2, s.data[c1Len+s.c3Len:])
|
||||
} else {
|
||||
return s.SetError(fmt.Errorf("cipher type not support"))
|
||||
}
|
||||
|
||||
err := s.sdk.Kdf(s.privateKey.Curve, dBC1X, dBC1Y, c2)
|
||||
if err != nil {
|
||||
return s.SetError(fmt.Errorf("kdf error: %v", err))
|
||||
}
|
||||
|
||||
u := s.sdk.CalculateHash(dBC1X, c2, dBC1Y)
|
||||
if bytes.Compare(u, c3) == 0 {
|
||||
s.toData = c2
|
||||
return s
|
||||
} else {
|
||||
return s.SetError(fmt.Errorf("decrypt error"))
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Sm2) Verify() *Sm2 {
|
||||
if err := s.encryptErrHandler(); err != nil {
|
||||
return s
|
||||
}
|
||||
c := s.publicKey.Curve
|
||||
N := c.Params().N
|
||||
if s.signature.R.Cmp(model.One) < 0 || s.signature.S.Cmp(model.One) < 0 {
|
||||
s.toData = model.VerifyFalse
|
||||
return s
|
||||
}
|
||||
if s.signature.R.Cmp(N) >= 0 || s.signature.S.Cmp(N) >= 0 {
|
||||
s.toData = model.VerifyFalse
|
||||
return s
|
||||
}
|
||||
z := s.sdk.GetZ(s.publicKey.X, s.publicKey.Y, s.uid)
|
||||
e := s.sdk.GetE(z, s.data)
|
||||
t := new(big.Int).Add(s.signature.R, s.signature.S)
|
||||
t.Mod(t, N)
|
||||
if t.Sign() == 0 {
|
||||
s.toData = model.VerifyFalse
|
||||
return s
|
||||
}
|
||||
var x *big.Int
|
||||
x1, y1 := c.ScalarBaseMult(s.signature.S.Bytes())
|
||||
x2, y2 := c.ScalarMult(s.publicKey.X, s.publicKey.Y, t.Bytes())
|
||||
x, _ = c.Add(x1, y1, x2, y2)
|
||||
|
||||
x.Add(x, e)
|
||||
x.Mod(x, N)
|
||||
if x.Cmp(s.signature.R) == 0 {
|
||||
s.toData = model.VerifyTrue
|
||||
} else {
|
||||
s.toData = model.VerifyFalse
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *Sm2) Sign() *Sm2 {
|
||||
if err := s.signErrHandler(); err != nil {
|
||||
return s
|
||||
}
|
||||
z := s.sdk.GetZ(s.privateKey.PublicKey.X, s.privateKey.PublicKey.Y, s.uid)
|
||||
e := s.sdk.GetE(z, s.data)
|
||||
|
||||
c := s.privateKey.PublicKey.Curve
|
||||
N := c.Params().N
|
||||
if N.Sign() == 0 {
|
||||
return s.SetError(fmt.Errorf("invalid curve order"))
|
||||
}
|
||||
var k, r, sb *big.Int
|
||||
var err error
|
||||
for {
|
||||
for {
|
||||
k, err = s.randFieldElement(c, rand.Reader)
|
||||
if err != nil {
|
||||
return s.SetError(fmt.Errorf("randFieldElement: %+v", err))
|
||||
}
|
||||
r, _ = s.privateKey.Curve.ScalarBaseMult(k.Bytes())
|
||||
r.Add(r, e)
|
||||
r.Mod(r, N)
|
||||
if r.Sign() != 0 {
|
||||
if t := new(big.Int).Add(r, k); t.Cmp(N) != 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
rD := new(big.Int).Mul(s.privateKey.D, r)
|
||||
sb = new(big.Int).Sub(k, rD)
|
||||
d1 := new(big.Int).Add(s.privateKey.D, model.One)
|
||||
d1Inv := new(big.Int).ModInverse(d1, N)
|
||||
sb.Mul(sb, d1Inv)
|
||||
sb.Mod(sb, N)
|
||||
if sb.Sign() != 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
s.signature = model.Signature{R: r, S: sb}
|
||||
si, err := asn1.Marshal(s.signature)
|
||||
if err != nil {
|
||||
return s.SetError(fmt.Errorf("asn1.Marshal: %+v", err))
|
||||
}
|
||||
s.toData = si
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *Sm2) randFieldElement(c elliptic.Curve, random io.Reader) (k *big.Int, err error) {
|
||||
params := c.Params()
|
||||
b := make([]byte, params.BitSize/8+8)
|
||||
_, err = io.ReadFull(random, b)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
k = new(big.Int).SetBytes(b)
|
||||
n := new(big.Int).Sub(params.N, model.One)
|
||||
k.Mod(k, n)
|
||||
k.Add(k, model.One)
|
||||
return
|
||||
}
|
||||
|
||||
func (s *Sm2) encrypted(encData []byte, in []byte) bool {
|
||||
encDataLen := len(encData)
|
||||
for i := 0; i != encDataLen; i++ {
|
||||
if encData[i] != in[i] {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (s *Sm2) SetCipherType(cipherType model.CipherType) *Sm2 {
|
||||
s.cipherType = cipherType
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *Sm2) SetHexPublicKey(hexStr string) *Sm2 {
|
||||
d, err := hex.DecodeString(hexStr)
|
||||
if err != nil {
|
||||
return s.SetError(fmt.Errorf("publicKey is not hex string: %s", err.Error()))
|
||||
}
|
||||
s.publicKey, err = util.HexToPublicKey(d)
|
||||
if err != nil {
|
||||
return s.SetError(fmt.Errorf("parse publicKey err: %+v", err))
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *Sm2) SetHexPrivateKey(hexStr string) *Sm2 {
|
||||
d, err := hex.DecodeString(hexStr)
|
||||
if err != nil {
|
||||
return s.SetError(fmt.Errorf("privateKey is not hex string: %s", err.Error()))
|
||||
}
|
||||
s.privateKey, err = util.HexToPrivateKey(d)
|
||||
if err != nil {
|
||||
return s.SetError(fmt.Errorf("parse privateKey err: %+v", err))
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *Sm2) SetPublicKey(publicKey *model.PublicKey) *Sm2 {
|
||||
s.publicKey = publicKey
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *Sm2) SetPrivateKey(privateKey *model.PrivateKey) *Sm2 {
|
||||
s.privateKey = privateKey
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *Sm2) SetHexSignature(hexStr string) *Sm2 {
|
||||
sign, err := hex.DecodeString(hexStr)
|
||||
if err != nil {
|
||||
return s.SetError(fmt.Errorf("signature is not hex string: %s", err.Error()))
|
||||
}
|
||||
_, err = asn1.Unmarshal(sign, &s.signature)
|
||||
if err != nil {
|
||||
return s.SetError(fmt.Errorf("signature is not asn1: %s", err.Error()))
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *Sm2) SetBase64Signature(base64Str string) *Sm2 {
|
||||
sign, err := base64.StdEncoding.DecodeString(base64Str)
|
||||
if err != nil {
|
||||
return s.SetError(fmt.Errorf("signature is not base64 string: %s", err.Error()))
|
||||
}
|
||||
_, err = asn1.Unmarshal(sign, &s.signature)
|
||||
if err != nil {
|
||||
return s.SetError(fmt.Errorf("signature is not asn1: %s", err.Error()))
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *Sm2) SetHexSignatureData(hexStr string) *Sm2 {
|
||||
sign, err := hex.DecodeString(hexStr)
|
||||
if err != nil {
|
||||
return s.SetError(fmt.Errorf("signature is not hex string: %s", err.Error()))
|
||||
}
|
||||
_, err = asn1.Unmarshal(sign, &s.signature)
|
||||
if err != nil {
|
||||
return s.SetError(fmt.Errorf("signature is not asn1: %s", err.Error()))
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *Sm2) SetSignature(signature model.Signature) *Sm2 {
|
||||
s.signature = signature
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *Sm2) SetSdk(sdk sdk.SDK) *Sm2 {
|
||||
s.sdk = sdk
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *Sm2) SetC3Len(c3Len int) *Sm2 {
|
||||
s.c3Len = c3Len
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *Sm2) SetUid(uid []byte) *Sm2 {
|
||||
s.uid = uid
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *Sm2) SetBase64StringData(base64String string) *Sm2 {
|
||||
data, err := base64.StdEncoding.DecodeString(base64String)
|
||||
if err != nil {
|
||||
return s.SetError(fmt.Errorf("data is not base64 string: %s", err.Error()))
|
||||
}
|
||||
s.data = data
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *Sm2) SetStringData(str string) *Sm2 {
|
||||
s.data = []byte(str)
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *Sm2) SetHexData(hexStr string) *Sm2 {
|
||||
data, err := hex.DecodeString(hexStr)
|
||||
if err != nil {
|
||||
return s.SetError(fmt.Errorf("data is not hex string: %s", err.Error()))
|
||||
}
|
||||
s.data = data
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *Sm2) SetData(data []byte) *Sm2 {
|
||||
s.data = data
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *Sm2) ToBytes() ([]byte, error) {
|
||||
if err := s.errHandle(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return s.toData, nil
|
||||
}
|
||||
|
||||
func (s *Sm2) ToString() (string, error) {
|
||||
if err := s.errHandle(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(s.toData), nil
|
||||
}
|
||||
|
||||
func (s *Sm2) ToBase64String() (string, error) {
|
||||
if err := s.errHandle(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return base64.StdEncoding.EncodeToString(s.toData), nil
|
||||
}
|
||||
|
||||
func (s *Sm2) ToHexString() (string, error) {
|
||||
if err := s.errHandle(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return hex.EncodeToString(s.toData), nil
|
||||
}
|
||||
|
||||
func (s *Sm2) ToBool() (bool, error) {
|
||||
if err := s.errHandle(); err != nil {
|
||||
return false, err
|
||||
}
|
||||
if bytes.Equal(s.toData, model.VerifyTrue) {
|
||||
return true, nil
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (s *Sm2) ToSignature() (*model.Signature, error) {
|
||||
if err := s.errHandle(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &s.signature, nil
|
||||
}
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
package sm2
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"voucher/internal/pkg/cmb/sm2/model"
|
||||
"voucher/internal/pkg/cmb/sm2/sdk"
|
||||
"voucher/internal/pkg/cmb/sm2/util"
|
||||
)
|
||||
|
||||
var (
|
||||
pubHexKey = "04a702106cf530dc981e44cd515b394747cfd6bb059247696b188b25281ea4278fe7c6e34a83680110eec71becd31f5db14abc671e5d8e67ce7ca3c6b3adc86674"
|
||||
priHexKey = "9450c673cf801164435b9c164ac1404e87997245bc6f323fde22015875a03f6e"
|
||||
enStr = "BI2O20YuamIpOpXH/RJDtB9gWIpNZPjFbTpbvX45lG8mcma7Cab1yRpE3rcM33oJ8xJ3mbbIvXf/1N507i97eXYQSbLzOBcl/8PyaB4dQ/Ub7QQncN+Npuif4Qp6s11tobdTVOFlz9S9i0VC"
|
||||
)
|
||||
|
||||
func TestSm2_Encrypt(t *testing.T) {
|
||||
encrypt, err := NewSm2().
|
||||
SetHexPublicKey(pubHexKey).
|
||||
SetStringData(`{"name":"zhangxx","phoneNo":"137xxxxxxxx"}`).
|
||||
SetSdk(sdk.NewCmbLifeSdk()).
|
||||
SetCipherType(model.C1C3C2).
|
||||
Encrypt().
|
||||
ToBase64String()
|
||||
if err != nil {
|
||||
t.Error("sm2 encrypt error:", err)
|
||||
return
|
||||
}
|
||||
t.Log("sm2 encrypt result:", encrypt)
|
||||
}
|
||||
|
||||
func TestSm2_Decrypt(t *testing.T) {
|
||||
decrypt, err := NewSm2().
|
||||
SetHexPrivateKey(priHexKey).
|
||||
SetBase64StringData(enStr).
|
||||
SetSdk(sdk.NewCmbLifeSdk()).
|
||||
SetCipherType(model.C1C3C2).
|
||||
Decrypt().
|
||||
ToString()
|
||||
if err != nil {
|
||||
t.Error("sm2 decrypt error:", err)
|
||||
return
|
||||
}
|
||||
t.Log("sm2 decrypt result:", decrypt)
|
||||
}
|
||||
|
||||
func TestSm2_EncryptDecrypt(t *testing.T) {
|
||||
n := NewSm2().
|
||||
SetHexPublicKey(pubHexKey).
|
||||
SetHexPrivateKey(priHexKey).
|
||||
SetSdk(sdk.NewCmbLifeSdk()).
|
||||
SetCipherType(model.C1C3C2)
|
||||
|
||||
encrypt, err := n.SetStringData(`{"name":"zhangxx","phoneNo":"137xxxxxxxx"}`).Encrypt().ToBase64String()
|
||||
if err != nil {
|
||||
t.Error("sm2 encrypt error:", err)
|
||||
return
|
||||
}
|
||||
t.Log("sm2 encrypt result:", encrypt)
|
||||
|
||||
decrypt, err := n.SetBase64StringData(encrypt).Decrypt().ToString()
|
||||
if err != nil {
|
||||
t.Error("sm2 decrypt error:", err)
|
||||
return
|
||||
}
|
||||
t.Log("sm2 decrypt result:", decrypt)
|
||||
}
|
||||
|
||||
func TestSm2_Sign(t *testing.T) {
|
||||
sign, err := NewSm2().
|
||||
SetUid([]byte("opv22s05zaezfccc")).
|
||||
SetHexPrivateKey("beb1c3ed9064052fabe745dac1d71592d16cb0a19abb82e25d9e52799fa85eda").
|
||||
SetStringData("a=1").
|
||||
Sign().
|
||||
ToHexString()
|
||||
if err != nil {
|
||||
t.Error("sm2 sign error:", err)
|
||||
return
|
||||
}
|
||||
t.Log("sm2 sign result:", sign)
|
||||
}
|
||||
|
||||
func TestSm2_Verify(t *testing.T) {
|
||||
s, err := util.HexToSignature("abd5a608aad610840bd387263c81f8813e7ab4b121cd69f0d69ac4736cc29978d44c47d9bbf497c712e067c320d3e6b8ef70063da284cc957440e36733f0ff81")
|
||||
if err != nil {
|
||||
t.Fatalf("hex to signature error: %v", err)
|
||||
}
|
||||
|
||||
verify, 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 {
|
||||
t.Error("sm2 verify error:", err)
|
||||
return
|
||||
}
|
||||
t.Log("sm2 verify result:", verify)
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,329 @@
|
|||
package util
|
||||
|
||||
import (
|
||||
"codeup.aliyun.com/lsxd/backend_deveoper/gmutil/sm2/model"
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/elliptic"
|
||||
"crypto/hmac"
|
||||
"crypto/md5"
|
||||
"crypto/rand"
|
||||
"crypto/sha1"
|
||||
"crypto/sha256"
|
||||
"crypto/sha512"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/asn1"
|
||||
"fmt"
|
||||
"hash"
|
||||
"math/big"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
/*
|
||||
* reference to RFC5959 and RFC2898
|
||||
*/
|
||||
|
||||
var (
|
||||
oidPBES2 = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 5, 13} // id-PBES2(PBES2)
|
||||
oidPBKDF2 = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 5, 12} // id-PBKDF2
|
||||
|
||||
oidAES128CBC = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 1, 2}
|
||||
oidAES256CBC = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 1, 42}
|
||||
|
||||
oidKEYMD5 = asn1.ObjectIdentifier{1, 2, 840, 113549, 2, 5}
|
||||
oidKEYSHA1 = asn1.ObjectIdentifier{1, 2, 840, 113549, 2, 7}
|
||||
oidKEYSHA256 = asn1.ObjectIdentifier{1, 2, 840, 113549, 2, 9}
|
||||
oidKEYSHA512 = asn1.ObjectIdentifier{1, 2, 840, 113549, 2, 11}
|
||||
|
||||
oidSM2 = asn1.ObjectIdentifier{1, 2, 840, 10045, 2, 1}
|
||||
)
|
||||
|
||||
type Sm2PrivateKey struct {
|
||||
Version int
|
||||
PrivateKey []byte
|
||||
NamedCurveOID asn1.ObjectIdentifier `asn1:"optional,explicit,tag:0"`
|
||||
PublicKey asn1.BitString `asn1:"optional,explicit,tag:1"`
|
||||
}
|
||||
|
||||
type pkcs8 struct {
|
||||
Version int
|
||||
Algo pkix.AlgorithmIdentifier
|
||||
PrivateKey []byte
|
||||
}
|
||||
|
||||
// EncryptedPrivateKeyInfo reference to https://www.rfc-editor.org/rfc/rfc5958.txt
|
||||
type EncryptedPrivateKeyInfo struct {
|
||||
EncryptionAlgorithm Pbes2Algorithms
|
||||
EncryptedData []byte
|
||||
}
|
||||
|
||||
// Pbes2Algorithms reference to https://www.ietf.org/rfc/rfc2898.txt
|
||||
type Pbes2Algorithms struct {
|
||||
IdPBES2 asn1.ObjectIdentifier
|
||||
Pbes2Params Pbes2Params
|
||||
}
|
||||
|
||||
// Pbes2Params reference to https://www.ietf.org/rfc/rfc2898.txt
|
||||
type Pbes2Params struct {
|
||||
KeyDerivationFunc Pbes2KDfs // PBES2-KDFs
|
||||
EncryptionScheme Pbes2Encs // PBES2-Encs
|
||||
}
|
||||
|
||||
// Pbes2KDfs reference to https://www.ietf.org/rfc/rfc2898.txt
|
||||
type Pbes2KDfs struct {
|
||||
IdPBKDF2 asn1.ObjectIdentifier
|
||||
Pkdf2Params Pkdf2Params
|
||||
}
|
||||
type Pbes2Encs struct {
|
||||
EncryAlgo asn1.ObjectIdentifier
|
||||
IV []byte
|
||||
}
|
||||
|
||||
// Pkdf2Params reference to https://www.ietf.org/rfc/rfc2898.txt
|
||||
type Pkdf2Params struct {
|
||||
Salt []byte
|
||||
IterationCount int
|
||||
Prf pkix.AlgorithmIdentifier
|
||||
}
|
||||
|
||||
func ParsePrivateKey(bytes []byte, pwd []byte) (*model.PrivateKey, error) {
|
||||
var priKey Sm2PrivateKey
|
||||
var err error
|
||||
if pwd == nil {
|
||||
priKey, err = ParsePKCS8UnEncryptedPrivateKey(bytes)
|
||||
} else {
|
||||
priKey, err = ParsePKCS8EncryptedPrivateKey(bytes, pwd)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parse private key err: %s", err.Error())
|
||||
}
|
||||
curve := NewP256Sm2()
|
||||
k := new(big.Int).SetBytes(priKey.PrivateKey)
|
||||
curveOrder := curve.Params().N
|
||||
if k.Cmp(curveOrder) >= 0 {
|
||||
return nil, fmt.Errorf("invalid elliptic curve private key value")
|
||||
}
|
||||
privateKey := make([]byte, (curveOrder.BitLen()+7)/8)
|
||||
for len(priKey.PrivateKey) > len(privateKey) {
|
||||
if priKey.PrivateKey[0] != 0 {
|
||||
return nil, fmt.Errorf("invalid private key")
|
||||
}
|
||||
priKey.PrivateKey = priKey.PrivateKey[1:]
|
||||
}
|
||||
copy(privateKey[len(privateKey)-len(priKey.PrivateKey):], priKey.PrivateKey)
|
||||
x, y := curve.ScalarBaseMult(privateKey)
|
||||
return &model.PrivateKey{
|
||||
PublicKey: &model.PublicKey{
|
||||
Curve: curve,
|
||||
X: x,
|
||||
Y: y,
|
||||
},
|
||||
D: k,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func ParsePKCS8UnEncryptedPrivateKey(bytes []byte) (Sm2PrivateKey, error) {
|
||||
var pk pkcs8
|
||||
var priKey Sm2PrivateKey
|
||||
|
||||
if _, err := asn1.Unmarshal(bytes, &pk); err != nil {
|
||||
return priKey, err
|
||||
}
|
||||
if !reflect.DeepEqual(pk.Algo.Algorithm, oidSM2) {
|
||||
return priKey, fmt.Errorf("not sm2 elliptic curve")
|
||||
}
|
||||
|
||||
if _, err := asn1.Unmarshal(pk.PrivateKey, &priKey); err != nil {
|
||||
return priKey, fmt.Errorf("privateKey is not sm2 private key: %s", err.Error())
|
||||
}
|
||||
return priKey, nil
|
||||
}
|
||||
|
||||
func ParsePKCS8EncryptedPrivateKey(bytes, pwd []byte) (Sm2PrivateKey, error) {
|
||||
var keyInfo EncryptedPrivateKeyInfo
|
||||
var priKey Sm2PrivateKey
|
||||
_, err := asn1.Unmarshal(bytes, &keyInfo)
|
||||
if err != nil {
|
||||
return priKey, fmt.Errorf("privateKey is not sm2 encrypted private key: %s", err.Error())
|
||||
}
|
||||
if !reflect.DeepEqual(keyInfo.EncryptionAlgorithm.IdPBES2, oidPBES2) {
|
||||
return priKey, fmt.Errorf("x509: only support PBES2")
|
||||
}
|
||||
encryptionScheme := keyInfo.EncryptionAlgorithm.Pbes2Params.EncryptionScheme
|
||||
keyDerivationFunc := keyInfo.EncryptionAlgorithm.Pbes2Params.KeyDerivationFunc
|
||||
if !reflect.DeepEqual(keyDerivationFunc.IdPBKDF2, oidPBKDF2) {
|
||||
return priKey, fmt.Errorf("x509: only support PBKDF2")
|
||||
}
|
||||
pkdf2Params := keyDerivationFunc.Pkdf2Params
|
||||
if !reflect.DeepEqual(encryptionScheme.EncryAlgo, oidAES128CBC) &&
|
||||
!reflect.DeepEqual(encryptionScheme.EncryAlgo, oidAES256CBC) {
|
||||
return priKey, fmt.Errorf("x509: only support AES")
|
||||
}
|
||||
iv := encryptionScheme.IV
|
||||
salt := pkdf2Params.Salt
|
||||
iter := pkdf2Params.IterationCount
|
||||
encryptedKey := keyInfo.EncryptedData
|
||||
var key []byte
|
||||
switch {
|
||||
case pkdf2Params.Prf.Algorithm.Equal(oidKEYMD5):
|
||||
key = pbkdf(pwd, salt, iter, 32, md5.New)
|
||||
break
|
||||
case pkdf2Params.Prf.Algorithm.Equal(oidKEYSHA1):
|
||||
key = pbkdf(pwd, salt, iter, 32, sha1.New)
|
||||
break
|
||||
case pkdf2Params.Prf.Algorithm.Equal(oidKEYSHA256):
|
||||
key = pbkdf(pwd, salt, iter, 32, sha256.New)
|
||||
break
|
||||
case pkdf2Params.Prf.Algorithm.Equal(oidKEYSHA512):
|
||||
key = pbkdf(pwd, salt, iter, 32, sha512.New)
|
||||
break
|
||||
default:
|
||||
return priKey, fmt.Errorf("x509: unknown hash algorithm")
|
||||
}
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
return priKey, err
|
||||
}
|
||||
mode := cipher.NewCBCDecrypter(block, iv)
|
||||
mode.CryptBlocks(encryptedKey, encryptedKey)
|
||||
return ParsePKCS8UnEncryptedPrivateKey(encryptedKey)
|
||||
}
|
||||
|
||||
// copy from crypto/pbkdf2.go
|
||||
func pbkdf(password, salt []byte, iter, keyLen int, h func() hash.Hash) []byte {
|
||||
prf := hmac.New(h, password)
|
||||
hashLen := prf.Size()
|
||||
numBlocks := (keyLen + hashLen - 1) / hashLen
|
||||
|
||||
var buf [4]byte
|
||||
dk := make([]byte, 0, numBlocks*hashLen)
|
||||
U := make([]byte, hashLen)
|
||||
for block := 1; block <= numBlocks; block++ {
|
||||
// N.B.: || means concatenation, ^ means XOR
|
||||
// for each block T_i = U_1 ^ U_2 ^ ... ^ U_iter
|
||||
// U_1 = PRF(password, salt || uint(i))
|
||||
prf.Reset()
|
||||
prf.Write(salt)
|
||||
buf[0] = byte(block >> 24)
|
||||
buf[1] = byte(block >> 16)
|
||||
buf[2] = byte(block >> 8)
|
||||
buf[3] = byte(block)
|
||||
prf.Write(buf[:4])
|
||||
dk = prf.Sum(dk)
|
||||
T := dk[len(dk)-hashLen:]
|
||||
copy(U, T)
|
||||
|
||||
// U_n = PRF(password, U_(n-1))
|
||||
for n := 2; n <= iter; n++ {
|
||||
prf.Reset()
|
||||
prf.Write(U)
|
||||
U = U[:0]
|
||||
U = prf.Sum(U)
|
||||
for x := range U {
|
||||
T[x] ^= U[x]
|
||||
}
|
||||
}
|
||||
}
|
||||
return dk[:keyLen]
|
||||
}
|
||||
|
||||
func MarshalSm2PrivateKey(key *model.PrivateKey, pwd []byte) ([]byte, error) {
|
||||
if pwd == nil {
|
||||
return MarshalSm2UnEncryptedPrivateKey(key)
|
||||
}
|
||||
return MarshalSm2EncryptedPrivateKey(key, pwd)
|
||||
}
|
||||
|
||||
func MarshalSm2EncryptedPrivateKey(priKey *model.PrivateKey, pwd []byte) ([]byte, error) {
|
||||
der, err := MarshalSm2UnEncryptedPrivateKey(priKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
iter := 2048
|
||||
salt := make([]byte, 8)
|
||||
iv := make([]byte, 16)
|
||||
rand.Reader.Read(salt)
|
||||
rand.Reader.Read(iv)
|
||||
key := pbkdf(pwd, salt, iter, 32, sha1.New) // 默认是SHA1
|
||||
padding := aes.BlockSize - len(der)%aes.BlockSize
|
||||
if padding > 0 {
|
||||
n := len(der)
|
||||
der = append(der, make([]byte, padding)...)
|
||||
for i := 0; i < padding; i++ {
|
||||
der[n+i] = byte(padding)
|
||||
}
|
||||
}
|
||||
encryptedKey := make([]byte, len(der))
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mode := cipher.NewCBCEncrypter(block, iv)
|
||||
mode.CryptBlocks(encryptedKey, der)
|
||||
var algorithmIdentifier pkix.AlgorithmIdentifier
|
||||
algorithmIdentifier.Algorithm = oidKEYSHA1
|
||||
algorithmIdentifier.Parameters.Tag = 5
|
||||
algorithmIdentifier.Parameters.IsCompound = false
|
||||
algorithmIdentifier.Parameters.FullBytes = []byte{5, 0}
|
||||
keyDerivationFunc := Pbes2KDfs{
|
||||
oidPBKDF2,
|
||||
Pkdf2Params{
|
||||
salt,
|
||||
iter,
|
||||
algorithmIdentifier,
|
||||
},
|
||||
}
|
||||
encryptionScheme := Pbes2Encs{
|
||||
oidAES256CBC,
|
||||
iv,
|
||||
}
|
||||
pbes2Algorithms := Pbes2Algorithms{
|
||||
oidPBES2,
|
||||
Pbes2Params{
|
||||
keyDerivationFunc,
|
||||
encryptionScheme,
|
||||
},
|
||||
}
|
||||
encryptedPkey := EncryptedPrivateKeyInfo{
|
||||
pbes2Algorithms,
|
||||
encryptedKey,
|
||||
}
|
||||
return asn1.Marshal(encryptedPkey)
|
||||
}
|
||||
|
||||
func MarshalSm2UnEncryptedPrivateKey(key *model.PrivateKey) ([]byte, error) {
|
||||
var r pkcs8
|
||||
var pri Sm2PrivateKey
|
||||
var algo pkix.AlgorithmIdentifier
|
||||
|
||||
algo.Algorithm = oidSM2
|
||||
algo.Parameters.Class = 0
|
||||
algo.Parameters.Tag = 6
|
||||
algo.Parameters.IsCompound = false
|
||||
algo.Parameters.FullBytes = []byte{6, 8, 42, 129, 28, 207, 85, 1, 130, 45} // asn1.Marshal(asn1.ObjectIdentifier{1, 2, 156, 10197, 1, 301})
|
||||
pri.Version = 1
|
||||
pri.NamedCurveOID = oidNamedCurveP256SM2
|
||||
pri.PublicKey = asn1.BitString{Bytes: elliptic.Marshal(key.Curve, key.X, key.Y)}
|
||||
pri.PrivateKey = key.D.Bytes()
|
||||
r.Version = 0
|
||||
r.Algo = algo
|
||||
r.PrivateKey, _ = asn1.Marshal(pri)
|
||||
return asn1.Marshal(r)
|
||||
}
|
||||
|
||||
func MarshalSm2PublicKey(key *model.PublicKey) ([]byte, error) {
|
||||
var r PKIXPublicKey
|
||||
var algo pkix.AlgorithmIdentifier
|
||||
|
||||
if key.Curve.Params() != NewP256Sm2().Params() {
|
||||
return nil, fmt.Errorf("x509: unsupported elliptic curve")
|
||||
}
|
||||
algo.Algorithm = oidSM2
|
||||
algo.Parameters.Class = 0
|
||||
algo.Parameters.Tag = 6
|
||||
algo.Parameters.IsCompound = false
|
||||
algo.Parameters.FullBytes = []byte{6, 8, 42, 129, 28, 207, 85, 1, 130, 45} // asn1.Marshal(asn1.ObjectIdentifier{1, 2, 156, 10197, 1, 301})
|
||||
r.Algo = algo
|
||||
r.BitString = asn1.BitString{Bytes: elliptic.Marshal(key.Curve, key.X, key.Y)}
|
||||
return asn1.Marshal(r)
|
||||
}
|
||||
|
|
@ -0,0 +1,245 @@
|
|||
package util
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"hash"
|
||||
)
|
||||
|
||||
type SM3 struct {
|
||||
digest [8]uint32 // digest represents the partial evaluation of V
|
||||
length uint64 // length of the message
|
||||
unHandleMsg []byte // uint8 //
|
||||
}
|
||||
|
||||
func (sm3 *SM3) ff0(x, y, z uint32) uint32 { return x ^ y ^ z }
|
||||
|
||||
func (sm3 *SM3) ff1(x, y, z uint32) uint32 { return (x & y) | (x & z) | (y & z) }
|
||||
|
||||
func (sm3 *SM3) gg0(x, y, z uint32) uint32 { return x ^ y ^ z }
|
||||
|
||||
func (sm3 *SM3) gg1(x, y, z uint32) uint32 { return (x & y) | (^x & z) }
|
||||
|
||||
func (sm3 *SM3) p0(x uint32) uint32 { return x ^ sm3.leftRotate(x, 9) ^ sm3.leftRotate(x, 17) }
|
||||
|
||||
func (sm3 *SM3) p1(x uint32) uint32 { return x ^ sm3.leftRotate(x, 15) ^ sm3.leftRotate(x, 23) }
|
||||
|
||||
func (sm3 *SM3) leftRotate(x uint32, i uint32) uint32 { return x<<(i%32) | x>>(32-i%32) }
|
||||
|
||||
func (sm3 *SM3) pad() []byte {
|
||||
msg := sm3.unHandleMsg
|
||||
msg = append(msg, 0x80) // Append '1'
|
||||
blockSize := 64 // Append until the resulting message length (in bits) is congruent to 448 (mod 512)
|
||||
for len(msg)%blockSize != 56 {
|
||||
msg = append(msg, 0x00)
|
||||
}
|
||||
// append message length
|
||||
msg = append(msg, uint8(sm3.length>>56&0xff))
|
||||
msg = append(msg, uint8(sm3.length>>48&0xff))
|
||||
msg = append(msg, uint8(sm3.length>>40&0xff))
|
||||
msg = append(msg, uint8(sm3.length>>32&0xff))
|
||||
msg = append(msg, uint8(sm3.length>>24&0xff))
|
||||
msg = append(msg, uint8(sm3.length>>16&0xff))
|
||||
msg = append(msg, uint8(sm3.length>>8&0xff))
|
||||
msg = append(msg, uint8(sm3.length>>0&0xff))
|
||||
|
||||
if len(msg)%64 != 0 {
|
||||
panic("------SM3 Pad: error msgLen =")
|
||||
}
|
||||
return msg
|
||||
}
|
||||
|
||||
func (sm3 *SM3) update(msg []byte) {
|
||||
var w [68]uint32
|
||||
var w1 [64]uint32
|
||||
|
||||
a, b, c, d, e, f, g, h := sm3.digest[0], sm3.digest[1], sm3.digest[2], sm3.digest[3], sm3.digest[4], sm3.digest[5], sm3.digest[6], sm3.digest[7]
|
||||
for len(msg) >= 64 {
|
||||
for i := 0; i < 16; i++ {
|
||||
w[i] = binary.BigEndian.Uint32(msg[4*i : 4*(i+1)])
|
||||
}
|
||||
for i := 16; i < 68; i++ {
|
||||
w[i] = sm3.p1(w[i-16]^w[i-9]^sm3.leftRotate(w[i-3], 15)) ^ sm3.leftRotate(w[i-13], 7) ^ w[i-6]
|
||||
}
|
||||
for i := 0; i < 64; i++ {
|
||||
w1[i] = w[i] ^ w[i+4]
|
||||
}
|
||||
A, B, C, D, E, F, G, H := a, b, c, d, e, f, g, h
|
||||
for i := 0; i < 16; i++ {
|
||||
SS1 := sm3.leftRotate(sm3.leftRotate(A, 12)+E+sm3.leftRotate(0x79cc4519, uint32(i)), 7)
|
||||
SS2 := SS1 ^ sm3.leftRotate(A, 12)
|
||||
TT1 := sm3.ff0(A, B, C) + D + SS2 + w1[i]
|
||||
TT2 := sm3.gg0(E, F, G) + H + SS1 + w[i]
|
||||
D = C
|
||||
C = sm3.leftRotate(B, 9)
|
||||
B = A
|
||||
A = TT1
|
||||
H = G
|
||||
G = sm3.leftRotate(F, 19)
|
||||
F = E
|
||||
E = sm3.p0(TT2)
|
||||
}
|
||||
for i := 16; i < 64; i++ {
|
||||
SS1 := sm3.leftRotate(sm3.leftRotate(A, 12)+E+sm3.leftRotate(0x7a879d8a, uint32(i)), 7)
|
||||
SS2 := SS1 ^ sm3.leftRotate(A, 12)
|
||||
TT1 := sm3.ff1(A, B, C) + D + SS2 + w1[i]
|
||||
TT2 := sm3.gg1(E, F, G) + H + SS1 + w[i]
|
||||
D = C
|
||||
C = sm3.leftRotate(B, 9)
|
||||
B = A
|
||||
A = TT1
|
||||
H = G
|
||||
G = sm3.leftRotate(F, 19)
|
||||
F = E
|
||||
E = sm3.p0(TT2)
|
||||
}
|
||||
a ^= A
|
||||
b ^= B
|
||||
c ^= C
|
||||
d ^= D
|
||||
e ^= E
|
||||
f ^= F
|
||||
g ^= G
|
||||
h ^= H
|
||||
msg = msg[64:]
|
||||
}
|
||||
sm3.digest[0], sm3.digest[1], sm3.digest[2], sm3.digest[3], sm3.digest[4], sm3.digest[5], sm3.digest[6], sm3.digest[7] = a, b, c, d, e, f, g, h
|
||||
}
|
||||
func (sm3 *SM3) update2(msg []byte) [8]uint32 {
|
||||
var w [68]uint32
|
||||
var w1 [64]uint32
|
||||
|
||||
a, b, c, d, e, f, g, h := sm3.digest[0], sm3.digest[1], sm3.digest[2], sm3.digest[3], sm3.digest[4], sm3.digest[5], sm3.digest[6], sm3.digest[7]
|
||||
for len(msg) >= 64 {
|
||||
for i := 0; i < 16; i++ {
|
||||
w[i] = binary.BigEndian.Uint32(msg[4*i : 4*(i+1)])
|
||||
}
|
||||
for i := 16; i < 68; i++ {
|
||||
w[i] = sm3.p1(w[i-16]^w[i-9]^sm3.leftRotate(w[i-3], 15)) ^ sm3.leftRotate(w[i-13], 7) ^ w[i-6]
|
||||
}
|
||||
for i := 0; i < 64; i++ {
|
||||
w1[i] = w[i] ^ w[i+4]
|
||||
}
|
||||
A, B, C, D, E, F, G, H := a, b, c, d, e, f, g, h
|
||||
for i := 0; i < 16; i++ {
|
||||
SS1 := sm3.leftRotate(sm3.leftRotate(A, 12)+E+sm3.leftRotate(0x79cc4519, uint32(i)), 7)
|
||||
SS2 := SS1 ^ sm3.leftRotate(A, 12)
|
||||
TT1 := sm3.ff0(A, B, C) + D + SS2 + w1[i]
|
||||
TT2 := sm3.gg0(E, F, G) + H + SS1 + w[i]
|
||||
D = C
|
||||
C = sm3.leftRotate(B, 9)
|
||||
B = A
|
||||
A = TT1
|
||||
H = G
|
||||
G = sm3.leftRotate(F, 19)
|
||||
F = E
|
||||
E = sm3.p0(TT2)
|
||||
}
|
||||
for i := 16; i < 64; i++ {
|
||||
SS1 := sm3.leftRotate(sm3.leftRotate(A, 12)+E+sm3.leftRotate(0x7a879d8a, uint32(i)), 7)
|
||||
SS2 := SS1 ^ sm3.leftRotate(A, 12)
|
||||
TT1 := sm3.ff1(A, B, C) + D + SS2 + w1[i]
|
||||
TT2 := sm3.gg1(E, F, G) + H + SS1 + w[i]
|
||||
D = C
|
||||
C = sm3.leftRotate(B, 9)
|
||||
B = A
|
||||
A = TT1
|
||||
H = G
|
||||
G = sm3.leftRotate(F, 19)
|
||||
F = E
|
||||
E = sm3.p0(TT2)
|
||||
}
|
||||
a ^= A
|
||||
b ^= B
|
||||
c ^= C
|
||||
d ^= D
|
||||
e ^= E
|
||||
f ^= F
|
||||
g ^= G
|
||||
h ^= H
|
||||
msg = msg[64:]
|
||||
}
|
||||
var digest [8]uint32
|
||||
digest[0], digest[1], digest[2], digest[3], digest[4], digest[5], digest[6], digest[7] = a, b, c, d, e, f, g, h
|
||||
return digest
|
||||
}
|
||||
|
||||
// New 创建哈希计算实例
|
||||
func New() hash.Hash {
|
||||
var sm3 SM3
|
||||
|
||||
sm3.Reset()
|
||||
return &sm3
|
||||
}
|
||||
|
||||
// BlockSize returns the hash's underlying block size.
|
||||
// The Write method must be able to accept any amount
|
||||
// of data, but it may operate more efficiently if all writes
|
||||
// are a multiple of the block size.
|
||||
func (sm3 *SM3) BlockSize() int { return 64 }
|
||||
|
||||
// Size returns the number of bytes Sum will return.
|
||||
func (sm3 *SM3) Size() int { return 32 }
|
||||
|
||||
// Reset clears the internal state by zeroing bytes in the state buffer.
|
||||
// This can be skipped for a newly-created hash state; the default zero-allocated state is correct.
|
||||
func (sm3 *SM3) Reset() {
|
||||
// Reset digest
|
||||
sm3.digest[0] = 0x7380166f
|
||||
sm3.digest[1] = 0x4914b2b9
|
||||
sm3.digest[2] = 0x172442d7
|
||||
sm3.digest[3] = 0xda8a0600
|
||||
sm3.digest[4] = 0xa96f30bc
|
||||
sm3.digest[5] = 0x163138aa
|
||||
sm3.digest[6] = 0xe38dee4d
|
||||
sm3.digest[7] = 0xb0fb0e4e
|
||||
|
||||
sm3.length = 0 // Reset numberic states
|
||||
sm3.unHandleMsg = []byte{}
|
||||
}
|
||||
|
||||
// Write (via the embedded io.Writer interface) adds more data to the running hash.
|
||||
// It never returns an error.
|
||||
func (sm3 *SM3) Write(p []byte) (int, error) {
|
||||
toWrite := len(p)
|
||||
sm3.length += uint64(len(p) * 8)
|
||||
msg := append(sm3.unHandleMsg, p...)
|
||||
nblocks := len(msg) / sm3.BlockSize()
|
||||
sm3.update(msg)
|
||||
// Update unHandleMsg
|
||||
sm3.unHandleMsg = msg[nblocks*sm3.BlockSize():]
|
||||
|
||||
return toWrite, nil
|
||||
}
|
||||
|
||||
// Sum 返回SM3哈希算法摘要值
|
||||
// Sum appends the current hash to b and returns the resulting slice.
|
||||
// It does not change the underlying hash state.
|
||||
func (sm3 *SM3) Sum(in []byte) []byte {
|
||||
_, _ = sm3.Write(in)
|
||||
msg := sm3.pad()
|
||||
//Finalize
|
||||
digest := sm3.update2(msg)
|
||||
|
||||
// save hash to in
|
||||
needed := sm3.Size()
|
||||
if cap(in)-len(in) < needed {
|
||||
newIn := make([]byte, len(in), len(in)+needed)
|
||||
copy(newIn, in)
|
||||
in = newIn
|
||||
}
|
||||
out := in[len(in) : len(in)+needed]
|
||||
for i := 0; i < 8; i++ {
|
||||
binary.BigEndian.PutUint32(out[i*4:], digest[i])
|
||||
}
|
||||
return out
|
||||
|
||||
}
|
||||
|
||||
// Sm3Sum 返回SM3哈希算法摘要值
|
||||
func Sm3Sum(data []byte) []byte {
|
||||
var sm3 SM3
|
||||
|
||||
sm3.Reset()
|
||||
_, _ = sm3.Write(data)
|
||||
return sm3.Sum(nil)
|
||||
}
|
||||
|
|
@ -0,0 +1,122 @@
|
|||
package util
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"voucher/internal/pkg/cmb/sm2/model"
|
||||
)
|
||||
|
||||
func BigIntToByte(n *big.Int) []byte {
|
||||
byteArray := n.Bytes()
|
||||
|
||||
// If the bytes is not a multiple of 32, pad with zero bytes.
|
||||
byteArrLen := len(byteArray)
|
||||
KeyBytes := 32
|
||||
if byteArrLen == KeyBytes {
|
||||
return byteArray
|
||||
}
|
||||
byteArray = append(make([]byte, KeyBytes-byteArrLen), byteArray...)
|
||||
|
||||
// If the most significant byte's most significant bit is set,
|
||||
// prepend a 0 byte to the slice to avoid being interpreted as a negative number.
|
||||
if (byteArray[0] & 0x80) != 0 {
|
||||
byteArray = append([]byte{0}, byteArray...)
|
||||
}
|
||||
return byteArray
|
||||
}
|
||||
|
||||
func JoinBytes(params ...[]byte) ([]byte, error) {
|
||||
var buffer bytes.Buffer
|
||||
for i := 0; i < len(params); i++ {
|
||||
_, err := buffer.Write(params[i])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return buffer.Bytes(), nil
|
||||
}
|
||||
|
||||
func HexToPrivateKey(d []byte) (*model.PrivateKey, error) {
|
||||
k := new(big.Int).SetBytes(d)
|
||||
c := NewP256Sm2()
|
||||
params := c.Params()
|
||||
n := new(big.Int).Sub(params.N, model.One)
|
||||
if k.Cmp(n) >= 0 {
|
||||
return nil, fmt.Errorf("privateKey is overflow")
|
||||
}
|
||||
pri := &model.PrivateKey{
|
||||
PublicKey: &model.PublicKey{},
|
||||
D: nil,
|
||||
}
|
||||
pri.PublicKey.Curve = c
|
||||
pri.D = k
|
||||
pri.PublicKey.X, pri.PublicKey.Y = c.ScalarBaseMult(k.Bytes())
|
||||
return pri, nil
|
||||
}
|
||||
|
||||
func HexToPublicKey(d []byte) (*model.PublicKey, error) {
|
||||
if len(d) == 65 && d[0] == byte(0x04) {
|
||||
d = d[1:]
|
||||
}
|
||||
if len(d) != 64 {
|
||||
return nil, fmt.Errorf("publicKey is not 64 bytes: %d", len(d))
|
||||
}
|
||||
pub := new(model.PublicKey)
|
||||
pub.Curve = NewP256Sm2()
|
||||
pub.X = new(big.Int).SetBytes(d[:32])
|
||||
pub.Y = new(big.Int).SetBytes(d[32:])
|
||||
return pub, nil
|
||||
}
|
||||
|
||||
func PrivateKeyToHex(key *model.PrivateKey) string {
|
||||
return key.D.Text(16)
|
||||
}
|
||||
|
||||
func PublicKeyToHex(key *model.PublicKey) string {
|
||||
x := key.X.Bytes()
|
||||
y := key.Y.Bytes()
|
||||
if n := len(x); n < 32 {
|
||||
x = append(zeroByteSlice()[:32-n], x...)
|
||||
}
|
||||
if n := len(y); n < 32 {
|
||||
y = append(zeroByteSlice()[:32-n], y...)
|
||||
}
|
||||
var c []byte
|
||||
c = append(c, x...)
|
||||
c = append(c, y...)
|
||||
c = append([]byte{0x04}, c...)
|
||||
return hex.EncodeToString(c)
|
||||
}
|
||||
|
||||
// 32byte
|
||||
func zeroByteSlice() []byte {
|
||||
return []byte{
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
}
|
||||
}
|
||||
|
||||
func HexToSignature(hexStr string) (s model.Signature, err error) {
|
||||
signData, err := hex.DecodeString(hexStr)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
rBy := make([]byte, 33)
|
||||
copy(rBy[1:], signData[:32])
|
||||
rBy[0] = 0x00
|
||||
s.R = new(big.Int).SetBytes(rBy)
|
||||
|
||||
sBy := make([]byte, 33)
|
||||
copy(sBy[1:], signData[32:64])
|
||||
sBy[0] = 0x00
|
||||
s.S = new(big.Int).SetBytes(sBy)
|
||||
return
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
package util
|
||||
|
||||
import (
|
||||
"codeup.aliyun.com/lsxd/backend_deveoper/gmutil/sm2/model"
|
||||
"crypto/elliptic"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/asn1"
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
var (
|
||||
oidNamedCurveP256SM2 = asn1.ObjectIdentifier{1, 2, 156, 10197, 1, 301} // I get the SM2 ID through parsing the pem file generated by gmssl
|
||||
)
|
||||
|
||||
// PKIXPublicKey reflects a PKIX public key structure. See SubjectPublicKeyInfo
|
||||
// in RFC 3280.
|
||||
type PKIXPublicKey struct {
|
||||
Algo pkix.AlgorithmIdentifier
|
||||
BitString asn1.BitString
|
||||
}
|
||||
|
||||
func ParsePublicKey(bytes []byte) (*model.PublicKey, error) {
|
||||
var pk PKIXPublicKey
|
||||
if _, err := asn1.Unmarshal(bytes, &pk); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !reflect.DeepEqual(pk.Algo.Algorithm, oidSM2) {
|
||||
return nil, fmt.Errorf("not sm2 elliptic curve")
|
||||
}
|
||||
curve := NewP256Sm2()
|
||||
x, y := elliptic.Unmarshal(curve, pk.BitString.Bytes)
|
||||
return &model.PublicKey{
|
||||
Curve: curve,
|
||||
X: x,
|
||||
Y: y,
|
||||
}, nil
|
||||
}
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
package cmb
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestGenerateSm2Key(t *testing.T) {
|
||||
got, got1 := GenerateSm2Key()
|
||||
t.Log("SM2私钥:", got, len(got))
|
||||
t.Log("SM2公钥:", got1, len(got1))
|
||||
|
||||
smbPrk := "a9106d11232db8ea5071c47c5f73c88668225438e61c1f81804016db75fac223"
|
||||
cmbPuk := "04a702106cf530dc981e44cd515b394747cfd6bb059247696b188b25281ea4278fe7c6e34a83680110eec71becd31f5db14abc671e5d8e67ce7ca3c6b3adc86674"
|
||||
t.Log("SM2私钥:", smbPrk, len(smbPrk))
|
||||
t.Log("SM2公钥:", cmbPuk, len(cmbPuk))
|
||||
}
|
||||
|
||||
func TestEncrypt(t *testing.T) {
|
||||
pukKey := "04a702106cf530dc981e44cd515b394747cfd6bb059247696b188b25281ea4278fe7c6e34a83680110eec71becd31f5db14abc671e5d8e67ce7ca3c6b3adc86674"
|
||||
content := `{"name":"zhangxx","phoneNo":"137xxxxxxxx"}`
|
||||
base64Content := base64.StdEncoding.EncodeToString([]byte(content))
|
||||
xx, err := encrypt(pukKey, base64Content)
|
||||
t.Log(xx, err)
|
||||
}
|
||||
|
||||
func TestDecrypt(t *testing.T) {
|
||||
priKey := "9450c673cf801164435b9c164ac1404e87997245bc6f323fde22015875a03f6e"
|
||||
content := "BHeko/ZYFzQOJn6Q3y46X1AjNz8Nh5fq1FfMuWebh+TangLnlK5iFqePCst4rjG/FKJInijiKO2Qq18sJULlMEEgri05s+bHHDKM+Y+73crAbCnIhHbZxUjt8A0cq2rKjzkl8bxW33dU18uuiTEAmsAvKvmZgE6zJ1eDyjFWefHEIFJaKCNY2cTQOInt|8UYFZFTkx0DovPhaWCbdBkAqbgGmegT14F5gwXLJ6G1uWdYNvX+i5QWAYUGtd8u9"
|
||||
base64Content := base64.StdEncoding.EncodeToString([]byte(content))
|
||||
xx, err := decrypt(priKey, base64Content)
|
||||
t.Log(xx, err)
|
||||
}
|
||||
|
||||
func TestEncryptDecrypt(t *testing.T) {
|
||||
priKey := "9450c673cf801164435b9c164ac1404e87997245bc6f323fde22015875a03f6e"
|
||||
pukKey := "04a702106cf530dc981e44cd515b394747cfd6bb059247696b188b25281ea4278fe7c6e34a83680110eec71becd31f5db14abc671e5d8e67ce7ca3c6b3adc86674"
|
||||
|
||||
content := `{"name":"zhangxx","phoneNo":"137xxxxxxxx"}`
|
||||
base64EncryptContent := base64.StdEncoding.EncodeToString([]byte(content))
|
||||
|
||||
xx, err := encrypt(pukKey, base64EncryptContent)
|
||||
if err != nil {
|
||||
t.Log(err)
|
||||
return
|
||||
}
|
||||
t.Log(xx)
|
||||
|
||||
base64DecryptContent := base64.StdEncoding.EncodeToString([]byte(xx))
|
||||
aa, err := decrypt(priKey, base64DecryptContent)
|
||||
if err != nil {
|
||||
t.Log(err)
|
||||
return
|
||||
}
|
||||
t.Log(aa)
|
||||
}
|
||||
|
||||
func TestSign(t *testing.T) {
|
||||
priKey := "E2C0860DAB46D3D2DBEF846450A1356B1F39E32F74770C165625E6822B2322F9"
|
||||
content := "accessToken.json?aid=9dad6d3900ec3ffabd80e46522a10ead&cmbKeyAlias=SM2_CMBLIFE&date=20240314091628&encryptBody=BNhquiza494xicGIOvE7G5jLr7nhQI6Tp4V5j3a+3P98oD+uUKVXAPXt+ae3GsDvs+FyOaqoNSzdYsSqNDW3rA1AFUbsljTI9EaWMB+FAHpZ3Wjn6Qyl8EzJpUIbCnqAIOWjr2hDsexJd+NPVxQwNqq9W66lC/PBC4/1/QCz+87Yq8b4hHx7bP2u5h95|YwTJn3uKMQfhDSuJKIx3hyFZcoLm9M2xKnVDmNLPq5PbGedoZY/4g1Z/sKk8cWzH&keyAlias=CO_PUB_KEY_SM2&mid=f806c259d86e3b9aa956c98d475b6af7&random=320bcb8c8cf7419e98d562439bdb3baa"
|
||||
base64Content := base64.StdEncoding.EncodeToString([]byte(content))
|
||||
xx, err := sign(priKey, base64Content)
|
||||
t.Log(xx, err)
|
||||
}
|
||||
|
||||
func TestVerify(t *testing.T) {
|
||||
priKey := "046E358B0EF1A12BEF28DF261DEF7FB7840037D9A1F5F6097DC8D5F8B036796558DA301220EB12C152FF3EC0B0A47DBAD9FA256446B070923B7CD17A6BAEAA45D7"
|
||||
content := "accessToken.json?aid=9dad6d3900ec3ffabd80e46522a10ead&cmbKeyAlias=SM2_CMBLIFE&date=20240314091628&encryptBody=BNhquiza494xicGIOvE7G5jLr7nhQI6Tp4V5j3a+3P98oD+uUKVXAPXt+ae3GsDvs+FyOaqoNSzdYsSqNDW3rA1AFUbsljTI9EaWMB+FAHpZ3Wjn6Qyl8EzJpUIbCnqAIOWjr2hDsexJd+NPVxQwNqq9W66lC/PBC4/1/QCz+87Yq8b4hHx7bP2u5h95|YwTJn3uKMQfhDSuJKIx3hyFZcoLm9M2xKnVDmNLPq5PbGedoZY/4g1Z/sKk8cWzH&keyAlias=CO_PUB_KEY_SM2&mid=f806c259d86e3b9aa956c98d475b6af7&random=320bcb8c8cf7419e98d562439bdb3baa"
|
||||
signDataBase64 := "MEQCIBI78ahUGpq7vE2pi48d79vUIKqld4jbPiCSg/UwZwv9AiB+d6DmFpPoGsRFUeY9pJd0fKujsXa8h8/wjEBoptd1Kg=="
|
||||
base64Content := base64.StdEncoding.EncodeToString([]byte(content))
|
||||
xx, err := verify(priKey, base64Content, signDataBase64)
|
||||
t.Log(xx, err)
|
||||
}
|
||||
|
|
@ -0,0 +1,111 @@
|
|||
package cmb
|
||||
|
||||
import (
|
||||
"crypto/cipher"
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"github.com/tjfoc/gmsm/sm4"
|
||||
)
|
||||
|
||||
func generateSm4Key() (string, error) {
|
||||
keyBytes, err := generateKey()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return ByteArrayToHexString(keyBytes)
|
||||
}
|
||||
|
||||
func generateKey() ([]byte, error) {
|
||||
key := make([]byte, sm4.BlockSize)
|
||||
_, err := rand.Read(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return key, nil
|
||||
}
|
||||
|
||||
// ByteArrayToHexString 将字节数组转换为十六进制字符串
|
||||
func ByteArrayToHexString(byteArray []byte) (string, error) {
|
||||
if byteArray == nil {
|
||||
return "", fmt.Errorf("byteArray is nil")
|
||||
}
|
||||
result := make([]byte, 0, len(byteArray)*2)
|
||||
for _, b := range byteArray {
|
||||
// 处理高 4 位
|
||||
result = append(result, byteToHexChar(b>>4))
|
||||
// 处理低 4 位
|
||||
result = append(result, byteToHexChar(b&0x0F))
|
||||
}
|
||||
return string(result), nil
|
||||
}
|
||||
|
||||
// byteToHexChar 将一个 4 位字节转换为对应的十六进制字符
|
||||
func byteToHexChar(n byte) byte {
|
||||
if n < 10 {
|
||||
return '0' + n
|
||||
}
|
||||
return 'a' + n - 10
|
||||
}
|
||||
|
||||
func SM4Encrypt(contentBytes []byte, encryptKey string) (string, error) {
|
||||
d, err := base64.StdEncoding.DecodeString(encryptKey)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
cipherBlock, err := sm4.NewCipher(d)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
blockSize := cipherBlock.BlockSize()
|
||||
iv := make([]byte, blockSize)
|
||||
for i := 0; i < blockSize; i++ {
|
||||
iv[i] = 0
|
||||
}
|
||||
|
||||
blockMode := cipher.NewCBCEncrypter(cipherBlock, iv)
|
||||
|
||||
padding := blockSize - len(contentBytes)%blockSize
|
||||
for i := 0; i < padding; i++ {
|
||||
contentBytes = append(contentBytes, byte(padding))
|
||||
}
|
||||
cipherText := make([]byte, len(contentBytes))
|
||||
blockMode.CryptBlocks(cipherText, contentBytes)
|
||||
|
||||
return base64.StdEncoding.EncodeToString(cipherText), nil
|
||||
}
|
||||
|
||||
func SM4Decrypt(encrypted, encryptKey string) (string, error) {
|
||||
d, err := base64.StdEncoding.DecodeString(encryptKey)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
cipherBlock, err := sm4.NewCipher(d)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
blockSize := cipherBlock.BlockSize()
|
||||
iv := make([]byte, blockSize)
|
||||
for i := 0; i < blockSize; i++ {
|
||||
iv[i] = 0
|
||||
}
|
||||
|
||||
cipherText, err := base64.StdEncoding.DecodeString(encrypted)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
plainText := make([]byte, len(cipherText))
|
||||
blockMode := cipher.NewCBCDecrypter(cipherBlock, iv)
|
||||
blockMode.CryptBlocks(plainText, cipherText)
|
||||
|
||||
plainTextLen := len(plainText)
|
||||
padding := int(plainText[plainTextLen-1])
|
||||
buff := plainText[:plainTextLen-padding]
|
||||
|
||||
return string(buff), nil
|
||||
}
|
||||
|
|
@ -0,0 +1,378 @@
|
|||
package sm4
|
||||
|
||||
import (
|
||||
"crypto/cipher"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"math/bits"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
const (
|
||||
BlockSize = 16
|
||||
KeySize = 16
|
||||
)
|
||||
|
||||
var sBox = [256]byte{
|
||||
0xd6, 0x90, 0xe9, 0xfe, 0xcc, 0xe1, 0x3d, 0xb7,
|
||||
0x16, 0xb6, 0x14, 0xc2, 0x28, 0xfb, 0x2c, 0x05,
|
||||
0x2b, 0x67, 0x9a, 0x76, 0x2a, 0xbe, 0x04, 0xc3,
|
||||
0xaa, 0x44, 0x13, 0x26, 0x49, 0x86, 0x06, 0x99,
|
||||
0x9c, 0x42, 0x50, 0xf4, 0x91, 0xef, 0x98, 0x7a,
|
||||
0x33, 0x54, 0x0b, 0x43, 0xed, 0xcf, 0xac, 0x62,
|
||||
0xe4, 0xb3, 0x1c, 0xa9, 0xc9, 0x08, 0xe8, 0x95,
|
||||
0x80, 0xdf, 0x94, 0xfa, 0x75, 0x8f, 0x3f, 0xa6,
|
||||
0x47, 0x07, 0xa7, 0xfc, 0xf3, 0x73, 0x17, 0xba,
|
||||
0x83, 0x59, 0x3c, 0x19, 0xe6, 0x85, 0x4f, 0xa8,
|
||||
0x68, 0x6b, 0x81, 0xb2, 0x71, 0x64, 0xda, 0x8b,
|
||||
0xf8, 0xeb, 0x0f, 0x4b, 0x70, 0x56, 0x9d, 0x35,
|
||||
0x1e, 0x24, 0x0e, 0x5e, 0x63, 0x58, 0xd1, 0xa2,
|
||||
0x25, 0x22, 0x7c, 0x3b, 0x01, 0x21, 0x78, 0x87,
|
||||
0xd4, 0x00, 0x46, 0x57, 0x9f, 0xd3, 0x27, 0x52,
|
||||
0x4c, 0x36, 0x02, 0xe7, 0xa0, 0xc4, 0xc8, 0x9e,
|
||||
0xea, 0xbf, 0x8a, 0xd2, 0x40, 0xc7, 0x38, 0xb5,
|
||||
0xa3, 0xf7, 0xf2, 0xce, 0xf9, 0x61, 0x15, 0xa1,
|
||||
0xe0, 0xae, 0x5d, 0xa4, 0x9b, 0x34, 0x1a, 0x55,
|
||||
0xad, 0x93, 0x32, 0x30, 0xf5, 0x8c, 0xb1, 0xe3,
|
||||
0x1d, 0xf6, 0xe2, 0x2e, 0x82, 0x66, 0xca, 0x60,
|
||||
0xc0, 0x29, 0x23, 0xab, 0x0d, 0x53, 0x4e, 0x6f,
|
||||
0xd5, 0xdb, 0x37, 0x45, 0xde, 0xfd, 0x8e, 0x2f,
|
||||
0x03, 0xff, 0x6a, 0x72, 0x6d, 0x6c, 0x5b, 0x51,
|
||||
0x8d, 0x1b, 0xaf, 0x92, 0xbb, 0xdd, 0xbc, 0x7f,
|
||||
0x11, 0xd9, 0x5c, 0x41, 0x1f, 0x10, 0x5a, 0xd8,
|
||||
0x0a, 0xc1, 0x31, 0x88, 0xa5, 0xcd, 0x7b, 0xbd,
|
||||
0x2d, 0x74, 0xd0, 0x12, 0xb8, 0xe5, 0xb4, 0xb0,
|
||||
0x89, 0x69, 0x97, 0x4a, 0x0c, 0x96, 0x77, 0x7e,
|
||||
0x65, 0xb9, 0xf1, 0x09, 0xc5, 0x6e, 0xc6, 0x84,
|
||||
0x18, 0xf0, 0x7d, 0xec, 0x3a, 0xdc, 0x4d, 0x20,
|
||||
0x79, 0xee, 0x5f, 0x3e, 0xd7, 0xcb, 0x39, 0x48,
|
||||
}
|
||||
|
||||
var cK = [32]uint32{
|
||||
0x00070e15, 0x1c232a31, 0x383f464d, 0x545b6269,
|
||||
0x70777e85, 0x8c939aa1, 0xa8afb6bd, 0xc4cbd2d9,
|
||||
0xe0e7eef5, 0xfc030a11, 0x181f262d, 0x343b4249,
|
||||
0x50575e65, 0x6c737a81, 0x888f969d, 0xa4abb2b9,
|
||||
0xc0c7ced5, 0xdce3eaf1, 0xf8ff060d, 0x141b2229,
|
||||
0x30373e45, 0x4c535a61, 0x686f767d, 0x848b9299,
|
||||
0xa0a7aeb5, 0xbcc3cad1, 0xd8dfe6ed, 0xf4fb0209,
|
||||
0x10171e25, 0x2c333a41, 0x484f565d, 0x646b7279,
|
||||
}
|
||||
|
||||
var fK = [4]uint32{
|
||||
0xa3b1bac6, 0x56aa3350, 0x677d9197, 0xb27022dc,
|
||||
}
|
||||
|
||||
type KeySizeError int
|
||||
|
||||
func (k KeySizeError) Error() string {
|
||||
return "sm4: invalid key size " + strconv.Itoa(int(k))
|
||||
}
|
||||
|
||||
type sm4Cipher struct {
|
||||
enc []uint32
|
||||
dec []uint32
|
||||
}
|
||||
|
||||
func NewCipher(key []byte) (cipher.Block, error) {
|
||||
n := len(key)
|
||||
if n != KeySize {
|
||||
return nil, KeySizeError(n)
|
||||
}
|
||||
c := new(sm4Cipher)
|
||||
c.enc = expandKey(key, true)
|
||||
c.dec = expandKey(key, false)
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func (c *sm4Cipher) BlockSize() int {
|
||||
return BlockSize
|
||||
}
|
||||
|
||||
func (c *sm4Cipher) Encrypt(dst, src []byte) {
|
||||
if len(src) < BlockSize {
|
||||
panic("sm4: input not full block")
|
||||
}
|
||||
if len(dst) < BlockSize {
|
||||
panic("sm4: output not full block")
|
||||
}
|
||||
processBlock(c.enc, src, dst)
|
||||
}
|
||||
|
||||
func (c *sm4Cipher) Decrypt(dst, src []byte) {
|
||||
if len(src) < BlockSize {
|
||||
panic("sm4: input not full block")
|
||||
}
|
||||
if len(dst) < BlockSize {
|
||||
panic("sm4: output not full block")
|
||||
}
|
||||
processBlock(c.dec, src, dst)
|
||||
}
|
||||
|
||||
func expandKey(key []byte, forEnc bool) []uint32 {
|
||||
var mK [4]uint32
|
||||
mK[0] = binary.BigEndian.Uint32(key[0:4])
|
||||
mK[1] = binary.BigEndian.Uint32(key[4:8])
|
||||
mK[2] = binary.BigEndian.Uint32(key[8:12])
|
||||
mK[3] = binary.BigEndian.Uint32(key[12:16])
|
||||
|
||||
var x [5]uint32
|
||||
x[0] = mK[0] ^ fK[0]
|
||||
x[1] = mK[1] ^ fK[1]
|
||||
x[2] = mK[2] ^ fK[2]
|
||||
x[3] = mK[3] ^ fK[3]
|
||||
|
||||
var rk [32]uint32
|
||||
if forEnc {
|
||||
for i := 0; i < 32; i++ {
|
||||
x[(i+4)%5] = encRound(x[i%5], x[(i+1)%5], x[(i+2)%5], x[(i+3)%5], x[(i+4)%5], rk[:], i)
|
||||
}
|
||||
} else {
|
||||
for i := 0; i < 32; i++ {
|
||||
x[(i+4)%5] = decRound(x[i%5], x[(i+1)%5], x[(i+2)%5], x[(i+3)%5], x[(i+4)%5], rk[:], i)
|
||||
}
|
||||
}
|
||||
return rk[:]
|
||||
}
|
||||
|
||||
func tau(a uint32) uint32 {
|
||||
var aArr [4]byte
|
||||
var bArr [4]byte
|
||||
binary.BigEndian.PutUint32(aArr[:], a)
|
||||
bArr[0] = sBox[aArr[0]]
|
||||
bArr[1] = sBox[aArr[1]]
|
||||
bArr[2] = sBox[aArr[2]]
|
||||
bArr[3] = sBox[aArr[3]]
|
||||
return binary.BigEndian.Uint32(bArr[:])
|
||||
}
|
||||
|
||||
func lAp(b uint32) uint32 {
|
||||
return b ^ bits.RotateLeft32(b, 13) ^ bits.RotateLeft32(b, 23)
|
||||
}
|
||||
|
||||
func tAp(z uint32) uint32 {
|
||||
return lAp(tau(z))
|
||||
}
|
||||
|
||||
func encRound(x0 uint32, x1 uint32, x2 uint32, x3 uint32, x4 uint32, rk []uint32, i int) uint32 {
|
||||
x4 = x0 ^ tAp(x1^x2^x3^cK[i])
|
||||
rk[i] = x4
|
||||
return x4
|
||||
}
|
||||
|
||||
func decRound(x0 uint32, x1 uint32, x2 uint32, x3 uint32, x4 uint32, rk []uint32, i int) uint32 {
|
||||
x4 = x0 ^ tAp(x1^x2^x3^cK[i])
|
||||
rk[31-i] = x4
|
||||
return x4
|
||||
}
|
||||
|
||||
func processBlock(rk []uint32, in []byte, out []byte) {
|
||||
var x [BlockSize / 4]uint32
|
||||
x[0] = binary.BigEndian.Uint32(in[0:4])
|
||||
x[1] = binary.BigEndian.Uint32(in[4:8])
|
||||
x[2] = binary.BigEndian.Uint32(in[8:12])
|
||||
x[3] = binary.BigEndian.Uint32(in[12:16])
|
||||
|
||||
for i := 0; i < 32; i += 4 {
|
||||
x[0] = f0(x[:], rk[i])
|
||||
x[1] = f1(x[:], rk[i+1])
|
||||
x[2] = f2(x[:], rk[i+2])
|
||||
x[3] = f3(x[:], rk[i+3])
|
||||
}
|
||||
r(x[:])
|
||||
|
||||
binary.BigEndian.PutUint32(out[0:4], x[0])
|
||||
binary.BigEndian.PutUint32(out[4:8], x[1])
|
||||
binary.BigEndian.PutUint32(out[8:12], x[2])
|
||||
binary.BigEndian.PutUint32(out[12:16], x[3])
|
||||
}
|
||||
|
||||
func l(b uint32) uint32 {
|
||||
return b ^ bits.RotateLeft32(b, 2) ^ bits.RotateLeft32(b, 10) ^
|
||||
bits.RotateLeft32(b, 18) ^ bits.RotateLeft32(b, 24)
|
||||
}
|
||||
|
||||
func t(z uint32) uint32 {
|
||||
return l(tau(z))
|
||||
}
|
||||
|
||||
func r(a []uint32) {
|
||||
a[0] = a[0] ^ a[3]
|
||||
a[3] = a[0] ^ a[3]
|
||||
a[0] = a[0] ^ a[3]
|
||||
a[1] = a[1] ^ a[2]
|
||||
a[2] = a[1] ^ a[2]
|
||||
a[1] = a[1] ^ a[2]
|
||||
}
|
||||
|
||||
func f0(x []uint32, rk uint32) uint32 {
|
||||
return x[0] ^ t(x[1]^x[2]^x[3]^rk)
|
||||
}
|
||||
|
||||
func f1(x []uint32, rk uint32) uint32 {
|
||||
return x[1] ^ t(x[2]^x[3]^x[0]^rk)
|
||||
}
|
||||
|
||||
func f2(x []uint32, rk uint32) uint32 {
|
||||
return x[2] ^ t(x[3]^x[0]^x[1]^rk)
|
||||
}
|
||||
|
||||
func f3(x []uint32, rk uint32) uint32 {
|
||||
return x[3] ^ t(x[0]^x[1]^x[2]^rk)
|
||||
}
|
||||
|
||||
func xor(in, iv []byte) (out []byte) {
|
||||
if len(in) != len(iv) {
|
||||
return nil
|
||||
}
|
||||
|
||||
out = make([]byte, len(in))
|
||||
for i := 0; i < len(in); i++ {
|
||||
out[i] = in[i] ^ iv[i]
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// ECBEncrypt 输入的plainText长度必须是BlockSize(16)的整数倍,也就是调用该方法前调用方需先加好padding
|
||||
func ECBEncrypt(key, plainText []byte) (cipherText []byte, err error) {
|
||||
plainTextLen := len(plainText)
|
||||
if plainTextLen%BlockSize != 0 {
|
||||
return nil, errors.New("input not full blocks")
|
||||
}
|
||||
|
||||
c, err := NewCipher(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cipherText = make([]byte, plainTextLen)
|
||||
for i := 0; i < plainTextLen; i += BlockSize {
|
||||
c.Encrypt(cipherText[i:i+BlockSize], plainText[i:i+BlockSize])
|
||||
}
|
||||
return cipherText, nil
|
||||
}
|
||||
|
||||
// ECBDecrypt 输出的plainText是加padding的明文,调用方需要自己去padding
|
||||
func ECBDecrypt(key, cipherText []byte) (plainText []byte, err error) {
|
||||
cipherTextLen := len(cipherText)
|
||||
if cipherTextLen%BlockSize != 0 {
|
||||
return nil, errors.New("input not full blocks")
|
||||
}
|
||||
|
||||
c, err := NewCipher(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
plainText = make([]byte, cipherTextLen)
|
||||
for i := 0; i < cipherTextLen; i += BlockSize {
|
||||
c.Decrypt(plainText[i:i+BlockSize], cipherText[i:i+BlockSize])
|
||||
}
|
||||
return plainText, nil
|
||||
}
|
||||
|
||||
// CBCEncrypt 输入的plainText长度必须是BlockSize(16)的整数倍,也就是调用该方法前调用方需先加好padding
|
||||
func CBCEncrypt(key, iv, plainText []byte) (cipherText []byte, err error) {
|
||||
plainTextLen := len(plainText)
|
||||
if plainTextLen%BlockSize != 0 {
|
||||
return nil, errors.New("input not full blocks")
|
||||
}
|
||||
|
||||
c, err := NewCipher(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
encrypter := cipher.NewCBCEncrypter(c, iv)
|
||||
cipherText = make([]byte, plainTextLen)
|
||||
encrypter.CryptBlocks(cipherText, plainText)
|
||||
return cipherText, nil
|
||||
}
|
||||
|
||||
// CBCDecrypt 输出的plainText是加padding的明文,调用方需要自己去padding
|
||||
func CBCDecrypt(key, iv, cipherText []byte) (plainText []byte, err error) {
|
||||
cipherTextLen := len(cipherText)
|
||||
if cipherTextLen%BlockSize != 0 {
|
||||
return nil, errors.New("input not full blocks")
|
||||
}
|
||||
|
||||
c, err := NewCipher(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
decrypter := cipher.NewCBCDecrypter(c, iv)
|
||||
plainText = make([]byte, len(cipherText))
|
||||
decrypter.CryptBlocks(plainText, cipherText)
|
||||
return plainText, nil
|
||||
}
|
||||
|
||||
// CFBEncrypt 输入的plainText长度必须是BlockSize(16)的整数倍,也就是调用该方法前调用方需先加好padding
|
||||
func CFBEncrypt(key, iv, plainText []byte) (cipherText []byte, err error) {
|
||||
plainTextLen := len(plainText)
|
||||
if plainTextLen%BlockSize != 0 {
|
||||
return nil, errors.New("input not full blocks")
|
||||
}
|
||||
|
||||
c, err := NewCipher(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cipherText = make([]byte, plainTextLen)
|
||||
copy(cipherText, plainText)
|
||||
cipher.NewCFBEncrypter(c, iv).XORKeyStream(cipherText, cipherText)
|
||||
return plainText, nil
|
||||
}
|
||||
|
||||
// CFBDecrypt 输出的plainText是加padding的明文,调用方需要自己去padding
|
||||
// https://blog.csdn.net/zy_strive_2012/article/details/102520356
|
||||
// https://blog.csdn.net/sinat_23338865/article/details/72869841
|
||||
func CFBDecrypt(key, iv, cipherText []byte) (plainText []byte, err error) {
|
||||
cipherTextLen := len(cipherText)
|
||||
if cipherTextLen%BlockSize != 0 {
|
||||
return nil, errors.New("input not full blocks")
|
||||
}
|
||||
|
||||
c, err := NewCipher(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
plainText = make([]byte, cipherTextLen)
|
||||
copy(plainText, cipherText)
|
||||
cipher.NewCFBDecrypter(c, iv).XORKeyStream(plainText, plainText)
|
||||
return plainText, nil
|
||||
}
|
||||
|
||||
// OFBEncrypt 输入反馈模式(Input feedback, OFB)
|
||||
func OFBEncrypt(key, iv, plainText []byte) (cipherText []byte, err error) {
|
||||
plainTextLen := len(plainText)
|
||||
if plainTextLen%BlockSize != 0 {
|
||||
return nil, errors.New("input not full blocks")
|
||||
}
|
||||
|
||||
c, err := NewCipher(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cipherText = make([]byte, plainTextLen)
|
||||
copy(cipherText, plainText)
|
||||
cipher.NewOFB(c, iv).XORKeyStream(cipherText, cipherText)
|
||||
return plainText, nil
|
||||
}
|
||||
|
||||
// OFBDecrypt 输出反馈模式(Output feedback, OFB)
|
||||
func OFBDecrypt(key, iv, cipherText []byte) (plainText []byte, err error) {
|
||||
cipherTextLen := len(cipherText)
|
||||
if cipherTextLen%BlockSize != 0 {
|
||||
return nil, errors.New("input not full blocks")
|
||||
}
|
||||
|
||||
c, err := NewCipher(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
plainText = make([]byte, cipherTextLen)
|
||||
copy(plainText, cipherText)
|
||||
cipher.NewOFB(c, iv).XORKeyStream(plainText, plainText)
|
||||
return plainText, nil
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
package sm4
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestECBDecrypt(t *testing.T) {
|
||||
decode, err := base64.StdEncoding.DecodeString("TfbbYELgZetVpVhhTK31Wg==")
|
||||
if err != nil {
|
||||
t.Fatalf("decode error: %v", err)
|
||||
}
|
||||
key := []byte{16, 101, 63, 34, 97, 41, 62, 49, 225, 208, 57, 189, 50, 158, 31, 100}
|
||||
//iv := []byte{34, 244, 188, 11, 120, 236, 119, 58, 191, 210, 3, 95, 85, 72, 172, 249}
|
||||
plainText, err := ECBDecrypt(key, decode)
|
||||
if err != nil {
|
||||
t.Fatalf("ecb decrypt error: %v", err)
|
||||
}
|
||||
t.Log("ecb decrypt result:", string(PKCS5UnPadding(plainText)))
|
||||
}
|
||||
|
||||
func TestCFBEncrypt(t *testing.T) {
|
||||
key := []byte{16, 101, 63, 34, 97, 41, 62, 49, 225, 208, 57, 189, 50, 158, 31, 100}
|
||||
iv := []byte{34, 244, 188, 11, 120, 236, 119, 58, 191, 210, 3, 95, 85, 72, 172, 249}
|
||||
decode, err := base64.StdEncoding.DecodeString("XO9I6k9h2zk/dHSK+zo3Dg==")
|
||||
if err != nil {
|
||||
t.Fatalf("decode error: %v", err)
|
||||
}
|
||||
bytes, err := OFBDecrypt(key, iv, decode)
|
||||
if err != nil {
|
||||
t.Fatalf("ecb decrypt error: %v", err)
|
||||
}
|
||||
t.Log("ecb decrypt result:", string(PKCS5UnPadding(bytes)))
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
package sm4
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func PKCS5Padding(src []byte, blockSize int) []byte {
|
||||
padding := blockSize - len(src)%blockSize
|
||||
padBytes := bytes.Repeat([]byte{byte(padding)}, padding)
|
||||
return append(src, padBytes...)
|
||||
}
|
||||
|
||||
func PKCS5UnPadding(src []byte) []byte {
|
||||
length := len(src)
|
||||
unPadding := int(src[length-1])
|
||||
return src[:(length - unPadding)]
|
||||
}
|
||||
|
||||
func PKCS7Padding(src []byte) []byte {
|
||||
padding := BlockSize - len(src)%BlockSize
|
||||
padBytes := bytes.Repeat([]byte{byte(padding)}, padding)
|
||||
return append(src, padBytes...)
|
||||
}
|
||||
|
||||
func PKCS7UnPadding(src []byte) ([]byte, error) {
|
||||
length := len(src)
|
||||
unPadding := int(src[length-1])
|
||||
if unPadding > BlockSize || unPadding == 0 {
|
||||
return nil, fmt.Errorf("invalid pkcs7 padding (unPadding > BlockSize || unPadding == 0)")
|
||||
}
|
||||
pad := src[len(src)-unPadding:]
|
||||
for i := 0; i < unPadding; i++ {
|
||||
if pad[i] != byte(unPadding) {
|
||||
return nil, fmt.Errorf("invalid pkcs7 padding (pad[i] != unPadding)")
|
||||
}
|
||||
}
|
||||
return src[:(length - unPadding)], nil
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
package cmb
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestGenerateSM4Key(t *testing.T) {
|
||||
got, err := generateSm4Key()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
t.Log(len(got))
|
||||
t.Log(len("ff875faf8b0fa394b811d62693d196f7"))
|
||||
t.Log("ff875faf8b0fa394b811d62693d196f7")
|
||||
t.Log(got)
|
||||
}
|
||||
|
||||
func TestSM4(t *testing.T) {
|
||||
encryptKey := "NnxLrCCyaYGZtL/FtUnraQ=="
|
||||
enc, err := SM4Encrypt([]byte("Ckm2BMNUppUJBNGA"), encryptKey)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
t.Log(enc)
|
||||
dec, err := SM4Decrypt(enc, encryptKey)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
t.Log(dec)
|
||||
}
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
package cmb
|
||||
|
||||
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 RandomBytes(16)
|
||||
}
|
||||
|
||||
func RandomBytes(length int) []byte {
|
||||
str := "qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM1234567890"
|
||||
buffer := make([]byte, length)
|
||||
for i := 0; i < 16; i++ {
|
||||
nextInt, _ := rand.Int(rand.Reader, big.NewInt(int64(len(str))))
|
||||
buffer[i] = str[nextInt.Int64()]
|
||||
}
|
||||
return buffer
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
func AssemblingByteArray(key, iv []byte) []byte {
|
||||
os := make([]byte, 0)
|
||||
os = append(os, key...)
|
||||
os = append(os, []byte("|")...)
|
||||
os = append(os, iv...)
|
||||
return os
|
||||
}
|
||||
Loading…
Reference in New Issue