diff --git a/broadcast/sizedBroadcast.go b/broadcast/sizedBroadcast.go
index e909ab30014ca926ad03a9040d8e5bbc9211ca29..770083a2d78058eac2831599d0002d225a7a30ec 100644
--- a/broadcast/sizedBroadcast.go
+++ b/broadcast/sizedBroadcast.go
@@ -49,7 +49,10 @@ func NewSizedBroadcast(maxPayloadSize int, payload []byte) ([]byte, error) {
 	b := make([]byte, sizeSize)
 	binary.LittleEndian.PutUint16(b, uint16(len(payload)))
 
-	return append(b, payload...), nil
+	ret := make([]byte, maxPayloadSize)
+	p := append(b, payload...)
+	copy(ret, p)
+	return ret, nil
 }
 
 // DecodeSizedBroadcast  the data into its original payload of the correct size.
diff --git a/broadcast/symmetricClient.go b/broadcast/symmetricClient.go
index 28d718868a0659f9f2816f7fd2b16a4feb9cb116..3f0c7104d5dcb905a54775fd0fe3b026c263d9cd 100644
--- a/broadcast/symmetricClient.go
+++ b/broadcast/symmetricClient.go
@@ -15,7 +15,9 @@ import (
 	"gitlab.com/elixxir/client/cmix/message"
 	crypto "gitlab.com/elixxir/crypto/broadcast"
 	"gitlab.com/elixxir/crypto/fastRNG"
+	"gitlab.com/elixxir/crypto/hash"
 	"gitlab.com/elixxir/primitives/format"
+	"gitlab.com/xx_network/crypto/signature/rsa"
 	"gitlab.com/xx_network/primitives/id"
 	"gitlab.com/xx_network/primitives/id/ephemeral"
 	"time"
@@ -62,6 +64,15 @@ type Client interface {
 // listening for new messages on the callback immediately.
 func NewSymmetricClient(channel crypto.Symmetric, listenerCb ListenerFunc,
 	net Client, rng *fastRNG.StreamGenerator) Symmetric {
+	sc := &symmetricClient{
+		channel: channel,
+		net:     net,
+		rng:     rng,
+	}
+	if !sc.verifyID() {
+		jww.FATAL.Panicf("Failed ID verification for symmetric channel")
+	}
+
 	// Add channel's identity
 	net.AddIdentity(channel.ReceptionID, identity.Forever, true)
 
@@ -83,11 +94,7 @@ func NewSymmetricClient(channel crypto.Symmetric, listenerCb ListenerFunc,
 	jww.INFO.Printf("New symmetric broadcast client created for channel %q (%s)",
 		channel.Name, channel.ReceptionID)
 
-	return &symmetricClient{
-		channel: channel,
-		net:     net,
-		rng:     rng,
-	}
+	return sc
 }
 
 // MaxPayloadSize returns the maximum size for a broadcasted payload.
@@ -141,3 +148,20 @@ func (s *symmetricClient) Stop() {
 	// Delete all registered services
 	s.net.DeleteClientService(s.channel.ReceptionID)
 }
+
+func (s *symmetricClient) verifyID() bool {
+	h, err := hash.NewCMixHash()
+	if err != nil {
+		jww.FATAL.Panicf("[verifyID] Failed to create cmix hash")
+		return false
+	}
+	h.Write([]byte(s.channel.Name))
+	h.Write([]byte(s.channel.Description))
+	h.Write(s.channel.Salt)
+	h.Write(rsa.CreatePublicKeyPem(s.channel.RsaPubKey))
+	ridBytes := h.Sum(nil)
+	gen := &id.ID{}
+	copy(gen[:], ridBytes)
+	gen.SetType(id.User)
+	return s.channel.ReceptionID.Cmp(gen)
+}
diff --git a/cmd/symmetric.go b/cmd/symmetric.go
new file mode 100644
index 0000000000000000000000000000000000000000..e61b87195e22132b04a57bd93c5517a795a1a85d
--- /dev/null
+++ b/cmd/symmetric.go
@@ -0,0 +1,220 @@
+package cmd
+
+import (
+	"fmt"
+	"github.com/spf13/cobra"
+	jww "github.com/spf13/jwalterweatherman"
+	"github.com/spf13/viper"
+	"gitlab.com/elixxir/client/broadcast"
+	"gitlab.com/elixxir/client/cmix"
+	"gitlab.com/elixxir/client/cmix/identity/receptionID"
+	"gitlab.com/elixxir/client/cmix/rounds"
+	crypto "gitlab.com/elixxir/crypto/broadcast"
+	"gitlab.com/elixxir/crypto/hash"
+	"gitlab.com/xx_network/crypto/signature/rsa"
+	"gitlab.com/xx_network/primitives/id"
+	"gitlab.com/xx_network/primitives/utils"
+	"os"
+	"time"
+)
+
+// singleCmd is the single-use subcommand that allows for sending and responding
+// to single-use messages.
+var symmetricCmd = &cobra.Command{
+	Use:   "symmetric",
+	Short: "Send symmetric broadcast messages",
+	Args:  cobra.NoArgs,
+	Run: func(cmd *cobra.Command, args []string) {
+		client := initClient()
+
+		// Write user contact to file
+		user := client.GetUser()
+		jww.INFO.Printf("User: %s", user.ReceptionID)
+		jww.INFO.Printf("User Transmission: %s", user.TransmissionID)
+		writeContact(user.GetContact())
+
+		err := client.StartNetworkFollower(5 * time.Second)
+		if err != nil {
+			jww.FATAL.Panicf("%+v", err)
+		}
+
+		// Wait until connected or crash on timeout
+		connected := make(chan bool, 10)
+		client.GetNetworkInterface().AddHealthCallback(
+			func(isconnected bool) {
+				connected <- isconnected
+			})
+		waitUntilConnected(connected)
+
+		// Create new symmetric or load from path if exists
+		path, err := utils.ExpandPath(viper.GetString("path"))
+		var symmetric *crypto.Symmetric
+		if utils.Exists(path) {
+			// Load symmetric from path
+			symmBytes, err := utils.ReadFile(path)
+			if err != nil {
+
+			}
+			symmetric, err = crypto.UnmarshalSymmetric(symmBytes)
+			if err != nil {
+
+			}
+		} else {
+			// New symmetric
+			name := viper.GetString("name")
+			desc := viper.GetString("description")
+			if name == "" {
+				jww.FATAL.Panicf("Name cannot be empty")
+			} else if desc == "" {
+				jww.FATAL.Panicf("description cannot be empty")
+			}
+
+			var pubKey *rsa.PublicKey
+			var salt, pubKeyBytes []byte
+			if viper.GetBool("new") {
+				privKey, err := rsa.GenerateKey(client.GetRng().GetStream(), rsa.DefaultRSABitLen)
+				if err != nil {
+
+				}
+				pubKey = privKey.GetPublic()
+				pubKeyBytes = rsa.CreatePublicKeyPem(pubKey)
+			} else {
+				pubKeyBytes := []byte(viper.GetString("rsaPub"))
+				pubKey, err = rsa.LoadPublicKeyFromPem(pubKeyBytes)
+				if err != nil {
+
+				}
+				salt = []byte(viper.GetString("salt"))
+			}
+
+			h, err := hash.NewCMixHash()
+			if err != nil {
+
+			}
+			h.Write([]byte(name))
+			h.Write([]byte(desc))
+			h.Write(salt)
+			h.Write(pubKeyBytes)
+			ridBytes := h.Sum(nil)
+
+			rid := &id.ID{}
+			copy(rid[:], ridBytes)
+			rid.SetType(id.User)
+
+			symmetric = &crypto.Symmetric{
+				ReceptionID: rid,
+				Name:        name,
+				Description: desc,
+				Salt:        salt,
+				RsaPubKey:   pubKey,
+			}
+
+			symmBytes, err := symmetric.Marshal()
+			if err != nil {
+
+			}
+			// Write to file if there
+			if path != "" {
+				err = utils.WriteFile(path, symmBytes, os.ModePerm, os.ModeDir)
+				if err != nil {
+
+				}
+			} else {
+				fmt.Printf("Symmetric marshalled: %+v", symmBytes)
+			}
+		}
+
+		// Create receiver callback
+		receiveChan := make(chan []byte, 100)
+		cb := func(payload []byte,
+			receptionID receptionID.EphemeralIdentity, round rounds.Round) {
+			jww.INFO.Printf("Received symmetric message from %s over round %d", receptionID, round)
+			receiveChan <- payload
+		}
+
+		// Connect to symmetric broadcast channel
+		scl := broadcast.NewSymmetricClient(*symmetric, cb, client.GetNetworkInterface(), client.GetRng())
+		message := viper.GetString("broadcast")
+		fmt.Println(message)
+		// Send a broadcast over the channel
+		if message != "" {
+			broadcastMessage, err := broadcast.NewSizedBroadcast(scl.MaxPayloadSize(), []byte(message))
+			if err != nil {
+
+			}
+			rid, eid, err := scl.Broadcast(broadcastMessage, cmix.GetDefaultCMIXParams())
+			if err != nil {
+				jww.ERROR.Printf("Failed to send symmentric broadcast message: %+v", err)
+			}
+			jww.INFO.Printf("Sent symmetric broadcast message to %s over round %d", eid, rid)
+		}
+
+		// Receive messages over the channel
+		expectedCnt := viper.GetUint("receiveCount")
+		waitSecs := viper.GetUint("waitTimeout")
+		waitTimeout := time.Duration(waitSecs) * time.Second
+		receivedCount := uint(0)
+		done := false
+		for !done && expectedCnt != 0 {
+			timeout := time.NewTimer(waitTimeout)
+			select {
+			case receivedPayload := <-receiveChan:
+				receivedCount++
+				receivedBroadcast, err := broadcast.DecodeSizedBroadcast(receivedPayload)
+				if err != nil {
+					jww.ERROR.Printf("Failed to decode sized broadcast: %+v", err)
+					continue
+				}
+				fmt.Printf("Symmetric broadcast message received: %s\n", string(receivedBroadcast))
+				if receivedCount == expectedCnt {
+					done = true
+				}
+			case <-timeout.C:
+				fmt.Println("Timed out")
+				jww.ERROR.Printf("Timed out on message reception after %s!", waitTimeout)
+				done = true
+			}
+		}
+
+		jww.INFO.Printf("Received %d/%d Messages!", receivedCount, expectedCnt)
+		err = client.StopNetworkFollower()
+		if err != nil {
+			jww.WARN.Printf(
+				"Failed to cleanly close threads: %+v\n",
+				err)
+		}
+	},
+}
+
+func init() {
+	// Single-use subcommand options
+	symmetricCmd.Flags().StringP("name", "", "",
+		"Symmetric channel name")
+	_ = viper.BindPFlag("name", symmetricCmd.Flags().Lookup("name"))
+
+	symmetricCmd.Flags().StringP("rsaPub", "", "",
+		"Symmetric channel rsa pub key")
+	_ = viper.BindPFlag("rsaPub", symmetricCmd.Flags().Lookup("rsaPub"))
+
+	symmetricCmd.Flags().StringP("salt", "", "",
+		"Symmetric channel salt")
+	_ = viper.BindPFlag("salt", symmetricCmd.Flags().Lookup("salt"))
+
+	symmetricCmd.Flags().StringP("description", "", "",
+		"Symmetric channel description")
+	_ = viper.BindPFlag("description", symmetricCmd.Flags().Lookup("description"))
+
+	symmetricCmd.Flags().StringP("path", "", "",
+		"Symmetric channel output path")
+	_ = viper.BindPFlag("path", symmetricCmd.Flags().Lookup("path"))
+
+	symmetricCmd.Flags().BoolP("new", "", false,
+		"Create new symmetric channel")
+	_ = viper.BindPFlag("new", symmetricCmd.Flags().Lookup("new"))
+
+	symmetricCmd.Flags().StringP("broadcast", "", "",
+		"Message to send via symmetric broadcast")
+	_ = viper.BindPFlag("broadcast", symmetricCmd.Flags().Lookup("broadcast"))
+
+	rootCmd.AddCommand(symmetricCmd)
+}