diff --git a/broadcast/asymmetricClient.go b/broadcast/asymmetricClient.go index ef397c2e50c925fcab4bd03a98a7645e91c76a10..d1e67eb9f61e434de1017c8c9b418c9dbe04eb30 100644 --- a/broadcast/asymmetricClient.go +++ b/broadcast/asymmetricClient.go @@ -2,12 +2,8 @@ package broadcast import ( "github.com/pkg/errors" - jww "github.com/spf13/jwalterweatherman" "gitlab.com/elixxir/client/cmix" - "gitlab.com/elixxir/client/cmix/identity" "gitlab.com/elixxir/client/cmix/message" - crypto "gitlab.com/elixxir/crypto/broadcast" - "gitlab.com/elixxir/crypto/fastRNG" "gitlab.com/xx_network/crypto/multicastRSA" "gitlab.com/xx_network/primitives/id" "gitlab.com/xx_network/primitives/id/ephemeral" @@ -18,60 +14,29 @@ const ( asymmCMixSendTag = "AsymmetricBroadcast" ) -type asymmetricClient struct { - channel crypto.Asymmetric - net Client - rng *fastRNG.StreamGenerator -} - -// Creates a -func NewAsymmetricClient(channel crypto.Asymmetric, listenerCb ListenerFunc, net Client, rng *fastRNG.StreamGenerator) Asymmetric { - // Add channel's identity - net.AddIdentity(channel.ReceptionID, identity.Forever, true) - - p := &asymmetricProcessor{ - ac: &channel, - cb: listenerCb, - } - - service := message.Service{ - Identifier: channel.ReceptionID.Bytes(), - Tag: asymmetricBroadcastServiceTag, - } - - net.AddService(channel.ReceptionID, service, p) +// TODO: what happens if this is called using a symmetric broadcast client (& vice versa) - jww.INFO.Printf("New asymmetric broadcast client created for channel %q (%s)", - channel.Name, channel.ReceptionID) - - return &asymmetricClient{ - channel: channel, - net: net, - rng: rng, - } -} - -// Broadcast broadcasts the payload to the channel. Requires a healthy network state to send +// BroadcastAsymmetric broadcasts the payload to the channel. Requires a healthy network state to send // Payload must be equal to ac.MaxPayloadSize, and the channel PrivateKey must be passed in -func (ac *asymmetricClient) Broadcast(pk multicastRSA.PrivateKey, payload []byte, cMixParams cmix.CMIXParams) ( +func (bc *broadcastClient) BroadcastAsymmetric(pk multicastRSA.PrivateKey, payload []byte, cMixParams cmix.CMIXParams) ( id.Round, ephemeral.Id, error) { - if !ac.net.IsHealthy() { + if !bc.net.IsHealthy() { return 0, ephemeral.Id{}, errors.New(errNetworkHealth) } - if len(payload) != ac.MaxPayloadSize() { + if len(payload) != bc.MaxAsymmetricPayloadSize() { return 0, ephemeral.Id{}, - errors.Errorf(errPayloadSize, len(payload), ac.MaxPayloadSize()) + errors.Errorf(errPayloadSize, len(payload), bc.MaxAsymmetricPayloadSize()) } // Encrypt payload to send using asymmetric channel - encryptedPayload, mac, fp, err := ac.channel.Encrypt(payload, pk, ac.rng.GetStream()) + encryptedPayload, mac, fp, err := bc.channel.EncryptAsymmetric(payload, pk, bc.rng.GetStream()) if err != nil { return 0, ephemeral.Id{}, errors.WithMessage(err, "Failed to encrypt asymmetric broadcast message") } // Create service object to send message service := message.Service{ - Identifier: ac.channel.ReceptionID.Bytes(), + Identifier: bc.channel.ReceptionID.Bytes(), Tag: asymmetricBroadcastServiceTag, } @@ -79,25 +44,11 @@ func (ac *asymmetricClient) Broadcast(pk multicastRSA.PrivateKey, payload []byte cMixParams.DebugTag = asymmCMixSendTag } - return ac.net.Send( - ac.channel.ReceptionID, fp, service, encryptedPayload, mac, cMixParams) -} - -// MaxPayloadSize returns the maximum size for a broadcasted payload. -func (ac *asymmetricClient) MaxPayloadSize() int { - return ac.net.GetMaxMessageLength() -} - -// Stop unregisters the listener callback and stops the channel's identity -// from being tracked. -func (ac *asymmetricClient) Stop() { - // Removes currently tracked identity - ac.net.RemoveIdentity(ac.channel.ReceptionID) - - // Delete all registered services - ac.net.DeleteClientService(ac.channel.ReceptionID) + return bc.net.Send( + bc.channel.ReceptionID, fp, service, encryptedPayload, mac, cMixParams) } -func (ac *asymmetricClient) Get() crypto.Asymmetric { - return ac.channel +// MaxAsymmetricPayloadSize returns the maximum size for an asymmetric broadcast payload. +func (bc *broadcastClient) MaxAsymmetricPayloadSize() int { + return bc.net.GetMaxMessageLength() // TODO: this is wrong, use math from xx_network/crypto layer } diff --git a/broadcast/broadcastClient.go b/broadcast/broadcastClient.go new file mode 100644 index 0000000000000000000000000000000000000000..ce54020210931be212b6961a04a67bff5ea7b341 --- /dev/null +++ b/broadcast/broadcastClient.go @@ -0,0 +1,90 @@ +package broadcast + +import ( + "github.com/pkg/errors" + jww "github.com/spf13/jwalterweatherman" + "gitlab.com/elixxir/client/cmix/identity" + "gitlab.com/elixxir/client/cmix/message" + crypto "gitlab.com/elixxir/crypto/broadcast" + "gitlab.com/elixxir/crypto/fastRNG" +) + +type Method uint8 + +const ( + Symmetric Method = iota + Asymmetric +) + +func (m Method) String() string { + switch m { + case Symmetric: + return "Symmetric" + case Asymmetric: + return "Asymmetric" + default: + return "Unknown" + } +} + +type Param struct { + Method Method +} + +type broadcastClient struct { + channel crypto.Channel + net Client + rng *fastRNG.StreamGenerator + param Param +} + +// NewBroadcastChannel creates a channel interface based on crypto.Channel, accepts net client connection & callback for received messages +func NewBroadcastChannel(channel crypto.Channel, listenerCb ListenerFunc, net Client, rng *fastRNG.StreamGenerator, param Param) (Channel, error) { + // Add channel's identity + net.AddIdentity(channel.ReceptionID, identity.Forever, true) + + p := &processor{ + c: &channel, + cb: listenerCb, + method: param.Method, + } + var tag string + switch param.Method { + case Symmetric: + tag = symmetricBroadcastServiceTag + case Asymmetric: + tag = asymmetricBroadcastServiceTag + default: + return nil, errors.Errorf("Cannot make broadcast client for unknown broadcast method %s", param.Method) + } + service := message.Service{ + Identifier: channel.ReceptionID.Bytes(), + Tag: tag, + } + + net.AddService(channel.ReceptionID, service, p) + + jww.INFO.Printf("New broadcast client created for channel %q (%s)", + channel.Name, channel.ReceptionID) + + return &broadcastClient{ + channel: channel, + net: net, + rng: rng, + param: param, + }, nil +} + +// Stop unregisters the listener callback and stops the channel's identity +// from being tracked. +func (bc *broadcastClient) Stop() { + // Removes currently tracked identity + bc.net.RemoveIdentity(bc.channel.ReceptionID) + + // Delete all registered services + bc.net.DeleteClientService(bc.channel.ReceptionID) +} + +func (bc *broadcastClient) Get() crypto.Channel { + return bc.channel +} diff --git a/broadcast/interface.go b/broadcast/interface.go index c12ae350fe9c6b0737b050ccbaf2178685e57af4..4b7e119d6167be5856282e1a1e06f083d976613f 100644 --- a/broadcast/interface.go +++ b/broadcast/interface.go @@ -10,11 +10,14 @@ package broadcast import ( "gitlab.com/elixxir/client/cmix" "gitlab.com/elixxir/client/cmix/identity/receptionID" + "gitlab.com/elixxir/client/cmix/message" "gitlab.com/elixxir/client/cmix/rounds" crypto "gitlab.com/elixxir/crypto/broadcast" + "gitlab.com/elixxir/primitives/format" "gitlab.com/xx_network/crypto/multicastRSA" "gitlab.com/xx_network/primitives/id" "gitlab.com/xx_network/primitives/id/ephemeral" + "time" ) // ListenerFunc is registered when creating a new broadcasting channel @@ -22,42 +25,41 @@ import ( type ListenerFunc func(payload []byte, receptionID receptionID.EphemeralIdentity, round rounds.Round) -// Symmetric manages the listening and broadcasting of a symmetric broadcast -// channel. -type Symmetric interface { - // MaxPayloadSize returns the maximum size for a broadcasted payload. - MaxPayloadSize() int +type Channel interface { + // MaxSymmetricPayloadSize returns the maximum size for a symmetric broadcasted payload. + MaxSymmetricPayloadSize() int - // Get returns the crypto.Symmetric object containing the cryptographic and - // identifying information about the channel. - Get() crypto.Symmetric + // MaxAsymmetricPayloadSize returns the maximum size for an asymmetric broadcasted payload. + MaxAsymmetricPayloadSize() int + + Get() crypto.Channel // Broadcast broadcasts the payload to the channel. The payload size must be // equal to MaxPayloadSize. Broadcast(payload []byte, cMixParams cmix.CMIXParams) ( id.Round, ephemeral.Id, error) - // Stop unregisters the listener callback and stops the channel's identity - // from being tracked. - Stop() -} - -// Asymmetric manages the listening and broadcasting of an asymmetric broadcast -// channel. -type Asymmetric interface { - // MaxPayloadSize returns the maximum size for a broadcasted payload. - MaxPayloadSize() int - - // Get returns the crypto.Asymmetric object containing the cryptographic and - // identifying information about the channel. - Get() crypto.Asymmetric - - // Broadcast broadcasts the payload to the channel. The payload size must be + // BroadcastAsymmetric broadcasts an asymmetric payload to the channel. The payload size must be // equal to MaxPayloadSize. - Broadcast(pk multicastRSA.PrivateKey, payload []byte, cMixParams cmix.CMIXParams) ( + BroadcastAsymmetric(pk multicastRSA.PrivateKey, payload []byte, cMixParams cmix.CMIXParams) ( id.Round, ephemeral.Id, error) // Stop unregisters the listener callback and stops the channel's identity // from being tracked. Stop() } + +// Client contains the methods from cmix.Client that are required by +// symmetricClient. +type Client interface { + GetMaxMessageLength() int + Send(recipient *id.ID, fingerprint format.Fingerprint, + service message.Service, payload, mac []byte, + cMixParams cmix.CMIXParams) (id.Round, ephemeral.Id, error) + IsHealthy() bool + AddIdentity(id *id.ID, validUntil time.Time, persistent bool) + AddService(clientID *id.ID, newService message.Service, + response message.Processor) + DeleteClientService(clientID *id.ID) + RemoveIdentity(id *id.ID) +} diff --git a/broadcast/processor.go b/broadcast/processor.go index 1fe50906852714822a8dd7c4d694df60f1b6f361..e715887eb3da0ff2f6a0a32993791e79dfaa766b 100644 --- a/broadcast/processor.go +++ b/broadcast/processor.go @@ -20,52 +20,39 @@ const ( errDecrypt = "[BCAST] Failed to decrypt payload for broadcast %s (%q): %+v" ) -// symmetricProcessor manages the reception and decryption of a symmetric broadcast message. -// Adheres to the message.Processor interface. -type symmetricProcessor struct { - s *crypto.Symmetric - cb ListenerFunc +type processor struct { + c *crypto.Channel + cb ListenerFunc + method Method } // Process decrypts the broadcast message and sends the results on the callback. -func (p *symmetricProcessor) Process(msg format.Message, +func (p *processor) Process(msg format.Message, receptionID receptionID.EphemeralIdentity, round rounds.Round) { - payload, err := p.s.Decrypt(msg.GetContents(), msg.GetMac(), msg.GetKeyFP()) - if err != nil { - jww.ERROR.Printf(errDecrypt, p.s.ReceptionID, p.s.Name, err) - return + var payload []byte + var err error + switch p.method { + case Asymmetric: + payload, err = p.c.DecryptAsymmetric(msg.GetContents()) + if err != nil { + jww.ERROR.Printf(errDecrypt, p.c.ReceptionID, p.c.Name, err) + return + } + case Symmetric: + payload, err = p.c.DecryptSymmetric(msg.GetContents(), msg.GetMac(), msg.GetKeyFP()) + if err != nil { + jww.ERROR.Printf(errDecrypt, p.c.ReceptionID, p.c.Name, err) + return + } + default: + jww.ERROR.Printf("Unrecognized broadcast method %d", p.method) } go p.cb(payload, receptionID, round) } // String returns a string identifying the symmetricProcessor for debugging purposes. -func (p *symmetricProcessor) String() string { - return "symmetricChannel-" + p.s.Name -} - -// asymmetricProcessor manages the reception and decryption of an asymmetric broadcast message -// Adheres to the message.Processor interface. -type asymmetricProcessor struct { - ac *crypto.Asymmetric - cb ListenerFunc -} - -// Process decrypts the broadcast message and sends the results on the callback. -func (p *asymmetricProcessor) Process(msg format.Message, - receptionID receptionID.EphemeralIdentity, round rounds.Round) { - - payload, err := p.ac.Decrypt(msg.GetContents()) - if err != nil { - jww.ERROR.Printf(errDecrypt, p.ac.ReceptionID, p.ac.Name, err) - return - } - - go p.cb(payload, receptionID, round) -} - -// String returns a string identifying the asymmetricProcessor for debugging purposes. -func (p *asymmetricProcessor) String() string { - return "symmetricChannel-" + p.ac.Name +func (p *processor) String() string { + return "broadcastChannel-" + p.c.Name } diff --git a/broadcast/symmetricClient.go b/broadcast/symmetricClient.go index 22832bbd06caf9b472a93cfeaa20e43bb4cd8127..9810b889c316e3a873cad5af9d92c84a6d72ed03 100644 --- a/broadcast/symmetricClient.go +++ b/broadcast/symmetricClient.go @@ -9,16 +9,10 @@ package broadcast import ( "github.com/pkg/errors" - jww "github.com/spf13/jwalterweatherman" "gitlab.com/elixxir/client/cmix" - "gitlab.com/elixxir/client/cmix/identity" "gitlab.com/elixxir/client/cmix/message" - crypto "gitlab.com/elixxir/crypto/broadcast" - "gitlab.com/elixxir/crypto/fastRNG" - "gitlab.com/elixxir/primitives/format" "gitlab.com/xx_network/primitives/id" "gitlab.com/xx_network/primitives/id/ephemeral" - "time" ) // Error messages. @@ -34,93 +28,31 @@ const ( symmetricBroadcastServiceTag = "SymmetricBroadcast" ) -// symmetricClient manages the sending and receiving of symmetric broadcast -// messages on a given symmetric broadcast channel. Adheres to the Symmetric -// interface. -type symmetricClient struct { - channel crypto.Symmetric - net Client - rng *fastRNG.StreamGenerator -} - -// Client contains the methods from cmix.Client that are required by -// symmetricClient. -type Client interface { - GetMaxMessageLength() int - Send(recipient *id.ID, fingerprint format.Fingerprint, - service message.Service, payload, mac []byte, - cMixParams cmix.CMIXParams) (id.Round, ephemeral.Id, error) - IsHealthy() bool - AddIdentity(id *id.ID, validUntil time.Time, persistent bool) - AddService(clientID *id.ID, newService message.Service, - response message.Processor) - DeleteClientService(clientID *id.ID) - RemoveIdentity(id *id.ID) -} - -// NewSymmetricClient generates a new Symmetric for the given channel. It starts -// listening for new messages on the callback immediately. -func NewSymmetricClient(channel crypto.Symmetric, listenerCb ListenerFunc, - net Client, rng *fastRNG.StreamGenerator) Symmetric { - // Add channel's identity - net.AddIdentity(channel.ReceptionID, identity.Forever, true) - - // Create new service - service := message.Service{ - Identifier: channel.ReceptionID.Bytes(), - Tag: symmetricBroadcastServiceTag, - } - - // Create new message symmetricProcessor - p := &symmetricProcessor{ - s: &channel, - cb: listenerCb, - } - - // Add service - net.AddService(channel.ReceptionID, service, p) - - jww.INFO.Printf("New symmetric broadcast client created for channel %q (%s)", - channel.Name, channel.ReceptionID) - - return &symmetricClient{ - channel: channel, - net: net, - rng: rng, - } -} - // MaxPayloadSize returns the maximum size for a broadcasted payload. -func (s *symmetricClient) MaxPayloadSize() int { - return s.net.GetMaxMessageLength() -} - -// Get returns the crypto.Symmetric object containing the cryptographic and -// identifying information about the channel. -func (s *symmetricClient) Get() crypto.Symmetric { - return s.channel +func (bc *broadcastClient) MaxSymmetricPayloadSize() int { + return bc.net.GetMaxMessageLength() } // Broadcast broadcasts the payload to the channel. -func (s *symmetricClient) Broadcast(payload []byte, cMixParams cmix.CMIXParams) ( +func (bc *broadcastClient) Broadcast(payload []byte, cMixParams cmix.CMIXParams) ( id.Round, ephemeral.Id, error) { - if !s.net.IsHealthy() { + if !bc.net.IsHealthy() { return 0, ephemeral.Id{}, errors.New(errNetworkHealth) } - if len(payload) != s.MaxPayloadSize() { + if len(payload) != bc.MaxSymmetricPayloadSize() { return 0, ephemeral.Id{}, - errors.Errorf(errPayloadSize, len(payload), s.MaxPayloadSize()) + errors.Errorf(errPayloadSize, len(payload), bc.MaxSymmetricPayloadSize()) } // Encrypt payload - rng := s.rng.GetStream() - encryptedPayload, mac, fp := s.channel.Encrypt(payload, rng) + rng := bc.rng.GetStream() + encryptedPayload, mac, fp := bc.channel.EncryptSymmetric(payload, rng) rng.Close() // Create service service := message.Service{ - Identifier: s.channel.ReceptionID.Bytes(), + Identifier: bc.channel.ReceptionID.Bytes(), Tag: symmetricBroadcastServiceTag, } @@ -128,16 +60,6 @@ func (s *symmetricClient) Broadcast(payload []byte, cMixParams cmix.CMIXParams) cMixParams.DebugTag = symmCMixSendTag } - return s.net.Send( - s.channel.ReceptionID, fp, service, encryptedPayload, mac, cMixParams) -} - -// Stop unregisters the listener callback and stops the channel's identity -// from being tracked. -func (s *symmetricClient) Stop() { - // Removes currently tracked identity - s.net.RemoveIdentity(s.channel.ReceptionID) - - // Delete all registered services - s.net.DeleteClientService(s.channel.ReceptionID) + return bc.net.Send( + bc.channel.ReceptionID, fp, service, encryptedPayload, mac, cMixParams) } diff --git a/go.mod b/go.mod index 7472776aa336ba3749e8d33cb45ba502a1696211..3d5655db5d01e0006b8de82f205a5e8380f4ca70 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,7 @@ require ( github.com/spf13/viper v1.7.1 gitlab.com/elixxir/bloomfilter v0.0.0-20211222005329-7d931ceead6f gitlab.com/elixxir/comms v0.0.4-0.20220323190139-9ed75f3a8b2c - gitlab.com/elixxir/crypto v0.0.7-0.20220510191648-70e5e956d3d5 + gitlab.com/elixxir/crypto v0.0.7-0.20220513133141-46faee2d8fca gitlab.com/elixxir/ekv v0.1.7 gitlab.com/elixxir/primitives v0.0.3-0.20220330212736-cce83b5f948f gitlab.com/xx_network/comms v0.0.4-0.20220315161313-76acb14429ac diff --git a/go.sum b/go.sum index 32805755ccd38e8cb756ad131883bd921f24d28d..fa944cd47a49236f96fe5c009e233166ae38951b 100644 --- a/go.sum +++ b/go.sum @@ -321,6 +321,8 @@ gitlab.com/elixxir/crypto v0.0.7-0.20220509151343-6e5a514a65fd h1:3lU8kF5ItUZYIu gitlab.com/elixxir/crypto v0.0.7-0.20220509151343-6e5a514a65fd/go.mod h1:cJF80ad9YCR+UcOlZNzfDVBAQqGEEhhs3y5taMEvXaE= gitlab.com/elixxir/crypto v0.0.7-0.20220510191648-70e5e956d3d5 h1:uzzFrmqx0CnqQ7AInGi6PA8w1mm2032hIpYn2G2SDKA= gitlab.com/elixxir/crypto v0.0.7-0.20220510191648-70e5e956d3d5/go.mod h1:cJF80ad9YCR+UcOlZNzfDVBAQqGEEhhs3y5taMEvXaE= +gitlab.com/elixxir/crypto v0.0.7-0.20220513133141-46faee2d8fca h1:0EINaZCe/0dPbQD2msOj8fwKpZ5lnZ57Y6zUZm85rEo= +gitlab.com/elixxir/crypto v0.0.7-0.20220513133141-46faee2d8fca/go.mod h1:cJF80ad9YCR+UcOlZNzfDVBAQqGEEhhs3y5taMEvXaE= gitlab.com/elixxir/ekv v0.1.6 h1:M2hUSNhH/ChxDd+s8xBqSEKgoPtmE6hOEBqQ73KbN6A= gitlab.com/elixxir/ekv v0.1.6/go.mod h1:e6WPUt97taFZe5PFLPb1Dupk7tqmDCTQu1kkstqJvw4= gitlab.com/elixxir/ekv v0.1.7 h1:OW2z+N4QCqqMFzouAwFTWWMKz0Y/PDhyYReN7gQ5NiQ=