mirror of
https://github.com/emmansun/gmsm.git
synced 2025-05-12 03:56:17 +08:00
SM9: add key exchange support
This commit is contained in:
parent
81c0dbb0fa
commit
410b1eea3a
@ -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
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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()
|
||||
}
|
||||
|
185
sm9/sm9.go
185
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
|
||||
}
|
||||
|
@ -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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user