diff --git a/sm9/sm9.go b/sm9/sm9.go index 1e4b336..419750a 100644 --- a/sm9/sm9.go +++ b/sm9/sm9.go @@ -16,6 +16,8 @@ import ( "golang.org/x/crypto/cryptobyte/asn1" ) +// SM9 ASN.1 format reference: Information security technology - SM9 cryptographic algorithm application specification + var bigOne = big.NewInt(1) type hashMode byte @@ -84,6 +86,7 @@ func randFieldElement(rand io.Reader) (k *big.Int, err error) { return } +// Pair generate the basepoint once func (pub *SignMasterPublicKey) Pair() *GT { pub.pairOnce.Do(func() { pub.basePoint = Pair(Gen1, pub.MasterPublicKey) @@ -116,6 +119,7 @@ func (pub *SignMasterPublicKey) generatorTable() *[32 * 2]gtTable { return pub.table } +// ScalarBaseMult compute basepoint^r with precomputed table func (pub *SignMasterPublicKey) ScalarBaseMult(r *big.Int) *GT { scalar := normalizeScalar(r.Bytes()) tables := pub.generatorTable() @@ -176,6 +180,7 @@ func Sign(rand io.Reader, priv *SignPrivateKey, hash []byte) (h *big.Int, s *G1, // 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 result is SM9Signature ASN.1 format. func (priv *SignPrivateKey) Sign(rand io.Reader, hash []byte, opts crypto.SignerOpts) ([]byte, error) { h, s, err := Sign(rand, priv, hash) if err != nil { @@ -194,7 +199,7 @@ func (priv *SignPrivateKey) Sign(rand io.Reader, hash []byte, opts crypto.Signer } // SignASN1 signs a hash (which should be the result of hashing a larger message) -// using the private key, priv. It returns the ASN.1 encoded signature. +// using the private key, priv. It returns the ASN.1 encoded signature of type SM9Signature. func SignASN1(rand io.Reader, priv *SignPrivateKey, hash []byte) ([]byte, error) { return priv.Sign(rand, hash, nil) } @@ -225,7 +230,7 @@ func Verify(pub *SignMasterPublicKey, uid []byte, hid byte, hash []byte, h *big. return h.Cmp(h2) == 0 } -// VerifyASN1 verifies the ASN.1 encoded signature, sig, of hash using the +// VerifyASN1 verifies the ASN.1 encoded signature of type SM9Signature, sig, of hash using the // public key, pub. Its return value records whether the signature is valid. func VerifyASN1(pub *SignMasterPublicKey, uid []byte, hid byte, hash, sig []byte) bool { var ( @@ -260,6 +265,7 @@ func (pub *SignMasterPublicKey) Verify(uid []byte, hid byte, hash, sig []byte) b return VerifyASN1(pub, uid, hid, hash, sig) } +// Pair generate the basepoint once func (pub *EncryptMasterPublicKey) Pair() *GT { pub.pairOnce.Do(func() { pub.basePoint = Pair(pub.MasterPublicKey, Gen2) @@ -292,6 +298,7 @@ func (pub *EncryptMasterPublicKey) generatorTable() *[32 * 2]gtTable { return pub.table } +// ScalarBaseMult compute basepoint^r with precomputed table func (pub *EncryptMasterPublicKey) ScalarBaseMult(r *big.Int) *GT { scalar := normalizeScalar(r.Bytes()) tables := pub.generatorTable() @@ -346,7 +353,7 @@ func WrapKey(rand io.Reader, pub *EncryptMasterPublicKey, uid []byte, hid byte, return } -// WrapKey wrap key and marshal the cipher as ASN1 format. +// WrapKey wrap key and marshal the cipher as ASN1 format, SM9PublicKey1 definition. func (pub *EncryptMasterPublicKey) WrapKey(rand io.Reader, uid []byte, hid byte, kLen int) ([]byte, []byte, error) { key, cipher, err := WrapKey(rand, pub, uid, hid, kLen) if err != nil { @@ -360,7 +367,7 @@ func (pub *EncryptMasterPublicKey) WrapKey(rand io.Reader, uid []byte, hid byte, } // WrapKeyASN1 wrap key and marshal the result of SM9KeyPackage as ASN1 format. according -// SM9 cryptographic algorithm application specification +// SM9 cryptographic algorithm application specification, SM9KeyPackage defnition. func (pub *EncryptMasterPublicKey) WrapKeyASN1(rand io.Reader, uid []byte, hid byte, kLen int) ([]byte, error) { key, cipher, err := WrapKey(rand, pub, uid, hid, kLen) if err != nil { @@ -416,6 +423,8 @@ func UnwrapKey(priv *EncryptPrivateKey, uid []byte, cipher *G1, kLen int) ([]byt return key, nil } +// UnwrapKey unwrap key from cipherDer, user id and aligned key length. +// cipherDer is SM9PublicKey1 format according SM9 cryptographic algorithm application specification. func (priv *EncryptPrivateKey) UnwrapKey(uid, cipherDer []byte, kLen int) ([]byte, error) { var bytes []byte input := cryptobyte.String(cipherDer) @@ -447,13 +456,13 @@ func Encrypt(rand io.Reader, pub *EncryptMasterPublicKey, uid []byte, hid byte, } // EncryptASN1 encrypt plaintext and output ciphertext with ASN.1 format according -// SM9 cryptographic algorithm application specification +// SM9 cryptographic algorithm application specification, SM9Cipher definition. func EncryptASN1(rand io.Reader, pub *EncryptMasterPublicKey, uid []byte, hid byte, plaintext []byte) ([]byte, error) { return pub.Encrypt(rand, uid, hid, plaintext) } // Encrypt encrypt plaintext and output ciphertext with ASN.1 format according -// SM9 cryptographic algorithm application specification +// SM9 cryptographic algorithm application specification, SM9Cipher definition. func (pub *EncryptMasterPublicKey) Encrypt(rand io.Reader, uid []byte, hid byte, plaintext []byte) ([]byte, error) { key, cipher, err := WrapKey(rand, pub, uid, hid, len(plaintext)+sm3.Size) if err != nil { @@ -504,7 +513,7 @@ func Decrypt(priv *EncryptPrivateKey, uid, ciphertext []byte) ([]byte, error) { } // DecryptASN1 decrypt chipher, ciphertext should be with ASN.1 format according -// SM9 cryptographic algorithm application specification +// SM9 cryptographic algorithm application specification, SM9Cipher definition. func DecryptASN1(priv *EncryptPrivateKey, uid, ciphertext []byte) ([]byte, error) { if len(ciphertext) <= 32+65 { return nil, errors.New("sm9: invalid ciphertext length") diff --git a/sm9/sm9_key.go b/sm9/sm9_key.go index 1798365..e43e7fe 100644 --- a/sm9/sm9_key.go +++ b/sm9/sm9_key.go @@ -9,40 +9,46 @@ import ( "golang.org/x/crypto/cryptobyte" ) +// SignMasterPrivateKey master private key for sign, generated by KGC type SignMasterPrivateKey struct { - SignMasterPublicKey - D *big.Int + SignMasterPublicKey // master public key + D *big.Int // master private key } +// SignMasterPublicKey master public key for sign, generated by KGC type SignMasterPublicKey struct { - MasterPublicKey *G2 + MasterPublicKey *G2 // master public key pairOnce sync.Once - basePoint *GT + basePoint *GT // the result of Pair(Gen1, pub.MasterPublicKey) tableGenOnce sync.Once - table *[32 * 2]gtTable + table *[32 * 2]gtTable // precomputed basePoint^n } +// SignPrivateKey user private key for sign, generated by KGC type SignPrivateKey struct { - PrivateKey *G1 - SignMasterPublicKey + PrivateKey *G1 // user private key + SignMasterPublicKey // master public key } +// EncryptMasterPrivateKey master private key for encryption, generated by KGC type EncryptMasterPrivateKey struct { - EncryptMasterPublicKey - D *big.Int + EncryptMasterPublicKey // master public key + D *big.Int // master private key } +// EncryptMasterPublicKey master private key for encryption, generated by KGC type EncryptMasterPublicKey struct { - MasterPublicKey *G1 + MasterPublicKey *G1 // public key pairOnce sync.Once - basePoint *GT + basePoint *GT // the result of Pair(pub.MasterPublicKey, Gen2) tableGenOnce sync.Once - table *[32 * 2]gtTable + table *[32 * 2]gtTable // precomputed basePoint^n } +// EncryptPrivateKey user private key for encryption, generated by KGC type EncryptPrivateKey struct { - PrivateKey *G2 - EncryptMasterPublicKey + PrivateKey *G2 // user private key + EncryptMasterPublicKey // master public key } // GenerateSignMasterKey generates a master public and private key pair for DSA usage. diff --git a/sm9/sm9_key_test.go b/sm9/sm9_key_test.go index 10b6ac2..cfd1c2e 100644 --- a/sm9/sm9_key_test.go +++ b/sm9/sm9_key_test.go @@ -39,7 +39,9 @@ func TestSignMasterPublicKeyMarshalASN1(t *testing.T) { if err != nil { t.Fatal(err) } - if masterKey.MasterPublicKey.p.x != pub2.MasterPublicKey.p.x || masterKey.MasterPublicKey.p.y != pub2.MasterPublicKey.p.y || masterKey.MasterPublicKey.p.z != pub2.MasterPublicKey.p.z { + if masterKey.MasterPublicKey.p.x != pub2.MasterPublicKey.p.x || + masterKey.MasterPublicKey.p.y != pub2.MasterPublicKey.p.y || + masterKey.MasterPublicKey.p.z != pub2.MasterPublicKey.p.z { t.Errorf("not same") } } @@ -64,7 +66,8 @@ func TestSignUserPrivateKeyMarshalASN1(t *testing.T) { if err != nil { t.Fatal(err) } - if userKey.PrivateKey.p.x != userKey2.PrivateKey.p.x || userKey.PrivateKey.p.y != userKey2.PrivateKey.p.y { + if userKey.PrivateKey.p.x != userKey2.PrivateKey.p.x || + userKey.PrivateKey.p.y != userKey2.PrivateKey.p.y { t.Errorf("not same") } } @@ -102,7 +105,8 @@ func TestEncryptMasterPublicKeyMarshalASN1(t *testing.T) { if err != nil { t.Fatal(err) } - if masterKey.MasterPublicKey.p.x != pub2.MasterPublicKey.p.x || masterKey.MasterPublicKey.p.y != pub2.MasterPublicKey.p.y { + if masterKey.MasterPublicKey.p.x != pub2.MasterPublicKey.p.x || + masterKey.MasterPublicKey.p.y != pub2.MasterPublicKey.p.y { t.Errorf("not same") } } @@ -127,7 +131,9 @@ func TestEncryptUserPrivateKeyMarshalASN1(t *testing.T) { if err != nil { t.Fatal(err) } - if userKey.PrivateKey.p.x != userKey2.PrivateKey.p.x || userKey.PrivateKey.p.y != userKey2.PrivateKey.p.y || userKey.PrivateKey.p.z != userKey2.PrivateKey.p.z { + if userKey.PrivateKey.p.x != userKey2.PrivateKey.p.x || + userKey.PrivateKey.p.y != userKey2.PrivateKey.p.y || + userKey.PrivateKey.p.z != userKey2.PrivateKey.p.z { t.Errorf("not same") } } diff --git a/sm9/sm9_test.go b/sm9/sm9_test.go index 774cfae..5c6bba4 100644 --- a/sm9/sm9_test.go +++ b/sm9/sm9_test.go @@ -78,6 +78,45 @@ func TestSignASN1(t *testing.T) { } } +// SM9 Appendix A +func TestSignSM9Sample(t *testing.T) { + expectedH := bigFromHex("823c4b21e4bd2dfe1ed92c606653e996668563152fc33f55d7bfbb9bd9705adb") + expectedS := "0473bf96923ce58b6ad0e13e9643a406d8eb98417c50ef1b29cef9adb48b6d598c856712f1c2e0968ab7769f42a99586aed139d5b8b3e15891827cc2aced9baa05" + hash := []byte("Chinese IBS standard") + hid := byte(0x01) + uid := []byte("Alice") + r := bigFromHex("033c8616b06704813203dfd00965022ed15975c662337aed648835dc4b1cbe") + masterKey := new(SignMasterPrivateKey) + masterKey.D = bigFromHex("0130E78459D78545CB54C587E02CF480CE0B66340F319F348A1D5B1F2DC5F4") + masterKey.MasterPublicKey = new(G2).ScalarBaseMult(masterKey.D) + userKey, err := masterKey.GenerateUserKey(uid, hid) + if err != nil { + t.Fatal(err) + } + w := userKey.SignMasterPublicKey.ScalarBaseMult(r) + + var buffer []byte + buffer = append(buffer, hash...) + buffer = append(buffer, w.Marshal()...) + + h := hashH2(buffer) + if h.Cmp(expectedH) != 0 { + t.Fatal("not same h") + } + + l := new(big.Int).Sub(r, h) + + if l.Sign() < 0 { + l.Add(l, Order) + } + + s := new(G1).ScalarMult(userKey.PrivateKey, l) + + if hex.EncodeToString(s.MarshalUncompressed()) != expectedS { + t.Fatal("not same S") + } +} + func TestWrapKey(t *testing.T) { masterKey, err := GenerateEncryptMasterKey(rand.Reader) hid := byte(0x01) @@ -161,6 +200,7 @@ func TestUnmarshalSM9KeyPackage(t *testing.T) { } } +// SM9 Appendix C func TestWrapKeySM9Sample(t *testing.T) { expectedKey := "4ff5cf86d2ad40c8f4bac98d76abdbde0c0e2f0a829d3f911ef5b2bce0695480" masterKey := new(EncryptMasterPrivateKey) @@ -209,6 +249,7 @@ func TestWrapKeySM9Sample(t *testing.T) { } } +// SM9 Appendix D func TestEncryptSM9Sample(t *testing.T) { plaintext := []byte("Chinese IBE standard") expectedCiphertext := "2445471164490618e1ee20528ff1d545b0f14c8bcaa44544f03dab5dac07d8ff42ffca97d57cddc05ea405f2e586feb3a6930715532b8000759f13059ed59ac0ba672387bcd6de5016a158a52bb2e7fc429197bcab70b25afee37a2b9db9f3671b5f5b0e951489682f3e64e1378cdd5da9513b1c"