diff --git a/broadcast/asymmetric.go b/broadcast/asymmetric.go index ed731ff2139eac6494601ef16d458d85122849d0..8fab1b5a24dad08ade68a369857f2dca06795c1e 100644 --- a/broadcast/asymmetric.go +++ b/broadcast/asymmetric.go @@ -8,6 +8,7 @@ package broadcast import ( + "encoding/binary" "github.com/pkg/errors" "gitlab.com/elixxir/client/cmix" "gitlab.com/elixxir/client/cmix/message" @@ -19,6 +20,7 @@ import ( const ( asymmetricBroadcastServiceTag = "AsymmBcast" asymmCMixSendTag = "AsymmetricBroadcast" + internalPayloadSizeLength = 2 ) // MaxAsymmetricPayloadSize returns the maximum size for an asymmetric broadcast payload @@ -28,20 +30,26 @@ func (bc *broadcastClient) maxAsymmetricPayload() int { // BroadcastAsymmetric broadcasts the payload to the channel. Requires a healthy network state to send // Payload must be equal to bc.MaxAsymmetricPayloadSize, and the channel PrivateKey must be passed in -// When a payload is sent, it is split into partitons of size bc.channel.MaxAsymmetricPayloadSize -// which are each encrypted using multicastRSA func (bc *broadcastClient) BroadcastAsymmetric(pk multicastRSA.PrivateKey, payload []byte, cMixParams cmix.CMIXParams) ( id.Round, ephemeral.Id, error) { + // Confirm network health if !bc.net.IsHealthy() { return 0, ephemeral.Id{}, errors.New(errNetworkHealth) } - if len(payload) != bc.MaxAsymmetricPayloadSize() { + // Check payload size + if len(payload) > bc.MaxAsymmetricPayloadSize() { return 0, ephemeral.Id{}, errors.Errorf(errPayloadSize, len(payload), bc.maxAsymmetricPayload()) } + payloadLength := uint16(len(payload)) - encryptedPayload, mac, fp, err := bc.channel.EncryptAsymmetric(payload, pk, bc.rng.GetStream()) + finalPayload := make([]byte, bc.maxAsymmetricPayloadSizeRaw()) + binary.BigEndian.PutUint16(finalPayload[:internalPayloadSizeLength], payloadLength) + copy(finalPayload[internalPayloadSizeLength:], payload) + + // Encrypt payload + encryptedPayload, mac, fp, err := bc.channel.EncryptAsymmetric(finalPayload, pk, bc.rng.GetStream()) if err != nil { return 0, ephemeral.Id{}, errors.WithMessage(err, "Failed to encrypt asymmetric broadcast message") } @@ -56,7 +64,9 @@ func (bc *broadcastClient) BroadcastAsymmetric(pk multicastRSA.PrivateKey, paylo cMixParams.DebugTag = asymmCMixSendTag } + // Create payload sized for sending over cmix sizedPayload := make([]byte, bc.net.GetMaxMessageLength()) + // Read random data into sized payload _, err = bc.rng.GetStream().Read(sizedPayload) if err != nil { return 0, ephemeral.Id{}, errors.WithMessage(err, "Failed to add random data to sized broadcast") diff --git a/broadcast/broadcastClient.go b/broadcast/broadcastClient.go index c80f4a50e0df89d6dc7463df39cb4e4c2b1414fa..6e1c7391cc6f97ed429cfd4164508444ac3eb0b3 100644 --- a/broadcast/broadcastClient.go +++ b/broadcast/broadcastClient.go @@ -102,5 +102,9 @@ func (bc *broadcastClient) MaxPayloadSize() int { } func (bc *broadcastClient) MaxAsymmetricPayloadSize() int { + return bc.maxAsymmetricPayloadSizeRaw() - internalPayloadSizeLength +} + +func (bc *broadcastClient) maxAsymmetricPayloadSizeRaw() int { return bc.channel.MaxAsymmetricPayloadSize() } diff --git a/broadcast/processor.go b/broadcast/processor.go index b747eac00111475d76cd8d599490613d65b8d4db..651974c4cb648aba5df3e56fa8f46901cc1a2899 100644 --- a/broadcast/processor.go +++ b/broadcast/processor.go @@ -8,6 +8,7 @@ package broadcast import ( + "encoding/binary" jww "github.com/spf13/jwalterweatherman" "gitlab.com/elixxir/client/cmix/identity/receptionID" "gitlab.com/elixxir/client/cmix/rounds" @@ -35,14 +36,15 @@ func (p *processor) Process(msg format.Message, var err error switch p.method { case Asymmetric: - // We use sized broadcast to fill any remaining bytes in the cmix payload, decode it here - encPartSize := p.c.RsaPubKey.Size() // Size of each chunk returned by multicast RSA encryption - encodedMessage := msg.GetContents()[:encPartSize] - payload, err = p.c.DecryptAsymmetric(encodedMessage) - if err != nil { - jww.ERROR.Printf(errDecrypt, p.c.ReceptionID, p.c.Name, err) + encPartSize := p.c.RsaPubKey.Size() // Size returned by multicast RSA encryption + encodedMessage := msg.GetContents()[:encPartSize] // Only one message is encoded, rest of it is random data + decodedMessage, decryptErr := p.c.DecryptAsymmetric(encodedMessage) + if decryptErr != nil { + jww.ERROR.Printf(errDecrypt, p.c.ReceptionID, p.c.Name, decryptErr) return } + size := binary.BigEndian.Uint16(decodedMessage[:internalPayloadSizeLength]) + payload = decodedMessage[internalPayloadSizeLength : size+internalPayloadSizeLength] case Symmetric: payload, err = p.c.DecryptSymmetric(msg.GetContents(), msg.GetMac(), msg.GetKeyFP()) diff --git a/broadcast/symmetric.go b/broadcast/symmetric.go index 10ca5a5b33bad72316973ee8dc4dc959331a20a1..e9b96f75c845dc0da8d91f87235d2e011db1cf2c 100644 --- a/broadcast/symmetric.go +++ b/broadcast/symmetric.go @@ -19,7 +19,7 @@ import ( const ( // symmetricClient.Broadcast errNetworkHealth = "cannot send broadcast when the network is not healthy" - errPayloadSize = "size of payload %d must be %d" + errPayloadSize = "size of payload %d must be less than %d" errBroadcastMethodType = "cannot call %s broadcast using %s channel" )