diff --git a/sm9/bn256/curve.go b/sm9/bn256/curve.go index ce0ca7b..b0db358 100644 --- a/sm9/bn256/curve.go +++ b/sm9/bn256/curve.go @@ -44,7 +44,7 @@ func (c *curvePoint) polynomial(x *gfP) *gfP { return x3 } -// IsOnCurve returns true iff c is on the curve. +// IsOnCurve returns true if c is on the curve. func (c *curvePoint) IsOnCurve() bool { c.MakeAffine() if c.IsInfinity() { // TBC: This is not same as golang elliptic diff --git a/sm9/bn256/g1.go b/sm9/bn256/g1.go index c846dfd..769ef17 100644 --- a/sm9/bn256/g1.go +++ b/sm9/bn256/g1.go @@ -333,6 +333,7 @@ func (e *G1) Unmarshal(m []byte) ([]byte, error) { return m[2*numBytes:], nil } +// Equal compare e and other func (e *G1) Equal(other *G1) bool { if e.p == nil && other.p == nil { return true @@ -343,6 +344,7 @@ func (e *G1) Equal(other *G1) bool { e.p.t == other.p.t } +// IsOnCurve returns true if e is on the curve. func (e *G1) IsOnCurve() bool { return e.p.IsOnCurve() } diff --git a/sm9/bn256/g2.go b/sm9/bn256/g2.go index 2753624..d60280c 100644 --- a/sm9/bn256/g2.go +++ b/sm9/bn256/g2.go @@ -318,6 +318,7 @@ func (e *G2) Unmarshal(m []byte) ([]byte, error) { return m[4*numBytes:], nil } +// Equal compare e and other func (e *G2) Equal(other *G2) bool { if e.p == nil && other.p == nil { return true @@ -328,6 +329,7 @@ func (e *G2) Equal(other *G2) bool { e.p.t == other.p.t } +// IsOnCurve returns true if e is on the twist curve. func (e *G2) IsOnCurve() bool { return e.p.IsOnCurve() } diff --git a/sm9/sm9.go b/sm9/sm9.go index fe5e4a4..2e1fdd4 100644 --- a/sm9/sm9.go +++ b/sm9/sm9.go @@ -485,3 +485,188 @@ func DecryptASN1(priv *EncryptPrivateKey, uid, ciphertext []byte) ([]byte, error xor.XorBytes(key, c2Bytes, key[:len(c2Bytes)]) return key[:len(c2Bytes)], nil } + +// Decrypt decrypt chipher, ciphertext should be with ASN.1 format according +// SM9 cryptographic algorithm application specification, SM9Cipher definition. +func (priv *EncryptPrivateKey) Decrypt(uid, ciphertext []byte) ([]byte, error) { + if ciphertext[0] == 0x30 { // should be ASN.1 format + return DecryptASN1(priv, uid, ciphertext) + } + // fallback to C1||C3||C2 raw format + return Decrypt(priv, uid, ciphertext) +} + +// KeyExchange key exchange struct, include internal stat in whole key exchange flow. +type KeyExchange struct { + genSignature bool + keyLength int + privateKey *EncryptPrivateKey + uid []byte + peerUID []byte + r *big.Int + secret *bn256.G1 + peerSecret *bn256.G1 + g1 *bn256.GT + g2 *bn256.GT + g3 *bn256.GT + key []byte +} + +// NewKeyExchange create 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 +} + +// GetKey return key after key alignment +func (ke *KeyExchange) GetKey() []byte { + return ke.key +} + +func initKeyExchange(ke *KeyExchange, hid byte, r *big.Int) { + pubB := ke.privateKey.GenerateUserPublicKey(ke.peerUID, hid) + ke.r = r + rA := new(bn256.G1).ScalarMult(pubB, ke.r) + ke.secret = rA +} + +// InitKeyExchange generate random with responder uid, for initiator's step A1-A4 +func (ke *KeyExchange) InitKeyExchange(rand io.Reader, hid byte) (*bn256.G1, error) { + r, err := randFieldElement(rand) + if err != nil { + return nil, err + } + initKeyExchange(ke, hid, r) + return ke.secret, nil +} + +func respondKeyExchange(ke *KeyExchange, hid byte, r *big.Int, rA *bn256.G1) (*bn256.G1, []byte, error) { + if !rA.IsOnCurve() { + return nil, nil, errors.New("SM9: received invalid random from initiator") + } + ke.peerSecret = rA + pubA := ke.privateKey.GenerateUserPublicKey(ke.peerUID, hid) + ke.r = r + rB := new(bn256.G1).ScalarMult(pubA, r) + ke.secret = rB + + ke.g1 = bn256.Pair(ke.peerSecret, ke.privateKey.PrivateKey) + ke.g3 = &bn256.GT{} + ke.g3.ScalarMult(ke.g1, r) + ke.g2 = ke.privateKey.EncryptMasterPublicKey.ScalarBaseMult(r) + + var buffer []byte + buffer = append(buffer, ke.peerUID...) + buffer = append(buffer, ke.uid...) + buffer = append(buffer, ke.peerSecret.Marshal()...) + buffer = append(buffer, ke.secret.Marshal()...) + buffer = append(buffer, ke.g1.Marshal()...) + buffer = append(buffer, ke.g2.Marshal()...) + buffer = append(buffer, ke.g3.Marshal()...) + + key, _ := sm3.Kdf(buffer, ke.keyLength) + ke.key = key + + if !ke.genSignature { + return ke.secret, nil, nil + } + + hash := sm3.New() + hash.Write(ke.g2.Marshal()) + hash.Write(ke.g3.Marshal()) + hash.Write(ke.peerUID) + hash.Write(ke.uid) + hash.Write(ke.peerSecret.Marshal()) + hash.Write(ke.secret.Marshal()) + buffer = hash.Sum(nil) + hash.Reset() + hash.Write([]byte{0x82}) + hash.Write(ke.g1.Marshal()) + hash.Write(buffer) + buffer = hash.Sum(nil) + return ke.secret, buffer, 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 := randFieldElement(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 *bn256.G1, sB []byte) ([]byte, error) { + hash := sm3.New() + // step 5 + ke.peerSecret = rB + ke.g1 = ke.privateKey.EncryptMasterPublicKey.ScalarBaseMult(ke.r) + ke.g2 = bn256.Pair(ke.peerSecret, ke.privateKey.PrivateKey) + ke.g3 = &bn256.GT{} + ke.g3.ScalarMult(ke.g2, ke.r) + // step 6, verify signature + var temp []byte + var buffer []byte + if len(sB) > 0 { + hash.Write(ke.g2.Marshal()) + hash.Write(ke.g3.Marshal()) + hash.Write(ke.uid) + hash.Write(ke.peerUID) + hash.Write(ke.secret.Marshal()) + hash.Write(ke.peerSecret.Marshal()) + temp = hash.Sum(nil) + hash.Reset() + hash.Write([]byte{0x82}) + hash.Write(ke.g1.Marshal()) + hash.Write(temp) + signature := hash.Sum(nil) + hash.Reset() + if goSubtle.ConstantTimeCompare(signature, sB) != 1 { + return nil, errors.New("sm9: verify signature fail") + } + } + 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()...) + + key, _ := sm3.Kdf(buffer, ke.keyLength) + ke.key = key + + hash.Write([]byte{0x83}) + hash.Write(ke.g1.Marshal()) + hash.Write(temp) + + return hash.Sum(nil), nil +} + +// ConfirmInitiator for responder's step B8 +func (ke *KeyExchange) ConfirmInitiator(s1 []byte) error { + hash := sm3.New() + var buffer []byte + hash.Write(ke.g2.Marshal()) + hash.Write(ke.g3.Marshal()) + hash.Write(ke.peerUID) + hash.Write(ke.uid) + hash.Write(ke.peerSecret.Marshal()) + hash.Write(ke.secret.Marshal()) + buffer = hash.Sum(nil) + hash.Reset() + hash.Write([]byte{0x83}) + hash.Write(ke.g1.Marshal()) + hash.Write(buffer) + buffer = hash.Sum(nil) + if goSubtle.ConstantTimeCompare(buffer, s1) != 1 { + return errors.New("sm9: verify signature fail") + } + return nil +} diff --git a/sm9/sm9_test.go b/sm9/sm9_test.go index 753655f..29f7c8a 100644 --- a/sm9/sm9_test.go +++ b/sm9/sm9_test.go @@ -126,6 +126,69 @@ func TestSignSM9Sample(t *testing.T) { } } +// SM9 Appendix B +func TestKeyExchangeSample(t *testing.T) { + hid := byte(0x02) + expectedKey := "c5c13a8f59a97cdeae64f16a2272a9e7" + expectedSignatureB := "3bb4bcee8139c960b4d6566db1e0d5f0b2767680e5e1bf934103e6c66e40ffee" + expectedSignatureA := "195d1b7256ba7e0e67c71202a25f8c94ff8241702c2f55d613ae1c6b98215172" + masterKey := new(EncryptMasterPrivateKey) + masterKey.D = bigFromHex("02E65B0762D042F51F0D23542B13ED8CFA2E9A0E7206361E013A283905E31F") + masterKey.MasterPublicKey = new(bn256.G1).ScalarBaseMult(masterKey.D) + fmt.Printf("Pub-e=%v\n", hex.EncodeToString(masterKey.MasterPublicKey.Marshal())) + + 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) + + // A1-A4 + initKeyExchange(initiator, hid, bigFromHex("5879DD1D51E175946F23B1B41E93BA31C584AE59A426EC1046A4D03B06C8")) + + if hex.EncodeToString(initiator.secret.Marshal()) != "7cba5b19069ee66aa79d490413d11846b9ba76dd22567f809cf23b6d964bb265a9760c99cb6f706343fed05637085864958d6c90902aba7d405fbedf7b781599" { + t.Fatal("not same") + } + + // B1 - B7 + rB, sigB, err := respondKeyExchange(responder, hid, bigFromHex("018B98C44BEF9F8537FB7D071B2C928B3BC65BD3D69E1EEE213564905634FE"), initiator.secret) + if err != nil { + t.Fatal(err) + } + if hex.EncodeToString(responder.key) != expectedKey { + t.Errorf("not expected key %v\n", hex.EncodeToString(responder.key)) + } + if hex.EncodeToString(sigB) != expectedSignatureB { + t.Errorf("not expected signature B") + } + + // A5 -A8 + sigA, err := initiator.ConfirmResponder(rB, sigB) + if err != nil { + t.Fatal(err) + } + if hex.EncodeToString(initiator.key) != expectedKey { + t.Errorf("not expected key %v\n", hex.EncodeToString(initiator.key)) + } + if hex.EncodeToString(sigA) != expectedSignatureA { + t.Errorf("not expected signature A") + } + // B8 + err = responder.ConfirmInitiator(sigA) + if err != nil { + t.Fatal(err) + } +} + func TestWrapKey(t *testing.T) { masterKey, err := GenerateEncryptMasterKey(rand.Reader) hid := byte(0x01)