diff --git a/go.mod b/go.mod index b8dc5b3..f5f061e 100644 --- a/go.mod +++ b/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 diff --git a/go.sum b/go.sum index 7a1e25f..c7e81e5 100644 --- a/go.sum +++ b/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= diff --git a/internal/pkg/cmb/sm2.go b/internal/pkg/cmb/sm2.go new file mode 100644 index 0000000..a270eb2 --- /dev/null +++ b/internal/pkg/cmb/sm2.go @@ -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 +} diff --git a/internal/pkg/cmb/sm2/errors.go b/internal/pkg/cmb/sm2/errors.go new file mode 100644 index 0000000..61499ce --- /dev/null +++ b/internal/pkg/cmb/sm2/errors.go @@ -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 +} diff --git a/internal/pkg/cmb/sm2/model/model.go b/internal/pkg/cmb/sm2/model/model.go new file mode 100644 index 0000000..56189ba --- /dev/null +++ b/internal/pkg/cmb/sm2/model/model.go @@ -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 +} diff --git a/internal/pkg/cmb/sm2/sdk/base.go b/internal/pkg/cmb/sm2/sdk/base.go new file mode 100644 index 0000000..c0d6313 --- /dev/null +++ b/internal/pkg/cmb/sm2/sdk/base.go @@ -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 +} diff --git a/internal/pkg/cmb/sm2/sdk/cmblife.go b/internal/pkg/cmb/sm2/sdk/cmblife.go new file mode 100644 index 0000000..c8fddb6 --- /dev/null +++ b/internal/pkg/cmb/sm2/sdk/cmblife.go @@ -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] + } +} diff --git a/internal/pkg/cmb/sm2/sdk/interface.go b/internal/pkg/cmb/sm2/sdk/interface.go new file mode 100644 index 0000000..eaaf83b --- /dev/null +++ b/internal/pkg/cmb/sm2/sdk/interface.go @@ -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) +} diff --git a/internal/pkg/cmb/sm2/sm2.go b/internal/pkg/cmb/sm2/sm2.go new file mode 100644 index 0000000..82d7a0d --- /dev/null +++ b/internal/pkg/cmb/sm2/sm2.go @@ -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 +} diff --git a/internal/pkg/cmb/sm2/sm2_test.go b/internal/pkg/cmb/sm2/sm2_test.go new file mode 100644 index 0000000..5fc9b5c --- /dev/null +++ b/internal/pkg/cmb/sm2/sm2_test.go @@ -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) +} diff --git a/internal/pkg/cmb/sm2/util/p256.go b/internal/pkg/cmb/sm2/util/p256.go new file mode 100644 index 0000000..cfc4a24 --- /dev/null +++ b/internal/pkg/cmb/sm2/util/p256.go @@ -0,0 +1,1143 @@ +package util + +import ( + "crypto/elliptic" + "math/big" + "sync" +) + +type sm2P256Curve struct { + RInverse *big.Int + *elliptic.CurveParams + a, b, gx, gy sm2P256FieldElement + A *big.Int +} + +var initOnce sync.Once +var sm2P256 sm2P256Curve + +type sm2P256FieldElement [9]uint32 +type sm2P256LargeFieldElement [17]uint64 + +const ( + bottom28Bits = 0xFFFFFFF + bottom29Bits = 0x1FFFFFFF +) + +func NewP256Sm2() sm2P256Curve { + initOnce.Do(initP256Sm2) + return sm2P256 +} + +func initP256Sm2() { + sm2P256.CurveParams = &elliptic.CurveParams{Name: "SM2-P-256"} // sm2 + sm2P256.A, _ = new(big.Int).SetString("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC", 16) + //SM2椭 椭 圆 曲 线 公 钥 密 码 算 法 推 荐 曲 线 参 数 + sm2P256.P, _ = new(big.Int).SetString("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF", 16) + sm2P256.N, _ = new(big.Int).SetString("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123", 16) + sm2P256.B, _ = new(big.Int).SetString("28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93", 16) + sm2P256.Gx, _ = new(big.Int).SetString("32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7", 16) + sm2P256.Gy, _ = new(big.Int).SetString("BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0", 16) + sm2P256.RInverse, _ = new(big.Int).SetString("7ffffffd80000002fffffffe000000017ffffffe800000037ffffffc80000002", 16) + sm2P256.BitSize = 256 + sm2P256FromBig(&sm2P256.a, sm2P256.A) + sm2P256FromBig(&sm2P256.gx, sm2P256.Gx) + sm2P256FromBig(&sm2P256.gy, sm2P256.Gy) + sm2P256FromBig(&sm2P256.b, sm2P256.B) +} + +func (curve sm2P256Curve) Params() *elliptic.CurveParams { + return sm2P256.CurveParams +} + +// y^2 = x^3 + ax + b +func (curve sm2P256Curve) IsOnCurve(X, Y *big.Int) bool { + var a, x, y, y2, x3 sm2P256FieldElement + + sm2P256FromBig(&x, X) + sm2P256FromBig(&y, Y) + + sm2P256Square(&x3, &x) // x3 = x ^ 2 + sm2P256Mul(&x3, &x3, &x) // x3 = x ^ 2 * x + sm2P256Mul(&a, &curve.a, &x) // a = a * x + sm2P256Add(&x3, &x3, &a) + sm2P256Add(&x3, &x3, &curve.b) + + sm2P256Square(&y2, &y) // y2 = y ^ 2 + return sm2P256ToBig(&x3).Cmp(sm2P256ToBig(&y2)) == 0 +} + +func zForAffine(x, y *big.Int) *big.Int { + z := new(big.Int) + if x.Sign() != 0 || y.Sign() != 0 { + z.SetInt64(1) + } + return z +} + +func (curve sm2P256Curve) Add(x1, y1, x2, y2 *big.Int) (*big.Int, *big.Int) { + var X1, Y1, Z1, X2, Y2, Z2, X3, Y3, Z3 sm2P256FieldElement + + z1 := zForAffine(x1, y1) + z2 := zForAffine(x2, y2) + sm2P256FromBig(&X1, x1) + sm2P256FromBig(&Y1, y1) + sm2P256FromBig(&Z1, z1) + sm2P256FromBig(&X2, x2) + sm2P256FromBig(&Y2, y2) + sm2P256FromBig(&Z2, z2) + sm2P256PointAdd(&X1, &Y1, &Z1, &X2, &Y2, &Z2, &X3, &Y3, &Z3) + return sm2P256ToAffine(&X3, &Y3, &Z3) +} + +func (curve sm2P256Curve) Double(x1, y1 *big.Int) (*big.Int, *big.Int) { + var X1, Y1, Z1 sm2P256FieldElement + + z1 := zForAffine(x1, y1) + sm2P256FromBig(&X1, x1) + sm2P256FromBig(&Y1, y1) + sm2P256FromBig(&Z1, z1) + sm2P256PointDouble(&X1, &Y1, &Z1, &X1, &Y1, &Z1) + return sm2P256ToAffine(&X1, &Y1, &Z1) +} + +func (curve sm2P256Curve) ScalarMult(x1, y1 *big.Int, k []byte) (*big.Int, *big.Int) { + var X, Y, Z, X1, Y1 sm2P256FieldElement + sm2P256FromBig(&X1, x1) + sm2P256FromBig(&Y1, y1) + scalar := sm2GenrateWNaf(k) + scalarReversed := WNafReversed(scalar) + sm2P256ScalarMult(&X, &Y, &Z, &X1, &Y1, scalarReversed) + return sm2P256ToAffine(&X, &Y, &Z) +} + +func (curve sm2P256Curve) ScalarBaseMult(k []byte) (*big.Int, *big.Int) { + var scalarReversed [32]byte + var X, Y, Z sm2P256FieldElement + + sm2P256GetScalar(&scalarReversed, k) + sm2P256ScalarBaseMult(&X, &Y, &Z, &scalarReversed) + return sm2P256ToAffine(&X, &Y, &Z) +} + +var sm2P256Precomputed = [9 * 2 * 15 * 2]uint32{ + 0x830053d, 0x328990f, 0x6c04fe1, 0xc0f72e5, 0x1e19f3c, 0x666b093, 0x175a87b, 0xec38276, 0x222cf4b, + 0x185a1bba, 0x354e593, 0x1295fac1, 0xf2bc469, 0x47c60fa, 0xc19b8a9, 0xf63533e, 0x903ae6b, 0xc79acba, + 0x15b061a4, 0x33e020b, 0xdffb34b, 0xfcf2c8, 0x16582e08, 0x262f203, 0xfb34381, 0xa55452, 0x604f0ff, + 0x41f1f90, 0xd64ced2, 0xee377bf, 0x75f05f0, 0x189467ae, 0xe2244e, 0x1e7700e8, 0x3fbc464, 0x9612d2e, + 0x1341b3b8, 0xee84e23, 0x1edfa5b4, 0x14e6030, 0x19e87be9, 0x92f533c, 0x1665d96c, 0x226653e, 0xa238d3e, + 0xf5c62c, 0x95bb7a, 0x1f0e5a41, 0x28789c3, 0x1f251d23, 0x8726609, 0xe918910, 0x8096848, 0xf63d028, + 0x152296a1, 0x9f561a8, 0x14d376fb, 0x898788a, 0x61a95fb, 0xa59466d, 0x159a003d, 0x1ad1698, 0x93cca08, + 0x1b314662, 0x706e006, 0x11ce1e30, 0x97b710, 0x172fbc0d, 0x8f50158, 0x11c7ffe7, 0xd182cce, 0xc6ad9e8, + 0x12ea31b2, 0xc4e4f38, 0x175b0d96, 0xec06337, 0x75a9c12, 0xb001fdf, 0x93e82f5, 0x34607de, 0xb8035ed, + 0x17f97924, 0x75cf9e6, 0xdceaedd, 0x2529924, 0x1a10c5ff, 0xb1a54dc, 0x19464d8, 0x2d1997, 0xde6a110, + 0x1e276ee5, 0x95c510c, 0x1aca7c7a, 0xfe48aca, 0x121ad4d9, 0xe4132c6, 0x8239b9d, 0x40ea9cd, 0x816c7b, + 0x632d7a4, 0xa679813, 0x5911fcf, 0x82b0f7c, 0x57b0ad5, 0xbef65, 0xd541365, 0x7f9921f, 0xc62e7a, + 0x3f4b32d, 0x58e50e1, 0x6427aed, 0xdcdda67, 0xe8c2d3e, 0x6aa54a4, 0x18df4c35, 0x49a6a8e, 0x3cd3d0c, + 0xd7adf2, 0xcbca97, 0x1bda5f2d, 0x3258579, 0x606b1e6, 0x6fc1b5b, 0x1ac27317, 0x503ca16, 0xa677435, + 0x57bc73, 0x3992a42, 0xbab987b, 0xfab25eb, 0x128912a4, 0x90a1dc4, 0x1402d591, 0x9ffbcfc, 0xaa48856, + 0x7a7c2dc, 0xcefd08a, 0x1b29bda6, 0xa785641, 0x16462d8c, 0x76241b7, 0x79b6c3b, 0x204ae18, 0xf41212b, + 0x1f567a4d, 0xd6ce6db, 0xedf1784, 0x111df34, 0x85d7955, 0x55fc189, 0x1b7ae265, 0xf9281ac, 0xded7740, + 0xf19468b, 0x83763bb, 0x8ff7234, 0x3da7df8, 0x9590ac3, 0xdc96f2a, 0x16e44896, 0x7931009, 0x99d5acc, + 0x10f7b842, 0xaef5e84, 0xc0310d7, 0xdebac2c, 0x2a7b137, 0x4342344, 0x19633649, 0x3a10624, 0x4b4cb56, + 0x1d809c59, 0xac007f, 0x1f0f4bcd, 0xa1ab06e, 0xc5042cf, 0x82c0c77, 0x76c7563, 0x22c30f3, 0x3bf1568, + 0x7a895be, 0xfcca554, 0x12e90e4c, 0x7b4ab5f, 0x13aeb76b, 0x5887e2c, 0x1d7fe1e3, 0x908c8e3, 0x95800ee, + 0xb36bd54, 0xf08905d, 0x4e73ae8, 0xf5a7e48, 0xa67cb0, 0x50e1067, 0x1b944a0a, 0xf29c83a, 0xb23cfb9, + 0xbe1db1, 0x54de6e8, 0xd4707f2, 0x8ebcc2d, 0x2c77056, 0x1568ce4, 0x15fcc849, 0x4069712, 0xe2ed85f, + 0x2c5ff09, 0x42a6929, 0x628e7ea, 0xbd5b355, 0xaf0bd79, 0xaa03699, 0xdb99816, 0x4379cef, 0x81d57b, + 0x11237f01, 0xe2a820b, 0xfd53b95, 0x6beb5ee, 0x1aeb790c, 0xe470d53, 0x2c2cfee, 0x1c1d8d8, 0xa520fc4, + 0x1518e034, 0xa584dd4, 0x29e572b, 0xd4594fc, 0x141a8f6f, 0x8dfccf3, 0x5d20ba3, 0x2eb60c3, 0x9f16eb0, + 0x11cec356, 0xf039f84, 0x1b0990c1, 0xc91e526, 0x10b65bae, 0xf0616e8, 0x173fa3ff, 0xec8ccf9, 0xbe32790, + 0x11da3e79, 0xe2f35c7, 0x908875c, 0xdacf7bd, 0x538c165, 0x8d1487f, 0x7c31aed, 0x21af228, 0x7e1689d, + 0xdfc23ca, 0x24f15dc, 0x25ef3c4, 0x35248cd, 0x99a0f43, 0xa4b6ecc, 0xd066b3, 0x2481152, 0x37a7688, + 0x15a444b6, 0xb62300c, 0x4b841b, 0xa655e79, 0xd53226d, 0xbeb348a, 0x127f3c2, 0xb989247, 0x71a277d, + 0x19e9dfcb, 0xb8f92d0, 0xe2d226c, 0x390a8b0, 0x183cc462, 0x7bd8167, 0x1f32a552, 0x5e02db4, 0xa146ee9, + 0x1a003957, 0x1c95f61, 0x1eeec155, 0x26f811f, 0xf9596ba, 0x3082bfb, 0x96df083, 0x3e3a289, 0x7e2d8be, + 0x157a63e0, 0x99b8941, 0x1da7d345, 0xcc6cd0, 0x10beed9a, 0x48e83c0, 0x13aa2e25, 0x7cad710, 0x4029988, + 0x13dfa9dd, 0xb94f884, 0x1f4adfef, 0xb88543, 0x16f5f8dc, 0xa6a67f4, 0x14e274e2, 0x5e56cf4, 0x2f24ef, + 0x1e9ef967, 0xfe09bad, 0xfe079b3, 0xcc0ae9e, 0xb3edf6d, 0x3e961bc, 0x130d7831, 0x31043d6, 0xba986f9, + 0x1d28055, 0x65240ca, 0x4971fa3, 0x81b17f8, 0x11ec34a5, 0x8366ddc, 0x1471809, 0xfa5f1c6, 0xc911e15, + 0x8849491, 0xcf4c2e2, 0x14471b91, 0x39f75be, 0x445c21e, 0xf1585e9, 0x72cc11f, 0x4c79f0c, 0xe5522e1, + 0x1874c1ee, 0x4444211, 0x7914884, 0x3d1b133, 0x25ba3c, 0x4194f65, 0x1c0457ef, 0xac4899d, 0xe1fa66c, + 0x130a7918, 0x9b8d312, 0x4b1c5c8, 0x61ccac3, 0x18c8aa6f, 0xe93cb0a, 0xdccb12c, 0xde10825, 0x969737d, + 0xf58c0c3, 0x7cee6a9, 0xc2c329a, 0xc7f9ed9, 0x107b3981, 0x696a40e, 0x152847ff, 0x4d88754, 0xb141f47, + 0x5a16ffe, 0x3a7870a, 0x18667659, 0x3b72b03, 0xb1c9435, 0x9285394, 0xa00005a, 0x37506c, 0x2edc0bb, + 0x19afe392, 0xeb39cac, 0x177ef286, 0xdf87197, 0x19f844ed, 0x31fe8, 0x15f9bfd, 0x80dbec, 0x342e96e, + 0x497aced, 0xe88e909, 0x1f5fa9ba, 0x530a6ee, 0x1ef4e3f1, 0x69ffd12, 0x583006d, 0x2ecc9b1, 0x362db70, + 0x18c7bdc5, 0xf4bb3c5, 0x1c90b957, 0xf067c09, 0x9768f2b, 0xf73566a, 0x1939a900, 0x198c38a, 0x202a2a1, + 0x4bbf5a6, 0x4e265bc, 0x1f44b6e7, 0x185ca49, 0xa39e81b, 0x24aff5b, 0x4acc9c2, 0x638bdd3, 0xb65b2a8, + 0x6def8be, 0xb94537a, 0x10b81dee, 0xe00ec55, 0x2f2cdf7, 0xc20622d, 0x2d20f36, 0xe03c8c9, 0x898ea76, + 0x8e3921b, 0x8905bff, 0x1e94b6c8, 0xee7ad86, 0x154797f2, 0xa620863, 0x3fbd0d9, 0x1f3caab, 0x30c24bd, + 0x19d3892f, 0x59c17a2, 0x1ab4b0ae, 0xf8714ee, 0x90c4098, 0xa9c800d, 0x1910236b, 0xea808d3, 0x9ae2f31, + 0x1a15ad64, 0xa48c8d1, 0x184635a4, 0xb725ef1, 0x11921dcc, 0x3f866df, 0x16c27568, 0xbdf580a, 0xb08f55c, + 0x186ee1c, 0xb1627fa, 0x34e82f6, 0x933837e, 0xf311be5, 0xfedb03b, 0x167f72cd, 0xa5469c0, 0x9c82531, + 0xb92a24b, 0x14fdc8b, 0x141980d1, 0xbdc3a49, 0x7e02bb1, 0xaf4e6dd, 0x106d99e1, 0xd4616fc, 0x93c2717, + 0x1c0a0507, 0xc6d5fed, 0x9a03d8b, 0xa1d22b0, 0x127853e3, 0xc4ac6b8, 0x1a048cf7, 0x9afb72c, 0x65d485d, + 0x72d5998, 0xe9fa744, 0xe49e82c, 0x253cf80, 0x5f777ce, 0xa3799a5, 0x17270cbb, 0xc1d1ef0, 0xdf74977, + 0x114cb859, 0xfa8e037, 0xb8f3fe5, 0xc734cc6, 0x70d3d61, 0xeadac62, 0x12093dd0, 0x9add67d, 0x87200d6, + 0x175bcbb, 0xb29b49f, 0x1806b79c, 0x12fb61f, 0x170b3a10, 0x3aaf1cf, 0xa224085, 0x79d26af, 0x97759e2, + 0x92e19f1, 0xb32714d, 0x1f00d9f1, 0xc728619, 0x9e6f627, 0xe745e24, 0x18ea4ace, 0xfc60a41, 0x125f5b2, + 0xc3cf512, 0x39ed486, 0xf4d15fa, 0xf9167fd, 0x1c1f5dd5, 0xc21a53e, 0x1897930, 0x957a112, 0x21059a0, + 0x1f9e3ddc, 0xa4dfced, 0x8427f6f, 0x726fbe7, 0x1ea658f8, 0x2fdcd4c, 0x17e9b66f, 0xb2e7c2e, 0x39923bf, + 0x1bae104, 0x3973ce5, 0xc6f264c, 0x3511b84, 0x124195d7, 0x11996bd, 0x20be23d, 0xdc437c4, 0x4b4f16b, + 0x11902a0, 0x6c29cc9, 0x1d5ffbe6, 0xdb0b4c7, 0x10144c14, 0x2f2b719, 0x301189, 0x2343336, 0xa0bf2ac, +} + +func sm2P256GetScalar(b *[32]byte, a []byte) { + var scalarBytes []byte + + n := new(big.Int).SetBytes(a) + if n.Cmp(sm2P256.N) >= 0 { + n.Mod(n, sm2P256.N) + scalarBytes = n.Bytes() + } else { + scalarBytes = a + } + for i, v := range scalarBytes { + b[len(scalarBytes)-(1+i)] = v + } +} + +func sm2P256PointAddMixed(xOut, yOut, zOut, x1, y1, z1, x2, y2 *sm2P256FieldElement) { + var z1z1, z1z1z1, s2, u2, h, i, j, r, rr, v, tmp sm2P256FieldElement + + sm2P256Square(&z1z1, z1) + sm2P256Add(&tmp, z1, z1) + + sm2P256Mul(&u2, x2, &z1z1) + sm2P256Mul(&z1z1z1, z1, &z1z1) + sm2P256Mul(&s2, y2, &z1z1z1) + sm2P256Sub(&h, &u2, x1) + sm2P256Add(&i, &h, &h) + sm2P256Square(&i, &i) + sm2P256Mul(&j, &h, &i) + sm2P256Sub(&r, &s2, y1) + sm2P256Add(&r, &r, &r) + sm2P256Mul(&v, x1, &i) + + sm2P256Mul(zOut, &tmp, &h) + sm2P256Square(&rr, &r) + sm2P256Sub(xOut, &rr, &j) + sm2P256Sub(xOut, xOut, &v) + sm2P256Sub(xOut, xOut, &v) + + sm2P256Sub(&tmp, &v, xOut) + sm2P256Mul(yOut, &tmp, &r) + sm2P256Mul(&tmp, y1, &j) + sm2P256Sub(yOut, yOut, &tmp) + sm2P256Sub(yOut, yOut, &tmp) +} + +// sm2P256CopyConditional sets out=in if mask = 0xffffffff in constant time. +// +// On entry: mask is either 0 or 0xffffffff. +func sm2P256CopyConditional(out, in *sm2P256FieldElement, mask uint32) { + for i := 0; i < 9; i++ { + tmp := mask & (in[i] ^ out[i]) + out[i] ^= tmp + } +} + +// sm2P256SelectAffinePoint sets {out_x,out_y} to the index'th entry of table. +// On entry: index < 16, table[0] must be zero. +func sm2P256SelectAffinePoint(xOut, yOut *sm2P256FieldElement, table []uint32, index uint32) { + for i := range xOut { + xOut[i] = 0 + } + for i := range yOut { + yOut[i] = 0 + } + + for i := uint32(1); i < 16; i++ { + mask := i ^ index + mask |= mask >> 2 + mask |= mask >> 1 + mask &= 1 + mask-- + for j := range xOut { + xOut[j] |= table[0] & mask + table = table[1:] + } + for j := range yOut { + yOut[j] |= table[0] & mask + table = table[1:] + } + } +} + +// sm2P256SelectJacobianPoint sets {out_x,out_y,out_z} to the index'th entry of +// table. +// On entry: index < 16, table[0] must be zero. +func sm2P256SelectJacobianPoint(xOut, yOut, zOut *sm2P256FieldElement, table *[16][3]sm2P256FieldElement, index uint32) { + for i := range xOut { + xOut[i] = 0 + } + for i := range yOut { + yOut[i] = 0 + } + for i := range zOut { + zOut[i] = 0 + } + + // The implicit value at index 0 is all zero. We don't need to perform that + // iteration of the loop because we already set out_* to zero. + for i := uint32(1); i < 16; i++ { + mask := i ^ index + mask |= mask >> 2 + mask |= mask >> 1 + mask &= 1 + mask-- + for j := range xOut { + xOut[j] |= table[i][0][j] & mask + } + for j := range yOut { + yOut[j] |= table[i][1][j] & mask + } + for j := range zOut { + zOut[j] |= table[i][2][j] & mask + } + } +} + +// sm2P256GetBit returns the bit'th bit of scalar. +func sm2P256GetBit(scalar *[32]uint8, bit uint) uint32 { + return uint32(((scalar[bit>>3]) >> (bit & 7)) & 1) +} + +// sm2P256ScalarBaseMult sets {xOut,yOut,zOut} = scalar*G where scalar is a +// little-endian number. Note that the value of scalar must be less than the +// order of the group. +func sm2P256ScalarBaseMult(xOut, yOut, zOut *sm2P256FieldElement, scalar *[32]uint8) { + nIsInfinityMask := ^uint32(0) + var px, py, tx, ty, tz sm2P256FieldElement + var pIsNoninfiniteMask, mask, tableOffset uint32 + + for i := range xOut { + xOut[i] = 0 + } + for i := range yOut { + yOut[i] = 0 + } + for i := range zOut { + zOut[i] = 0 + } + + // The loop adds bits at positions 0, 64, 128 and 192, followed by + // positions 32,96,160 and 224 and does this 32 times. + for i := uint(0); i < 32; i++ { + if i != 0 { + sm2P256PointDouble(xOut, yOut, zOut, xOut, yOut, zOut) + } + tableOffset = 0 + for j := uint(0); j <= 32; j += 32 { + bit0 := sm2P256GetBit(scalar, 31-i+j) + bit1 := sm2P256GetBit(scalar, 95-i+j) + bit2 := sm2P256GetBit(scalar, 159-i+j) + bit3 := sm2P256GetBit(scalar, 223-i+j) + index := bit0 | (bit1 << 1) | (bit2 << 2) | (bit3 << 3) + + sm2P256SelectAffinePoint(&px, &py, sm2P256Precomputed[tableOffset:], index) + tableOffset += 30 * 9 + + // Since scalar is less than the order of the group, we know that + // {xOut,yOut,zOut} != {px,py,1}, unless both are zero, which we handle + // below. + sm2P256PointAddMixed(&tx, &ty, &tz, xOut, yOut, zOut, &px, &py) + // The result of pointAddMixed is incorrect if {xOut,yOut,zOut} is zero + // (a.k.a. the point at infinity). We handle that situation by + // copying the point from the table. + sm2P256CopyConditional(xOut, &px, nIsInfinityMask) + sm2P256CopyConditional(yOut, &py, nIsInfinityMask) + sm2P256CopyConditional(zOut, &sm2P256Factor[1], nIsInfinityMask) + + // Equally, the result is also wrong if the point from the table is + // zero, which happens when the index is zero. We handle that by + // only copying from {tx,ty,tz} to {xOut,yOut,zOut} if index != 0. + pIsNoninfiniteMask = nonZeroToAllOnes(index) + mask = pIsNoninfiniteMask & ^nIsInfinityMask + sm2P256CopyConditional(xOut, &tx, mask) + sm2P256CopyConditional(yOut, &ty, mask) + sm2P256CopyConditional(zOut, &tz, mask) + // If p was not zero, then n is now non-zero. + nIsInfinityMask &^= pIsNoninfiniteMask + } + } +} + +func sm2P256PointToAffine(xOut, yOut, x, y, z *sm2P256FieldElement) { + var zInv, zInvSq sm2P256FieldElement + + zz := sm2P256ToBig(z) + zz.ModInverse(zz, sm2P256.P) + sm2P256FromBig(&zInv, zz) + + sm2P256Square(&zInvSq, &zInv) + sm2P256Mul(xOut, x, &zInvSq) + sm2P256Mul(&zInv, &zInv, &zInvSq) + sm2P256Mul(yOut, y, &zInv) +} + +func sm2P256ToAffine(x, y, z *sm2P256FieldElement) (xOut, yOut *big.Int) { + var xx, yy sm2P256FieldElement + + sm2P256PointToAffine(&xx, &yy, x, y, z) + return sm2P256ToBig(&xx), sm2P256ToBig(&yy) +} + +var sm2P256Factor = []sm2P256FieldElement{ + sm2P256FieldElement{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, + sm2P256FieldElement{0x2, 0x0, 0x1FFFFF00, 0x7FF, 0x0, 0x0, 0x0, 0x2000000, 0x0}, + sm2P256FieldElement{0x4, 0x0, 0x1FFFFE00, 0xFFF, 0x0, 0x0, 0x0, 0x4000000, 0x0}, + sm2P256FieldElement{0x6, 0x0, 0x1FFFFD00, 0x17FF, 0x0, 0x0, 0x0, 0x6000000, 0x0}, + sm2P256FieldElement{0x8, 0x0, 0x1FFFFC00, 0x1FFF, 0x0, 0x0, 0x0, 0x8000000, 0x0}, + sm2P256FieldElement{0xA, 0x0, 0x1FFFFB00, 0x27FF, 0x0, 0x0, 0x0, 0xA000000, 0x0}, + sm2P256FieldElement{0xC, 0x0, 0x1FFFFA00, 0x2FFF, 0x0, 0x0, 0x0, 0xC000000, 0x0}, + sm2P256FieldElement{0xE, 0x0, 0x1FFFF900, 0x37FF, 0x0, 0x0, 0x0, 0xE000000, 0x0}, + sm2P256FieldElement{0x10, 0x0, 0x1FFFF800, 0x3FFF, 0x0, 0x0, 0x0, 0x0, 0x01}, +} + +func sm2P256Scalar(b *sm2P256FieldElement, a int) { + sm2P256Mul(b, b, &sm2P256Factor[a]) +} + +// (x3, y3, z3) = (x1, y1, z1) + (x2, y2, z2) +func sm2P256PointAdd(x1, y1, z1, x2, y2, z2, x3, y3, z3 *sm2P256FieldElement) { + var u1, u2, z22, z12, z23, z13, s1, s2, h, h2, r, r2, tm sm2P256FieldElement + + if sm2P256ToBig(z1).Sign() == 0 { + sm2P256Dup(x3, x2) + sm2P256Dup(y3, y2) + sm2P256Dup(z3, z2) + return + } + + if sm2P256ToBig(z2).Sign() == 0 { + sm2P256Dup(x3, x1) + sm2P256Dup(y3, y1) + sm2P256Dup(z3, z1) + return + } + + sm2P256Square(&z12, z1) // z12 = z1 ^ 2 + sm2P256Square(&z22, z2) // z22 = z2 ^ 2 + + sm2P256Mul(&z13, &z12, z1) // z13 = z1 ^ 3 + sm2P256Mul(&z23, &z22, z2) // z23 = z2 ^ 3 + + sm2P256Mul(&u1, x1, &z22) // u1 = x1 * z2 ^ 2 + sm2P256Mul(&u2, x2, &z12) // u2 = x2 * z1 ^ 2 + + sm2P256Mul(&s1, y1, &z23) // s1 = y1 * z2 ^ 3 + sm2P256Mul(&s2, y2, &z13) // s2 = y2 * z1 ^ 3 + + if sm2P256ToBig(&u1).Cmp(sm2P256ToBig(&u2)) == 0 && + sm2P256ToBig(&s1).Cmp(sm2P256ToBig(&s2)) == 0 { + sm2P256PointDouble(x1, y1, z1, x1, y1, z1) + } + + sm2P256Sub(&h, &u2, &u1) // h = u2 - u1 + sm2P256Sub(&r, &s2, &s1) // r = s2 - s1 + + sm2P256Square(&r2, &r) // r2 = r ^ 2 + sm2P256Square(&h2, &h) // h2 = h ^ 2 + + sm2P256Mul(&tm, &h2, &h) // tm = h ^ 3 + sm2P256Sub(x3, &r2, &tm) + sm2P256Mul(&tm, &u1, &h2) + sm2P256Scalar(&tm, 2) // tm = 2 * (u1 * h ^ 2) + sm2P256Sub(x3, x3, &tm) // x3 = r ^ 2 - h ^ 3 - 2 * u1 * h ^ 2 + + sm2P256Mul(&tm, &u1, &h2) // tm = u1 * h ^ 2 + sm2P256Sub(&tm, &tm, x3) // tm = u1 * h ^ 2 - x3 + sm2P256Mul(y3, &r, &tm) + sm2P256Mul(&tm, &h2, &h) // tm = h ^ 3 + sm2P256Mul(&tm, &tm, &s1) // tm = s1 * h ^ 3 + sm2P256Sub(y3, y3, &tm) // y3 = r * (u1 * h ^ 2 - x3) - s1 * h ^ 3 + + sm2P256Mul(z3, z1, z2) + sm2P256Mul(z3, z3, &h) // z3 = z1 * z3 * h +} + +// (x3, y3, z3) = (x1, y1, z1)- (x2, y2, z2) +func sm2P256PointSub(x1, y1, z1, x2, y2, z2, x3, y3, z3 *sm2P256FieldElement) { + var u1, u2, z22, z12, z23, z13, s1, s2, h, h2, r, r2, tm sm2P256FieldElement + y := sm2P256ToBig(y2) + zero := new(big.Int).SetInt64(0) + y.Sub(zero, y) + sm2P256FromBig(y2, y) + + if sm2P256ToBig(z1).Sign() == 0 { + sm2P256Dup(x3, x2) + sm2P256Dup(y3, y2) + sm2P256Dup(z3, z2) + return + } + + if sm2P256ToBig(z2).Sign() == 0 { + sm2P256Dup(x3, x1) + sm2P256Dup(y3, y1) + sm2P256Dup(z3, z1) + return + } + + sm2P256Square(&z12, z1) // z12 = z1 ^ 2 + sm2P256Square(&z22, z2) // z22 = z2 ^ 2 + + sm2P256Mul(&z13, &z12, z1) // z13 = z1 ^ 3 + sm2P256Mul(&z23, &z22, z2) // z23 = z2 ^ 3 + + sm2P256Mul(&u1, x1, &z22) // u1 = x1 * z2 ^ 2 + sm2P256Mul(&u2, x2, &z12) // u2 = x2 * z1 ^ 2 + + sm2P256Mul(&s1, y1, &z23) // s1 = y1 * z2 ^ 3 + sm2P256Mul(&s2, y2, &z13) // s2 = y2 * z1 ^ 3 + + if sm2P256ToBig(&u1).Cmp(sm2P256ToBig(&u2)) == 0 && + sm2P256ToBig(&s1).Cmp(sm2P256ToBig(&s2)) == 0 { + sm2P256PointDouble(x1, y1, z1, x1, y1, z1) + } + + sm2P256Sub(&h, &u2, &u1) // h = u2 - u1 + sm2P256Sub(&r, &s2, &s1) // r = s2 - s1 + + sm2P256Square(&r2, &r) // r2 = r ^ 2 + sm2P256Square(&h2, &h) // h2 = h ^ 2 + + sm2P256Mul(&tm, &h2, &h) // tm = h ^ 3 + sm2P256Sub(x3, &r2, &tm) + sm2P256Mul(&tm, &u1, &h2) + sm2P256Scalar(&tm, 2) // tm = 2 * (u1 * h ^ 2) + sm2P256Sub(x3, x3, &tm) // x3 = r ^ 2 - h ^ 3 - 2 * u1 * h ^ 2 + + sm2P256Mul(&tm, &u1, &h2) // tm = u1 * h ^ 2 + sm2P256Sub(&tm, &tm, x3) // tm = u1 * h ^ 2 - x3 + sm2P256Mul(y3, &r, &tm) + sm2P256Mul(&tm, &h2, &h) // tm = h ^ 3 + sm2P256Mul(&tm, &tm, &s1) // tm = s1 * h ^ 3 + sm2P256Sub(y3, y3, &tm) // y3 = r * (u1 * h ^ 2 - x3) - s1 * h ^ 3 + + sm2P256Mul(z3, z1, z2) + sm2P256Mul(z3, z3, &h) // z3 = z1 * z3 * h +} + +func sm2P256PointDouble(x3, y3, z3, x, y, z *sm2P256FieldElement) { + var s, m, m2, x2, y2, z2, z4, y4, az4 sm2P256FieldElement + + sm2P256Square(&x2, x) // x2 = x ^ 2 + sm2P256Square(&y2, y) // y2 = y ^ 2 + sm2P256Square(&z2, z) // z2 = z ^ 2 + + sm2P256Square(&z4, z) // z4 = z ^ 2 + sm2P256Mul(&z4, &z4, z) // z4 = z ^ 3 + sm2P256Mul(&z4, &z4, z) // z4 = z ^ 4 + + sm2P256Square(&y4, y) // y4 = y ^ 2 + sm2P256Mul(&y4, &y4, y) // y4 = y ^ 3 + sm2P256Mul(&y4, &y4, y) // y4 = y ^ 4 + sm2P256Scalar(&y4, 8) // y4 = 8 * y ^ 4 + + sm2P256Mul(&s, x, &y2) + sm2P256Scalar(&s, 4) // s = 4 * x * y ^ 2 + + sm2P256Dup(&m, &x2) + sm2P256Scalar(&m, 3) + sm2P256Mul(&az4, &sm2P256.a, &z4) + sm2P256Add(&m, &m, &az4) // m = 3 * x ^ 2 + a * z ^ 4 + + sm2P256Square(&m2, &m) // m2 = m ^ 2 + + sm2P256Add(z3, y, z) + sm2P256Square(z3, z3) + sm2P256Sub(z3, z3, &z2) + sm2P256Sub(z3, z3, &y2) // z' = (y + z) ^2 - z ^ 2 - y ^ 2 + + sm2P256Sub(x3, &m2, &s) + sm2P256Sub(x3, x3, &s) // x' = m2 - 2 * s + + sm2P256Sub(y3, &s, x3) + sm2P256Mul(y3, y3, &m) + sm2P256Sub(y3, y3, &y4) // y' = m * (s - x') - 8 * y ^ 4 +} + +// p256Zero31 is 0 mod p. +var sm2P256Zero31 = sm2P256FieldElement{0x7FFFFFF8, 0x3FFFFFFC, 0x800003FC, 0x3FFFDFFC, 0x7FFFFFFC, 0x3FFFFFFC, 0x7FFFFFFC, 0x37FFFFFC, 0x7FFFFFFC} + +// c = a + b +func sm2P256Add(c, a, b *sm2P256FieldElement) { + carry := uint32(0) + for i := 0; ; i++ { + c[i] = a[i] + b[i] + c[i] += carry + carry = c[i] >> 29 + c[i] &= bottom29Bits + i++ + if i == 9 { + break + } + c[i] = a[i] + b[i] + c[i] += carry + carry = c[i] >> 28 + c[i] &= bottom28Bits + } + sm2P256ReduceCarry(c, carry) +} + +// c = a - b +func sm2P256Sub(c, a, b *sm2P256FieldElement) { + var carry uint32 + + for i := 0; ; i++ { + c[i] = a[i] - b[i] + c[i] += sm2P256Zero31[i] + c[i] += carry + carry = c[i] >> 29 + c[i] &= bottom29Bits + i++ + if i == 9 { + break + } + c[i] = a[i] - b[i] + c[i] += sm2P256Zero31[i] + c[i] += carry + carry = c[i] >> 28 + c[i] &= bottom28Bits + } + sm2P256ReduceCarry(c, carry) +} + +// c = a * b +func sm2P256Mul(c, a, b *sm2P256FieldElement) { + var tmp sm2P256LargeFieldElement + + tmp[0] = uint64(a[0]) * uint64(b[0]) + tmp[1] = uint64(a[0])*(uint64(b[1])<<0) + + uint64(a[1])*(uint64(b[0])<<0) + tmp[2] = uint64(a[0])*(uint64(b[2])<<0) + + uint64(a[1])*(uint64(b[1])<<1) + + uint64(a[2])*(uint64(b[0])<<0) + tmp[3] = uint64(a[0])*(uint64(b[3])<<0) + + uint64(a[1])*(uint64(b[2])<<0) + + uint64(a[2])*(uint64(b[1])<<0) + + uint64(a[3])*(uint64(b[0])<<0) + tmp[4] = uint64(a[0])*(uint64(b[4])<<0) + + uint64(a[1])*(uint64(b[3])<<1) + + uint64(a[2])*(uint64(b[2])<<0) + + uint64(a[3])*(uint64(b[1])<<1) + + uint64(a[4])*(uint64(b[0])<<0) + tmp[5] = uint64(a[0])*(uint64(b[5])<<0) + + uint64(a[1])*(uint64(b[4])<<0) + + uint64(a[2])*(uint64(b[3])<<0) + + uint64(a[3])*(uint64(b[2])<<0) + + uint64(a[4])*(uint64(b[1])<<0) + + uint64(a[5])*(uint64(b[0])<<0) + tmp[6] = uint64(a[0])*(uint64(b[6])<<0) + + uint64(a[1])*(uint64(b[5])<<1) + + uint64(a[2])*(uint64(b[4])<<0) + + uint64(a[3])*(uint64(b[3])<<1) + + uint64(a[4])*(uint64(b[2])<<0) + + uint64(a[5])*(uint64(b[1])<<1) + + uint64(a[6])*(uint64(b[0])<<0) + tmp[7] = uint64(a[0])*(uint64(b[7])<<0) + + uint64(a[1])*(uint64(b[6])<<0) + + uint64(a[2])*(uint64(b[5])<<0) + + uint64(a[3])*(uint64(b[4])<<0) + + uint64(a[4])*(uint64(b[3])<<0) + + uint64(a[5])*(uint64(b[2])<<0) + + uint64(a[6])*(uint64(b[1])<<0) + + uint64(a[7])*(uint64(b[0])<<0) + // tmp[8] has the greatest value but doesn't overflow. See logic in + // p256Square. + tmp[8] = uint64(a[0])*(uint64(b[8])<<0) + + uint64(a[1])*(uint64(b[7])<<1) + + uint64(a[2])*(uint64(b[6])<<0) + + uint64(a[3])*(uint64(b[5])<<1) + + uint64(a[4])*(uint64(b[4])<<0) + + uint64(a[5])*(uint64(b[3])<<1) + + uint64(a[6])*(uint64(b[2])<<0) + + uint64(a[7])*(uint64(b[1])<<1) + + uint64(a[8])*(uint64(b[0])<<0) + tmp[9] = uint64(a[1])*(uint64(b[8])<<0) + + uint64(a[2])*(uint64(b[7])<<0) + + uint64(a[3])*(uint64(b[6])<<0) + + uint64(a[4])*(uint64(b[5])<<0) + + uint64(a[5])*(uint64(b[4])<<0) + + uint64(a[6])*(uint64(b[3])<<0) + + uint64(a[7])*(uint64(b[2])<<0) + + uint64(a[8])*(uint64(b[1])<<0) + tmp[10] = uint64(a[2])*(uint64(b[8])<<0) + + uint64(a[3])*(uint64(b[7])<<1) + + uint64(a[4])*(uint64(b[6])<<0) + + uint64(a[5])*(uint64(b[5])<<1) + + uint64(a[6])*(uint64(b[4])<<0) + + uint64(a[7])*(uint64(b[3])<<1) + + uint64(a[8])*(uint64(b[2])<<0) + tmp[11] = uint64(a[3])*(uint64(b[8])<<0) + + uint64(a[4])*(uint64(b[7])<<0) + + uint64(a[5])*(uint64(b[6])<<0) + + uint64(a[6])*(uint64(b[5])<<0) + + uint64(a[7])*(uint64(b[4])<<0) + + uint64(a[8])*(uint64(b[3])<<0) + tmp[12] = uint64(a[4])*(uint64(b[8])<<0) + + uint64(a[5])*(uint64(b[7])<<1) + + uint64(a[6])*(uint64(b[6])<<0) + + uint64(a[7])*(uint64(b[5])<<1) + + uint64(a[8])*(uint64(b[4])<<0) + tmp[13] = uint64(a[5])*(uint64(b[8])<<0) + + uint64(a[6])*(uint64(b[7])<<0) + + uint64(a[7])*(uint64(b[6])<<0) + + uint64(a[8])*(uint64(b[5])<<0) + tmp[14] = uint64(a[6])*(uint64(b[8])<<0) + + uint64(a[7])*(uint64(b[7])<<1) + + uint64(a[8])*(uint64(b[6])<<0) + tmp[15] = uint64(a[7])*(uint64(b[8])<<0) + + uint64(a[8])*(uint64(b[7])<<0) + tmp[16] = uint64(a[8]) * (uint64(b[8]) << 0) + sm2P256ReduceDegree(c, &tmp) +} + +// b = a * a +func sm2P256Square(b, a *sm2P256FieldElement) { + var tmp sm2P256LargeFieldElement + + tmp[0] = uint64(a[0]) * uint64(a[0]) + tmp[1] = uint64(a[0]) * (uint64(a[1]) << 1) + tmp[2] = uint64(a[0])*(uint64(a[2])<<1) + + uint64(a[1])*(uint64(a[1])<<1) + tmp[3] = uint64(a[0])*(uint64(a[3])<<1) + + uint64(a[1])*(uint64(a[2])<<1) + tmp[4] = uint64(a[0])*(uint64(a[4])<<1) + + uint64(a[1])*(uint64(a[3])<<2) + + uint64(a[2])*uint64(a[2]) + tmp[5] = uint64(a[0])*(uint64(a[5])<<1) + + uint64(a[1])*(uint64(a[4])<<1) + + uint64(a[2])*(uint64(a[3])<<1) + tmp[6] = uint64(a[0])*(uint64(a[6])<<1) + + uint64(a[1])*(uint64(a[5])<<2) + + uint64(a[2])*(uint64(a[4])<<1) + + uint64(a[3])*(uint64(a[3])<<1) + tmp[7] = uint64(a[0])*(uint64(a[7])<<1) + + uint64(a[1])*(uint64(a[6])<<1) + + uint64(a[2])*(uint64(a[5])<<1) + + uint64(a[3])*(uint64(a[4])<<1) + // tmp[8] has the greatest value of 2**61 + 2**60 + 2**61 + 2**60 + 2**60, + // which is < 2**64 as required. + tmp[8] = uint64(a[0])*(uint64(a[8])<<1) + + uint64(a[1])*(uint64(a[7])<<2) + + uint64(a[2])*(uint64(a[6])<<1) + + uint64(a[3])*(uint64(a[5])<<2) + + uint64(a[4])*uint64(a[4]) + tmp[9] = uint64(a[1])*(uint64(a[8])<<1) + + uint64(a[2])*(uint64(a[7])<<1) + + uint64(a[3])*(uint64(a[6])<<1) + + uint64(a[4])*(uint64(a[5])<<1) + tmp[10] = uint64(a[2])*(uint64(a[8])<<1) + + uint64(a[3])*(uint64(a[7])<<2) + + uint64(a[4])*(uint64(a[6])<<1) + + uint64(a[5])*(uint64(a[5])<<1) + tmp[11] = uint64(a[3])*(uint64(a[8])<<1) + + uint64(a[4])*(uint64(a[7])<<1) + + uint64(a[5])*(uint64(a[6])<<1) + tmp[12] = uint64(a[4])*(uint64(a[8])<<1) + + uint64(a[5])*(uint64(a[7])<<2) + + uint64(a[6])*uint64(a[6]) + tmp[13] = uint64(a[5])*(uint64(a[8])<<1) + + uint64(a[6])*(uint64(a[7])<<1) + tmp[14] = uint64(a[6])*(uint64(a[8])<<1) + + uint64(a[7])*(uint64(a[7])<<1) + tmp[15] = uint64(a[7]) * (uint64(a[8]) << 1) + tmp[16] = uint64(a[8]) * uint64(a[8]) + sm2P256ReduceDegree(b, &tmp) +} + +// nonZeroToAllOnes returns: +// +// 0xffffffff for 0 < x <= 2**31 +// 0 for x == 0 or x > 2**31. +func nonZeroToAllOnes(x uint32) uint32 { + return ((x - 1) >> 31) - 1 +} + +var sm2P256Carry = [8 * 9]uint32{ + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x2, 0x0, 0x1FFFFF00, 0x7FF, 0x0, 0x0, 0x0, 0x2000000, 0x0, + 0x4, 0x0, 0x1FFFFE00, 0xFFF, 0x0, 0x0, 0x0, 0x4000000, 0x0, + 0x6, 0x0, 0x1FFFFD00, 0x17FF, 0x0, 0x0, 0x0, 0x6000000, 0x0, + 0x8, 0x0, 0x1FFFFC00, 0x1FFF, 0x0, 0x0, 0x0, 0x8000000, 0x0, + 0xA, 0x0, 0x1FFFFB00, 0x27FF, 0x0, 0x0, 0x0, 0xA000000, 0x0, + 0xC, 0x0, 0x1FFFFA00, 0x2FFF, 0x0, 0x0, 0x0, 0xC000000, 0x0, + 0xE, 0x0, 0x1FFFF900, 0x37FF, 0x0, 0x0, 0x0, 0xE000000, 0x0, +} + +// carry < 2 ^ 3 +func sm2P256ReduceCarry(a *sm2P256FieldElement, carry uint32) { + a[0] += sm2P256Carry[carry*9+0] + a[2] += sm2P256Carry[carry*9+2] + a[3] += sm2P256Carry[carry*9+3] + a[7] += sm2P256Carry[carry*9+7] +} + +func sm2P256ReduceDegree(a *sm2P256FieldElement, b *sm2P256LargeFieldElement) { + var tmp [18]uint32 + var carry, x, xMask uint32 + + // tmp + // 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 ... + // 29 | 28 | 29 | 28 | 29 | 28 | 29 | 28 | 29 | 28 | 29 ... + tmp[0] = uint32(b[0]) & bottom29Bits + tmp[1] = uint32(b[0]) >> 29 + tmp[1] |= (uint32(b[0]>>32) << 3) & bottom28Bits + tmp[1] += uint32(b[1]) & bottom28Bits + carry = tmp[1] >> 28 + tmp[1] &= bottom28Bits + for i := 2; i < 17; i++ { + tmp[i] = (uint32(b[i-2] >> 32)) >> 25 + tmp[i] += (uint32(b[i-1])) >> 28 + tmp[i] += (uint32(b[i-1]>>32) << 4) & bottom29Bits + tmp[i] += uint32(b[i]) & bottom29Bits + tmp[i] += carry + carry = tmp[i] >> 29 + tmp[i] &= bottom29Bits + + i++ + if i == 17 { + break + } + tmp[i] = uint32(b[i-2]>>32) >> 25 + tmp[i] += uint32(b[i-1]) >> 29 + tmp[i] += ((uint32(b[i-1] >> 32)) << 3) & bottom28Bits + tmp[i] += uint32(b[i]) & bottom28Bits + tmp[i] += carry + carry = tmp[i] >> 28 + tmp[i] &= bottom28Bits + } + tmp[17] = uint32(b[15]>>32) >> 25 + tmp[17] += uint32(b[16]) >> 29 + tmp[17] += uint32(b[16]>>32) << 3 + tmp[17] += carry + + for i := 0; ; i += 2 { + + tmp[i+1] += tmp[i] >> 29 + x = tmp[i] & bottom29Bits + tmp[i] = 0 + if x > 0 { + set4 := uint32(0) + set7 := uint32(0) + xMask = nonZeroToAllOnes(x) + tmp[i+2] += (x << 7) & bottom29Bits + tmp[i+3] += x >> 22 + if tmp[i+3] < 0x10000000 { + set4 = 1 + tmp[i+3] += 0x10000000 & xMask + tmp[i+3] -= (x << 10) & bottom28Bits + } else { + tmp[i+3] -= (x << 10) & bottom28Bits + } + if tmp[i+4] < 0x20000000 { + tmp[i+4] += 0x20000000 & xMask + tmp[i+4] -= set4 // 借位 + tmp[i+4] -= x >> 18 + if tmp[i+5] < 0x10000000 { + tmp[i+5] += 0x10000000 & xMask + tmp[i+5] -= 1 // 借位 + if tmp[i+6] < 0x20000000 { + set7 = 1 + tmp[i+6] += 0x20000000 & xMask + tmp[i+6] -= 1 // 借位 + } else { + tmp[i+6] -= 1 // 借位 + } + } else { + tmp[i+5] -= 1 + } + } else { + tmp[i+4] -= set4 // 借位 + tmp[i+4] -= x >> 18 + } + if tmp[i+7] < 0x10000000 { + tmp[i+7] += 0x10000000 & xMask + tmp[i+7] -= set7 + tmp[i+7] -= (x << 24) & bottom28Bits + tmp[i+8] += (x << 28) & bottom29Bits + if tmp[i+8] < 0x20000000 { + tmp[i+8] += 0x20000000 & xMask + tmp[i+8] -= 1 + tmp[i+8] -= x >> 4 + tmp[i+9] += ((x >> 1) - 1) & xMask + } else { + tmp[i+8] -= 1 + tmp[i+8] -= x >> 4 + tmp[i+9] += (x >> 1) & xMask + } + } else { + tmp[i+7] -= set7 // 借位 + tmp[i+7] -= (x << 24) & bottom28Bits + tmp[i+8] += (x << 28) & bottom29Bits + if tmp[i+8] < 0x20000000 { + tmp[i+8] += 0x20000000 & xMask + tmp[i+8] -= x >> 4 + tmp[i+9] += ((x >> 1) - 1) & xMask + } else { + tmp[i+8] -= x >> 4 + tmp[i+9] += (x >> 1) & xMask + } + } + + } + + if i+1 == 9 { + break + } + + tmp[i+2] += tmp[i+1] >> 28 + x = tmp[i+1] & bottom28Bits + tmp[i+1] = 0 + if x > 0 { + set5 := uint32(0) + set8 := uint32(0) + set9 := uint32(0) + xMask = nonZeroToAllOnes(x) + tmp[i+3] += (x << 7) & bottom28Bits + tmp[i+4] += x >> 21 + if tmp[i+4] < 0x20000000 { + set5 = 1 + tmp[i+4] += 0x20000000 & xMask + tmp[i+4] -= (x << 11) & bottom29Bits + } else { + tmp[i+4] -= (x << 11) & bottom29Bits + } + if tmp[i+5] < 0x10000000 { + tmp[i+5] += 0x10000000 & xMask + tmp[i+5] -= set5 // 借位 + tmp[i+5] -= x >> 18 + if tmp[i+6] < 0x20000000 { + tmp[i+6] += 0x20000000 & xMask + tmp[i+6] -= 1 // 借位 + if tmp[i+7] < 0x10000000 { + set8 = 1 + tmp[i+7] += 0x10000000 & xMask + tmp[i+7] -= 1 // 借位 + } else { + tmp[i+7] -= 1 // 借位 + } + } else { + tmp[i+6] -= 1 // 借位 + } + } else { + tmp[i+5] -= set5 // 借位 + tmp[i+5] -= x >> 18 + } + if tmp[i+8] < 0x20000000 { + set9 = 1 + tmp[i+8] += 0x20000000 & xMask + tmp[i+8] -= set8 + tmp[i+8] -= (x << 25) & bottom29Bits + } else { + tmp[i+8] -= set8 + tmp[i+8] -= (x << 25) & bottom29Bits + } + if tmp[i+9] < 0x10000000 { + tmp[i+9] += 0x10000000 & xMask + tmp[i+9] -= set9 // 借位 + tmp[i+9] -= x >> 4 + tmp[i+10] += (x - 1) & xMask + } else { + tmp[i+9] -= set9 // 借位 + tmp[i+9] -= x >> 4 + tmp[i+10] += x & xMask + } + } + } + + carry = uint32(0) + for i := 0; i < 8; i++ { + a[i] = tmp[i+9] + a[i] += carry + a[i] += (tmp[i+10] << 28) & bottom29Bits + carry = a[i] >> 29 + a[i] &= bottom29Bits + + i++ + a[i] = tmp[i+9] >> 1 + a[i] += carry + carry = a[i] >> 28 + a[i] &= bottom28Bits + } + a[8] = tmp[17] + a[8] += carry + carry = a[8] >> 29 + a[8] &= bottom29Bits + sm2P256ReduceCarry(a, carry) +} + +// b = a +func sm2P256Dup(b, a *sm2P256FieldElement) { + *b = *a +} + +// X = a * R mod P +func sm2P256FromBig(X *sm2P256FieldElement, a *big.Int) { + x := new(big.Int).Lsh(a, 257) + x.Mod(x, sm2P256.P) + for i := 0; i < 9; i++ { + if bits := x.Bits(); len(bits) > 0 { + X[i] = uint32(bits[0]) & bottom29Bits + } else { + X[i] = 0 + } + x.Rsh(x, 29) + i++ + if i == 9 { + break + } + if bits := x.Bits(); len(bits) > 0 { + X[i] = uint32(bits[0]) & bottom28Bits + } else { + X[i] = 0 + } + x.Rsh(x, 28) + } +} + +// X = r * R mod P +// r = X * R' mod P +func sm2P256ToBig(X *sm2P256FieldElement) *big.Int { + r, tm := new(big.Int), new(big.Int) + r.SetInt64(int64(X[8])) + for i := 7; i >= 0; i-- { + if (i & 1) == 0 { + r.Lsh(r, 29) + } else { + r.Lsh(r, 28) + } + tm.SetInt64(int64(X[i])) + r.Add(r, tm) + } + r.Mul(r, sm2P256.RInverse) + r.Mod(r, sm2P256.P) + return r +} +func WNafReversed(wnaf []int8) []int8 { + wnafRev := make([]int8, len(wnaf), len(wnaf)) + for i, v := range wnaf { + wnafRev[len(wnaf)-(1+i)] = v + } + return wnafRev +} +func sm2GenrateWNaf(b []byte) []int8 { + n := new(big.Int).SetBytes(b) + var k *big.Int + if n.Cmp(sm2P256.N) >= 0 { + n.Mod(n, sm2P256.N) + k = n + } else { + k = n + } + wnaf := make([]int8, k.BitLen()+1, k.BitLen()+1) + if k.Sign() == 0 { + return wnaf + } + var width, pow2, sign int + width, pow2, sign = 4, 16, 8 + var mask int64 = 15 + var carry bool + var length, pos int + for pos <= k.BitLen() { + if k.Bit(pos) == boolToUint(carry) { + pos++ + continue + } + k.Rsh(k, uint(pos)) + var digit int + digit = int(k.Int64() & mask) + if carry { + digit++ + } + carry = (digit & sign) != 0 + if carry { + digit -= pow2 + } + length += pos + wnaf[length] = int8(digit) + pos = int(width) + } + if len(wnaf) > length+1 { + t := make([]int8, length+1, length+1) + copy(t, wnaf[0:length+1]) + wnaf = t + } + return wnaf +} +func boolToUint(b bool) uint { + if b { + return 1 + } + return 0 +} +func abs(a int8) uint32 { + if a < 0 { + return uint32(-a) + } + return uint32(a) +} + +func sm2P256ScalarMult(xOut, yOut, zOut, x, y *sm2P256FieldElement, scalar []int8) { + var precomp [16][3]sm2P256FieldElement + var px, py, pz, tx, ty, tz sm2P256FieldElement + var nIsInfinityMask, index, pIsNoninfiniteMask, mask uint32 + + // We precompute 0,1,2,... times {x,y}. + precomp[1][0] = *x + precomp[1][1] = *y + precomp[1][2] = sm2P256Factor[1] + + for i := 2; i < 8; i += 2 { + sm2P256PointDouble(&precomp[i][0], &precomp[i][1], &precomp[i][2], &precomp[i/2][0], &precomp[i/2][1], &precomp[i/2][2]) + sm2P256PointAddMixed(&precomp[i+1][0], &precomp[i+1][1], &precomp[i+1][2], &precomp[i][0], &precomp[i][1], &precomp[i][2], x, y) + } + + for i := range xOut { + xOut[i] = 0 + } + for i := range yOut { + yOut[i] = 0 + } + for i := range zOut { + zOut[i] = 0 + } + nIsInfinityMask = ^uint32(0) + var zeroes int16 + for i := 0; i < len(scalar); i++ { + if scalar[i] == 0 { + zeroes++ + continue + } + if zeroes > 0 { + for ; zeroes > 0; zeroes-- { + sm2P256PointDouble(xOut, yOut, zOut, xOut, yOut, zOut) + } + } + index = abs(scalar[i]) + sm2P256PointDouble(xOut, yOut, zOut, xOut, yOut, zOut) + sm2P256SelectJacobianPoint(&px, &py, &pz, &precomp, index) + if scalar[i] > 0 { + sm2P256PointAdd(xOut, yOut, zOut, &px, &py, &pz, &tx, &ty, &tz) + } else { + sm2P256PointSub(xOut, yOut, zOut, &px, &py, &pz, &tx, &ty, &tz) + } + sm2P256CopyConditional(xOut, &px, nIsInfinityMask) + sm2P256CopyConditional(yOut, &py, nIsInfinityMask) + sm2P256CopyConditional(zOut, &pz, nIsInfinityMask) + pIsNoninfiniteMask = nonZeroToAllOnes(index) + mask = pIsNoninfiniteMask & ^nIsInfinityMask + sm2P256CopyConditional(xOut, &tx, mask) + sm2P256CopyConditional(yOut, &ty, mask) + sm2P256CopyConditional(zOut, &tz, mask) + nIsInfinityMask &^= pIsNoninfiniteMask + } + if zeroes > 0 { + for ; zeroes > 0; zeroes-- { + sm2P256PointDouble(xOut, yOut, zOut, xOut, yOut, zOut) + } + } +} diff --git a/internal/pkg/cmb/sm2/util/pkcs8.go b/internal/pkg/cmb/sm2/util/pkcs8.go new file mode 100644 index 0000000..c97d9f0 --- /dev/null +++ b/internal/pkg/cmb/sm2/util/pkcs8.go @@ -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) +} diff --git a/internal/pkg/cmb/sm2/util/sm3.go b/internal/pkg/cmb/sm2/util/sm3.go new file mode 100644 index 0000000..d71fc75 --- /dev/null +++ b/internal/pkg/cmb/sm2/util/sm3.go @@ -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) +} diff --git a/internal/pkg/cmb/sm2/util/util.go b/internal/pkg/cmb/sm2/util/util.go new file mode 100644 index 0000000..c5a4572 --- /dev/null +++ b/internal/pkg/cmb/sm2/util/util.go @@ -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 +} diff --git a/internal/pkg/cmb/sm2/util/x509.go b/internal/pkg/cmb/sm2/util/x509.go new file mode 100644 index 0000000..b8614dc --- /dev/null +++ b/internal/pkg/cmb/sm2/util/x509.go @@ -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 +} diff --git a/internal/pkg/cmb/sm2_test.go b/internal/pkg/cmb/sm2_test.go new file mode 100644 index 0000000..f04905a --- /dev/null +++ b/internal/pkg/cmb/sm2_test.go @@ -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) +} diff --git a/internal/pkg/cmb/sm4.go b/internal/pkg/cmb/sm4.go new file mode 100644 index 0000000..4f700d9 --- /dev/null +++ b/internal/pkg/cmb/sm4.go @@ -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 +} diff --git a/internal/pkg/cmb/sm4/sm4.go b/internal/pkg/cmb/sm4/sm4.go new file mode 100644 index 0000000..26b4fea --- /dev/null +++ b/internal/pkg/cmb/sm4/sm4.go @@ -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 +} diff --git a/internal/pkg/cmb/sm4/sm4_test.go b/internal/pkg/cmb/sm4/sm4_test.go new file mode 100644 index 0000000..9842324 --- /dev/null +++ b/internal/pkg/cmb/sm4/sm4_test.go @@ -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))) +} diff --git a/internal/pkg/cmb/sm4/util.go b/internal/pkg/cmb/sm4/util.go new file mode 100644 index 0000000..c400d65 --- /dev/null +++ b/internal/pkg/cmb/sm4/util.go @@ -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 +} diff --git a/internal/pkg/cmb/sm4_test.go b/internal/pkg/cmb/sm4_test.go new file mode 100644 index 0000000..1bc32ad --- /dev/null +++ b/internal/pkg/cmb/sm4_test.go @@ -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) +} diff --git a/internal/pkg/cmb/smutil.go b/internal/pkg/cmb/smutil.go new file mode 100644 index 0000000..e075184 --- /dev/null +++ b/internal/pkg/cmb/smutil.go @@ -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 +}