From 43ffd49e2fed5a445188a29c5529b5718fa00deb Mon Sep 17 00:00:00 2001 From: Sun Yimin Date: Thu, 13 Mar 2025 13:46:14 +0800 Subject: [PATCH] sm9: refactoring, do not expose bn256 types to caller #314 --- {sm9 => internal/sm9}/bn256/LICENSE | 0 {sm9 => internal/sm9}/bn256/README.md | 0 {sm9 => internal/sm9}/bn256/bn_pair.go | 0 {sm9 => internal/sm9}/bn256/bn_pair_b6.go | 0 .../sm9}/bn256/bn_pair_b6_test.go | 0 {sm9 => internal/sm9}/bn256/bn_pair_test.go | 0 {sm9 => internal/sm9}/bn256/constants.go | 25 +- {sm9 => internal/sm9}/bn256/curve.go | 0 {sm9 => internal/sm9}/bn256/elliptic.go | 0 {sm9 => internal/sm9}/bn256/g1.go | 0 {sm9 => internal/sm9}/bn256/g1_test.go | 0 {sm9 => internal/sm9}/bn256/g2.go | 0 {sm9 => internal/sm9}/bn256/g2_test.go | 0 {sm9 => internal/sm9}/bn256/generate.go | 0 {sm9 => internal/sm9}/bn256/gfp.go | 0 {sm9 => internal/sm9}/bn256/gfp12.go | 0 {sm9 => internal/sm9}/bn256/gfp12_b6.go | 0 {sm9 => internal/sm9}/bn256/gfp12_b6_test.go | 0 {sm9 => internal/sm9}/bn256/gfp12_exp_u.go | 0 {sm9 => internal/sm9}/bn256/gfp12_test.go | 0 {sm9 => internal/sm9}/bn256/gfp12b6_exp_u.go | 0 {sm9 => internal/sm9}/bn256/gfp2.go | 0 {sm9 => internal/sm9}/bn256/gfp2_g1_amd64.s | 0 {sm9 => internal/sm9}/bn256/gfp2_g1_arm64.s | 0 {sm9 => internal/sm9}/bn256/gfp2_g1_decl.go | 0 .../sm9}/bn256/gfp2_g1_generic.go | 0 {sm9 => internal/sm9}/bn256/gfp2_sqrt.go | 0 {sm9 => internal/sm9}/bn256/gfp2_test.go | 0 {sm9 => internal/sm9}/bn256/gfp4.go | 0 {sm9 => internal/sm9}/bn256/gfp4_test.go | 0 {sm9 => internal/sm9}/bn256/gfp6.go | 0 {sm9 => internal/sm9}/bn256/gfp6_test.go | 0 {sm9 => internal/sm9}/bn256/gfp_amd64.s | 0 {sm9 => internal/sm9}/bn256/gfp_arm64.s | 0 {sm9 => internal/sm9}/bn256/gfp_cmn_amd64.s | 0 {sm9 => internal/sm9}/bn256/gfp_decl.go | 0 {sm9 => internal/sm9}/bn256/gfp_generic.go | 0 .../sm9}/bn256/gfp_invert_sqrt.go | 0 .../sm9}/bn256/gfp_macros_amd64.s | 0 .../sm9}/bn256/gfp_plugin_amd64.s | 0 {sm9 => internal/sm9}/bn256/gfp_ppc64x.s | 0 {sm9 => internal/sm9}/bn256/gfp_test.go | 0 {sm9 => internal/sm9}/bn256/gt.go | 0 {sm9 => internal/sm9}/bn256/gt_test.go | 0 {sm9 => internal/sm9}/bn256/params.go | 0 {sm9 => internal/sm9}/bn256/params_test.go | 0 {sm9 => internal/sm9}/bn256/select_amd64.s | 0 {sm9 => internal/sm9}/bn256/select_arm64.s | 0 {sm9 => internal/sm9}/bn256/select_decl.go | 0 {sm9 => internal/sm9}/bn256/select_generic.go | 0 {sm9 => internal/sm9}/bn256/select_ppc64x.s | 0 {sm9 => internal/sm9}/bn256/select_test.go | 0 {sm9 => internal/sm9}/bn256/twist.go | 0 {sm9 => internal/sm9}/bn256/twist_test.go | 0 internal/sm9/sm9.go | 454 +++++++++++ internal/sm9/sm9_key.go | 510 ++++++++++++ internal/sm9/sm9_key_test.go | 40 + internal/sm9/sm9_test.go | 596 ++++++++++++++ pkcs8/pkcs8_test.go | 8 +- sm9/sm9.go | 493 ++--------- sm9/sm9_key.go | 346 +++----- sm9/sm9_key_test.go | 30 +- sm9/sm9_test.go | 764 ++++-------------- smx509/pkcs8_test.go | 13 +- 64 files changed, 1957 insertions(+), 1322 deletions(-) rename {sm9 => internal/sm9}/bn256/LICENSE (100%) rename {sm9 => internal/sm9}/bn256/README.md (100%) rename {sm9 => internal/sm9}/bn256/bn_pair.go (100%) rename {sm9 => internal/sm9}/bn256/bn_pair_b6.go (100%) rename {sm9 => internal/sm9}/bn256/bn_pair_b6_test.go (100%) rename {sm9 => internal/sm9}/bn256/bn_pair_test.go (100%) rename {sm9 => internal/sm9}/bn256/constants.go (85%) rename {sm9 => internal/sm9}/bn256/curve.go (100%) rename {sm9 => internal/sm9}/bn256/elliptic.go (100%) rename {sm9 => internal/sm9}/bn256/g1.go (100%) rename {sm9 => internal/sm9}/bn256/g1_test.go (100%) rename {sm9 => internal/sm9}/bn256/g2.go (100%) rename {sm9 => internal/sm9}/bn256/g2_test.go (100%) rename {sm9 => internal/sm9}/bn256/generate.go (100%) rename {sm9 => internal/sm9}/bn256/gfp.go (100%) rename {sm9 => internal/sm9}/bn256/gfp12.go (100%) rename {sm9 => internal/sm9}/bn256/gfp12_b6.go (100%) rename {sm9 => internal/sm9}/bn256/gfp12_b6_test.go (100%) rename {sm9 => internal/sm9}/bn256/gfp12_exp_u.go (100%) rename {sm9 => internal/sm9}/bn256/gfp12_test.go (100%) rename {sm9 => internal/sm9}/bn256/gfp12b6_exp_u.go (100%) rename {sm9 => internal/sm9}/bn256/gfp2.go (100%) rename {sm9 => internal/sm9}/bn256/gfp2_g1_amd64.s (100%) rename {sm9 => internal/sm9}/bn256/gfp2_g1_arm64.s (100%) rename {sm9 => internal/sm9}/bn256/gfp2_g1_decl.go (100%) rename {sm9 => internal/sm9}/bn256/gfp2_g1_generic.go (100%) rename {sm9 => internal/sm9}/bn256/gfp2_sqrt.go (100%) rename {sm9 => internal/sm9}/bn256/gfp2_test.go (100%) rename {sm9 => internal/sm9}/bn256/gfp4.go (100%) rename {sm9 => internal/sm9}/bn256/gfp4_test.go (100%) rename {sm9 => internal/sm9}/bn256/gfp6.go (100%) rename {sm9 => internal/sm9}/bn256/gfp6_test.go (100%) rename {sm9 => internal/sm9}/bn256/gfp_amd64.s (100%) rename {sm9 => internal/sm9}/bn256/gfp_arm64.s (100%) rename {sm9 => internal/sm9}/bn256/gfp_cmn_amd64.s (100%) rename {sm9 => internal/sm9}/bn256/gfp_decl.go (100%) rename {sm9 => internal/sm9}/bn256/gfp_generic.go (100%) rename {sm9 => internal/sm9}/bn256/gfp_invert_sqrt.go (100%) rename {sm9 => internal/sm9}/bn256/gfp_macros_amd64.s (100%) rename {sm9 => internal/sm9}/bn256/gfp_plugin_amd64.s (100%) rename {sm9 => internal/sm9}/bn256/gfp_ppc64x.s (100%) rename {sm9 => internal/sm9}/bn256/gfp_test.go (100%) rename {sm9 => internal/sm9}/bn256/gt.go (100%) rename {sm9 => internal/sm9}/bn256/gt_test.go (100%) rename {sm9 => internal/sm9}/bn256/params.go (100%) rename {sm9 => internal/sm9}/bn256/params_test.go (100%) rename {sm9 => internal/sm9}/bn256/select_amd64.s (100%) rename {sm9 => internal/sm9}/bn256/select_arm64.s (100%) rename {sm9 => internal/sm9}/bn256/select_decl.go (100%) rename {sm9 => internal/sm9}/bn256/select_generic.go (100%) rename {sm9 => internal/sm9}/bn256/select_ppc64x.s (100%) rename {sm9 => internal/sm9}/bn256/select_test.go (100%) rename {sm9 => internal/sm9}/bn256/twist.go (100%) rename {sm9 => internal/sm9}/bn256/twist_test.go (100%) create mode 100644 internal/sm9/sm9.go create mode 100644 internal/sm9/sm9_key.go create mode 100644 internal/sm9/sm9_key_test.go create mode 100644 internal/sm9/sm9_test.go diff --git a/sm9/bn256/LICENSE b/internal/sm9/bn256/LICENSE similarity index 100% rename from sm9/bn256/LICENSE rename to internal/sm9/bn256/LICENSE diff --git a/sm9/bn256/README.md b/internal/sm9/bn256/README.md similarity index 100% rename from sm9/bn256/README.md rename to internal/sm9/bn256/README.md diff --git a/sm9/bn256/bn_pair.go b/internal/sm9/bn256/bn_pair.go similarity index 100% rename from sm9/bn256/bn_pair.go rename to internal/sm9/bn256/bn_pair.go diff --git a/sm9/bn256/bn_pair_b6.go b/internal/sm9/bn256/bn_pair_b6.go similarity index 100% rename from sm9/bn256/bn_pair_b6.go rename to internal/sm9/bn256/bn_pair_b6.go diff --git a/sm9/bn256/bn_pair_b6_test.go b/internal/sm9/bn256/bn_pair_b6_test.go similarity index 100% rename from sm9/bn256/bn_pair_b6_test.go rename to internal/sm9/bn256/bn_pair_b6_test.go diff --git a/sm9/bn256/bn_pair_test.go b/internal/sm9/bn256/bn_pair_test.go similarity index 100% rename from sm9/bn256/bn_pair_test.go rename to internal/sm9/bn256/bn_pair_test.go diff --git a/sm9/bn256/constants.go b/internal/sm9/bn256/constants.go similarity index 85% rename from sm9/bn256/constants.go rename to internal/sm9/bn256/constants.go index bb9f977..5e9a7ed 100644 --- a/sm9/bn256/constants.go +++ b/internal/sm9/bn256/constants.go @@ -1,5 +1,7 @@ package bn256 +import "math/big" + // u is the BN parameter that determines the prime: 600000000058f98a. var u = bigFromHex("600000000058f98a") @@ -17,8 +19,29 @@ var sixU2Plus1 = bigFromHex("d8000000019062ed0000b98b0cb27659") // p is a prime over which we form a basic field: 36u⁴+36u³+24u²+6u+1. var p = bigFromHex("b640000002a3a6f1d603ab4ff58ec74521f2934b1a7aeedbe56f9b27e351457d") +var OrderBytes = []byte{ + 0xb6, 0x40, 0x00, 0x00, 0x02, 0xa3, 0xa6, 0xf1, + 0xd6, 0x03, 0xab, 0x4f, 0xf5, 0x8e, 0xc7, 0x44, + 0x49, 0xf2, 0x93, 0x4b, 0x18, 0xea, 0x8b, 0xee, + 0xe5, 0x6e, 0xe1, 0x9c, 0xd6, 0x9e, 0xcf, 0x25, +} + // Order is the number of elements in both G₁ and G₂: 36u⁴+36u³+18u²+6u+1. -var Order = bigFromHex("b640000002a3a6f1d603ab4ff58ec74449f2934b18ea8beee56ee19cd69ecf25") +var Order = new(big.Int).SetBytes(OrderBytes) + +var OrderMinus1Bytes = []byte{ + 0xb6, 0x40, 0x00, 0x00, 0x02, 0xa3, 0xa6, 0xf1, + 0xd6, 0x03, 0xab, 0x4f, 0xf5, 0x8e, 0xc7, 0x44, + 0x49, 0xf2, 0x93, 0x4b, 0x18, 0xea, 0x8b, 0xee, + 0xe5, 0x6e, 0xe1, 0x9c, 0xd6, 0x9e, 0xcf, 0x24, +} + +var OrderMinus2Bytes = []byte{ + 0xb6, 0x40, 0x00, 0x00, 0x02, 0xa3, 0xa6, 0xf1, + 0xd6, 0x03, 0xab, 0x4f, 0xf5, 0x8e, 0xc7, 0x44, + 0x49, 0xf2, 0x93, 0x4b, 0x18, 0xea, 0x8b, 0xee, + 0xe5, 0x6e, 0xe1, 0x9c, 0xd6, 0x9e, 0xcf, 0x23, +} // p2 is p, represented as little-endian 64-bit words. var p2 = [4]uint64{0xe56f9b27e351457d, 0x21f2934b1a7aeedb, 0xd603ab4ff58ec745, 0xb640000002a3a6f1} diff --git a/sm9/bn256/curve.go b/internal/sm9/bn256/curve.go similarity index 100% rename from sm9/bn256/curve.go rename to internal/sm9/bn256/curve.go diff --git a/sm9/bn256/elliptic.go b/internal/sm9/bn256/elliptic.go similarity index 100% rename from sm9/bn256/elliptic.go rename to internal/sm9/bn256/elliptic.go diff --git a/sm9/bn256/g1.go b/internal/sm9/bn256/g1.go similarity index 100% rename from sm9/bn256/g1.go rename to internal/sm9/bn256/g1.go diff --git a/sm9/bn256/g1_test.go b/internal/sm9/bn256/g1_test.go similarity index 100% rename from sm9/bn256/g1_test.go rename to internal/sm9/bn256/g1_test.go diff --git a/sm9/bn256/g2.go b/internal/sm9/bn256/g2.go similarity index 100% rename from sm9/bn256/g2.go rename to internal/sm9/bn256/g2.go diff --git a/sm9/bn256/g2_test.go b/internal/sm9/bn256/g2_test.go similarity index 100% rename from sm9/bn256/g2_test.go rename to internal/sm9/bn256/g2_test.go diff --git a/sm9/bn256/generate.go b/internal/sm9/bn256/generate.go similarity index 100% rename from sm9/bn256/generate.go rename to internal/sm9/bn256/generate.go diff --git a/sm9/bn256/gfp.go b/internal/sm9/bn256/gfp.go similarity index 100% rename from sm9/bn256/gfp.go rename to internal/sm9/bn256/gfp.go diff --git a/sm9/bn256/gfp12.go b/internal/sm9/bn256/gfp12.go similarity index 100% rename from sm9/bn256/gfp12.go rename to internal/sm9/bn256/gfp12.go diff --git a/sm9/bn256/gfp12_b6.go b/internal/sm9/bn256/gfp12_b6.go similarity index 100% rename from sm9/bn256/gfp12_b6.go rename to internal/sm9/bn256/gfp12_b6.go diff --git a/sm9/bn256/gfp12_b6_test.go b/internal/sm9/bn256/gfp12_b6_test.go similarity index 100% rename from sm9/bn256/gfp12_b6_test.go rename to internal/sm9/bn256/gfp12_b6_test.go diff --git a/sm9/bn256/gfp12_exp_u.go b/internal/sm9/bn256/gfp12_exp_u.go similarity index 100% rename from sm9/bn256/gfp12_exp_u.go rename to internal/sm9/bn256/gfp12_exp_u.go diff --git a/sm9/bn256/gfp12_test.go b/internal/sm9/bn256/gfp12_test.go similarity index 100% rename from sm9/bn256/gfp12_test.go rename to internal/sm9/bn256/gfp12_test.go diff --git a/sm9/bn256/gfp12b6_exp_u.go b/internal/sm9/bn256/gfp12b6_exp_u.go similarity index 100% rename from sm9/bn256/gfp12b6_exp_u.go rename to internal/sm9/bn256/gfp12b6_exp_u.go diff --git a/sm9/bn256/gfp2.go b/internal/sm9/bn256/gfp2.go similarity index 100% rename from sm9/bn256/gfp2.go rename to internal/sm9/bn256/gfp2.go diff --git a/sm9/bn256/gfp2_g1_amd64.s b/internal/sm9/bn256/gfp2_g1_amd64.s similarity index 100% rename from sm9/bn256/gfp2_g1_amd64.s rename to internal/sm9/bn256/gfp2_g1_amd64.s diff --git a/sm9/bn256/gfp2_g1_arm64.s b/internal/sm9/bn256/gfp2_g1_arm64.s similarity index 100% rename from sm9/bn256/gfp2_g1_arm64.s rename to internal/sm9/bn256/gfp2_g1_arm64.s diff --git a/sm9/bn256/gfp2_g1_decl.go b/internal/sm9/bn256/gfp2_g1_decl.go similarity index 100% rename from sm9/bn256/gfp2_g1_decl.go rename to internal/sm9/bn256/gfp2_g1_decl.go diff --git a/sm9/bn256/gfp2_g1_generic.go b/internal/sm9/bn256/gfp2_g1_generic.go similarity index 100% rename from sm9/bn256/gfp2_g1_generic.go rename to internal/sm9/bn256/gfp2_g1_generic.go diff --git a/sm9/bn256/gfp2_sqrt.go b/internal/sm9/bn256/gfp2_sqrt.go similarity index 100% rename from sm9/bn256/gfp2_sqrt.go rename to internal/sm9/bn256/gfp2_sqrt.go diff --git a/sm9/bn256/gfp2_test.go b/internal/sm9/bn256/gfp2_test.go similarity index 100% rename from sm9/bn256/gfp2_test.go rename to internal/sm9/bn256/gfp2_test.go diff --git a/sm9/bn256/gfp4.go b/internal/sm9/bn256/gfp4.go similarity index 100% rename from sm9/bn256/gfp4.go rename to internal/sm9/bn256/gfp4.go diff --git a/sm9/bn256/gfp4_test.go b/internal/sm9/bn256/gfp4_test.go similarity index 100% rename from sm9/bn256/gfp4_test.go rename to internal/sm9/bn256/gfp4_test.go diff --git a/sm9/bn256/gfp6.go b/internal/sm9/bn256/gfp6.go similarity index 100% rename from sm9/bn256/gfp6.go rename to internal/sm9/bn256/gfp6.go diff --git a/sm9/bn256/gfp6_test.go b/internal/sm9/bn256/gfp6_test.go similarity index 100% rename from sm9/bn256/gfp6_test.go rename to internal/sm9/bn256/gfp6_test.go diff --git a/sm9/bn256/gfp_amd64.s b/internal/sm9/bn256/gfp_amd64.s similarity index 100% rename from sm9/bn256/gfp_amd64.s rename to internal/sm9/bn256/gfp_amd64.s diff --git a/sm9/bn256/gfp_arm64.s b/internal/sm9/bn256/gfp_arm64.s similarity index 100% rename from sm9/bn256/gfp_arm64.s rename to internal/sm9/bn256/gfp_arm64.s diff --git a/sm9/bn256/gfp_cmn_amd64.s b/internal/sm9/bn256/gfp_cmn_amd64.s similarity index 100% rename from sm9/bn256/gfp_cmn_amd64.s rename to internal/sm9/bn256/gfp_cmn_amd64.s diff --git a/sm9/bn256/gfp_decl.go b/internal/sm9/bn256/gfp_decl.go similarity index 100% rename from sm9/bn256/gfp_decl.go rename to internal/sm9/bn256/gfp_decl.go diff --git a/sm9/bn256/gfp_generic.go b/internal/sm9/bn256/gfp_generic.go similarity index 100% rename from sm9/bn256/gfp_generic.go rename to internal/sm9/bn256/gfp_generic.go diff --git a/sm9/bn256/gfp_invert_sqrt.go b/internal/sm9/bn256/gfp_invert_sqrt.go similarity index 100% rename from sm9/bn256/gfp_invert_sqrt.go rename to internal/sm9/bn256/gfp_invert_sqrt.go diff --git a/sm9/bn256/gfp_macros_amd64.s b/internal/sm9/bn256/gfp_macros_amd64.s similarity index 100% rename from sm9/bn256/gfp_macros_amd64.s rename to internal/sm9/bn256/gfp_macros_amd64.s diff --git a/sm9/bn256/gfp_plugin_amd64.s b/internal/sm9/bn256/gfp_plugin_amd64.s similarity index 100% rename from sm9/bn256/gfp_plugin_amd64.s rename to internal/sm9/bn256/gfp_plugin_amd64.s diff --git a/sm9/bn256/gfp_ppc64x.s b/internal/sm9/bn256/gfp_ppc64x.s similarity index 100% rename from sm9/bn256/gfp_ppc64x.s rename to internal/sm9/bn256/gfp_ppc64x.s diff --git a/sm9/bn256/gfp_test.go b/internal/sm9/bn256/gfp_test.go similarity index 100% rename from sm9/bn256/gfp_test.go rename to internal/sm9/bn256/gfp_test.go diff --git a/sm9/bn256/gt.go b/internal/sm9/bn256/gt.go similarity index 100% rename from sm9/bn256/gt.go rename to internal/sm9/bn256/gt.go diff --git a/sm9/bn256/gt_test.go b/internal/sm9/bn256/gt_test.go similarity index 100% rename from sm9/bn256/gt_test.go rename to internal/sm9/bn256/gt_test.go diff --git a/sm9/bn256/params.go b/internal/sm9/bn256/params.go similarity index 100% rename from sm9/bn256/params.go rename to internal/sm9/bn256/params.go diff --git a/sm9/bn256/params_test.go b/internal/sm9/bn256/params_test.go similarity index 100% rename from sm9/bn256/params_test.go rename to internal/sm9/bn256/params_test.go diff --git a/sm9/bn256/select_amd64.s b/internal/sm9/bn256/select_amd64.s similarity index 100% rename from sm9/bn256/select_amd64.s rename to internal/sm9/bn256/select_amd64.s diff --git a/sm9/bn256/select_arm64.s b/internal/sm9/bn256/select_arm64.s similarity index 100% rename from sm9/bn256/select_arm64.s rename to internal/sm9/bn256/select_arm64.s diff --git a/sm9/bn256/select_decl.go b/internal/sm9/bn256/select_decl.go similarity index 100% rename from sm9/bn256/select_decl.go rename to internal/sm9/bn256/select_decl.go diff --git a/sm9/bn256/select_generic.go b/internal/sm9/bn256/select_generic.go similarity index 100% rename from sm9/bn256/select_generic.go rename to internal/sm9/bn256/select_generic.go diff --git a/sm9/bn256/select_ppc64x.s b/internal/sm9/bn256/select_ppc64x.s similarity index 100% rename from sm9/bn256/select_ppc64x.s rename to internal/sm9/bn256/select_ppc64x.s diff --git a/sm9/bn256/select_test.go b/internal/sm9/bn256/select_test.go similarity index 100% rename from sm9/bn256/select_test.go rename to internal/sm9/bn256/select_test.go diff --git a/sm9/bn256/twist.go b/internal/sm9/bn256/twist.go similarity index 100% rename from sm9/bn256/twist.go rename to internal/sm9/bn256/twist.go diff --git a/sm9/bn256/twist_test.go b/internal/sm9/bn256/twist_test.go similarity index 100% rename from sm9/bn256/twist_test.go rename to internal/sm9/bn256/twist_test.go diff --git a/internal/sm9/sm9.go b/internal/sm9/sm9.go new file mode 100644 index 0000000..85d2d97 --- /dev/null +++ b/internal/sm9/sm9.go @@ -0,0 +1,454 @@ +// Package sm9 implements ShangMi(SM) sm9 digital signature, encryption and key exchange algorithms. +package sm9 + +import ( + "crypto" + goSubtle "crypto/subtle" + "errors" + "io" + + "github.com/emmansun/gmsm/internal/bigmod" + "github.com/emmansun/gmsm/internal/byteorder" + "github.com/emmansun/gmsm/internal/randutil" + "github.com/emmansun/gmsm/internal/sm3" + "github.com/emmansun/gmsm/internal/sm9/bn256" + "github.com/emmansun/gmsm/internal/subtle" +) + +// SM9 ASN.1 format reference: Information security technology - SM9 cryptographic algorithm application specification +var ( + orderNat *bigmod.Modulus +) + +func init() { + orderNat, _ = bigmod.NewModulus(bn256.OrderBytes) +} + +type hashMode byte + +const ( + // hashmode used in h1: 0x01 + H1 hashMode = 1 + iota + // hashmode used in h2: 0x02 + H2 +) + +// hash implements H1(Z,n) or H2(Z,n) in sm9 algorithm. +func hash(z []byte, h hashMode) *bigmod.Nat { + md := sm3.New() + var ha [64]byte + var countBytes [4]byte + var ct uint32 = 1 + + byteorder.BEPutUint32(countBytes[:], ct) + md.Write([]byte{byte(h)}) + md.Write(z) + md.Write(countBytes[:]) + copy(ha[:], md.Sum(nil)) + ct++ + md.Reset() + + byteorder.BEPutUint32(countBytes[:], ct) + md.Write([]byte{byte(h)}) + md.Write(z) + md.Write(countBytes[:]) + copy(ha[sm3.Size:], md.Sum(nil)) + + return bigmod.NewNat().SetOverflowedBytes(ha[:40], orderNat) +} + +func hashH1(z []byte) *bigmod.Nat { + return hash(z, H1) +} + +func hashH2(z []byte) *bigmod.Nat { + return hash(z, H2) +} + +func randomScalar(rand io.Reader) (k *bigmod.Nat, err error) { + k = bigmod.NewNat() + for { + b := make([]byte, orderNat.Size()) + if _, err = io.ReadFull(rand, b); err != nil { + return + } + + // Mask off any excess bits to increase the chance of hitting a value in + // (0, N). These are the most dangerous lines in the package and maybe in + // the library: a single bit of bias in the selection of nonces would likely + // lead to key recovery, but no tests would fail. Look but DO NOT TOUCH. + if excess := len(b)*8 - orderNat.BitLen(); excess > 0 { + // Just to be safe, assert that this only happens for the one curve that + // doesn't have a round number of bits. + if excess != 0 { + panic("sm9: internal error: unexpectedly masking off bits") + } + b[0] >>= excess + } + + // FIPS 186-4 makes us check k <= N - 2 and then add one. + // Checking 0 < k <= N - 1 is strictly equivalent. + // None of this matters anyway because the chance of selecting + // zero is cryptographically negligible. + if _, err = k.SetBytes(b, orderNat); err == nil && k.IsZero() == 0 { + break + } + } + return +} + +// Sign signs digest with user's DSA key, reading randomness from rand. The opts argument +// is not currently used but, in keeping with the crypto.Signer interface. +// +// The signature is randomized. Most applications should use [crypto/rand.Reader] +// as rand. Note that the returned signature does not depend deterministically on +// the bytes read from rand, and may change between calls and/or between versions. +func (priv *SignPrivateKey) Sign(rand io.Reader, hash []byte, opts crypto.SignerOpts) ([]byte, []byte, error) { + var ( + hNat *bigmod.Nat + s *bn256.G1 + ) + randutil.MaybeReadByte(rand) + for { + r, err := randomScalar(rand) + if err != nil { + return nil, nil, err + } + + w, err := priv.SignMasterPublicKey.ScalarBaseMult(r.Bytes(orderNat)) + if err != nil { + return nil, nil, err + } + + var buffer []byte + buffer = append(append(buffer, hash...), w.Marshal()...) + + hNat = hashH2(buffer) + r.Sub(hNat, orderNat) + + if r.IsZero() == 0 { + s, err = new(bn256.G1).ScalarMult(priv.PrivateKey, r.Bytes(orderNat)) + if err != nil { + return nil, nil, err + } + break + } + } + return hNat.Bytes(orderNat), s.MarshalUncompressed(), nil +} + +// Verify checks the validity of a signature using the provided parameters. +func (pub *SignMasterPublicKey) Verify(uid []byte, hid byte, hash, h, s []byte) bool { + sPoint := new(bn256.G1) + _, err := sPoint.Unmarshal(s[1:]) + if err != nil || !sPoint.IsOnCurve() { + return false + } + hNat, err := bigmod.NewNat().SetBytes(h, orderNat) + if err != nil || hNat.IsZero() == 1 { + return false + } + t, err := pub.ScalarBaseMult(hNat.Bytes(orderNat)) + if err != nil { + return false + } + + // user sign public key p generation + p := pub.GenerateUserPublicKey(uid, hid) + + u := bn256.Pair(sPoint, p) + w := new(bn256.GT).Add(u, t) + + var buffer []byte + buffer = append(append(buffer, hash...), w.Marshal()...) + h2 := hashH2(buffer) + + return h2.Equal(hNat) == 1 +} + +// WrapKey generates a wrapped key and its corresponding ciphertext. +// +// Parameters: +// - rand: an io.Reader used to generate random values. +// - uid: a byte slice representing the user ID. +// - hid: a byte representing the hash ID. +// - kLen: an integer specifying the desired key length. +// +// Returns: +// - A byte slice containing the generated key. +// - A byte slice containing the uncompressed ciphertext. +// - An error if any occurs during the key wrapping process. +func (pub *EncryptMasterPublicKey) WrapKey(rand io.Reader, uid []byte, hid byte, kLen int) ([]byte, []byte, error) { + q := pub.GenerateUserPublicKey(uid, hid) + var ( + err error + r *bigmod.Nat + w *bn256.GT + cipher *bn256.G1 + key []byte + ) + for { + r, err = randomScalar(rand) + if err != nil { + return nil, nil, err + } + + rBytes := r.Bytes(orderNat) + cipher, err = new(bn256.G1).ScalarMult(q, rBytes) + if err != nil { + return nil, nil, err + } + + w, err = pub.ScalarBaseMult(rBytes) + if err != nil { + return nil, nil, err + } + var buffer []byte + buffer = append(buffer, cipher.Marshal()...) + buffer = append(buffer, w.Marshal()...) + buffer = append(buffer, uid...) + + key = sm3.Kdf(buffer, kLen) + if subtle.ConstantTimeAllZero(key) == 0 { + break + } + } + return key, cipher.MarshalUncompressed(), nil +} + + +// UnwrapKey decrypts the given cipher text using the private key and user ID (uid). +// It returns the decrypted key of the specified length (kLen) or an error if decryption fails. +func (priv *EncryptPrivateKey) UnwrapKey(uid, cipher []byte, kLen int) ([]byte, error) { + if len(cipher) == 65 && cipher[0] != 0x04 { + return nil, ErrDecryption + } + if len(cipher) == 65 { + cipher = cipher[1:] + } + p := new(bn256.G1) + _, err := p.Unmarshal(cipher) + if err != nil || !p.IsOnCurve() { + return nil, ErrDecryption + } + + w := bn256.Pair(p, priv.PrivateKey) + + var buffer []byte + buffer = append(buffer, cipher...) + buffer = append(buffer, w.Marshal()...) + buffer = append(buffer, uid...) + + key := sm3.Kdf(buffer, kLen) + if subtle.ConstantTimeAllZero(key) == 1 { + return nil, ErrDecryption + } + return key, nil +} + +// ErrDecryption represents a failure to decrypt a message. +// It is deliberately vague to avoid adaptive attacks. +var ErrDecryption = errors.New("sm9: decryption error") + +// KeyExchange represents key exchange struct, include internal stat in whole key exchange flow. +// Initiator's flow will be: NewKeyExchange -> InitKeyExchange -> transmission -> ConfirmResponder +// Responder's flow will be: NewKeyExchange -> waiting ... -> RepondKeyExchange -> transmission -> ConfirmInitiator +type KeyExchange struct { + genSignature bool // control the optional sign/verify step triggered by responsder + keyLength int // key length + privateKey *EncryptPrivateKey // owner's encryption private key + uid []byte // owner uid + peerUID []byte // peer uid + r *bigmod.Nat // random which will be used to compute secret + secret []byte // generated secret which will be passed to peer + peerSecret []byte // received peer's secret + g1 *bn256.GT // internal state which will be used when compute the key and signature + g2 *bn256.GT // internal state which will be used when compute the key and signature + g3 *bn256.GT // internal state which will be used when compute the key and signature +} + +// NewKeyExchange creates one new KeyExchange object +func (priv *EncryptPrivateKey) NewKeyExchange(uid, peerUID []byte, keyLen int, genSignature bool) *KeyExchange { + ke := &KeyExchange{} + ke.genSignature = genSignature + ke.keyLength = keyLen + ke.privateKey = priv + ke.uid = uid + ke.peerUID = peerUID + return ke +} + +// Destroy clears all internal state and Ephemeral private/public keys +func (ke *KeyExchange) Destroy() { + if ke.r != nil { + ke.r.SetBytes([]byte{0}, orderNat) + } + if ke.g1 != nil { + ke.g1.SetOne() + } + if ke.g2 != nil { + ke.g2.SetOne() + } + if ke.g3 != nil { + ke.g3.SetOne() + } +} + +func initKeyExchange(ke *KeyExchange, hid byte, r *bigmod.Nat) { + pubB := ke.privateKey.GenerateUserPublicKey(ke.peerUID, hid) + ke.r = r + rA, err := new(bn256.G1).ScalarMult(pubB, ke.r.Bytes(orderNat)) + if err != nil { + panic(err) + } + ke.secret = rA.MarshalUncompressed() +} + +// InitKeyExchange generates random with responder uid, for initiator's step A1-A4 +func (ke *KeyExchange) InitKeyExchange(rand io.Reader, hid byte) ([]byte, error) { + r, err := randomScalar(rand) + if err != nil { + return nil, err + } + initKeyExchange(ke, hid, r) + return ke.secret, nil +} + +func (ke *KeyExchange) sign(isResponder bool, prefix byte) []byte { + var buffer []byte + hash := sm3.New() + hash.Write(ke.g2.Marshal()) + hash.Write(ke.g3.Marshal()) + if isResponder { + hash.Write(ke.peerUID) + hash.Write(ke.uid) + hash.Write(ke.peerSecret[1:]) + hash.Write(ke.secret[1:]) + } else { + hash.Write(ke.uid) + hash.Write(ke.peerUID) + hash.Write(ke.secret[1:]) + hash.Write(ke.peerSecret[1:]) + } + buffer = hash.Sum(nil) + hash.Reset() + hash.Write([]byte{prefix}) + hash.Write(ke.g1.Marshal()) + hash.Write(buffer) + return hash.Sum(nil) +} + +func (ke *KeyExchange) generateSharedKey(isResponder bool) ([]byte, error) { + var buffer []byte + if isResponder { + buffer = append(buffer, ke.peerUID...) + buffer = append(buffer, ke.uid...) + buffer = append(buffer, ke.peerSecret[1:]...) + buffer = append(buffer, ke.secret[1:]...) + } else { + buffer = append(buffer, ke.uid...) + buffer = append(buffer, ke.peerUID...) + buffer = append(buffer, ke.secret[1:]...) + buffer = append(buffer, ke.peerSecret[1:]...) + } + buffer = append(buffer, ke.g1.Marshal()...) + buffer = append(buffer, ke.g2.Marshal()...) + buffer = append(buffer, ke.g3.Marshal()...) + + return sm3.Kdf(buffer, ke.keyLength), nil +} + +func respondKeyExchange(ke *KeyExchange, hid byte, r *bigmod.Nat, rA []byte) ([]byte, []byte, error) { + rP := new(bn256.G1) + _, err := rP.Unmarshal(rA[1:]) + if err != nil || !rP.IsOnCurve() { + return nil, nil, errors.New("sm9: invalid initiator's ephemeral public key") + } + ke.peerSecret = rA + pubA := ke.privateKey.GenerateUserPublicKey(ke.peerUID, hid) + ke.r = r + rBytes := r.Bytes(orderNat) + rB, err := new(bn256.G1).ScalarMult(pubA, rBytes) + if err != nil { + return nil, nil, err + } + ke.secret = rB.MarshalUncompressed() + + ke.g1 = bn256.Pair(rP, ke.privateKey.PrivateKey) + ke.g3 = &bn256.GT{} + g3, err := bn256.ScalarMultGT(ke.g1, rBytes) + if err != nil { + return nil, nil, err + } + ke.g3 = g3 + + g2, err := ke.privateKey.EncryptMasterPublicKey.ScalarBaseMult(rBytes) + if err != nil { + return nil, nil, err + } + ke.g2 = g2 + + if !ke.genSignature { + return ke.secret, nil, nil + } + + return ke.secret, ke.sign(true, 0x82), nil +} + +// RespondKeyExchange when responder receive rA, for responder's step B1-B7 +func (ke *KeyExchange) RespondKeyExchange(rand io.Reader, hid byte, rA []byte) ([]byte, []byte, error) { + r, err := randomScalar(rand) + if err != nil { + return nil, nil, err + } + return respondKeyExchange(ke, hid, r, rA) +} + +// ConfirmResponder for initiator's step A5-A7 +func (ke *KeyExchange) ConfirmResponder(rB, sB []byte) ([]byte, []byte, error) { + pB := new(bn256.G1) + _, err := pB.Unmarshal(rB[1:]) + if err != nil || !pB.IsOnCurve() { + return nil, nil, errors.New("sm9: invalid responder's ephemeral public key") + } + // step 5 + ke.peerSecret = rB + g1, err := ke.privateKey.EncryptMasterPublicKey.ScalarBaseMult(ke.r.Bytes(orderNat)) + if err != nil { + return nil, nil, err + } + ke.g1 = g1 + ke.g2 = bn256.Pair(pB, ke.privateKey.PrivateKey) + ke.g3 = &bn256.GT{} + g3, err := bn256.ScalarMultGT(ke.g2, ke.r.Bytes(orderNat)) + if err != nil { + return nil, nil, err + } + ke.g3 = g3 + // step 6, verify signature + if len(sB) > 0 { + signature := ke.sign(false, 0x82) + if goSubtle.ConstantTimeCompare(signature, sB) != 1 { + return nil, nil, errors.New("sm9: invalid responder's signature") + } + } + key, err := ke.generateSharedKey(false) + if err != nil { + return nil, nil, err + } + if !ke.genSignature { + return key, nil, nil + } + return key, ke.sign(false, 0x83), nil +} + +// ConfirmInitiator for responder's step B8 +func (ke *KeyExchange) ConfirmInitiator(s1 []byte) ([]byte, error) { + if s1 != nil { + buffer := ke.sign(true, 0x83) + if goSubtle.ConstantTimeCompare(buffer, s1) != 1 { + return nil, errors.New("sm9: invalid initiator's signature") + } + } + return ke.generateSharedKey(true) +} diff --git a/internal/sm9/sm9_key.go b/internal/sm9/sm9_key.go new file mode 100644 index 0000000..65b674f --- /dev/null +++ b/internal/sm9/sm9_key.go @@ -0,0 +1,510 @@ +package sm9 + +import ( + _subtle "crypto/subtle" + "encoding/binary" + "errors" + "io" + "math/bits" + "sync" + + "slices" + + "github.com/emmansun/gmsm/internal/bigmod" + "github.com/emmansun/gmsm/internal/randutil" + "github.com/emmansun/gmsm/internal/sm9/bn256" + "github.com/emmansun/gmsm/internal/subtle" +) + +// SignMasterPrivateKey master private key for sign, generated by KGC +type SignMasterPrivateKey struct { + *SignMasterPublicKey // master public key + privateKey []byte // master private key +} + +// SignMasterPublicKey master public key for sign, generated by KGC +type SignMasterPublicKey struct { + MasterPublicKey *bn256.G2 // master public key + pairOnce sync.Once + basePoint *bn256.GT // the result of Pair(Gen1, pub.MasterPublicKey) + tableGenOnce sync.Once + table *[32 * 2]bn256.GTFieldTable // precomputed basePoint^n +} + +// SignPrivateKey user private key for sign, generated by KGC +type SignPrivateKey struct { + PrivateKey *bn256.G1 // user private key + *SignMasterPublicKey // master public key +} + +// EncryptMasterPrivateKey master private key for encryption, generated by KGC +type EncryptMasterPrivateKey struct { + *EncryptMasterPublicKey // master public key + privateKey []byte // master private key +} + +// EncryptMasterPublicKey master private key for encryption, generated by KGC +type EncryptMasterPublicKey struct { + MasterPublicKey *bn256.G1 // public key + pairOnce sync.Once + basePoint *bn256.GT // the result of Pair(pub.MasterPublicKey, Gen2) + tableGenOnce sync.Once + table *[32 * 2]bn256.GTFieldTable // precomputed basePoint^n +} + +// EncryptPrivateKey user private key for encryption, generated by KGC +type EncryptPrivateKey struct { + PrivateKey *bn256.G2 // user private key + *EncryptMasterPublicKey // master public key +} + +// GenerateSignMasterKey generates a master public and private key pair for DSA usage. +func GenerateSignMasterKey(rand io.Reader) (*SignMasterPrivateKey, error) { + key := make([]byte, len(bn256.OrderMinus1Bytes)) + randutil.MaybeReadByte(rand) + + for { + if _, err := io.ReadFull(rand, key); err != nil { + return nil, err + } + // In tests, rand will return all zeros and NewPrivateKey will reject + // the zero key as it generates the identity as a public key. This also + // makes this function consistent with crypto/elliptic.GenerateKey. + key[1] ^= 0x42 + + k, err := NewSignMasterPrivateKey(key) + if err == errInvalidPrivateKey { + continue + } + return k, err + } +} + +// NewSignMasterPrivateKey creates a new SignMasterPrivateKey from the given byte slice. +// The provided key must have the same length as bn256.OrderMinus1Bytes and must be less than bn256.OrderMinus1Bytes. +// If the key is invalid, an error is returned. +// +// Parameters: +// - key: A byte slice representing the master private key. +// +// Returns: +// - *SignMasterPrivateKey: A pointer to the newly created SignMasterPrivateKey. +// - error: An error if the key is invalid or if there is an issue during key generation. +func NewSignMasterPrivateKey(key []byte) (*SignMasterPrivateKey, error) { + if len(key) != len(bn256.OrderMinus1Bytes) { + return nil, errors.New("sm9: invalid master sign private key size") + } + if subtle.ConstantTimeAllZero(key) == 1 || !isLess(key, bn256.OrderMinus1Bytes) { + return nil, errInvalidPrivateKey + } + p, err := new(bn256.G2).ScalarBaseMult(key) + if err != nil { + return nil, err + } + priv := new(SignMasterPrivateKey) + priv.privateKey = append([]byte{}, key...) + priv.SignMasterPublicKey = new(SignMasterPublicKey) + priv.MasterPublicKey = p + return priv, nil +} + +// Equal compares the receiver SignMasterPrivateKey with another SignMasterPrivateKey x. +// It returns true if both the MasterPublicKey and privateKey fields are equal, using +// constant time comparison for the privateKey to prevent timing attacks. +func (master *SignMasterPrivateKey) Equal(x *SignMasterPrivateKey) bool { + return master.MasterPublicKey.Equal(x.MasterPublicKey) && _subtle.ConstantTimeCompare(master.privateKey, x.privateKey) == 1 +} + +// Bytes returns the byte representation of the SignMasterPrivateKey. +// It creates a new byte slice and appends the private key bytes to it, +// ensuring that the original private key data is not modified. +func (master *SignMasterPrivateKey) Bytes() []byte { + return slices.Clone(master.privateKey) +} + +// GenerateUserKey generate an user dsa key. +func (master *SignMasterPrivateKey) GenerateUserKey(uid []byte, hid byte) (*SignPrivateKey, error) { + var id []byte + id = append(append(id, uid...), hid) + + t1Nat := hashH1(id) + + d, err := bigmod.NewNat().SetBytes(master.privateKey, orderNat) + if err != nil { + return nil, err + } + + t1Nat.Add(d, orderNat) + if t1Nat.IsZero() == 1 { + return nil, errors.New("sm9: need to re-generate sign master private key") + } + + t1Nat = bigmod.NewNat().Exp(t1Nat, bn256.OrderMinus2Bytes, orderNat) + t1Nat.Mul(d, orderNat) + + priv := new(SignPrivateKey) + priv.SignMasterPublicKey = master.SignMasterPublicKey + g1, err := new(bn256.G1).ScalarBaseMult(t1Nat.Bytes(orderNat)) + if err != nil { + return nil, err + } + priv.PrivateKey = g1 + + return priv, nil +} + +// Public returns the public key corresponding to priv. +func (master *SignMasterPrivateKey) Public() *SignMasterPublicKey { + return master.SignMasterPublicKey +} + +// Equal compares the receiver SignMasterPublicKey with another SignMasterPublicKey +// and returns true if they are equal, otherwise it returns false. +func (pub *SignMasterPublicKey) Equal(x *SignMasterPublicKey) bool { + return pub.MasterPublicKey.Equal(x.MasterPublicKey) +} + +// Bytes returns the byte representation of the SignMasterPublicKey +// by marshaling the MasterPublicKey in an uncompressed format. +func (pub *SignMasterPublicKey) Bytes() []byte { + return pub.MasterPublicKey.MarshalUncompressed() +} + +// pair generate the basepoint once +func (pub *SignMasterPublicKey) pair() *bn256.GT { + pub.pairOnce.Do(func() { + pub.basePoint = bn256.Pair(bn256.Gen1, pub.MasterPublicKey) + }) + return pub.basePoint +} + +func (pub *SignMasterPublicKey) generatorTable() *[32 * 2]bn256.GTFieldTable { + pub.tableGenOnce.Do(func() { + pub.table = bn256.GenerateGTFieldTable(pub.pair()) + }) + return pub.table +} + +// ScalarBaseMult compute basepoint^r with precomputed table +// The base point = pair(Gen1, ) +func (pub *SignMasterPublicKey) ScalarBaseMult(scalar []byte) (*bn256.GT, error) { + tables := pub.generatorTable() + return bn256.ScalarBaseMultGT(tables, scalar) +} + +// GenerateUserPublicKey generate user sign public key +func (pub *SignMasterPublicKey) GenerateUserPublicKey(uid []byte, hid byte) *bn256.G2 { + var buffer []byte + buffer = append(append(buffer, uid...), hid) + h1 := hashH1(buffer) + p, err := new(bn256.G2).ScalarBaseMult(h1.Bytes(orderNat)) + if err != nil { + panic(err) + } + p.Add(p, pub.MasterPublicKey) + return p +} + +// Equal compares the SignPrivateKey receiver with another SignPrivateKey x +// and returns true if they are equal, otherwise it returns false. +func (priv *SignPrivateKey) Equal(x *SignPrivateKey) bool { + return priv.PrivateKey.Equal(x.PrivateKey) +} + +// Bytes returns the byte representation of the SignPrivateKey. +// It marshals the private key in an uncompressed format. +func (priv *SignPrivateKey) Bytes() []byte { + return priv.PrivateKey.MarshalUncompressed() +} + +// MasterPublic returns the master public key corresponding to priv. +func (priv *SignPrivateKey) MasterPublic() *SignMasterPublicKey { + return priv.SignMasterPublicKey +} + +// SetMasterPublicKey bind the sign master public key to it. +func (priv *SignPrivateKey) SetMasterPublicKey(pub *SignMasterPublicKey) { + if priv.SignMasterPublicKey == nil || priv.SignMasterPublicKey.MasterPublicKey == nil { + priv.SignMasterPublicKey = pub + } +} + +func unmarshalG2(bytes []byte) (*bn256.G2, error) { + g2 := new(bn256.G2) + switch bytes[0] { + case 4: + _, err := g2.Unmarshal(bytes[1:]) + if err != nil { + return nil, err + } + case 2, 3: + _, err := g2.UnmarshalCompressed(bytes) + if err != nil { + return nil, err + } + default: + return nil, errors.New("sm9: invalid point identity byte") + } + return g2, nil +} + +// UnmarshalRaw unmarsal raw bytes data to sign master public key +func (pub *SignMasterPublicKey) UnmarshalRaw(bytes []byte) error { + g2, err := unmarshalG2(bytes) + if err != nil { + return err + } + pub.MasterPublicKey = g2 + return nil +} + +func unmarshalG1(bytes []byte) (*bn256.G1, error) { + g := new(bn256.G1) + switch bytes[0] { + case 4: + _, err := g.Unmarshal(bytes[1:]) + if err != nil { + return nil, err + } + case 2, 3: + _, err := g.UnmarshalCompressed(bytes) + if err != nil { + return nil, err + } + default: + return nil, errors.New("sm9: invalid point identity byte") + } + return g, nil +} + +// UnmarshalRaw unmarsal raw bytes data to sign user private key +// Note, priv's SignMasterPublicKey should be handled separately. +func (priv *SignPrivateKey) UnmarshalRaw(bytes []byte) error { + g, err := unmarshalG1(bytes) + if err != nil { + return err + } + priv.PrivateKey = g + return nil +} + +// GenerateEncryptMasterKey generates a master public and private key pair for encryption usage. +func GenerateEncryptMasterKey(rand io.Reader) (*EncryptMasterPrivateKey, error) { + key := make([]byte, len(bn256.OrderMinus1Bytes)) + randutil.MaybeReadByte(rand) + + for { + if _, err := io.ReadFull(rand, key); err != nil { + return nil, err + } + // In tests, rand will return all zeros and NewPrivateKey will reject + // the zero key as it generates the identity as a public key. This also + // makes this function consistent with crypto/elliptic.GenerateKey. + key[1] ^= 0x42 + + k, err := NewEncryptMasterPrivateKey(key) + if err == errInvalidPrivateKey { + continue + } + return k, err + } +} + +// NewEncryptMasterPrivateKey creates a new EncryptMasterPrivateKey from the given key bytes. +// The key must have a length equal to bn256.OrderMinus1Bytes. If the key is all zeros or not +// less than bn256.OrderMinus1Bytes, an error is returned. +// +// Parameters: +// - key: A byte slice representing the master private key. +// +// Returns: +// - *EncryptMasterPrivateKey: A pointer to the newly created EncryptMasterPrivateKey. +// - error: An error if the key is invalid or if there is an issue during key generation. +func NewEncryptMasterPrivateKey(key []byte) (*EncryptMasterPrivateKey, error) { + if len(key) != len(bn256.OrderMinus1Bytes) { + return nil, errors.New("sm9: invalid master encrypt private key size") + } + if subtle.ConstantTimeAllZero(key) == 1 || !isLess(key, bn256.OrderMinus1Bytes) { + return nil, errInvalidPrivateKey + } + p, err := new(bn256.G1).ScalarBaseMult(key) + if err != nil { + return nil, err + } + priv := new(EncryptMasterPrivateKey) + priv.privateKey = append([]byte{}, key...) + priv.EncryptMasterPublicKey = new(EncryptMasterPublicKey) + priv.MasterPublicKey = p + return priv, nil +} + +// Bytes returns a copy of the private key bytes from the EncryptMasterPrivateKey. +// This method ensures that the original private key data is not modified by +// returning a new slice containing the same data. +func (master *EncryptMasterPrivateKey) Bytes() []byte { + return append([]byte{}, master.privateKey...) +} + +// Equal compares the receiver EncryptMasterPrivateKey with another EncryptMasterPrivateKey x. +// It returns true if both the public keys and private keys are equal, otherwise it returns false. +// The comparison of private keys is done in constant time to prevent timing attacks. +func (master *EncryptMasterPrivateKey) Equal(x *EncryptMasterPrivateKey) bool { + return master.EncryptMasterPublicKey.Equal(x.EncryptMasterPublicKey) && _subtle.ConstantTimeCompare(master.privateKey, x.privateKey) == 1 +} + +// GenerateUserKey generate an user key for encryption. +func (master *EncryptMasterPrivateKey) GenerateUserKey(uid []byte, hid byte) (*EncryptPrivateKey, error) { + var id []byte + id = append(append(id, uid...), hid) + + t1Nat := hashH1(id) + + d, err := bigmod.NewNat().SetBytes(master.privateKey, orderNat) + if err != nil { + return nil, err + } + + t1Nat.Add(d, orderNat) + if t1Nat.IsZero() == 1 { + return nil, errors.New("sm9: need to re-generate encrypt master private key") + } + + t1Nat = bigmod.NewNat().Exp(t1Nat, bn256.OrderMinus2Bytes, orderNat) + t1Nat.Mul(d, orderNat) + + priv := new(EncryptPrivateKey) + priv.EncryptMasterPublicKey = master.EncryptMasterPublicKey + p, err := new(bn256.G2).ScalarBaseMult(t1Nat.Bytes(orderNat)) + if err != nil { + panic(err) + } + priv.PrivateKey = p + + return priv, nil +} + +// Public returns the public key corresponding to priv. +func (master *EncryptMasterPrivateKey) Public() *EncryptMasterPublicKey { + return master.EncryptMasterPublicKey +} + +// Equal compares the receiver EncryptMasterPublicKey with another EncryptMasterPublicKey +// and returns true if they are equal, otherwise false. +func (pub *EncryptMasterPublicKey) Equal(x *EncryptMasterPublicKey) bool { + return pub.MasterPublicKey.Equal(x.MasterPublicKey) +} + +func (pub *EncryptMasterPublicKey) Bytes() []byte { + return pub.MasterPublicKey.MarshalUncompressed() +} + +// pair generate the basepoint once +func (pub *EncryptMasterPublicKey) pair() *bn256.GT { + pub.pairOnce.Do(func() { + pub.basePoint = bn256.Pair(pub.MasterPublicKey, bn256.Gen2) + }) + return pub.basePoint +} + +func (pub *EncryptMasterPublicKey) generatorTable() *[32 * 2]bn256.GTFieldTable { + pub.tableGenOnce.Do(func() { + pub.table = bn256.GenerateGTFieldTable(pub.pair()) + }) + return pub.table +} + +// ScalarBaseMult compute basepoint^r with precomputed table. +// The base point = pair(, Gen2) +func (pub *EncryptMasterPublicKey) ScalarBaseMult(scalar []byte) (*bn256.GT, error) { + tables := pub.generatorTable() + return bn256.ScalarBaseMultGT(tables, scalar) +} + +// GenerateUserPublicKey generate user encrypt public key +func (pub *EncryptMasterPublicKey) GenerateUserPublicKey(uid []byte, hid byte) *bn256.G1 { + var buffer []byte + buffer = append(append(buffer, uid...), hid) + h1 := hashH1(buffer) + p, err := new(bn256.G1).ScalarBaseMult(h1.Bytes(orderNat)) + if err != nil { + panic(err) + } + p.Add(p, pub.MasterPublicKey) + return p +} + +// Equal compares the calling EncryptPrivateKey with another EncryptPrivateKey +// and returns true if they are equal, otherwise it returns false. +func (priv *EncryptPrivateKey) Equal(x *EncryptPrivateKey) bool { + return priv.PrivateKey.Equal(x.PrivateKey) +} + +// Bytes returns the byte representation of the EncryptPrivateKey. +// It marshals the private key in an uncompressed format. +func (priv *EncryptPrivateKey) Bytes() []byte { + return priv.PrivateKey.MarshalUncompressed() +} + +// MasterPublic returns the master public key corresponding to priv. +func (priv *EncryptPrivateKey) MasterPublic() *EncryptMasterPublicKey { + return priv.EncryptMasterPublicKey +} + +// SetMasterPublicKey bind the encrypt master public key to it. +func (priv *EncryptPrivateKey) SetMasterPublicKey(pub *EncryptMasterPublicKey) { + if priv.EncryptMasterPublicKey == nil || priv.EncryptMasterPublicKey.MasterPublicKey == nil { + priv.EncryptMasterPublicKey = pub + } +} + +// UnmarshalRaw unmarsal raw bytes data to encrypt master public key +func (pub *EncryptMasterPublicKey) UnmarshalRaw(bytes []byte) error { + g, err := unmarshalG1(bytes) + if err != nil { + return err + } + pub.MasterPublicKey = g + return nil +} + +// UnmarshalRaw unmarsal raw bytes data to encrypt user private key +// Note, priv's EncryptMasterPublicKey should be handled separately. +func (priv *EncryptPrivateKey) UnmarshalRaw(bytes []byte) error { + g, err := unmarshalG2(bytes) + if err != nil { + return err + } + priv.PrivateKey = g + return nil +} + +// isLess returns whether a < b, where a and b are big-endian buffers of the +// same length and shorter than 72 bytes. +func isLess(a, b []byte) bool { + if len(a) != len(b) { + panic("sm9: internal error: mismatched isLess inputs") + } + + // Copy the values into a fixed-size preallocated little-endian buffer. + // 72 bytes is enough for every scalar in this package, and having a fixed + // size lets us avoid heap allocations. + if len(a) > 72 { + panic("sm9: internal error: isLess input too large") + } + bufA, bufB := make([]byte, 72), make([]byte, 72) + for i := range a { + bufA[i], bufB[i] = a[len(a)-i-1], b[len(b)-i-1] + } + + // Perform a subtraction with borrow. + var borrow uint64 + for i := 0; i < len(bufA); i += 8 { + limbA, limbB := binary.LittleEndian.Uint64(bufA[i:]), binary.LittleEndian.Uint64(bufB[i:]) + _, borrow = bits.Sub64(limbA, limbB, borrow) + } + + // If there is a borrow at the end of the operation, then a < b. + return borrow == 1 +} + +var errInvalidPrivateKey = errors.New("sm9: invalid private key") diff --git a/internal/sm9/sm9_key_test.go b/internal/sm9/sm9_key_test.go new file mode 100644 index 0000000..b89ce0f --- /dev/null +++ b/internal/sm9/sm9_key_test.go @@ -0,0 +1,40 @@ +package sm9 + +import ( + "crypto/rand" + "testing" +) + +func BenchmarkGenerateSignPrivKey(b *testing.B) { + masterKey, err := GenerateSignMasterKey(rand.Reader) + uid := []byte("emmansun") + hid := byte(0x01) + if err != nil { + b.Fatal(err) + } + b.ReportAllocs() + b.ResetTimer() + + for i := 0; i < b.N; i++ { + if _, err := masterKey.GenerateUserKey(uid, hid); err != nil { + b.Fatal(err) + } + } +} + +func BenchmarkGenerateEncryptPrivKey(b *testing.B) { + masterKey, err := GenerateEncryptMasterKey(rand.Reader) + uid := []byte("emmansun") + hid := byte(0x01) + if err != nil { + b.Fatal(err) + } + b.ReportAllocs() + b.ResetTimer() + + for i := 0; i < b.N; i++ { + if _, err := masterKey.GenerateUserKey(uid, hid); err != nil { + b.Fatal(err) + } + } +} diff --git a/internal/sm9/sm9_test.go b/internal/sm9/sm9_test.go new file mode 100644 index 0000000..b4862d9 --- /dev/null +++ b/internal/sm9/sm9_test.go @@ -0,0 +1,596 @@ +package sm9 + +import ( + "bytes" + "crypto/rand" + "crypto/subtle" + "encoding/hex" + "math/big" + "testing" + + "github.com/emmansun/gmsm/internal/alias" + "github.com/emmansun/gmsm/internal/bigmod" + "github.com/emmansun/gmsm/internal/sm3" + "github.com/emmansun/gmsm/internal/sm4" + "github.com/emmansun/gmsm/internal/sm9/bn256" +) + +func TestHashH1(t *testing.T) { + expected := "2acc468c3926b0bdb2767e99ff26e084de9ced8dbc7d5fbf418027b667862fab" + h := hashH1([]byte{0x41, 0x6c, 0x69, 0x63, 0x65, 0x01}) + if hex.EncodeToString(h.Bytes(orderNat)) != expected { + t.Errorf("got %v, expected %v", h.Bytes(orderNat), expected) + } +} + +func TestHashH2(t *testing.T) { + expected := "823c4b21e4bd2dfe1ed92c606653e996668563152fc33f55d7bfbb9bd9705adb" + zStr := "4368696E65736520494253207374616E6461726481377B8FDBC2839B4FA2D0E0F8AA6853BBBE9E9C4099608F8612C6078ACD7563815AEBA217AD502DA0F48704CC73CABB3C06209BD87142E14CBD99E8BCA1680F30DADC5CD9E207AEE32209F6C3CA3EC0D800A1A42D33C73153DED47C70A39D2E8EAF5D179A1836B359A9D1D9BFC19F2EFCDB829328620962BD3FDF15F2567F58A543D25609AE943920679194ED30328BB33FD15660BDE485C6B79A7B32B013983F012DB04BA59FE88DB889321CC2373D4C0C35E84F7AB1FF33679BCA575D67654F8624EB435B838CCA77B2D0347E65D5E46964412A096F4150D8C5EDE5440DDF0656FCB663D24731E80292188A2471B8B68AA993899268499D23C89755A1A89744643CEAD40F0965F28E1CD2895C3D118E4F65C9A0E3E741B6DD52C0EE2D25F5898D60848026B7EFB8FCC1B2442ECF0795F8A81CEE99A6248F294C82C90D26BD6A814AAF475F128AEF43A128E37F80154AE6CB92CAD7D1501BAE30F750B3A9BD1F96B08E97997363911314705BFB9A9DBB97F75553EC90FBB2DDAE53C8F68E42" + z, err := hex.DecodeString(zStr) + if err != nil { + t.Fatal(err) + } + h := hashH2(z) + if hex.EncodeToString(h.Bytes(orderNat)) != expected { + t.Errorf("got %v, expected %v", h.Bytes(orderNat), expected) + } +} + +func TestSign(t *testing.T) { + masterKey, err := GenerateSignMasterKey(rand.Reader) + hashed := []byte("Chinese IBS standard") + uid := []byte("emmansun") + hid := byte(0x01) + if err != nil { + t.Fatal(err) + } + userKey, err := masterKey.GenerateUserKey(uid, hid) + if err != nil { + t.Fatal(err) + } + h, s, err := userKey.Sign(rand.Reader, hashed, nil) + if err != nil { + t.Fatal(err) + } + if !masterKey.Public().Verify(uid, hid, hashed, h, s) { + t.Errorf("Verify failed") + } + sNeg := new(bn256.G1) + sNeg.Unmarshal(s[1:]) + sNeg.Neg(sNeg) + if masterKey.Public().Verify(uid, hid, hashed, h, sNeg.MarshalUncompressed()) { + t.Errorf("Verify with s=-s succeeded") + } + hashed[0] ^= 0xff + if masterKey.Public().Verify(uid, hid, hashed, h, s) { + t.Errorf("Verify always works!") + } +} + +func TestNegativeInputs(t *testing.T) { + masterKey, err := GenerateSignMasterKey(rand.Reader) + hashed := []byte("Chinese IBS standard") + uid := []byte("emmansun") + hid := byte(0x01) + if err != nil { + t.Fatal(err) + } + h := new(big.Int).SetInt64(1) + h.Lsh(h, 550 /* larger than any supported curve */) + h.Neg(h) + if masterKey.Public().Verify(uid, hid, hashed, h.Bytes(), bn256.Gen1.MarshalUncompressed()) { + t.Errorf("bogus signature accepted") + } +} + +func TestZeroSignature(t *testing.T) { + masterKey, err := GenerateSignMasterKey(rand.Reader) + hashed := []byte("Chinese IBS standard") + uid := []byte("emmansun") + hid := byte(0x01) + if err != nil { + t.Fatal(err) + } + if masterKey.Public().Verify(uid, hid, hashed, big.NewInt(0).Bytes(), bn256.Gen1.MarshalUncompressed()) { + t.Error("Verify with h=0 succeeded") + } + if masterKey.Public().Verify(uid, hid, hashed, bn256.OrderBytes, bn256.Gen1.MarshalUncompressed()) { + t.Error("Verify with h=order succeeded") + } +} + +// SM9 Appendix A +func TestSignSM9Sample(t *testing.T) { + expectedH, _ := hex.DecodeString("823c4b21e4bd2dfe1ed92c606653e996668563152fc33f55d7bfbb9bd9705adb") + expectedHNat, err := bigmod.NewNat().SetBytes(expectedH, orderNat) + if err != nil { + t.Fatal(err) + } + expectedS := "0473bf96923ce58b6ad0e13e9643a406d8eb98417c50ef1b29cef9adb48b6d598c856712f1c2e0968ab7769f42a99586aed139d5b8b3e15891827cc2aced9baa05" + hash := []byte("Chinese IBS standard") + hid := byte(0x01) + uid := []byte("Alice") + r, _ := hex.DecodeString("033c8616b06704813203dfd00965022ed15975c662337aed648835dc4b1cbe") + rNat, err := bigmod.NewNat().SetBytes(r, orderNat) + if err != nil { + t.Fatal(err) + } + kb, _ := hex.DecodeString("000130E78459D78545CB54C587E02CF480CE0B66340F319F348A1D5B1F2DC5F4") + masterKey, err := NewSignMasterPrivateKey(kb) + if err != nil { + t.Fatal(err) + } + + userKey, err := masterKey.GenerateUserKey(uid, hid) + if err != nil { + t.Fatal(err) + } + w, err := userKey.SignMasterPublicKey.ScalarBaseMult(bn256.NormalizeScalar(r)) + if err != nil { + t.Fatal(err) + } + + var buffer []byte + buffer = append(buffer, hash...) + buffer = append(buffer, w.Marshal()...) + + h := hashH2(buffer) + if h.Equal(expectedHNat) == 0 { + t.Fatal("not same h") + } + + rNat.Sub(h, orderNat) + + s, err := new(bn256.G1).ScalarMult(userKey.PrivateKey, rNat.Bytes(orderNat)) + if err != nil { + t.Fatal(err) + } + + if hex.EncodeToString(s.MarshalUncompressed()) != expectedS { + t.Fatal("not same S") + } +} + +func TestWrapKey(t *testing.T) { + masterKey, err := GenerateEncryptMasterKey(rand.Reader) + hid := byte(0x01) + uid := []byte("emmansun") + if err != nil { + t.Fatal(err) + } + userKey, err := masterKey.GenerateUserKey(uid, hid) + if err != nil { + t.Fatal(err) + } + key, cipher, err := masterKey.Public().WrapKey(rand.Reader, uid, hid, 16) + if err != nil { + t.Fatal(err) + } + + key2, err := userKey.UnwrapKey(uid, cipher, 16) + if err != nil { + t.Fatal(err) + } + + if !bytes.Equal(key, key2) { + t.Errorf("expected %x, got %x", key, key2) + } +} + +// SM9 Appendix C +func TestWrapKeySM9Sample(t *testing.T) { + expectedMasterPublicKey := "787ed7b8a51f3ab84e0a66003f32da5c720b17eca7137d39abc66e3c80a892ff769de61791e5adc4b9ff85a31354900b202871279a8c49dc3f220f644c57a7b1" + expectedUserPrivateKey := "94736acd2c8c8796cc4785e938301a139a059d3537b6414140b2d31eecf41683115bae85f5d8bc6c3dbd9e5342979acccf3c2f4f28420b1cb4f8c0b59a19b1587aa5e47570da7600cd760a0cf7beaf71c447f3844753fe74fa7ba92ca7d3b55f27538a62e7f7bfb51dce08704796d94c9d56734f119ea44732b50e31cdeb75c1" + expectedUserPublicKey := "709d165808b0a43e2574e203fa885abcbab16a240c4c1916552e7c43d09763b8693269a6be2456f43333758274786b6051ff87b7f198da4ba1a2c6e336f51fcc" + expectedCipher := "1edee2c3f465914491de44cefb2cb434ab02c308d9dc5e2067b4fed5aaac8a0f1c9b4c435eca35ab83bb734174c0f78fde81a53374aff3b3602bbc5e37be9a4c" + expectedKey := "4ff5cf86d2ad40c8f4bac98d76abdbde0c0e2f0a829d3f911ef5b2bce0695480" + + kb, _ := hex.DecodeString("0001EDEE3778F441F8DEA3D9FA0ACC4E07EE36C93F9A08618AF4AD85CEDE1C22") + masterKey, err := NewEncryptMasterPrivateKey(kb) + if err != nil { + t.Fatal(err) + } + if hex.EncodeToString(masterKey.MasterPublicKey.Marshal()) != expectedMasterPublicKey { + t.Errorf("not expected master public key") + } + + uid := []byte("Bob") + hid := byte(0x03) + + userKey, err := masterKey.GenerateUserKey(uid, hid) + if err != nil { + t.Fatal(err) + } + if hex.EncodeToString(userKey.PrivateKey.Marshal()) != expectedUserPrivateKey { + t.Errorf("not expected user private key") + } + + q := masterKey.Public().GenerateUserPublicKey(uid, hid) + if hex.EncodeToString(q.Marshal()) != expectedUserPublicKey { + t.Errorf("not expected user public key") + } + + rb, _ := hex.DecodeString("74015F8489C01EF4270456F9E6475BFB602BDE7F33FD482AB4E3684A6722") + var r *big.Int = new(big.Int).SetBytes(rb) + cipher, err := new(bn256.G1).ScalarMult(q, bn256.NormalizeScalar(r.Bytes())) + if err != nil { + t.Fatal(err) + } + if hex.EncodeToString(cipher.Marshal()) != expectedCipher { + t.Errorf("not expected cipher") + } + + g := bn256.Pair(masterKey.Public().MasterPublicKey, bn256.Gen2) + w := new(bn256.GT).ScalarMult(g, r) + + var buffer []byte + buffer = append(buffer, cipher.Marshal()...) + buffer = append(buffer, w.Marshal()...) + buffer = append(buffer, uid...) + + key := sm3.Kdf(buffer, 32) + + if hex.EncodeToString(key) != expectedKey { + t.Errorf("expected %v, got %v\n", expectedKey, hex.EncodeToString(key)) + } + + key2, err := userKey.UnwrapKey(uid, cipher.MarshalUncompressed(), 32) + if err != nil { + t.Fatal(err) + } + if hex.EncodeToString(key2) != expectedKey { + t.Errorf("expected %v, got %v\n", expectedKey, hex.EncodeToString(key2)) + } +} + +// SM9 Appendix D +func TestEncryptSM9Sample(t *testing.T) { + plaintext := []byte("Chinese IBE standard") + expectedMasterPublicKey := "787ed7b8a51f3ab84e0a66003f32da5c720b17eca7137d39abc66e3c80a892ff769de61791e5adc4b9ff85a31354900b202871279a8c49dc3f220f644c57a7b1" + expectedUserPrivateKey := "94736acd2c8c8796cc4785e938301a139a059d3537b6414140b2d31eecf41683115bae85f5d8bc6c3dbd9e5342979acccf3c2f4f28420b1cb4f8c0b59a19b1587aa5e47570da7600cd760a0cf7beaf71c447f3844753fe74fa7ba92ca7d3b55f27538a62e7f7bfb51dce08704796d94c9d56734f119ea44732b50e31cdeb75c1" + expectedUserPublicKey := "709d165808b0a43e2574e203fa885abcbab16a240c4c1916552e7c43d09763b8693269a6be2456f43333758274786b6051ff87b7f198da4ba1a2c6e336f51fcc" + expectedCipher := "2445471164490618e1ee20528ff1d545b0f14c8bcaa44544f03dab5dac07d8ff42ffca97d57cddc05ea405f2e586feb3a6930715532b8000759f13059ed59ac0" + expectedKey := "58373260f067ec48667c21c144f8bc33cd3049788651ffd5f738003e51df31174d0e4e402fd87f4581b612f74259db574f67ece6" + expectedCiphertext := "2445471164490618e1ee20528ff1d545b0f14c8bcaa44544f03dab5dac07d8ff42ffca97d57cddc05ea405f2e586feb3a6930715532b8000759f13059ed59ac0ba672387bcd6de5016a158a52bb2e7fc429197bcab70b25afee37a2b9db9f3671b5f5b0e951489682f3e64e1378cdd5da9513b1c" + + kb, _ := hex.DecodeString("0001EDEE3778F441F8DEA3D9FA0ACC4E07EE36C93F9A08618AF4AD85CEDE1C22") + masterKey, err := NewEncryptMasterPrivateKey(kb) + if err != nil { + t.Fatal(err) + } + if hex.EncodeToString(masterKey.MasterPublicKey.Marshal()) != expectedMasterPublicKey { + t.Errorf("not expected master public key") + } + + uid := []byte("Bob") + hid := byte(0x03) + + userKey, err := masterKey.GenerateUserKey(uid, hid) + if err != nil { + t.Fatal(err) + } + if hex.EncodeToString(userKey.PrivateKey.Marshal()) != expectedUserPrivateKey { + t.Errorf("not expected user private key") + } + + q := masterKey.Public().GenerateUserPublicKey(uid, hid) + if hex.EncodeToString(q.Marshal()) != expectedUserPublicKey { + t.Errorf("not expected user public key") + } + + rb, _ := hex.DecodeString("AAC0541779C8FC45E3E2CB25C12B5D2576B2129AE8BB5EE2CBE5EC9E785C") + var r *big.Int = new(big.Int).SetBytes(rb) + cipher, err := new(bn256.G1).ScalarMult(q, bn256.NormalizeScalar(r.Bytes())) + if err != nil { + t.Fatal(err) + } + if hex.EncodeToString(cipher.Marshal()) != expectedCipher { + t.Errorf("not expected cipher") + } + + g := bn256.Pair(masterKey.Public().MasterPublicKey, bn256.Gen2) + w := new(bn256.GT).ScalarMult(g, r) + + var buffer []byte + buffer = append(buffer, cipher.Marshal()...) + buffer = append(buffer, w.Marshal()...) + buffer = append(buffer, uid...) + + key := sm3.Kdf(buffer, len(plaintext)+32) + + if hex.EncodeToString(key) != expectedKey { + t.Errorf("not expected key") + } + subtle.XORBytes(key, key[:len(plaintext)], plaintext) + + hash := sm3.New() + hash.Write(key) + c3 := hash.Sum(nil) + + ciphertext := append(cipher.Marshal(), c3...) + ciphertext = append(ciphertext, key[:len(plaintext)]...) + if hex.EncodeToString(ciphertext) != expectedCiphertext { + t.Errorf("expected %v, got %v\n", expectedCiphertext, hex.EncodeToString(ciphertext)) + } +} + +func TestEncryptSM9SampleBlockMode(t *testing.T) { + plaintext := []byte("Chinese IBE standard") + expectedMasterPublicKey := "787ed7b8a51f3ab84e0a66003f32da5c720b17eca7137d39abc66e3c80a892ff769de61791e5adc4b9ff85a31354900b202871279a8c49dc3f220f644c57a7b1" + expectedUserPrivateKey := "94736acd2c8c8796cc4785e938301a139a059d3537b6414140b2d31eecf41683115bae85f5d8bc6c3dbd9e5342979acccf3c2f4f28420b1cb4f8c0b59a19b1587aa5e47570da7600cd760a0cf7beaf71c447f3844753fe74fa7ba92ca7d3b55f27538a62e7f7bfb51dce08704796d94c9d56734f119ea44732b50e31cdeb75c1" + expectedUserPublicKey := "709d165808b0a43e2574e203fa885abcbab16a240c4c1916552e7c43d09763b8693269a6be2456f43333758274786b6051ff87b7f198da4ba1a2c6e336f51fcc" + expectedCipher := "2445471164490618e1ee20528ff1d545b0f14c8bcaa44544f03dab5dac07d8ff42ffca97d57cddc05ea405f2e586feb3a6930715532b8000759f13059ed59ac0" + expectedKey := "58373260f067ec48667c21c144f8bc33cd3049788651ffd5f738003e51df31174d0e4e402fd87f4581b612f74259db57" + expectedCiphertext := "2445471164490618e1ee20528ff1d545b0f14c8bcaa44544f03dab5dac07d8ff42ffca97d57cddc05ea405f2e586feb3a6930715532b8000759f13059ed59ac0fd3c98dd92c44c68332675a370cceede31e0c5cd209c257601149d12b394a2bee05b6fac6f11b965268c994f00dba7a8bb00fd60583546cbdf4649250863f10a" + + kb, _ := hex.DecodeString("0001EDEE3778F441F8DEA3D9FA0ACC4E07EE36C93F9A08618AF4AD85CEDE1C22") + masterKey, err := NewEncryptMasterPrivateKey(kb) + if err != nil { + t.Fatal(err) + } + if hex.EncodeToString(masterKey.MasterPublicKey.Marshal()) != expectedMasterPublicKey { + t.Errorf("not expected master public key") + } + + uid := []byte("Bob") + hid := byte(0x03) + + userKey, err := masterKey.GenerateUserKey(uid, hid) + if err != nil { + t.Fatal(err) + } + if hex.EncodeToString(userKey.PrivateKey.Marshal()) != expectedUserPrivateKey { + t.Errorf("not expected user private key") + } + + q := masterKey.Public().GenerateUserPublicKey(uid, hid) + if hex.EncodeToString(q.Marshal()) != expectedUserPublicKey { + t.Errorf("not expected user public key") + } + + rb, _ := hex.DecodeString("AAC0541779C8FC45E3E2CB25C12B5D2576B2129AE8BB5EE2CBE5EC9E785C") + var r *big.Int = new(big.Int).SetBytes(rb) + cipher, err := new(bn256.G1).ScalarMult(q, bn256.NormalizeScalar(r.Bytes())) + if err != nil { + t.Fatal(err) + } + if hex.EncodeToString(cipher.Marshal()) != expectedCipher { + t.Errorf("not expected cipher") + } + + g := bn256.Pair(masterKey.Public().MasterPublicKey, bn256.Gen2) + w := new(bn256.GT).ScalarMult(g, r) + + var buffer []byte + buffer = append(buffer, cipher.Marshal()...) + buffer = append(buffer, w.Marshal()...) + buffer = append(buffer, uid...) + + key := sm3.Kdf(buffer, 16+32) + + if hex.EncodeToString(key) != expectedKey { + t.Errorf("not expected key, expected %v, got %x\n", expectedKey, key) + } + + // ECB mode with PKCS7 padding + block, err := sm4.NewCipher(key[:16]) + if err != nil { + t.Fatal(err) + } + overhead := sm4.BlockSize - len(plaintext)%sm4.BlockSize + c2, out := alias.SliceForAppend(plaintext, overhead) + for i := range overhead { + out[i] = byte(overhead) + } + ret := c2 + for len(ret) > 0 { + block.Encrypt(ret, ret) + ret = ret[sm4.BlockSize:] + } + + hash := sm3.New() + hash.Write(c2) + hash.Write(key[16:]) + c3 := hash.Sum(nil) + + ciphertext := append(cipher.Marshal(), c3...) + ciphertext = append(ciphertext, c2...) + if hex.EncodeToString(ciphertext) != expectedCiphertext { + t.Errorf("expected %v, got %v\n", expectedCiphertext, hex.EncodeToString(ciphertext)) + } +} + +func TestKeyExchange(t *testing.T) { + hid := byte(0x02) + userA := []byte("Alice") + userB := []byte("Bob") + masterKey, err := GenerateEncryptMasterKey(rand.Reader) + if err != nil { + t.Fatal(err) + } + + userKey, err := masterKey.GenerateUserKey(userA, hid) + if err != nil { + t.Fatal(err) + } + initiator := userKey.NewKeyExchange(userA, userB, 16, true) + + userKey, err = masterKey.GenerateUserKey(userB, hid) + if err != nil { + t.Fatal(err) + } + responder := userKey.NewKeyExchange(userB, userA, 16, true) + defer func() { + initiator.Destroy() + responder.Destroy() + }() + // A1-A4 + rA, err := initiator.InitKeyExchange(rand.Reader, hid) + if err != nil { + t.Fatal(err) + } + + // B1 - B7 + rB, sigB, err := responder.RespondKeyExchange(rand.Reader, hid, rA) + if err != nil { + t.Fatal(err) + } + + // A5 -A8 + key1, sigA, err := initiator.ConfirmResponder(rB, sigB) + if err != nil { + t.Fatal(err) + } + + // B8 + key2, err := responder.ConfirmInitiator(sigA) + if err != nil { + t.Fatal(err) + } + + if hex.EncodeToString(key1) != hex.EncodeToString(key2) { + t.Errorf("got different key") + } +} + +func TestKeyExchangeWithoutSignature(t *testing.T) { + hid := byte(0x02) + userA := []byte("Alice") + userB := []byte("Bob") + masterKey, err := GenerateEncryptMasterKey(rand.Reader) + if err != nil { + t.Fatal(err) + } + + userKey, err := masterKey.GenerateUserKey(userA, hid) + if err != nil { + t.Fatal(err) + } + initiator := userKey.NewKeyExchange(userA, userB, 16, false) + + userKey, err = masterKey.GenerateUserKey(userB, hid) + if err != nil { + t.Fatal(err) + } + responder := userKey.NewKeyExchange(userB, userA, 16, false) + defer func() { + initiator.Destroy() + responder.Destroy() + }() + // A1-A4 + rA, err := initiator.InitKeyExchange(rand.Reader, hid) + if err != nil { + t.Fatal(err) + } + + // B1 - B7 + rB, sigB, err := responder.RespondKeyExchange(rand.Reader, hid, rA) + if err != nil { + t.Fatal(err) + } + if len(sigB) != 0 { + t.Errorf("should no signature") + } + + // A5 -A8 + key1, sigA, err := initiator.ConfirmResponder(rB, sigB) + if err != nil { + t.Fatal(err) + } + if len(sigA) != 0 { + t.Errorf("should no signature") + } + + key2, err := responder.ConfirmInitiator(nil) + if err != nil { + t.Fatal(err) + } + + if hex.EncodeToString(key1) != hex.EncodeToString(key2) { + t.Errorf("got different key") + } +} + +// SM9 Appendix B +func TestKeyExchangeSample(t *testing.T) { + hid := byte(0x02) + expectedPube := "9174542668e8f14ab273c0945c3690c66e5dd09678b86f734c4350567ed0628354e598c6bf749a3dacc9fffedd9db6866c50457cfc7aa2a4ad65c3168ff74210" + expectedKey := "c5c13a8f59a97cdeae64f16a2272a9e7" + expectedSignatureB := "3bb4bcee8139c960b4d6566db1e0d5f0b2767680e5e1bf934103e6c66e40ffee" + expectedSignatureA := "195d1b7256ba7e0e67c71202a25f8c94ff8241702c2f55d613ae1c6b98215172" + + kb, _ := hex.DecodeString("0002E65B0762D042F51F0D23542B13ED8CFA2E9A0E7206361E013A283905E31F") + masterKey, err := NewEncryptMasterPrivateKey(kb) + if err != nil { + t.Fatal(err) + } + + if hex.EncodeToString(masterKey.MasterPublicKey.Marshal()) != expectedPube { + t.Errorf("not expected master public key") + } + + userA := []byte("Alice") + userB := []byte("Bob") + + userKey, err := masterKey.GenerateUserKey(userA, hid) + if err != nil { + t.Fatal(err) + } + initiator := userKey.NewKeyExchange(userA, userB, 16, true) + + userKey, err = masterKey.GenerateUserKey(userB, hid) + if err != nil { + t.Fatal(err) + } + responder := userKey.NewKeyExchange(userB, userA, 16, true) + defer func() { + initiator.Destroy() + responder.Destroy() + }() + // A1-A4 + b, _ := hex.DecodeString("5879DD1D51E175946F23B1B41E93BA31C584AE59A426EC1046A4D03B06C8") + k, err := bigmod.NewNat().SetBytes(b, orderNat) + if err != nil { + t.Fatal(err) + } + initKeyExchange(initiator, hid, k) + + if hex.EncodeToString(initiator.secret) != "047cba5b19069ee66aa79d490413d11846b9ba76dd22567f809cf23b6d964bb265a9760c99cb6f706343fed05637085864958d6c90902aba7d405fbedf7b781599" { + t.Fatal("not same") + } + + // B1 - B7 + b, _ = hex.DecodeString("018B98C44BEF9F8537FB7D071B2C928B3BC65BD3D69E1EEE213564905634FE") + k, err = bigmod.NewNat().SetBytes(b, orderNat) + if err != nil { + t.Fatal(err) + } + rB, sigB, err := respondKeyExchange(responder, hid, k, initiator.secret) + if err != nil { + t.Fatal(err) + } + + if hex.EncodeToString(sigB) != expectedSignatureB { + t.Errorf("not expected signature B") + } + + // A5 -A8 + key1, sigA, err := initiator.ConfirmResponder(rB, sigB) + if err != nil { + t.Fatal(err) + } + if hex.EncodeToString(key1) != expectedKey { + t.Errorf("not expected key %v\n", hex.EncodeToString(key1)) + } + if hex.EncodeToString(sigA) != expectedSignatureA { + t.Errorf("not expected signature A") + } + // B8 + key2, err := responder.ConfirmInitiator(sigA) + if err != nil { + t.Fatal(err) + } + if hex.EncodeToString(key2) != expectedKey { + t.Errorf("not expected key %v\n", hex.EncodeToString(key2)) + } +} diff --git a/pkcs8/pkcs8_test.go b/pkcs8/pkcs8_test.go index cb67fb5..9671119 100644 --- a/pkcs8/pkcs8_test.go +++ b/pkcs8/pkcs8_test.go @@ -622,7 +622,7 @@ func TestMarshalPrivateKey(t *testing.T) { t.Fatalf("%d: ParseSM9SignPrivateKey should return error", i) } - if sm9SignMasterPrivateKey.D.Cmp(decodedSM9SignMasterPrivateKey.D) != 0 { + if !sm9SignMasterPrivateKey.Equal(decodedSM9SignMasterPrivateKey) { t.Fatalf("%d: Decoded key does not match original key", i) } @@ -642,7 +642,7 @@ func TestMarshalPrivateKey(t *testing.T) { if err == nil { t.Fatalf("%d: ParseSM9SignMasterPrivateKey should return error", i) } - if !sm9SignPrivateKey.PrivateKey.Equal(decodedSM9SignPrivateKey.PrivateKey) { + if !sm9SignPrivateKey.Equal(decodedSM9SignPrivateKey) { t.Fatalf("%d: Decoded key does not match original key", i) } @@ -663,7 +663,7 @@ func TestMarshalPrivateKey(t *testing.T) { if err == nil { t.Fatalf("%d: ParseSM9EncryptPrivateKey should return error", i) } - if sm9EncMasterPrivateKey.D.Cmp(decodedSM9EncMasterPrivateKey.D) != 0 { + if !sm9EncMasterPrivateKey.Equal(decodedSM9EncMasterPrivateKey) { t.Fatalf("%d: Decoded key does not match original key", i) } @@ -683,7 +683,7 @@ func TestMarshalPrivateKey(t *testing.T) { if err == nil { t.Fatalf("%d: ParseSM9EncryptMasterPrivateKey should return error", i) } - if !sm9EncPrivateKey.PrivateKey.Equal(decodedSM9EncPrivateKey.PrivateKey) { + if !sm9EncPrivateKey.Equal(decodedSM9EncPrivateKey) { t.Fatalf("%d: Decoded key does not match original key", i) } diff --git a/sm9/sm9.go b/sm9/sm9.go index 6fb2aa0..ec8d0ef 100644 --- a/sm9/sm9.go +++ b/sm9/sm9.go @@ -8,36 +8,13 @@ import ( "io" "math/big" - "github.com/emmansun/gmsm/internal/bigmod" - "github.com/emmansun/gmsm/internal/byteorder" - "github.com/emmansun/gmsm/internal/randutil" - "github.com/emmansun/gmsm/internal/subtle" + "github.com/emmansun/gmsm/internal/sm9" "github.com/emmansun/gmsm/sm3" - "github.com/emmansun/gmsm/sm9/bn256" "golang.org/x/crypto/cryptobyte" "golang.org/x/crypto/cryptobyte/asn1" ) // SM9 ASN.1 format reference: Information security technology - SM9 cryptographic algorithm application specification -var ( - orderMinus2 []byte - orderNat *bigmod.Modulus -) - -func init() { - orderMinus2 = new(big.Int).Sub(bn256.Order, big.NewInt(2)).Bytes() - orderNat, _ = bigmod.NewModulus(bn256.Order.Bytes()) -} - -type hashMode byte - -const ( - // hashmode used in h1: 0x01 - H1 hashMode = 1 + iota - // hashmode used in h2: 0x02 - H2 -) - type encryptType byte const ( @@ -48,70 +25,6 @@ const ( ENC_TYPE_CFB encryptType = 8 ) -// hash implements H1(Z,n) or H2(Z,n) in sm9 algorithm. -func hash(z []byte, h hashMode) *bigmod.Nat { - md := sm3.New() - var ha [64]byte - var countBytes [4]byte - var ct uint32 = 1 - - byteorder.BEPutUint32(countBytes[:], ct) - md.Write([]byte{byte(h)}) - md.Write(z) - md.Write(countBytes[:]) - copy(ha[:], md.Sum(nil)) - ct++ - md.Reset() - - byteorder.BEPutUint32(countBytes[:], ct) - md.Write([]byte{byte(h)}) - md.Write(z) - md.Write(countBytes[:]) - copy(ha[sm3.Size:], md.Sum(nil)) - - return bigmod.NewNat().SetOverflowedBytes(ha[:40], orderNat) -} - -func hashH1(z []byte) *bigmod.Nat { - return hash(z, H1) -} - -func hashH2(z []byte) *bigmod.Nat { - return hash(z, H2) -} - -func randomScalar(rand io.Reader) (k *bigmod.Nat, err error) { - k = bigmod.NewNat() - for { - b := make([]byte, orderNat.Size()) - if _, err = io.ReadFull(rand, b); err != nil { - return - } - - // Mask off any excess bits to increase the chance of hitting a value in - // (0, N). These are the most dangerous lines in the package and maybe in - // the library: a single bit of bias in the selection of nonces would likely - // lead to key recovery, but no tests would fail. Look but DO NOT TOUCH. - if excess := len(b)*8 - orderNat.BitLen(); excess > 0 { - // Just to be safe, assert that this only happens for the one curve that - // doesn't have a round number of bits. - if excess != 0 { - panic("sm9: internal error: unexpectedly masking off bits") - } - b[0] >>= excess - } - - // FIPS 186-4 makes us check k <= N - 2 and then add one. - // Checking 0 < k <= N - 1 is strictly equivalent. - // None of this matters anyway because the chance of selecting - // zero is cryptographically negligible. - if _, err = k.SetBytes(b, orderNat); err == nil && k.IsZero() == 0 { - break - } - } - return -} - // Sign signs a hash (which should be the result of hashing a larger message) // using the user dsa key. It returns the signature as a pair of h and s. // Please use SignASN1 instead. @@ -119,12 +32,13 @@ func randomScalar(rand io.Reader) (k *bigmod.Nat, err error) { // The signature is randomized. Most applications should use [crypto/rand.Reader] // as rand. Note that the returned signature does not depend deterministically on // the bytes read from rand, and may change between calls and/or between versions. -func Sign(rand io.Reader, priv *SignPrivateKey, hash []byte) (h *big.Int, s *bn256.G1, err error) { - sig, err := SignASN1(rand, priv, hash) +func Sign(rand io.Reader, priv *SignPrivateKey, hash []byte) (*big.Int, []byte, error) { + h, s, err := priv.privateKey.Sign(rand, hash, nil) if err != nil { return nil, nil, err } - return parseSignatureLegacy(sig) + return new(big.Int).SetBytes(h), s, nil + } // Sign signs digest with user's DSA key, reading randomness from rand. The opts argument @@ -135,7 +49,11 @@ func Sign(rand io.Reader, priv *SignPrivateKey, hash []byte) (h *big.Int, s *bn2 // as rand. Note that the returned signature does not depend deterministically on // the bytes read from rand, and may change between calls and/or between versions. func (priv *SignPrivateKey) Sign(rand io.Reader, hash []byte, opts crypto.SignerOpts) ([]byte, error) { - return SignASN1(rand, priv, hash) + h, s, err := priv.privateKey.Sign(rand, hash, opts) + if err != nil { + return nil, err + } + return encodeSignature(h, s) } // SignASN1 signs a hash (which should be the result of hashing a larger message) @@ -145,63 +63,28 @@ func (priv *SignPrivateKey) Sign(rand io.Reader, hash []byte, opts crypto.Signer // as rand. Note that the returned signature does not depend deterministically on // the bytes read from rand, and may change between calls and/or between versions. func SignASN1(rand io.Reader, priv *SignPrivateKey, hash []byte) ([]byte, error) { - var ( - hNat *bigmod.Nat - s *bn256.G1 - ) - randutil.MaybeReadByte(rand) - for { - r, err := randomScalar(rand) - if err != nil { - return nil, err - } - - w, err := priv.SignMasterPublicKey.ScalarBaseMult(r.Bytes(orderNat)) - if err != nil { - return nil, err - } - - var buffer []byte - buffer = append(append(buffer, hash...), w.Marshal()...) - - hNat = hashH2(buffer) - r.Sub(hNat, orderNat) - - if r.IsZero() == 0 { - s, err = new(bn256.G1).ScalarMult(priv.PrivateKey, r.Bytes(orderNat)) - if err != nil { - return nil, err - } - break - } - } - - return encodeSignature(hNat.Bytes(orderNat), s) + return priv.Sign(rand, hash, nil) } // Verify verifies the signature in h, s of hash using the master dsa public key and user id, uid and hid. // Its return value records whether the signature is valid. Please use VerifyASN1 instead. -func Verify(pub *SignMasterPublicKey, uid []byte, hid byte, hash []byte, h *big.Int, s *bn256.G1) bool { +func Verify(pub *SignMasterPublicKey, uid []byte, hid byte, hash []byte, h *big.Int, s []byte) bool { if h.Sign() <= 0 { return false } - sig, err := encodeSignature(h.Bytes(), s) - if err != nil { - return false - } - return VerifyASN1(pub, uid, hid, hash, sig) + return pub.publicKey.Verify(uid, hid, hash, h.Bytes(), s) } -func encodeSignature(hBytes []byte, s *bn256.G1) ([]byte, error) { +func encodeSignature(h, s []byte) ([]byte, error) { var b cryptobyte.Builder b.AddASN1(asn1.SEQUENCE, func(b *cryptobyte.Builder) { - b.AddASN1OctetString(hBytes) - b.AddASN1BitString(s.MarshalUncompressed()) + b.AddASN1OctetString(h) + b.AddASN1BitString(s) }) return b.Bytes() } -func parseSignature(sig []byte) ([]byte, *bn256.G1, error) { +func parseSignature(sig []byte) ([]byte, []byte, error) { var ( hBytes []byte sBytes []byte @@ -218,20 +101,7 @@ func parseSignature(sig []byte) ([]byte, *bn256.G1, error) { if sBytes[0] != 4 { return nil, nil, errors.New("sm9: invalid point format") } - s := new(bn256.G1) - _, err := s.Unmarshal(sBytes[1:]) - if err != nil { - return nil, nil, err - } - return hBytes, s, nil -} - -func parseSignatureLegacy(sig []byte) (*big.Int, *bn256.G1, error) { - hBytes, s, err := parseSignature(sig) - if err != nil { - return nil, nil, err - } - return new(big.Int).SetBytes(hBytes), s, nil + return hBytes, sBytes, nil } // VerifyASN1 verifies the ASN.1 encoded signature of type SM9Signature, sig, of hash using the @@ -241,34 +111,7 @@ func VerifyASN1(pub *SignMasterPublicKey, uid []byte, hid byte, hash, sig []byte if err != nil { return false } - if !s.IsOnCurve() { - return false - } - - hNat, err := bigmod.NewNat().SetBytes(h, orderNat) - if err != nil { - return false - } - if hNat.IsZero() == 1 { - return false - } - - t, err := pub.ScalarBaseMult(hNat.Bytes(orderNat)) - if err != nil { - return false - } - - // user sign public key p generation - p := pub.GenerateUserPublicKey(uid, hid) - - u := bn256.Pair(s, p) - w := new(bn256.GT).Add(u, t) - - var buffer []byte - buffer = append(append(buffer, hash...), w.Marshal()...) - h2 := hashH2(buffer) - - return h2.Equal(hNat) == 1 + return pub.publicKey.Verify(uid, hid, hash, h, s) } // Verify verifies the ASN.1 encoded signature, sig, of hash using the @@ -282,39 +125,8 @@ func (pub *SignMasterPublicKey) Verify(uid []byte, hid byte, hash, sig []byte) b // The rand parameter is used as a source of entropy to ensure that // calls this function twice doesn't result in the same key. // Most applications should use [crypto/rand.Reader] as random. -func WrapKey(rand io.Reader, pub *EncryptMasterPublicKey, uid []byte, hid byte, kLen int) (key []byte, cipher *bn256.G1, err error) { - q := pub.GenerateUserPublicKey(uid, hid) - var ( - r *bigmod.Nat - w *bn256.GT - ) - for { - r, err = randomScalar(rand) - if err != nil { - return - } - - rBytes := r.Bytes(orderNat) - cipher, err = new(bn256.G1).ScalarMult(q, rBytes) - if err != nil { - return - } - - w, err = pub.ScalarBaseMult(rBytes) - if err != nil { - return - } - var buffer []byte - buffer = append(buffer, cipher.Marshal()...) - buffer = append(buffer, w.Marshal()...) - buffer = append(buffer, uid...) - - key = sm3.Kdf(buffer, kLen) - if subtle.ConstantTimeAllZero(key) == 0 { - break - } - } - return +func WrapKey(rand io.Reader, pub *EncryptMasterPublicKey, uid []byte, hid byte, kLen int) ([]byte, []byte, error) { + return pub.publicKey.WrapKey(rand, uid, hid, kLen) } // WrapKey wraps key and converts the cipher as ASN1 format, SM9PublicKey1 definition. @@ -328,7 +140,7 @@ func (pub *EncryptMasterPublicKey) WrapKey(rand io.Reader, uid []byte, hid byte, return nil, nil, err } var b cryptobyte.Builder - b.AddASN1BitString(cipher.MarshalUncompressed()) + b.AddASN1BitString(cipher) cipherASN1, err := b.Bytes() return key, cipherASN1, err @@ -348,31 +160,25 @@ func (pub *EncryptMasterPublicKey) WrapKeyASN1(rand io.Reader, uid []byte, hid b var b cryptobyte.Builder b.AddASN1(asn1.SEQUENCE, func(b *cryptobyte.Builder) { b.AddASN1OctetString(key) - b.AddASN1BitString(cipher.MarshalUncompressed()) + b.AddASN1BitString(cipher) }) return b.Bytes() } // UnmarshalSM9KeyPackage is an utility to unmarshal SM9KeyPackage -func UnmarshalSM9KeyPackage(der []byte) ([]byte, *bn256.G1, error) { +func UnmarshalSM9KeyPackage(der []byte) (key []byte, cipher []byte, err error) { input := cryptobyte.String(der) var ( - key []byte - cipherBytes []byte - inner cryptobyte.String + inner cryptobyte.String ) if !input.ReadASN1(&inner, asn1.SEQUENCE) || !input.Empty() || !inner.ReadASN1Bytes(&key, asn1.OCTET_STRING) || - !inner.ReadASN1BitStringAsBytes(&cipherBytes) || + !inner.ReadASN1BitStringAsBytes(&cipher) || !inner.Empty() { return nil, nil, errors.New("sm9: invalid SM9KeyPackage asn.1 data") } - g, err := unmarshalG1(cipherBytes) - if err != nil { - return nil, nil, err - } - return key, g, nil + return } // ErrDecryption represents a failure to decrypt a message. @@ -383,23 +189,8 @@ var ErrDecryption = errors.New("sm9: decryption error") var ErrEmptyPlaintext = errors.New("sm9: empty plaintext") // UnwrapKey unwraps key from cipher, user id and aligned key length -func UnwrapKey(priv *EncryptPrivateKey, uid []byte, cipher *bn256.G1, kLen int) ([]byte, error) { - if !cipher.IsOnCurve() { - return nil, ErrDecryption - } - - w := bn256.Pair(cipher, priv.PrivateKey) - - var buffer []byte - buffer = append(buffer, cipher.Marshal()...) - buffer = append(buffer, w.Marshal()...) - buffer = append(buffer, uid...) - - key := sm3.Kdf(buffer, kLen) - if subtle.ConstantTimeAllZero(key) == 1 { - return nil, ErrDecryption - } - return key, nil +func UnwrapKey(priv *EncryptPrivateKey, uid, cipher []byte, kLen int) ([]byte, error) { + return priv.privateKey.UnwrapKey(uid, cipher, kLen) } // UnwrapKey unwraps key from cipherDer, user id and aligned key length. @@ -410,11 +201,7 @@ func (priv *EncryptPrivateKey) UnwrapKey(uid, cipherDer []byte, kLen int) ([]byt if !input.ReadASN1BitStringAsBytes(&bytes) || !input.Empty() { return nil, ErrDecryption } - g, err := unmarshalG1(bytes) - if err != nil { - return nil, ErrDecryption - } - return UnwrapKey(priv, uid, g, kLen) + return UnwrapKey(priv, uid, bytes, kLen) } // Encrypt encrypts plaintext, returns ciphertext with format C1||C3||C2. @@ -423,12 +210,12 @@ func Encrypt(rand io.Reader, pub *EncryptMasterPublicKey, uid []byte, hid byte, if err != nil { return nil, err } - ciphertext := append(c1.Marshal(), c3...) + ciphertext := append(c1[1:], c3...) ciphertext = append(ciphertext, c2...) return ciphertext, nil } -func encrypt(rand io.Reader, pub *EncryptMasterPublicKey, uid []byte, hid byte, plaintext []byte, opts EncrypterOpts) (c1 *bn256.G1, c2, c3 []byte, err error) { +func encrypt(rand io.Reader, pub *EncryptMasterPublicKey, uid []byte, hid byte, plaintext []byte, opts EncrypterOpts) (c1, c2, c3 []byte, err error) { if opts == nil { opts = DefaultEncrypterOpts } @@ -473,7 +260,7 @@ func (pub *EncryptMasterPublicKey) Encrypt(rand io.Reader, uid []byte, hid byte, var b cryptobyte.Builder b.AddASN1(asn1.SEQUENCE, func(b *cryptobyte.Builder) { b.AddASN1Int64(int64(opts.GetEncryptType())) - b.AddASN1BitString(c1.MarshalUncompressed()) + b.AddASN1BitString(c1) b.AddASN1OctetString(c3) b.AddASN1OctetString(c2) }) @@ -486,26 +273,21 @@ func Decrypt(priv *EncryptPrivateKey, uid, ciphertext []byte, opts EncrypterOpts opts = DefaultEncrypterOpts } - c := &bn256.G1{} - c3c2, err := c.Unmarshal(ciphertext) - if err != nil { - return nil, ErrDecryption - } - - _ = c3c2[sm3.Size] // bounds check elimination hint + c1 := ciphertext[:64] + c3c2 := ciphertext[64:] c3 := c3c2[:sm3.Size] c2 := c3c2[sm3.Size:] key1Len := opts.GetKeySize(c2) - key, err := UnwrapKey(priv, uid, c, key1Len+sm3.Size) + key, err := UnwrapKey(priv, uid, c1, key1Len+sm3.Size) if err != nil { return nil, err } _ = key[key1Len] // bounds check elimination hint - return decrypt(c, key[:key1Len], key[key1Len:], c2, c3, opts) + return decrypt(key[:key1Len], key[key1Len:], c2, c3, opts) } -func decrypt(cipher *bn256.G1, key1, key2, c2, c3 []byte, opts EncrypterOpts) ([]byte, error) { +func decrypt(key1, key2, c2, c3 []byte, opts EncrypterOpts) ([]byte, error) { hash := sm3.New() hash.Write(c2) hash.Write(key2) @@ -546,19 +328,14 @@ func DecryptASN1(priv *EncryptPrivateKey, uid, ciphertext []byte) ([]byte, error if opts == nil { return nil, ErrDecryption } - c, err := unmarshalG1(c1Bytes) - if err != nil { - return nil, ErrDecryption - } - key1Len := opts.GetKeySize(c2Bytes) - key, err := UnwrapKey(priv, uid, c, key1Len+sm3.Size) + key, err := UnwrapKey(priv, uid, c1Bytes, key1Len+sm3.Size) if err != nil { return nil, err } _ = key[key1Len] // bounds check elimination hint - return decrypt(c, key[:key1Len], key[key1Len:], c2Bytes, c3Bytes, opts) + return decrypt(key[:key1Len], key[key1Len:], c2Bytes, c3Bytes, opts) } // Decrypt decrypts chipher, the ciphertext should be with format C1||C3||C2 @@ -576,197 +353,33 @@ func (priv *EncryptPrivateKey) DecryptASN1(uid, ciphertext []byte) ([]byte, erro // Initiator's flow will be: NewKeyExchange -> InitKeyExchange -> transmission -> ConfirmResponder // Responder's flow will be: NewKeyExchange -> waiting ... -> RepondKeyExchange -> transmission -> ConfirmInitiator type KeyExchange struct { - genSignature bool // control the optional sign/verify step triggered by responsder - keyLength int // key length - privateKey *EncryptPrivateKey // owner's encryption private key - uid []byte // owner uid - peerUID []byte // peer uid - r *bigmod.Nat // random which will be used to compute secret - secret *bn256.G1 // generated secret which will be passed to peer - peerSecret *bn256.G1 // received peer's secret - g1 *bn256.GT // internal state which will be used when compute the key and signature - g2 *bn256.GT // internal state which will be used when compute the key and signature - g3 *bn256.GT // internal state which will be used when compute the key and signature + ke *sm9.KeyExchange } -// NewKeyExchange creates one new KeyExchange object -func NewKeyExchange(priv *EncryptPrivateKey, uid, peerUID []byte, keyLen int, genSignature bool) *KeyExchange { - ke := &KeyExchange{} - ke.genSignature = genSignature - ke.keyLength = keyLen - ke.privateKey = priv - ke.uid = uid - ke.peerUID = peerUID - return ke +func (priv *EncryptPrivateKey) NewKeyExchange(uid, peerUID []byte, keyLen int, genSignature bool) *KeyExchange { + return &KeyExchange{ke: priv.privateKey.NewKeyExchange(uid, peerUID, keyLen, genSignature)} } -// Destroy clears all internal state and Ephemeral private/public keys func (ke *KeyExchange) Destroy() { - if ke.r != nil { - ke.r.SetBytes([]byte{0}, orderNat) - } - if ke.g1 != nil { - ke.g1.SetOne() - } - if ke.g2 != nil { - ke.g2.SetOne() - } - if ke.g3 != nil { - ke.g3.SetOne() - } -} - -func initKeyExchange(ke *KeyExchange, hid byte, r *bigmod.Nat) { - pubB := ke.privateKey.GenerateUserPublicKey(ke.peerUID, hid) - ke.r = r - rA, err := new(bn256.G1).ScalarMult(pubB, ke.r.Bytes(orderNat)) - if err != nil { - panic(err) - } - ke.secret = rA + ke.ke.Destroy() } // InitKeyExchange generates random with responder uid, for initiator's step A1-A4 -func (ke *KeyExchange) InitKeyExchange(rand io.Reader, hid byte) (*bn256.G1, error) { - r, err := randomScalar(rand) - if err != nil { - return nil, err - } - initKeyExchange(ke, hid, r) - return ke.secret, nil +func (ke *KeyExchange) InitKeyExchange(rand io.Reader, hid byte) ([]byte, error) { + return ke.ke.InitKeyExchange(rand, hid) } -func (ke *KeyExchange) sign(isResponder bool, prefix byte) []byte { - var buffer []byte - hash := sm3.New() - hash.Write(ke.g2.Marshal()) - hash.Write(ke.g3.Marshal()) - if isResponder { - hash.Write(ke.peerUID) - hash.Write(ke.uid) - hash.Write(ke.peerSecret.Marshal()) - hash.Write(ke.secret.Marshal()) - } else { - hash.Write(ke.uid) - hash.Write(ke.peerUID) - hash.Write(ke.secret.Marshal()) - hash.Write(ke.peerSecret.Marshal()) - } - buffer = hash.Sum(nil) - hash.Reset() - hash.Write([]byte{prefix}) - hash.Write(ke.g1.Marshal()) - hash.Write(buffer) - return hash.Sum(nil) -} - -func (ke *KeyExchange) generateSharedKey(isResponder bool) ([]byte, error) { - var buffer []byte - if isResponder { - buffer = append(buffer, ke.peerUID...) - buffer = append(buffer, ke.uid...) - buffer = append(buffer, ke.peerSecret.Marshal()...) - buffer = append(buffer, ke.secret.Marshal()...) - } else { - buffer = append(buffer, ke.uid...) - buffer = append(buffer, ke.peerUID...) - buffer = append(buffer, ke.secret.Marshal()...) - buffer = append(buffer, ke.peerSecret.Marshal()...) - } - buffer = append(buffer, ke.g1.Marshal()...) - buffer = append(buffer, ke.g2.Marshal()...) - buffer = append(buffer, ke.g3.Marshal()...) - - return sm3.Kdf(buffer, ke.keyLength), nil -} - -func respondKeyExchange(ke *KeyExchange, hid byte, r *bigmod.Nat, rA *bn256.G1) (*bn256.G1, []byte, error) { - if !rA.IsOnCurve() { - return nil, nil, errors.New("sm9: invalid initiator's ephemeral public key") - } - ke.peerSecret = rA - pubA := ke.privateKey.GenerateUserPublicKey(ke.peerUID, hid) - ke.r = r - rBytes := r.Bytes(orderNat) - rB, err := new(bn256.G1).ScalarMult(pubA, rBytes) - if err != nil { - return nil, nil, err - } - ke.secret = rB - - ke.g1 = bn256.Pair(ke.peerSecret, ke.privateKey.PrivateKey) - ke.g3 = &bn256.GT{} - g3, err := bn256.ScalarMultGT(ke.g1, rBytes) - if err != nil { - return nil, nil, err - } - ke.g3 = g3 - - g2, err := ke.privateKey.EncryptMasterPublicKey.ScalarBaseMult(rBytes) - if err != nil { - return nil, nil, err - } - ke.g2 = g2 - - if !ke.genSignature { - return ke.secret, nil, nil - } - - return ke.secret, ke.sign(true, 0x82), nil -} - -// RepondKeyExchange when responder receive rA, for responder's step B1-B7 -func (ke *KeyExchange) RepondKeyExchange(rand io.Reader, hid byte, rA *bn256.G1) (*bn256.G1, []byte, error) { - r, err := randomScalar(rand) - if err != nil { - return nil, nil, err - } - return respondKeyExchange(ke, hid, r, rA) +// RespondKeyExchange when responder receive rA, for responder's step B1-B7 +func (ke *KeyExchange) RespondKeyExchange(rand io.Reader, hid byte, peerData []byte) ([]byte, []byte, error) { + return ke.ke.RespondKeyExchange(rand, hid, peerData) } // ConfirmResponder for initiator's step A5-A7 -func (ke *KeyExchange) ConfirmResponder(rB *bn256.G1, sB []byte) ([]byte, []byte, error) { - if !rB.IsOnCurve() { - return nil, nil, errors.New("sm9: invalid responder's ephemeral public key") - } - // step 5 - ke.peerSecret = rB - g1, err := ke.privateKey.EncryptMasterPublicKey.ScalarBaseMult(ke.r.Bytes(orderNat)) - if err != nil { - return nil, nil, err - } - ke.g1 = g1 - ke.g2 = bn256.Pair(ke.peerSecret, ke.privateKey.PrivateKey) - ke.g3 = &bn256.GT{} - g3, err := bn256.ScalarMultGT(ke.g2, ke.r.Bytes(orderNat)) - if err != nil { - return nil, nil, err - } - ke.g3 = g3 - // step 6, verify signature - if len(sB) > 0 { - signature := ke.sign(false, 0x82) - if goSubtle.ConstantTimeCompare(signature, sB) != 1 { - return nil, nil, errors.New("sm9: invalid responder's signature") - } - } - key, err := ke.generateSharedKey(false) - if err != nil { - return nil, nil, err - } - if !ke.genSignature { - return key, nil, nil - } - return key, ke.sign(false, 0x83), nil +func (ke *KeyExchange) ConfirmResponder(rB, sB []byte) ([]byte, []byte, error) { + return ke.ke.ConfirmResponder(rB, sB) } // ConfirmInitiator for responder's step B8 -func (ke *KeyExchange) ConfirmInitiator(s1 []byte) ([]byte, error) { - if s1 != nil { - buffer := ke.sign(true, 0x83) - if goSubtle.ConstantTimeCompare(buffer, s1) != 1 { - return nil, errors.New("sm9: invalid initiator's signature") - } - } - return ke.generateSharedKey(true) +func (ke *KeyExchange) ConfirmInitiator(peerData []byte) ([]byte, error) { + return ke.ke.ConfirmInitiator(peerData) } diff --git a/sm9/sm9_key.go b/sm9/sm9_key.go index 8719753..2d2ae53 100644 --- a/sm9/sm9_key.go +++ b/sm9/sm9_key.go @@ -6,80 +6,69 @@ import ( "errors" "io" "math/big" - "sync" - "github.com/emmansun/gmsm/internal/bigmod" - "github.com/emmansun/gmsm/sm9/bn256" + "github.com/emmansun/gmsm/internal/sm9" "golang.org/x/crypto/cryptobyte" cryptobyte_asn1 "golang.org/x/crypto/cryptobyte/asn1" ) // SignMasterPrivateKey master private key for sign, generated by KGC type SignMasterPrivateKey struct { - *SignMasterPublicKey // master public key - D *big.Int // master private key + privateKey *sm9.SignMasterPrivateKey } // SignMasterPublicKey master public key for sign, generated by KGC type SignMasterPublicKey struct { - MasterPublicKey *bn256.G2 // master public key - pairOnce sync.Once - basePoint *bn256.GT // the result of Pair(Gen1, pub.MasterPublicKey) - tableGenOnce sync.Once - table *[32 * 2]bn256.GTFieldTable // precomputed basePoint^n + publicKey *sm9.SignMasterPublicKey } // SignPrivateKey user private key for sign, generated by KGC type SignPrivateKey struct { - PrivateKey *bn256.G1 // user private key - *SignMasterPublicKey // master public key + privateKey *sm9.SignPrivateKey } // EncryptMasterPrivateKey master private key for encryption, generated by KGC type EncryptMasterPrivateKey struct { - *EncryptMasterPublicKey // master public key - D *big.Int // master private key + privateKey *sm9.EncryptMasterPrivateKey } // EncryptMasterPublicKey master private key for encryption, generated by KGC type EncryptMasterPublicKey struct { - MasterPublicKey *bn256.G1 // public key - pairOnce sync.Once - basePoint *bn256.GT // the result of Pair(pub.MasterPublicKey, Gen2) - tableGenOnce sync.Once - table *[32 * 2]bn256.GTFieldTable // precomputed basePoint^n + publicKey *sm9.EncryptMasterPublicKey } // EncryptPrivateKey user private key for encryption, generated by KGC type EncryptPrivateKey struct { - PrivateKey *bn256.G2 // user private key - *EncryptMasterPublicKey // master public key + privateKey *sm9.EncryptPrivateKey } // GenerateSignMasterKey generates a master public and private key pair for DSA usage. func GenerateSignMasterKey(rand io.Reader) (*SignMasterPrivateKey, error) { - k, err := randomScalar(rand) - if err != nil { - return nil, err - } - kBytes := k.Bytes(orderNat) - p, err := new(bn256.G2).ScalarBaseMult(kBytes) + priv, err := sm9.GenerateSignMasterKey(rand) if err != nil { return nil, err } + return &SignMasterPrivateKey{privateKey: priv}, nil +} - priv := new(SignMasterPrivateKey) - priv.D = new(big.Int).SetBytes(kBytes) - priv.SignMasterPublicKey = new(SignMasterPublicKey) - priv.MasterPublicKey = p - return priv, nil +// Equal compares the receiver SignMasterPrivateKey with another SignMasterPrivateKey +// and returns true if they are equal, otherwise it returns false. +func (master *SignMasterPrivateKey) Equal(x *SignMasterPrivateKey) bool { + return master.privateKey.Equal(x.privateKey) +} + +// Bytes returns the byte representation of the SignMasterPrivateKey. +// It converts the private key to a byte slice. +func (master *SignMasterPrivateKey) Bytes() []byte { + return master.privateKey.Bytes() } // MarshalASN1 marshal sign master private key to asn.1 format data according // SM9 cryptographic algorithm application specification func (master *SignMasterPrivateKey) MarshalASN1() ([]byte, error) { + d := new(big.Int).SetBytes(master.privateKey.Bytes()) var b cryptobyte.Builder - b.AddASN1BigInt(master.D) + b.AddASN1BigInt(d) return b.Bytes() } @@ -89,6 +78,7 @@ func (master *SignMasterPrivateKey) UnmarshalASN1(der []byte) error { d := &big.Int{} var inner cryptobyte.String var pubBytes []byte + var err error if der[0] == 0x30 { if !input.ReadASN1(&inner, cryptobyte_asn1.SEQUENCE) || !input.Empty() || @@ -102,92 +92,44 @@ func (master *SignMasterPrivateKey) UnmarshalASN1(der []byte) error { } else if !input.ReadASN1Integer(d) || !input.Empty() { return errors.New("sm9: invalid sign master private key asn1 data") } - master.D = d - master.SignMasterPublicKey = new(SignMasterPublicKey) - p, err := new(bn256.G2).ScalarBaseMult(bn256.NormalizeScalar(d.Bytes())) + master.privateKey, err = sm9.NewSignMasterPrivateKey(d.Bytes()) if err != nil { return err } - master.MasterPublicKey = p return nil } // GenerateUserKey generate an user dsa key. func (master *SignMasterPrivateKey) GenerateUserKey(uid []byte, hid byte) (*SignPrivateKey, error) { - var id []byte - id = append(append(id, uid...), hid) - - t1Nat := hashH1(id) - - d, err := bigmod.NewNat().SetBytes(master.D.Bytes(), orderNat) + priv, err := master.privateKey.GenerateUserKey(uid, hid) if err != nil { return nil, err } - - t1Nat.Add(d, orderNat) - if t1Nat.IsZero() == 1 { - return nil, errors.New("sm9: need to re-generate sign master private key") - } - - t1Nat = bigmod.NewNat().Exp(t1Nat, orderMinus2, orderNat) - t1Nat.Mul(d, orderNat) - - priv := new(SignPrivateKey) - priv.SignMasterPublicKey = master.SignMasterPublicKey - g1, err := new(bn256.G1).ScalarBaseMult(t1Nat.Bytes(orderNat)) - if err != nil { - return nil, err - } - priv.PrivateKey = g1 - - return priv, nil + return &SignPrivateKey{privateKey: priv}, nil } // Public returns the public key corresponding to priv. func (master *SignMasterPrivateKey) Public() *SignMasterPublicKey { - return master.SignMasterPublicKey + return &SignMasterPublicKey{master.privateKey.Public()} } -// pair generate the basepoint once -func (pub *SignMasterPublicKey) pair() *bn256.GT { - pub.pairOnce.Do(func() { - pub.basePoint = bn256.Pair(bn256.Gen1, pub.MasterPublicKey) - }) - return pub.basePoint +// Equal compares the receiver SignMasterPublicKey with another SignMasterPublicKey +// and returns true if they are equal, otherwise false. +func (pub *SignMasterPublicKey) Equal(x *SignMasterPublicKey) bool { + return pub.publicKey.Equal(x.publicKey) } -func (pub *SignMasterPublicKey) generatorTable() *[32 * 2]bn256.GTFieldTable { - pub.tableGenOnce.Do(func() { - pub.table = bn256.GenerateGTFieldTable(pub.pair()) - }) - return pub.table -} - -// ScalarBaseMult compute basepoint^r with precomputed table -// The base point = pair(Gen1, ) -func (pub *SignMasterPublicKey) ScalarBaseMult(scalar []byte) (*bn256.GT, error) { - tables := pub.generatorTable() - return bn256.ScalarBaseMultGT(tables, scalar) -} - -// GenerateUserPublicKey generate user sign public key -func (pub *SignMasterPublicKey) GenerateUserPublicKey(uid []byte, hid byte) *bn256.G2 { - var buffer []byte - buffer = append(append(buffer, uid...), hid) - h1 := hashH1(buffer) - p, err := new(bn256.G2).ScalarBaseMult(h1.Bytes(orderNat)) - if err != nil { - panic(err) - } - p.Add(p, pub.MasterPublicKey) - return p +// Bytes returns the byte representation of the SignMasterPublicKey. +// It calls the Bytes method on the underlying publicKey field. +func (pub *SignMasterPublicKey) Bytes() []byte { + return pub.publicKey.Bytes() } // MarshalASN1 marshal sign master public key to asn.1 format data according // SM9 cryptographic algorithm application specification func (pub *SignMasterPublicKey) MarshalASN1() ([]byte, error) { var b cryptobyte.Builder - b.AddASN1BitString(pub.MasterPublicKey.MarshalUncompressed()) + b.AddASN1BitString(pub.publicKey.MasterPublicKey.MarshalUncompressed()) return b.Bytes() } @@ -195,37 +137,16 @@ func (pub *SignMasterPublicKey) MarshalASN1() ([]byte, error) { // SM9 cryptographic algorithm application specification, the curve point is in compressed form. func (pub *SignMasterPublicKey) MarshalCompressedASN1() ([]byte, error) { var b cryptobyte.Builder - b.AddASN1BitString(pub.MasterPublicKey.MarshalCompressed()) + b.AddASN1BitString(pub.publicKey.MasterPublicKey.MarshalCompressed()) return b.Bytes() } -func unmarshalG2(bytes []byte) (*bn256.G2, error) { - g2 := new(bn256.G2) - switch bytes[0] { - case 4: - _, err := g2.Unmarshal(bytes[1:]) - if err != nil { - return nil, err - } - case 2, 3: - _, err := g2.UnmarshalCompressed(bytes) - if err != nil { - return nil, err - } - default: - return nil, errors.New("sm9: invalid point identity byte") - } - return g2, nil -} - // UnmarshalRaw unmarsal raw bytes data to sign master public key func (pub *SignMasterPublicKey) UnmarshalRaw(bytes []byte) error { - g2, err := unmarshalG2(bytes) - if err != nil { - return err + if pub.publicKey == nil { + pub.publicKey = new(sm9.SignMasterPublicKey) } - pub.MasterPublicKey = g2 - return nil + return pub.publicKey.UnmarshalRaw(bytes) } // UnmarshalASN1 unmarsal der data to sign master public key @@ -255,23 +176,29 @@ func (pub *SignMasterPublicKey) ParseFromPEM(data []byte) error { return pub.UnmarshalASN1(block.Bytes) } +func (priv *SignPrivateKey) Equal(x *SignPrivateKey) bool { + return priv.privateKey.Equal(x.privateKey) +} + +func (priv *SignPrivateKey) Bytes() []byte { + return priv.privateKey.Bytes() +} + // MasterPublic returns the master public key corresponding to priv. func (priv *SignPrivateKey) MasterPublic() *SignMasterPublicKey { - return priv.SignMasterPublicKey + return &SignMasterPublicKey{priv.privateKey.MasterPublic()} } // SetMasterPublicKey bind the sign master public key to it. func (priv *SignPrivateKey) SetMasterPublicKey(pub *SignMasterPublicKey) { - if priv.SignMasterPublicKey == nil || priv.SignMasterPublicKey.MasterPublicKey == nil { - priv.SignMasterPublicKey = pub - } + priv.privateKey.SetMasterPublicKey(pub.publicKey) } // MarshalASN1 marshal sign user private key to asn.1 format data according // SM9 cryptographic algorithm application specification func (priv *SignPrivateKey) MarshalASN1() ([]byte, error) { var b cryptobyte.Builder - b.AddASN1BitString(priv.PrivateKey.MarshalUncompressed()) + b.AddASN1BitString(priv.privateKey.PrivateKey.MarshalUncompressed()) return b.Bytes() } @@ -279,38 +206,17 @@ func (priv *SignPrivateKey) MarshalASN1() ([]byte, error) { // SM9 cryptographic algorithm application specification, the curve point is in compressed form. func (priv *SignPrivateKey) MarshalCompressedASN1() ([]byte, error) { var b cryptobyte.Builder - b.AddASN1BitString(priv.PrivateKey.MarshalCompressed()) + b.AddASN1BitString(priv.privateKey.PrivateKey.MarshalCompressed()) return b.Bytes() } -func unmarshalG1(bytes []byte) (*bn256.G1, error) { - g := new(bn256.G1) - switch bytes[0] { - case 4: - _, err := g.Unmarshal(bytes[1:]) - if err != nil { - return nil, err - } - case 2, 3: - _, err := g.UnmarshalCompressed(bytes) - if err != nil { - return nil, err - } - default: - return nil, errors.New("sm9: invalid point identity byte") - } - return g, nil -} - // UnmarshalRaw unmarsal raw bytes data to sign user private key // Note, priv's SignMasterPublicKey should be handled separately. func (priv *SignPrivateKey) UnmarshalRaw(bytes []byte) error { - g, err := unmarshalG1(bytes) - if err != nil { - return err + if priv.privateKey == nil { + priv.privateKey = new(sm9.SignPrivateKey) } - priv.PrivateKey = g - return nil + return priv.privateKey.UnmarshalRaw(bytes) } // UnmarshalASN1 unmarsal der data to sign user private key @@ -349,64 +255,45 @@ func (priv *SignPrivateKey) UnmarshalASN1(der []byte) error { // GenerateEncryptMasterKey generates a master public and private key pair for encryption usage. func GenerateEncryptMasterKey(rand io.Reader) (*EncryptMasterPrivateKey, error) { - k, err := randomScalar(rand) + priv, err := sm9.GenerateEncryptMasterKey(rand) if err != nil { return nil, err } - kBytes := k.Bytes(orderNat) + return &EncryptMasterPrivateKey{privateKey: priv}, nil +} - priv := new(EncryptMasterPrivateKey) - priv.D = new(big.Int).SetBytes(kBytes) - priv.EncryptMasterPublicKey = new(EncryptMasterPublicKey) - p, err := new(bn256.G1).ScalarBaseMult(kBytes) - if err != nil { - panic(err) - } - priv.MasterPublicKey = p - return priv, nil +// Bytes returns the byte representation of the EncryptMasterPrivateKey. +// It delegates the call to the Bytes method of the underlying privateKey. +func (master *EncryptMasterPrivateKey) Bytes() []byte { + return master.privateKey.Bytes() +} + +// Equal compares the receiver EncryptMasterPrivateKey with another EncryptMasterPrivateKey +// and returns true if they are equal, otherwise it returns false. +func (master *EncryptMasterPrivateKey) Equal(x *EncryptMasterPrivateKey) bool { + return master.privateKey.Equal(x.privateKey) } // GenerateUserKey generate an user key for encryption. func (master *EncryptMasterPrivateKey) GenerateUserKey(uid []byte, hid byte) (*EncryptPrivateKey, error) { - var id []byte - id = append(append(id, uid...), hid) - - t1Nat := hashH1(id) - - d, err := bigmod.NewNat().SetBytes(master.D.Bytes(), orderNat) + priv, err := master.privateKey.GenerateUserKey(uid, hid) if err != nil { return nil, err } - - t1Nat.Add(d, orderNat) - if t1Nat.IsZero() == 1 { - return nil, errors.New("sm9: need to re-generate encrypt master private key") - } - - t1Nat = bigmod.NewNat().Exp(t1Nat, orderMinus2, orderNat) - t1Nat.Mul(d, orderNat) - - priv := new(EncryptPrivateKey) - priv.EncryptMasterPublicKey = master.EncryptMasterPublicKey - p, err := new(bn256.G2).ScalarBaseMult(t1Nat.Bytes(orderNat)) - if err != nil { - panic(err) - } - priv.PrivateKey = p - - return priv, nil + return &EncryptPrivateKey{privateKey: priv}, nil } // Public returns the public key corresponding to priv. func (master *EncryptMasterPrivateKey) Public() *EncryptMasterPublicKey { - return master.EncryptMasterPublicKey + return &EncryptMasterPublicKey{publicKey: master.privateKey.Public()} } // MarshalASN1 marshal encrypt master private key to asn.1 format data according // SM9 cryptographic algorithm application specification func (master *EncryptMasterPrivateKey) MarshalASN1() ([]byte, error) { + d := new(big.Int).SetBytes(master.privateKey.Bytes()) var b cryptobyte.Builder - b.AddASN1BigInt(master.D) + b.AddASN1BigInt(d) return b.Bytes() } @@ -429,56 +316,31 @@ func (master *EncryptMasterPrivateKey) UnmarshalASN1(der []byte) error { } else if !input.ReadASN1Integer(d) || !input.Empty() { return errors.New("sm9: invalid encrypt master private key asn1 data") } - master.D = d - master.EncryptMasterPublicKey = new(EncryptMasterPublicKey) - p, err := new(bn256.G1).ScalarBaseMult(bn256.NormalizeScalar(d.Bytes())) + var err error + master.privateKey, err = sm9.NewEncryptMasterPrivateKey(d.Bytes()) if err != nil { return err } - master.MasterPublicKey = p return nil } -// pair generate the basepoint once -func (pub *EncryptMasterPublicKey) pair() *bn256.GT { - pub.pairOnce.Do(func() { - pub.basePoint = bn256.Pair(pub.MasterPublicKey, bn256.Gen2) - }) - return pub.basePoint +// Equal compares the receiver EncryptMasterPublicKey with another EncryptMasterPublicKey +// and returns true if they are equal, otherwise it returns false. +func (pub *EncryptMasterPublicKey) Equal(x *EncryptMasterPublicKey) bool { + return pub.publicKey.Equal(x.publicKey) } -func (pub *EncryptMasterPublicKey) generatorTable() *[32 * 2]bn256.GTFieldTable { - pub.tableGenOnce.Do(func() { - pub.table = bn256.GenerateGTFieldTable(pub.pair()) - }) - return pub.table -} - -// ScalarBaseMult compute basepoint^r with precomputed table. -// The base point = pair(, Gen2) -func (pub *EncryptMasterPublicKey) ScalarBaseMult(scalar []byte) (*bn256.GT, error) { - tables := pub.generatorTable() - return bn256.ScalarBaseMultGT(tables, scalar) -} - -// GenerateUserPublicKey generate user encrypt public key -func (pub *EncryptMasterPublicKey) GenerateUserPublicKey(uid []byte, hid byte) *bn256.G1 { - var buffer []byte - buffer = append(append(buffer, uid...), hid) - h1 := hashH1(buffer) - p, err := new(bn256.G1).ScalarBaseMult(h1.Bytes(orderNat)) - if err != nil { - panic(err) - } - p.Add(p, pub.MasterPublicKey) - return p +// Bytes returns the byte representation of the EncryptMasterPublicKey. +// It delegates the call to the Bytes method of the underlying publicKey. +func (pub *EncryptMasterPublicKey) Bytes() []byte { + return pub.publicKey.Bytes() } // MarshalASN1 marshal encrypt master public key to asn.1 format data according // SM9 cryptographic algorithm application specification func (pub *EncryptMasterPublicKey) MarshalASN1() ([]byte, error) { var b cryptobyte.Builder - b.AddASN1BitString(pub.MasterPublicKey.MarshalUncompressed()) + b.AddASN1BitString(pub.publicKey.MasterPublicKey.MarshalUncompressed()) return b.Bytes() } @@ -486,18 +348,16 @@ func (pub *EncryptMasterPublicKey) MarshalASN1() ([]byte, error) { // SM9 cryptographic algorithm application specification, the curve point is in compressed form. func (pub *EncryptMasterPublicKey) MarshalCompressedASN1() ([]byte, error) { var b cryptobyte.Builder - b.AddASN1BitString(pub.MasterPublicKey.MarshalCompressed()) + b.AddASN1BitString(pub.publicKey.MasterPublicKey.MarshalCompressed()) return b.Bytes() } // UnmarshalRaw unmarsal raw bytes data to encrypt master public key func (pub *EncryptMasterPublicKey) UnmarshalRaw(bytes []byte) error { - g, err := unmarshalG1(bytes) - if err != nil { - return err + if pub.publicKey == nil { + pub.publicKey = new(sm9.EncryptMasterPublicKey) } - pub.MasterPublicKey = g - return nil + return pub.publicKey.UnmarshalRaw(bytes) } // ParseFromPEM just for GMSSL, there are no Algorithm pkix.AlgorithmIdentifier @@ -529,21 +389,19 @@ func (pub *EncryptMasterPublicKey) UnmarshalASN1(der []byte) error { // MasterPublic returns the master public key corresponding to priv. func (priv *EncryptPrivateKey) MasterPublic() *EncryptMasterPublicKey { - return priv.EncryptMasterPublicKey + return &EncryptMasterPublicKey{priv.privateKey.MasterPublic()} } // SetMasterPublicKey bind the encrypt master public key to it. func (priv *EncryptPrivateKey) SetMasterPublicKey(pub *EncryptMasterPublicKey) { - if priv.EncryptMasterPublicKey == nil || priv.EncryptMasterPublicKey.MasterPublicKey == nil { - priv.EncryptMasterPublicKey = pub - } + priv.privateKey.SetMasterPublicKey(pub.publicKey) } // MarshalASN1 marshal encrypt user private key to asn.1 format data according // SM9 cryptographic algorithm application specification func (priv *EncryptPrivateKey) MarshalASN1() ([]byte, error) { var b cryptobyte.Builder - b.AddASN1BitString(priv.PrivateKey.MarshalUncompressed()) + b.AddASN1BitString(priv.privateKey.PrivateKey.MarshalUncompressed()) return b.Bytes() } @@ -551,19 +409,17 @@ func (priv *EncryptPrivateKey) MarshalASN1() ([]byte, error) { // SM9 cryptographic algorithm application specification, the curve point is in compressed form. func (priv *EncryptPrivateKey) MarshalCompressedASN1() ([]byte, error) { var b cryptobyte.Builder - b.AddASN1BitString(priv.PrivateKey.MarshalCompressed()) + b.AddASN1BitString(priv.privateKey.PrivateKey.MarshalCompressed()) return b.Bytes() } // UnmarshalRaw unmarsal raw bytes data to encrypt user private key // Note, priv's EncryptMasterPublicKey should be handled separately. func (priv *EncryptPrivateKey) UnmarshalRaw(bytes []byte) error { - g, err := unmarshalG2(bytes) - if err != nil { - return err + if priv.privateKey == nil { + priv.privateKey = new(sm9.EncryptPrivateKey) } - priv.PrivateKey = g - return nil + return priv.privateKey.UnmarshalRaw(bytes) } // UnmarshalASN1 unmarsal der data to encrypt user private key @@ -599,3 +455,15 @@ func (priv *EncryptPrivateKey) UnmarshalASN1(der []byte) error { } return nil } + +// Equal compares the receiver EncryptPrivateKey with another EncryptPrivateKey x +// and returns true if they are equal, otherwise false. +func (priv *EncryptPrivateKey) Equal(x *EncryptPrivateKey) bool { + return priv.privateKey.Equal(x.privateKey) +} + +// Bytes returns the byte representation of the EncryptPrivateKey. +// It delegates the call to the Bytes method of the underlying privateKey. +func (priv *EncryptPrivateKey) Bytes() []byte { + return priv.privateKey.Bytes() +} diff --git a/sm9/sm9_key_test.go b/sm9/sm9_key_test.go index a57edf6..c3f9237 100644 --- a/sm9/sm9_key_test.go +++ b/sm9/sm9_key_test.go @@ -24,8 +24,8 @@ func TestSignMasterPrivateKeyMarshalASN1(t *testing.T) { if err != nil { t.Fatal(err) } - if masterKey.D.Cmp(masterKey2.D) != 0 { - t.Errorf("expected %v, got %v", hex.EncodeToString(masterKey.D.Bytes()), hex.EncodeToString(masterKey2.D.Bytes())) + if !masterKey.Equal(masterKey2) { + t.Errorf("expected %v, got %v", hex.EncodeToString(masterKey.Bytes()), hex.EncodeToString(masterKey2.Bytes())) } } @@ -43,7 +43,7 @@ func TestSignMasterPublicKeyMarshalASN1(t *testing.T) { if err != nil { t.Fatal(err) } - if !masterKey.MasterPublicKey.Equal(pub2.MasterPublicKey) { + if !masterKey.Public().Equal(pub2) { t.Errorf("not same") } } @@ -62,7 +62,7 @@ func TestSignMasterPublicKeyMarshalCompressedASN1(t *testing.T) { if err != nil { t.Fatal(err) } - if !masterKey.MasterPublicKey.Equal(pub2.MasterPublicKey) { + if !masterKey.Public().Equal(pub2) { t.Errorf("not same") } } @@ -87,7 +87,7 @@ func TestSignUserPrivateKeyMarshalASN1(t *testing.T) { if err != nil { t.Fatal(err) } - if !userKey.PrivateKey.Equal(userKey2.PrivateKey) { + if !userKey.Equal(userKey2) { t.Errorf("not same") } } @@ -112,7 +112,7 @@ func TestSignUserPrivateKeyMarshalCompressedASN1(t *testing.T) { if err != nil { t.Fatal(err) } - if !userKey.PrivateKey.Equal(userKey2.PrivateKey) { + if !userKey.Equal(userKey2) { t.Errorf("not same") } } @@ -131,8 +131,8 @@ func TestEncryptMasterPrivateKeyMarshalASN1(t *testing.T) { if err != nil { t.Fatal(err) } - if masterKey.D.Cmp(masterKey2.D) != 0 { - t.Errorf("expected %v, got %v", hex.EncodeToString(masterKey.D.Bytes()), hex.EncodeToString(masterKey2.D.Bytes())) + if !masterKey.Equal(masterKey2) { + t.Errorf("expected %v, got %v", hex.EncodeToString(masterKey.Bytes()), hex.EncodeToString(masterKey2.Bytes())) } } @@ -150,7 +150,7 @@ func TestEncryptMasterPublicKeyMarshalASN1(t *testing.T) { if err != nil { t.Fatal(err) } - if !masterKey.MasterPublicKey.Equal(pub2.MasterPublicKey) { + if !masterKey.Public().Equal(pub2) { t.Errorf("not same") } } @@ -169,7 +169,7 @@ func TestEncryptMasterPublicKeyMarshalCompressedASN1(t *testing.T) { if err != nil { t.Fatal(err) } - if !masterKey.MasterPublicKey.Equal(pub2.MasterPublicKey) { + if !masterKey.Public().Equal(pub2) { t.Errorf("not same") } } @@ -194,7 +194,7 @@ func TestEncryptUserPrivateKeyMarshalASN1(t *testing.T) { if err != nil { t.Fatal(err) } - if !userKey.PrivateKey.Equal(userKey2.PrivateKey) { + if !userKey.Equal(userKey2) { t.Errorf("not same") } } @@ -219,7 +219,7 @@ func TestEncryptUserPrivateKeyMarshalCompressedASN1(t *testing.T) { if err != nil { t.Fatal(err) } - if !userKey.PrivateKey.Equal(userKey2.PrivateKey) { + if !userKey.Equal(userKey2) { t.Errorf("not same") } } @@ -271,7 +271,7 @@ func TestParseSM9SignMasterPublicKey(t *testing.T) { if err != nil { t.Fatal(err) } - if key.MasterPublicKey == nil { + if key == nil { t.Errorf("not expected nil") } @@ -305,7 +305,7 @@ func TestParseSM9EncryptMasterPublicKey(t *testing.T) { if err != nil { t.Fatal(err) } - if key.MasterPublicKey == nil { + if key == nil { t.Errorf("not expected nil") } @@ -313,7 +313,7 @@ func TestParseSM9EncryptMasterPublicKey(t *testing.T) { var b cryptobyte.Builder b.AddASN1(cryptobyte_asn1.SEQUENCE, func(b *cryptobyte.Builder) { - b.AddASN1BitString(key.MasterPublicKey.MarshalUncompressed()) + b.AddASN1BitString(key.Bytes()) }) data, err := b.Bytes() if err != nil { diff --git a/sm9/sm9_test.go b/sm9/sm9_test.go index 8698d43..3466547 100644 --- a/sm9/sm9_test.go +++ b/sm9/sm9_test.go @@ -1,108 +1,12 @@ package sm9 import ( + "bytes" "crypto/rand" "encoding/hex" - "math/big" "testing" - - "github.com/emmansun/gmsm/internal/bigmod" - "github.com/emmansun/gmsm/internal/subtle" - "github.com/emmansun/gmsm/sm3" - "github.com/emmansun/gmsm/sm9/bn256" - "golang.org/x/crypto/cryptobyte" ) -func bigFromHex(s string) *big.Int { - b, ok := new(big.Int).SetString(s, 16) - if !ok { - panic("sm9/elliptic: internal error: invalid encoding") - } - return b -} - -func TestHashH1(t *testing.T) { - expected := "2acc468c3926b0bdb2767e99ff26e084de9ced8dbc7d5fbf418027b667862fab" - h := hashH1([]byte{0x41, 0x6c, 0x69, 0x63, 0x65, 0x01}) - if hex.EncodeToString(h.Bytes(orderNat)) != expected { - t.Errorf("got %v, expected %v", h.Bytes(orderNat), expected) - } -} - -func TestHashH2(t *testing.T) { - expected := "823c4b21e4bd2dfe1ed92c606653e996668563152fc33f55d7bfbb9bd9705adb" - zStr := "4368696E65736520494253207374616E6461726481377B8FDBC2839B4FA2D0E0F8AA6853BBBE9E9C4099608F8612C6078ACD7563815AEBA217AD502DA0F48704CC73CABB3C06209BD87142E14CBD99E8BCA1680F30DADC5CD9E207AEE32209F6C3CA3EC0D800A1A42D33C73153DED47C70A39D2E8EAF5D179A1836B359A9D1D9BFC19F2EFCDB829328620962BD3FDF15F2567F58A543D25609AE943920679194ED30328BB33FD15660BDE485C6B79A7B32B013983F012DB04BA59FE88DB889321CC2373D4C0C35E84F7AB1FF33679BCA575D67654F8624EB435B838CCA77B2D0347E65D5E46964412A096F4150D8C5EDE5440DDF0656FCB663D24731E80292188A2471B8B68AA993899268499D23C89755A1A89744643CEAD40F0965F28E1CD2895C3D118E4F65C9A0E3E741B6DD52C0EE2D25F5898D60848026B7EFB8FCC1B2442ECF0795F8A81CEE99A6248F294C82C90D26BD6A814AAF475F128AEF43A128E37F80154AE6CB92CAD7D1501BAE30F750B3A9BD1F96B08E97997363911314705BFB9A9DBB97F75553EC90FBB2DDAE53C8F68E42" - z, err := hex.DecodeString(zStr) - if err != nil { - t.Fatal(err) - } - h := hashH2(z) - if hex.EncodeToString(h.Bytes(orderNat)) != expected { - t.Errorf("got %v, expected %v", h.Bytes(orderNat), expected) - } -} - -func TestSign(t *testing.T) { - masterKey, err := GenerateSignMasterKey(rand.Reader) - hashed := []byte("Chinese IBS standard") - uid := []byte("emmansun") - hid := byte(0x01) - if err != nil { - t.Fatal(err) - } - userKey, err := masterKey.GenerateUserKey(uid, hid) - if err != nil { - t.Fatal(err) - } - h, s, err := Sign(rand.Reader, userKey, hashed) - if err != nil { - t.Fatal(err) - } - if !Verify(masterKey.Public(), uid, hid, hashed, h, s) { - t.Errorf("Verify failed") - } - sNeg := new(bn256.G1).Neg(s) - if Verify(masterKey.Public(), uid, hid, hashed, h, sNeg) { - t.Errorf("Verify with s=-s succeeded") - } - hashed[0] ^= 0xff - if Verify(masterKey.Public(), uid, hid, hashed, h, s) { - t.Errorf("Verify always works!") - } -} - -func TestNegativeInputs(t *testing.T) { - masterKey, err := GenerateSignMasterKey(rand.Reader) - hashed := []byte("Chinese IBS standard") - uid := []byte("emmansun") - hid := byte(0x01) - if err != nil { - t.Fatal(err) - } - h := new(big.Int).SetInt64(1) - h.Lsh(h, 550 /* larger than any supported curve */) - h.Neg(h) - if Verify(masterKey.Public(), uid, hid, hashed, h, bn256.Gen1) { - t.Errorf("bogus signature accepted") - } -} - -func TestZeroSignature(t *testing.T) { - masterKey, err := GenerateSignMasterKey(rand.Reader) - hashed := []byte("Chinese IBS standard") - uid := []byte("emmansun") - hid := byte(0x01) - if err != nil { - t.Fatal(err) - } - if Verify(masterKey.Public(), uid, hid, hashed, big.NewInt(0), bn256.Gen1) { - t.Error("Verify with h=0 succeeded") - } - if Verify(masterKey.Public(), uid, hid, hashed, bn256.Order, bn256.Gen1) { - t.Error("Verify with h=order succeeded") - } -} - func TestSignASN1(t *testing.T) { masterKey, err := GenerateSignMasterKey(rand.Reader) hashed := []byte("Chinese IBS standard") @@ -149,266 +53,6 @@ func TestParseInvalidASN1(t *testing.T) { } } -func signMasterPrivateKeyFromHex(s string) (*SignMasterPrivateKey, error) { - kb, err := hex.DecodeString(s) - if err != nil { - return nil, err - } - var b cryptobyte.Builder - b.AddASN1BigInt(new(big.Int).SetBytes(kb)) - kb, _ = b.Bytes() - testkey := new(SignMasterPrivateKey) - err = testkey.UnmarshalASN1(kb) - if err != nil { - return nil, err - } - return testkey, nil -} - -// SM9 Appendix A -func TestSignSM9Sample(t *testing.T) { - expectedH := bigFromHex("823c4b21e4bd2dfe1ed92c606653e996668563152fc33f55d7bfbb9bd9705adb") - expectedHNat, err := bigmod.NewNat().SetBytes(expectedH.Bytes(), orderNat) - if err != nil { - t.Fatal(err) - } - expectedS := "0473bf96923ce58b6ad0e13e9643a406d8eb98417c50ef1b29cef9adb48b6d598c856712f1c2e0968ab7769f42a99586aed139d5b8b3e15891827cc2aced9baa05" - hash := []byte("Chinese IBS standard") - hid := byte(0x01) - uid := []byte("Alice") - r := bigFromHex("033c8616b06704813203dfd00965022ed15975c662337aed648835dc4b1cbe") - rNat, err := bigmod.NewNat().SetBytes(r.Bytes(), orderNat) - if err != nil { - t.Fatal(err) - } - - masterKey, err := signMasterPrivateKeyFromHex("0130E78459D78545CB54C587E02CF480CE0B66340F319F348A1D5B1F2DC5F4") - if err != nil { - t.Fatal(err) - } - - userKey, err := masterKey.GenerateUserKey(uid, hid) - if err != nil { - t.Fatal(err) - } - w, err := userKey.SignMasterPublicKey.ScalarBaseMult(bn256.NormalizeScalar(r.Bytes())) - if err != nil { - t.Fatal(err) - } - - var buffer []byte - buffer = append(buffer, hash...) - buffer = append(buffer, w.Marshal()...) - - h := hashH2(buffer) - if h.Equal(expectedHNat) == 0 { - t.Fatal("not same h") - } - - rNat.Sub(h, orderNat) - - s, err := new(bn256.G1).ScalarMult(userKey.PrivateKey, rNat.Bytes(orderNat)) - if err != nil { - t.Fatal(err) - } - - if hex.EncodeToString(s.MarshalUncompressed()) != expectedS { - t.Fatal("not same S") - } -} - -// SM9 Appendix B -func TestKeyExchangeSample(t *testing.T) { - hid := byte(0x02) - expectedPube := "9174542668e8f14ab273c0945c3690c66e5dd09678b86f734c4350567ed0628354e598c6bf749a3dacc9fffedd9db6866c50457cfc7aa2a4ad65c3168ff74210" - expectedKey := "c5c13a8f59a97cdeae64f16a2272a9e7" - expectedSignatureB := "3bb4bcee8139c960b4d6566db1e0d5f0b2767680e5e1bf934103e6c66e40ffee" - expectedSignatureA := "195d1b7256ba7e0e67c71202a25f8c94ff8241702c2f55d613ae1c6b98215172" - - masterKey, err := encryptMasterPrivateKeyFromHex("02E65B0762D042F51F0D23542B13ED8CFA2E9A0E7206361E013A283905E31F") - if err != nil { - t.Fatal(err) - } - - if hex.EncodeToString(masterKey.MasterPublicKey.Marshal()) != expectedPube { - t.Errorf("not expected master public key") - } - - userA := []byte("Alice") - userB := []byte("Bob") - - userKey, err := masterKey.GenerateUserKey(userA, hid) - if err != nil { - t.Fatal(err) - } - initiator := NewKeyExchange(userKey, userA, userB, 16, true) - - userKey, err = masterKey.GenerateUserKey(userB, hid) - if err != nil { - t.Fatal(err) - } - responder := NewKeyExchange(userKey, userB, userA, 16, true) - defer func() { - initiator.Destroy() - responder.Destroy() - }() - // A1-A4 - k, err := bigmod.NewNat().SetBytes(bigFromHex("5879DD1D51E175946F23B1B41E93BA31C584AE59A426EC1046A4D03B06C8").Bytes(), orderNat) - if err != nil { - t.Fatal(err) - } - initKeyExchange(initiator, hid, k) - - if hex.EncodeToString(initiator.secret.Marshal()) != "7cba5b19069ee66aa79d490413d11846b9ba76dd22567f809cf23b6d964bb265a9760c99cb6f706343fed05637085864958d6c90902aba7d405fbedf7b781599" { - t.Fatal("not same") - } - - // B1 - B7 - k, err = bigmod.NewNat().SetBytes(bigFromHex("018B98C44BEF9F8537FB7D071B2C928B3BC65BD3D69E1EEE213564905634FE").Bytes(), orderNat) - if err != nil { - t.Fatal(err) - } - rB, sigB, err := respondKeyExchange(responder, hid, k, initiator.secret) - if err != nil { - t.Fatal(err) - } - - if hex.EncodeToString(sigB) != expectedSignatureB { - t.Errorf("not expected signature B") - } - - // A5 -A8 - key1, sigA, err := initiator.ConfirmResponder(rB, sigB) - if err != nil { - t.Fatal(err) - } - if hex.EncodeToString(key1) != expectedKey { - t.Errorf("not expected key %v\n", hex.EncodeToString(key1)) - } - if hex.EncodeToString(sigA) != expectedSignatureA { - t.Errorf("not expected signature A") - } - // B8 - key2, err := responder.ConfirmInitiator(sigA) - if err != nil { - t.Fatal(err) - } - if hex.EncodeToString(key2) != expectedKey { - t.Errorf("not expected key %v\n", hex.EncodeToString(key2)) - } -} - -func TestKeyExchange(t *testing.T) { - hid := byte(0x02) - userA := []byte("Alice") - userB := []byte("Bob") - masterKey, err := GenerateEncryptMasterKey(rand.Reader) - if err != nil { - t.Fatal(err) - } - - userKey, err := masterKey.GenerateUserKey(userA, hid) - if err != nil { - t.Fatal(err) - } - initiator := NewKeyExchange(userKey, userA, userB, 16, true) - - userKey, err = masterKey.GenerateUserKey(userB, hid) - if err != nil { - t.Fatal(err) - } - responder := NewKeyExchange(userKey, userB, userA, 16, true) - defer func() { - initiator.Destroy() - responder.Destroy() - }() - // A1-A4 - rA, err := initiator.InitKeyExchange(rand.Reader, hid) - if err != nil { - t.Fatal(err) - } - - // B1 - B7 - rB, sigB, err := responder.RepondKeyExchange(rand.Reader, hid, rA) - if err != nil { - t.Fatal(err) - } - - // A5 -A8 - key1, sigA, err := initiator.ConfirmResponder(rB, sigB) - if err != nil { - t.Fatal(err) - } - - // B8 - key2, err := responder.ConfirmInitiator(sigA) - if err != nil { - t.Fatal(err) - } - - if hex.EncodeToString(key1) != hex.EncodeToString(key2) { - t.Errorf("got different key") - } -} - -func TestKeyExchangeWithoutSignature(t *testing.T) { - hid := byte(0x02) - userA := []byte("Alice") - userB := []byte("Bob") - masterKey, err := GenerateEncryptMasterKey(rand.Reader) - if err != nil { - t.Fatal(err) - } - - userKey, err := masterKey.GenerateUserKey(userA, hid) - if err != nil { - t.Fatal(err) - } - initiator := NewKeyExchange(userKey, userA, userB, 16, false) - - userKey, err = masterKey.GenerateUserKey(userB, hid) - if err != nil { - t.Fatal(err) - } - responder := NewKeyExchange(userKey, userB, userA, 16, false) - defer func() { - initiator.Destroy() - responder.Destroy() - }() - // A1-A4 - rA, err := initiator.InitKeyExchange(rand.Reader, hid) - if err != nil { - t.Fatal(err) - } - - // B1 - B7 - rB, sigB, err := responder.RepondKeyExchange(rand.Reader, hid, rA) - if err != nil { - t.Fatal(err) - } - if len(sigB) != 0 { - t.Errorf("should no signature") - } - - // A5 -A8 - key1, sigA, err := initiator.ConfirmResponder(rB, sigB) - if err != nil { - t.Fatal(err) - } - if len(sigA) != 0 { - t.Errorf("should no signature") - } - - key2, err := responder.ConfirmInitiator(nil) - if err != nil { - t.Fatal(err) - } - - if hex.EncodeToString(key1) != hex.EncodeToString(key2) { - t.Errorf("got different key") - } -} - func TestWrapKey(t *testing.T) { masterKey, err := GenerateEncryptMasterKey(rand.Reader) hid := byte(0x01) @@ -420,18 +64,18 @@ func TestWrapKey(t *testing.T) { if err != nil { t.Fatal(err) } - key, cipher, err := WrapKey(rand.Reader, masterKey.Public(), uid, hid, 16) + key, cipher, err := masterKey.Public().WrapKey(rand.Reader, uid, hid, 16) if err != nil { t.Fatal(err) } - key2, err := UnwrapKey(userKey, uid, cipher, 16) + key2, err := userKey.UnwrapKey(uid, cipher, 16) if err != nil { t.Fatal(err) } - if hex.EncodeToString(key) != hex.EncodeToString(key2) { - t.Errorf("expected %v, got %v\n", hex.EncodeToString(key), hex.EncodeToString(key2)) + if !bytes.Equal(key, key2) { + t.Errorf("expected %x, got %x", key, key2) } } @@ -461,260 +105,8 @@ func TestWrapKeyASN1(t *testing.T) { t.Fatal(err) } - if hex.EncodeToString(key1) != hex.EncodeToString(key2) { - t.Errorf("expected %v, got %v\n", hex.EncodeToString(key1), hex.EncodeToString(key2)) - } -} - -func TestUnmarshalSM9KeyPackage(t *testing.T) { - masterKey, err := GenerateEncryptMasterKey(rand.Reader) - hid := byte(0x01) - uid := []byte("emmansun") - if err != nil { - t.Fatal(err) - } - userKey, err := masterKey.GenerateUserKey(uid, hid) - if err != nil { - t.Fatal(err) - } - p, err := masterKey.Public().WrapKeyASN1(rand.Reader, uid, hid, 16) - if err != nil { - t.Fatal(err) - } - - key, cipher, err := UnmarshalSM9KeyPackage(p) - if err != nil { - t.Fatal(err) - } - - key2, err := UnwrapKey(userKey, uid, cipher, 16) - if err != nil { - t.Fatal(err) - } - - if hex.EncodeToString(key) != hex.EncodeToString(key2) { - t.Errorf("expected %v, got %v\n", hex.EncodeToString(key), hex.EncodeToString(key2)) - } -} - -func encryptMasterPrivateKeyFromHex(s string) (*EncryptMasterPrivateKey, error) { - kb, err := hex.DecodeString(s) - if err != nil { - return nil, err - } - var b cryptobyte.Builder - b.AddASN1BigInt(new(big.Int).SetBytes(kb)) - kb, _ = b.Bytes() - testkey := new(EncryptMasterPrivateKey) - err = testkey.UnmarshalASN1(kb) - if err != nil { - return nil, err - } - return testkey, nil -} - -// SM9 Appendix C -func TestWrapKeySM9Sample(t *testing.T) { - expectedMasterPublicKey := "787ed7b8a51f3ab84e0a66003f32da5c720b17eca7137d39abc66e3c80a892ff769de61791e5adc4b9ff85a31354900b202871279a8c49dc3f220f644c57a7b1" - expectedUserPrivateKey := "94736acd2c8c8796cc4785e938301a139a059d3537b6414140b2d31eecf41683115bae85f5d8bc6c3dbd9e5342979acccf3c2f4f28420b1cb4f8c0b59a19b1587aa5e47570da7600cd760a0cf7beaf71c447f3844753fe74fa7ba92ca7d3b55f27538a62e7f7bfb51dce08704796d94c9d56734f119ea44732b50e31cdeb75c1" - expectedUserPublicKey := "709d165808b0a43e2574e203fa885abcbab16a240c4c1916552e7c43d09763b8693269a6be2456f43333758274786b6051ff87b7f198da4ba1a2c6e336f51fcc" - expectedCipher := "1edee2c3f465914491de44cefb2cb434ab02c308d9dc5e2067b4fed5aaac8a0f1c9b4c435eca35ab83bb734174c0f78fde81a53374aff3b3602bbc5e37be9a4c" - expectedKey := "4ff5cf86d2ad40c8f4bac98d76abdbde0c0e2f0a829d3f911ef5b2bce0695480" - - masterKey, err := encryptMasterPrivateKeyFromHex("01EDEE3778F441F8DEA3D9FA0ACC4E07EE36C93F9A08618AF4AD85CEDE1C22") - if err != nil { - t.Fatal(err) - } - if hex.EncodeToString(masterKey.MasterPublicKey.Marshal()) != expectedMasterPublicKey { - t.Errorf("not expected master public key") - } - - uid := []byte("Bob") - hid := byte(0x03) - - userKey, err := masterKey.GenerateUserKey(uid, hid) - if err != nil { - t.Fatal(err) - } - if hex.EncodeToString(userKey.PrivateKey.Marshal()) != expectedUserPrivateKey { - t.Errorf("not expected user private key") - } - - q := masterKey.Public().GenerateUserPublicKey(uid, hid) - if hex.EncodeToString(q.Marshal()) != expectedUserPublicKey { - t.Errorf("not expected user public key") - } - - var r *big.Int = bigFromHex("74015F8489C01EF4270456F9E6475BFB602BDE7F33FD482AB4E3684A6722") - cipher, err := new(bn256.G1).ScalarMult(q, bn256.NormalizeScalar(r.Bytes())) - if err != nil { - t.Fatal(err) - } - if hex.EncodeToString(cipher.Marshal()) != expectedCipher { - t.Errorf("not expected cipher") - } - - g := bn256.Pair(masterKey.Public().MasterPublicKey, bn256.Gen2) - w := new(bn256.GT).ScalarMult(g, r) - - var buffer []byte - buffer = append(buffer, cipher.Marshal()...) - buffer = append(buffer, w.Marshal()...) - buffer = append(buffer, uid...) - - key := sm3.Kdf(buffer, 32) - - if hex.EncodeToString(key) != expectedKey { - t.Errorf("expected %v, got %v\n", expectedKey, hex.EncodeToString(key)) - } - - key2, err := UnwrapKey(userKey, uid, cipher, 32) - if err != nil { - t.Fatal(err) - } - if hex.EncodeToString(key2) != expectedKey { - t.Errorf("expected %v, got %v\n", expectedKey, hex.EncodeToString(key2)) - } -} - -// SM9 Appendix D -func TestEncryptSM9Sample(t *testing.T) { - plaintext := []byte("Chinese IBE standard") - expectedMasterPublicKey := "787ed7b8a51f3ab84e0a66003f32da5c720b17eca7137d39abc66e3c80a892ff769de61791e5adc4b9ff85a31354900b202871279a8c49dc3f220f644c57a7b1" - expectedUserPrivateKey := "94736acd2c8c8796cc4785e938301a139a059d3537b6414140b2d31eecf41683115bae85f5d8bc6c3dbd9e5342979acccf3c2f4f28420b1cb4f8c0b59a19b1587aa5e47570da7600cd760a0cf7beaf71c447f3844753fe74fa7ba92ca7d3b55f27538a62e7f7bfb51dce08704796d94c9d56734f119ea44732b50e31cdeb75c1" - expectedUserPublicKey := "709d165808b0a43e2574e203fa885abcbab16a240c4c1916552e7c43d09763b8693269a6be2456f43333758274786b6051ff87b7f198da4ba1a2c6e336f51fcc" - expectedCipher := "2445471164490618e1ee20528ff1d545b0f14c8bcaa44544f03dab5dac07d8ff42ffca97d57cddc05ea405f2e586feb3a6930715532b8000759f13059ed59ac0" - expectedKey := "58373260f067ec48667c21c144f8bc33cd3049788651ffd5f738003e51df31174d0e4e402fd87f4581b612f74259db574f67ece6" - expectedCiphertext := "2445471164490618e1ee20528ff1d545b0f14c8bcaa44544f03dab5dac07d8ff42ffca97d57cddc05ea405f2e586feb3a6930715532b8000759f13059ed59ac0ba672387bcd6de5016a158a52bb2e7fc429197bcab70b25afee37a2b9db9f3671b5f5b0e951489682f3e64e1378cdd5da9513b1c" - - masterKey, err := encryptMasterPrivateKeyFromHex("01EDEE3778F441F8DEA3D9FA0ACC4E07EE36C93F9A08618AF4AD85CEDE1C22") - if err != nil { - t.Fatal(err) - } - if hex.EncodeToString(masterKey.MasterPublicKey.Marshal()) != expectedMasterPublicKey { - t.Errorf("not expected master public key") - } - - uid := []byte("Bob") - hid := byte(0x03) - - userKey, err := masterKey.GenerateUserKey(uid, hid) - if err != nil { - t.Fatal(err) - } - if hex.EncodeToString(userKey.PrivateKey.Marshal()) != expectedUserPrivateKey { - t.Errorf("not expected user private key") - } - - q := masterKey.Public().GenerateUserPublicKey(uid, hid) - if hex.EncodeToString(q.Marshal()) != expectedUserPublicKey { - t.Errorf("not expected user public key") - } - - var r *big.Int = bigFromHex("AAC0541779C8FC45E3E2CB25C12B5D2576B2129AE8BB5EE2CBE5EC9E785C") - cipher, err := new(bn256.G1).ScalarMult(q, bn256.NormalizeScalar(r.Bytes())) - if err != nil { - t.Fatal(err) - } - if hex.EncodeToString(cipher.Marshal()) != expectedCipher { - t.Errorf("not expected cipher") - } - - g := bn256.Pair(masterKey.Public().MasterPublicKey, bn256.Gen2) - w := new(bn256.GT).ScalarMult(g, r) - - var buffer []byte - buffer = append(buffer, cipher.Marshal()...) - buffer = append(buffer, w.Marshal()...) - buffer = append(buffer, uid...) - - key := sm3.Kdf(buffer, len(plaintext)+32) - - if hex.EncodeToString(key) != expectedKey { - t.Errorf("not expected key") - } - subtle.XORBytes(key, key[:len(plaintext)], plaintext) - - hash := sm3.New() - hash.Write(key) - c3 := hash.Sum(nil) - - ciphertext := append(cipher.Marshal(), c3...) - ciphertext = append(ciphertext, key[:len(plaintext)]...) - if hex.EncodeToString(ciphertext) != expectedCiphertext { - t.Errorf("expected %v, got %v\n", expectedCiphertext, hex.EncodeToString(ciphertext)) - } -} - -func TestEncryptSM9SampleBlockMode(t *testing.T) { - plaintext := []byte("Chinese IBE standard") - expectedMasterPublicKey := "787ed7b8a51f3ab84e0a66003f32da5c720b17eca7137d39abc66e3c80a892ff769de61791e5adc4b9ff85a31354900b202871279a8c49dc3f220f644c57a7b1" - expectedUserPrivateKey := "94736acd2c8c8796cc4785e938301a139a059d3537b6414140b2d31eecf41683115bae85f5d8bc6c3dbd9e5342979acccf3c2f4f28420b1cb4f8c0b59a19b1587aa5e47570da7600cd760a0cf7beaf71c447f3844753fe74fa7ba92ca7d3b55f27538a62e7f7bfb51dce08704796d94c9d56734f119ea44732b50e31cdeb75c1" - expectedUserPublicKey := "709d165808b0a43e2574e203fa885abcbab16a240c4c1916552e7c43d09763b8693269a6be2456f43333758274786b6051ff87b7f198da4ba1a2c6e336f51fcc" - expectedCipher := "2445471164490618e1ee20528ff1d545b0f14c8bcaa44544f03dab5dac07d8ff42ffca97d57cddc05ea405f2e586feb3a6930715532b8000759f13059ed59ac0" - expectedKey := "58373260f067ec48667c21c144f8bc33cd3049788651ffd5f738003e51df31174d0e4e402fd87f4581b612f74259db57" - expectedCiphertext := "2445471164490618e1ee20528ff1d545b0f14c8bcaa44544f03dab5dac07d8ff42ffca97d57cddc05ea405f2e586feb3a6930715532b8000759f13059ed59ac0fd3c98dd92c44c68332675a370cceede31e0c5cd209c257601149d12b394a2bee05b6fac6f11b965268c994f00dba7a8bb00fd60583546cbdf4649250863f10a" - - masterKey, err := encryptMasterPrivateKeyFromHex("01EDEE3778F441F8DEA3D9FA0ACC4E07EE36C93F9A08618AF4AD85CEDE1C22") - if err != nil { - t.Fatal(err) - } - if hex.EncodeToString(masterKey.MasterPublicKey.Marshal()) != expectedMasterPublicKey { - t.Errorf("not expected master public key") - } - - uid := []byte("Bob") - hid := byte(0x03) - - userKey, err := masterKey.GenerateUserKey(uid, hid) - if err != nil { - t.Fatal(err) - } - if hex.EncodeToString(userKey.PrivateKey.Marshal()) != expectedUserPrivateKey { - t.Errorf("not expected user private key") - } - - q := masterKey.Public().GenerateUserPublicKey(uid, hid) - if hex.EncodeToString(q.Marshal()) != expectedUserPublicKey { - t.Errorf("not expected user public key") - } - - var r *big.Int = bigFromHex("AAC0541779C8FC45E3E2CB25C12B5D2576B2129AE8BB5EE2CBE5EC9E785C") - cipher, err := new(bn256.G1).ScalarMult(q, bn256.NormalizeScalar(r.Bytes())) - if err != nil { - t.Fatal(err) - } - if hex.EncodeToString(cipher.Marshal()) != expectedCipher { - t.Errorf("not expected cipher") - } - - g := bn256.Pair(masterKey.Public().MasterPublicKey, bn256.Gen2) - w := new(bn256.GT).ScalarMult(g, r) - - var buffer []byte - buffer = append(buffer, cipher.Marshal()...) - buffer = append(buffer, w.Marshal()...) - buffer = append(buffer, uid...) - - key := sm3.Kdf(buffer, 16+32) - - if hex.EncodeToString(key) != expectedKey { - t.Errorf("not expected key, expected %v, got %x\n", expectedKey, key) - } - - c2, err := SM4ECBEncrypterOpts.Encrypt(nil, key[:16], plaintext) - if err != nil { - t.Fatal(err) - } - hash := sm3.New() - hash.Write(c2) - hash.Write(key[16:]) - c3 := hash.Sum(nil) - - ciphertext := append(cipher.Marshal(), c3...) - ciphertext = append(ciphertext, c2...) - if hex.EncodeToString(ciphertext) != expectedCiphertext { - t.Errorf("expected %v, got %v\n", expectedCiphertext, hex.EncodeToString(ciphertext)) + if !bytes.Equal(key1, key2) { + t.Errorf("expected %x, got %x", key1, key2) } } @@ -817,6 +209,148 @@ func TestEncryptDecryptASN1(t *testing.T) { } } +func TestUnmarshalSM9KeyPackage(t *testing.T) { + masterKey, err := GenerateEncryptMasterKey(rand.Reader) + hid := byte(0x01) + uid := []byte("emmansun") + if err != nil { + t.Fatal(err) + } + userKey, err := masterKey.GenerateUserKey(uid, hid) + if err != nil { + t.Fatal(err) + } + p, err := masterKey.Public().WrapKeyASN1(rand.Reader, uid, hid, 16) + if err != nil { + t.Fatal(err) + } + + key, cipher, err := UnmarshalSM9KeyPackage(p) + if err != nil { + t.Fatal(err) + } + + key2, err := UnwrapKey(userKey, uid, cipher, 16) + if err != nil { + t.Fatal(err) + } + + if hex.EncodeToString(key) != hex.EncodeToString(key2) { + t.Errorf("expected %v, got %v\n", hex.EncodeToString(key), hex.EncodeToString(key2)) + } +} + +func TestKeyExchange(t *testing.T) { + hid := byte(0x02) + userA := []byte("Alice") + userB := []byte("Bob") + masterKey, err := GenerateEncryptMasterKey(rand.Reader) + if err != nil { + t.Fatal(err) + } + + userKey, err := masterKey.GenerateUserKey(userA, hid) + if err != nil { + t.Fatal(err) + } + initiator := userKey.NewKeyExchange(userA, userB, 16, true) + + userKey, err = masterKey.GenerateUserKey(userB, hid) + if err != nil { + t.Fatal(err) + } + responder := userKey.NewKeyExchange(userB, userA, 16, true) + defer func() { + initiator.Destroy() + responder.Destroy() + }() + // A1-A4 + rA, err := initiator.InitKeyExchange(rand.Reader, hid) + if err != nil { + t.Fatal(err) + } + + // B1 - B7 + rB, sigB, err := responder.RespondKeyExchange(rand.Reader, hid, rA) + if err != nil { + t.Fatal(err) + } + + // A5 -A8 + key1, sigA, err := initiator.ConfirmResponder(rB, sigB) + if err != nil { + t.Fatal(err) + } + + // B8 + key2, err := responder.ConfirmInitiator(sigA) + if err != nil { + t.Fatal(err) + } + + if hex.EncodeToString(key1) != hex.EncodeToString(key2) { + t.Errorf("got different key") + } +} + +func TestKeyExchangeWithoutSignature(t *testing.T) { + hid := byte(0x02) + userA := []byte("Alice") + userB := []byte("Bob") + masterKey, err := GenerateEncryptMasterKey(rand.Reader) + if err != nil { + t.Fatal(err) + } + + userKey, err := masterKey.GenerateUserKey(userA, hid) + if err != nil { + t.Fatal(err) + } + initiator := userKey.NewKeyExchange(userA, userB, 16, false) + + userKey, err = masterKey.GenerateUserKey(userB, hid) + if err != nil { + t.Fatal(err) + } + responder := userKey.NewKeyExchange(userB, userA, 16, false) + defer func() { + initiator.Destroy() + responder.Destroy() + }() + // A1-A4 + rA, err := initiator.InitKeyExchange(rand.Reader, hid) + if err != nil { + t.Fatal(err) + } + + // B1 - B7 + rB, sigB, err := responder.RespondKeyExchange(rand.Reader, hid, rA) + if err != nil { + t.Fatal(err) + } + if len(sigB) != 0 { + t.Errorf("should no signature") + } + + // A5 -A8 + key1, sigA, err := initiator.ConfirmResponder(rB, sigB) + if err != nil { + t.Fatal(err) + } + if len(sigA) != 0 { + t.Errorf("should no signature") + } + + key2, err := responder.ConfirmInitiator(nil) + if err != nil { + t.Fatal(err) + } + + if hex.EncodeToString(key1) != hex.EncodeToString(key2) { + t.Errorf("got different key") + } +} + func BenchmarkSign(b *testing.B) { hashed := []byte("Chinese IBS standard") uid := []byte("emmansun") diff --git a/smx509/pkcs8_test.go b/smx509/pkcs8_test.go index d143072..95c74bb 100644 --- a/smx509/pkcs8_test.go +++ b/smx509/pkcs8_test.go @@ -219,8 +219,7 @@ func TestMarshalPKCS8SM9SignPrivateKey(t *testing.T) { if !ok { t.Fatalf("not expected key") } - if !privateKey.PrivateKey.Equal(privateKey2.PrivateKey) || - !privateKey.MasterPublicKey.Equal(privateKey2.MasterPublicKey) { + if !privateKey.Equal(privateKey2) { t.Fatalf("not same key") } } @@ -246,8 +245,7 @@ func TestMarshalPKCS8SM9EncPrivateKey(t *testing.T) { if !ok { t.Fatalf("not expected key") } - if !privateKey.PrivateKey.Equal(privateKey2.PrivateKey) || - !privateKey.MasterPublicKey.Equal(privateKey2.MasterPublicKey) { + if !privateKey.Equal(privateKey2) { t.Fatalf("not same key") } } @@ -269,8 +267,8 @@ func TestMarshalPKCS8SM9SignMasterPrivateKey(t *testing.T) { if !ok { t.Fatalf("not expected key") } - masterKey2.MasterPublicKey.Marshal() - if !(masterKey.D.Cmp(masterKey2.D) == 0 && masterKey.MasterPublicKey.Equal(masterKey2.MasterPublicKey)) { + + if !masterKey.Equal(masterKey2) { t.Fatalf("not same key") } } @@ -292,8 +290,7 @@ func TestMarshalPKCS8SM9EncMasterPrivateKey(t *testing.T) { if !ok { t.Fatalf("not expected key") } - masterKey2.MasterPublicKey.Marshal() - if !(masterKey.D.Cmp(masterKey2.D) == 0 && masterKey.MasterPublicKey.Equal(masterKey2.MasterPublicKey)) { + if !masterKey.Equal(masterKey2) { t.Fatalf("not same key") } }