SM9: add key exchange support

This commit is contained in:
Sun Yimin 2022-06-16 14:43:28 +08:00 committed by GitHub
parent 81c0dbb0fa
commit 410b1eea3a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 253 additions and 1 deletions

View File

@ -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

View File

@ -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()
}

View File

@ -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()
}

View File

@ -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
}

View File

@ -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)