From f310d7a9866f19cc5b3023d8c7c6dfe942eb2957 Mon Sep 17 00:00:00 2001 From: Andrea Maria Piana Date: Mon, 20 May 2019 11:54:31 +0200 Subject: [PATCH] Set up topic on sending --- services/shhext/chat/protocol.go | 9 +++++-- services/shhext/chat/topic/service.go | 30 ++++++++++++++-------- services/shhext/chat/topic/service_test.go | 12 ++++++--- 3 files changed, 34 insertions(+), 17 deletions(-) diff --git a/services/shhext/chat/protocol.go b/services/shhext/chat/protocol.go index 1b17277bed..327bf152c1 100644 --- a/services/shhext/chat/protocol.go +++ b/services/shhext/chat/protocol.go @@ -89,13 +89,14 @@ func (p *ProtocolService) BuildDirectMessage(myIdentityKey *ecdsa.PrivateKey, pu // across devices var installationIDs []string var sharedSecret []byte + var agreed bool for installationID := range protocolMessage.GetDirectMessage() { if installationID != noInstallationID { installationIDs = append(installationIDs, installationID) } } if len(installationIDs) != 0 { - sharedSecret, err = p.topic.Send(publicKey, installationIDs) + sharedSecret, agreed, err = p.topic.Send(myIdentityKey, p.encryption.config.InstallationID, publicKey, installationIDs) if err != nil { return nil, nil, err } @@ -106,7 +107,11 @@ func (p *ProtocolService) BuildDirectMessage(myIdentityKey *ecdsa.PrivateKey, pu p.onNewTopicHandler([][]byte{sharedSecret}) } - return msg, sharedSecret, nil + if agreed { + return msg, sharedSecret, nil + } else { + return msg, nil, nil + } } // BuildDHMessage builds a message with DH encryption so that it can be decrypted by any other device. diff --git a/services/shhext/chat/topic/service.go b/services/shhext/chat/topic/service.go index 34e2df7f45..def6efad6a 100644 --- a/services/shhext/chat/topic/service.go +++ b/services/shhext/chat/topic/service.go @@ -17,9 +17,8 @@ func NewService(persistence PersistenceService) *Service { return &Service{persistence: persistence} } -// Receive will generate a shared secret for a given identity, and return it -func (s *Service) Receive(myPrivateKey *ecdsa.PrivateKey, theirPublicKey *ecdsa.PublicKey, installationID string) ([]byte, error) { - log.Info("Receive called for", "installationID", installationID) +func (s *Service) setupTopic(myPrivateKey *ecdsa.PrivateKey, theirPublicKey *ecdsa.PublicKey, installationID string) ([]byte, error) { + log.Info("Setup topic called for", "installationID", installationID) sharedKey, err := ecies.ImportECDSA(myPrivateKey).GenerateShared( ecies.ImportECDSAPublic(theirPublicKey), sskLen, @@ -37,22 +36,31 @@ func (s *Service) Receive(myPrivateKey *ecdsa.PrivateKey, theirPublicKey *ecdsa. return sharedKey, err } -// Send returns a shared key if we have received a message from all the installationIDs -func (s *Service) Send(theirPublicKey *ecdsa.PublicKey, installationIDs []string) ([]byte, error) { - theirIdentity := crypto.CompressPubkey(theirPublicKey) +// Receive will generate a shared secret for a given identity, and return it +func (s *Service) Receive(myPrivateKey *ecdsa.PrivateKey, theirPublicKey *ecdsa.PublicKey, installationID string) ([]byte, error) { + return s.setupTopic(myPrivateKey, theirPublicKey, installationID) +} - response, err := s.persistence.Get(theirIdentity, installationIDs) +// Send returns a shared key and whether it has been acknowledged from all the installationIDs +func (s *Service) Send(myPrivateKey *ecdsa.PrivateKey, myInstallationID string, theirPublicKey *ecdsa.PublicKey, theirInstallationIDs []string) ([]byte, bool, error) { + sharedKey, err := s.setupTopic(myPrivateKey, theirPublicKey, myInstallationID) if err != nil { - return nil, err + return nil, false, err + } + + theirIdentity := crypto.CompressPubkey(theirPublicKey) + response, err := s.persistence.Get(theirIdentity, theirInstallationIDs) + if err != nil { + return nil, false, err } - for _, installationID := range installationIDs { + for _, installationID := range theirInstallationIDs { if !response.installationIDs[installationID] { - return nil, nil + return sharedKey, false, nil } } - return response.secret, nil + return response.secret, true, nil } func (s *Service) All() ([][]byte, error) { diff --git a/services/shhext/chat/topic/service_test.go b/services/shhext/chat/topic/service_test.go index 9eb4d49495..9accef7e40 100644 --- a/services/shhext/chat/topic/service_test.go +++ b/services/shhext/chat/topic/service_test.go @@ -37,6 +37,7 @@ func (s *ServiceTestSuite) TearDownTest() { } func (s *ServiceTestSuite) TestSingleInstallationID() { + ourInstallationID := "our" installationID1 := "1" installationID2 := "2" @@ -52,15 +53,17 @@ func (s *ServiceTestSuite) TestSingleInstallationID() { s.Require().NotNil(sharedKey1, "it generates a shared key") // We want to send a message to installationID1 - sharedKey2, err := s.service.Send(&theirKey.PublicKey, []string{installationID1}) + sharedKey2, agreed2, err := s.service.Send(myKey, ourInstallationID, &theirKey.PublicKey, []string{installationID1}) s.Require().NoError(err) + s.Require().True(agreed2) s.Require().NotNil(sharedKey2, "We can retrieve a shared secret") s.Require().Equal(sharedKey1, sharedKey2, "The shared secret is the same as the one stored") // We want to send a message to multiple installationIDs, one of which we haven't never communicated with - sharedKey3, err := s.service.Send(&theirKey.PublicKey, []string{installationID1, installationID2}) + sharedKey3, agreed3, err := s.service.Send(myKey, ourInstallationID, &theirKey.PublicKey, []string{installationID1, installationID2}) s.Require().NoError(err) - s.Require().Nil(sharedKey3, "No shared key is returned") + s.Require().NotNil(sharedKey3, "A shared key is returned") + s.Require().False(agreed3) // We receive a message from installationID2 sharedKey4, err := s.service.Receive(myKey, &theirKey.PublicKey, installationID2) @@ -69,9 +72,10 @@ func (s *ServiceTestSuite) TestSingleInstallationID() { s.Require().Equal(sharedKey1, sharedKey4, "It generates the same key") // We want to send a message to installationID 1 & 2, both have been - sharedKey5, err := s.service.Send(&theirKey.PublicKey, []string{installationID1, installationID2}) + sharedKey5, agreed5, err := s.service.Send(myKey, ourInstallationID, &theirKey.PublicKey, []string{installationID1, installationID2}) s.Require().NoError(err) s.Require().NotNil(sharedKey5, "We can retrieve a shared secret") + s.Require().True(agreed5) s.Require().Equal(sharedKey1, sharedKey5, "The shared secret is the same as the one stored") }