diff --git a/api/client.go b/api/client.go
index 35bb2e8b1b8ed2dff03ca64229026b8a824ef7e4..13586c9c05721d3f5a4f7499d0f980675d5105fb 100644
--- a/api/client.go
+++ b/api/client.go
@@ -363,8 +363,8 @@ func (cl *Client) Login(UID *id.User, email, addr string, tlsCert string) (strin
 func (cl *Client) Send(message parse.MessageInterface) error {
 	// FIXME: There should (at least) be a version of this that takes a byte array
 	recipientID := message.GetRecipient()
-	err := cl.comm.SendMessage(cl.sess, recipientID, message.Pack())
-	return err
+	cryptoType := message.GetCryptoType()
+	return cl.comm.SendMessage(cl.sess, recipientID, cryptoType, message.Pack())
 }
 
 // DisableBlockingTransmission turns off blocking transmission, for
diff --git a/api/mockserver_test.go b/api/mockserver_test.go
index 2585ad51f3d9568462d6257dbcb6059c85dde6e0..80c2591692d2bfdb4ba69962021500b1faa98890 100644
--- a/api/mockserver_test.go
+++ b/api/mockserver_test.go
@@ -10,7 +10,7 @@ package api
 import (
 	"fmt"
 	jww "github.com/spf13/jwalterweatherman"
-	"gitlab.com/elixxir/client/crypto"
+	"gitlab.com/elixxir/client/globals"
 	"gitlab.com/elixxir/client/user"
 	"gitlab.com/elixxir/comms/gateway"
 	pb "gitlab.com/elixxir/comms/mixmessages"
@@ -285,7 +285,7 @@ func testMainWrapper(m *testing.M) int {
 }
 
 func getGroup() *cyclic.Group {
-	return crypto.InitCrypto()
+	return globals.InitCrypto()
 }
 
 func fmtAddress(port int) string { return fmt.Sprintf("localhost:%d", port)}
diff --git a/bindings/client.go b/bindings/client.go
index 0fd6118632a7284c764158b69d19843cf6a42665..28f4eabc26255827e1f274b930c979f00d87c617 100644
--- a/bindings/client.go
+++ b/bindings/client.go
@@ -169,18 +169,25 @@ func (cl *Client) Login(UID []byte, email, addr string,
 // Sends a message structured via the message interface
 // Automatically serializes the message type before the rest of the payload
 // Returns an error if either sender or recipient are too short
-func (cl *Client) Send(m Message) error {
+func (cl *Client) Send(m Message, encrypt bool) error {
 	sender := new(id.User).SetBytes(m.GetSender())
 	recipient := new(id.User).SetBytes(m.GetRecipient())
 
+	var cryptoType format.CryptoType
+	if encrypt {
+		cryptoType = format.E2E
+	} else {
+		cryptoType = format.Unencrypted
+	}
+
 	return cl.client.Send(&parse.Message{
 		TypedBody: parse.TypedBody{
 			MessageType: m.GetMessageType(),
-			Body:      m.GetPayload(),
+			Body:        m.GetPayload(),
 		},
-		CryptoType: format.Unencrypted,
-		Sender:    sender,
-		Receiver:  recipient,
+		CryptoType: cryptoType,
+		Sender:     sender,
+		Receiver:   recipient,
 	})
 }
 
diff --git a/bots/bots.go b/bots/bots.go
index 1e4da644572051c6f5713a3347dff9ecb586b56b..e7d54b89587af40ca53802c22ccd0c4da034ce3f 100644
--- a/bots/bots.go
+++ b/bots/bots.go
@@ -86,7 +86,8 @@ func InitBots(s user.Session,m io.Communications) {
 // Callers that need to wait on a response should implement waiting with a
 // listener.
 func sendCommand(botID *id.User, command []byte) error {
-	return messaging.SendMessage(session, botID, command)
+	return messaging.SendMessage(session, botID,
+		format.Unencrypted, command)
 }
 
 // Nickname Lookup function
diff --git a/bots/bots_test.go b/bots/bots_test.go
index bf9543736bae42f5664799f65adbbe3933b724b2..517b3954fc1c24180e4fc2b61e8c2debb11ae51b 100644
--- a/bots/bots_test.go
+++ b/bots/bots_test.go
@@ -32,6 +32,7 @@ type dummyMessaging struct {
 // SendMessage to the server
 func (d *dummyMessaging) SendMessage(sess user.Session,
 	recipientID *id.User,
+	cryptoType format.CryptoType,
 	message []byte) error {
 	jww.INFO.Printf("Sending: %s", string(message))
 	return nil
diff --git a/cmd/root.go b/cmd/root.go
index 60d5ec5e8f32cbeafceb8eda3d0c73d2b7d7ea18..62b8378e6370c001c235d85a6934c64da0210997 100644
--- a/cmd/root.go
+++ b/cmd/root.go
@@ -15,10 +15,8 @@ import (
 	jww "github.com/spf13/jwalterweatherman"
 	"github.com/spf13/viper"
 	"gitlab.com/elixxir/client/api"
-	"gitlab.com/elixxir/client/bindings"
 	"gitlab.com/elixxir/client/bots"
 	"gitlab.com/elixxir/client/cmixproto"
-	"gitlab.com/elixxir/client/crypto"
 	"gitlab.com/elixxir/client/globals"
 	"gitlab.com/elixxir/client/parse"
 	"gitlab.com/elixxir/client/user"
@@ -311,7 +309,7 @@ var rootCmd = &cobra.Command{
 				parseUdbMessage(message, client)
 			} else {
 				// Handle sending to any other destination
-				wireOut := bindings.FormatTextMessage(message)
+				wireOut := api.FormatTextMessage(message)
 
 				fmt.Printf("Sending Message to %d, %v: %s\n", destinationUserId,
 					recipientNick, message)
@@ -350,7 +348,7 @@ var rootCmd = &cobra.Command{
 					Sender: userID,
 					TypedBody: parse.TypedBody{
 						MessageType: int32(cmixproto.Type_TEXT_MESSAGE),
-						Body:      bindings.FormatTextMessage(message),
+						Body:      api.FormatTextMessage(message),
 					},
 					CryptoType: format.Unencrypted,
 					Receiver:  recipientId}
@@ -458,7 +456,7 @@ func SetCertPaths(gwCertPath, registrationCertPath string) {
 // initConfig reads in config file and ENV variables if set.
 func initConfig() {
 	// Temporarily need to get group as JSON data into viper
-	json, err := crypto.InitCrypto().MarshalJSON()
+	json, err := globals.InitCrypto().MarshalJSON()
 	if err != nil {
 		// panic
 	}
diff --git a/crypto/decrypt.go b/crypto/decrypt.go
index 07743c8ad28595677f4b3422fb9e1eef105f1485..a1ea8b2aeda6a9028ed492885cf19b749e1bcf4f 100644
--- a/crypto/decrypt.go
+++ b/crypto/decrypt.go
@@ -9,72 +9,68 @@ package crypto
 import (
 	"errors"
 	jww "github.com/spf13/jwalterweatherman"
-	pb "gitlab.com/elixxir/comms/mixmessages"
+	"gitlab.com/elixxir/client/keyStore"
+	"gitlab.com/elixxir/client/user"
+	"gitlab.com/elixxir/crypto/cmix"
 	"gitlab.com/elixxir/crypto/cyclic"
 	"gitlab.com/elixxir/crypto/e2e"
 	"gitlab.com/elixxir/crypto/hash"
+	pb "gitlab.com/elixxir/comms/mixmessages"
 	"gitlab.com/elixxir/primitives/format"
 )
 
-// Decrypt decrypts messages
-func Decrypt(nodeKey *cyclic.Int, grp *cyclic.Group,
-	cmixMsg *pb.CmixMessage) (
-	*format.Message, error) {
-
-	// Receive and decrypt a message
-	payload := grp.NewIntFromBytes(cmixMsg.MessagePayload)
+// CMIX Decrypt performs the decryption
+// of a message from a team of nodes
+// It returns a new message
+func CMIX_Decrypt(session user.Session,
+	msg *pb.CmixMessage) *format.Message {
+	salt := msg.Salt
+	nodeKeys := session.GetKeys()
+	baseKeys := make([]*cyclic.Int, len(nodeKeys))
+	for i, key := range nodeKeys {
+		baseKeys[i] = key.ReceptionKey
+		//TODO: Add KMAC verification here
+	}
 
-	// perform the CMIX decryption
-	grp.Mul(payload, nodeKey, payload)
+	newMsg := format.NewMessage()
+	newMsg.Payload = format.DeserializePayload(
+		msg.MessagePayload)
+	newMsg.AssociatedData = format.DeserializeAssociatedData(
+		msg.AssociatedData)
 
-	// unpack the message from a MessageBytes
-	var message format.Message
-	payloadSerial := payload.LeftpadBytes(uint64(format.TOTAL_LEN))
-	message.AssociatedData = format.DeserializeAssociatedData(cmixMsg.AssociatedData)
-	message.Payload = format.DeserializePayload(payloadSerial)
+	return cmix.ClientEncryptDecrypt(false, session.GetGroup(), newMsg, salt, baseKeys)
+}
 
-	// TODO Should salt be []byte instead of cyclic.Int?
-	// TODO Should the method return []byte instead of cyclic.Int?
-	// That might give better results in the case that the key happens to be
-	// not the correct length in bytes. Unlikely, but possible.
-	clientKey := e2e.Keygen(grp, nil, nil)
-	// Assuming that result of e2e.Keygen() will be nil for non-e2e messages
-	// TODO BC: why is this assumption valid ?
-	if clientKey != nil {
-		clientKeyBytes := clientKey.LeftpadBytes(uint64(format.TOTAL_LEN))
-		// First thing to do is check MAC
-		if !hash.VerifyHMAC(payloadSerial, message.GetMAC(), clientKeyBytes) {
-			return nil, errors.New("HMAC failed for end-to-end message")
-		}
-		var iv [e2e.AESBlockSize]byte
-		fp := message.GetKeyFingerprint()
-		copy(iv[:], fp[:e2e.AESBlockSize])
-		// decrypt the timestamp in the associated data
-		decryptedTimestamp, err := e2e.DecryptAES256WithIV(clientKeyBytes, iv, message.GetTimestamp())
-		if err != nil {
-			jww.ERROR.Panicf(err.Error())
-		}
-		// TODO deserialize this somewhere along the line and provide methods
-		// to mobile developers on the bindings to interact with the timestamps
-		message.SetTimestamp(decryptedTimestamp)
-		// Decrypt e2e
-		decryptedPayload, err := e2e.Decrypt(grp, clientKey, payloadSerial)
-		if err != nil {
-			return nil, errors.New(err.Error() +
-				"Failed to decrypt e2e message despite non" +
-				"-nil client key result")
-		}
-		if message.SetSplitPayload(decryptedPayload) != len(decryptedPayload) {
-			jww.ERROR.Panicf("Error setting decrypted payload")
-		}
-		return &message, nil
-	} else {
-		// Check MAC for non-e2e
-		fp := message.GetKeyFingerprint()
-		if hash.VerifyHMAC(payloadSerial, message.GetMAC(), fp[:]) {
-			return &message, nil
-		} else {
-			return nil, errors.New("HMAC failed for plaintext message")
-		}
+// E2E_Decrypt uses the E2E key to decrypt the message
+// It returns an error in case of HMAC verification failure
+// or in case of a decryption error (related to padding)
+// If it succeeds, it modifies the passed message
+func E2E_Decrypt(key *keyStore.E2EKey, grp *cyclic.Group,
+	msg *format.Message) error {
+	// First thing to do is check MAC
+	if !hash.VerifyHMAC(msg.SerializePayload(),
+		msg.GetMAC(), key.GetKey().Bytes()) {
+		return errors.New("HMAC verification failed for E2E message")
+	}
+	var iv [e2e.AESBlockSize]byte
+	fp := msg.GetKeyFingerprint()
+	copy(iv[:], fp[:e2e.AESBlockSize])
+	// decrypt the timestamp in the associated data
+	decryptedTimestamp, err := e2e.DecryptAES256WithIV(
+		key.GetKey().Bytes(), iv, msg.GetTimestamp())
+	if err != nil {
+		jww.ERROR.Panicf(err.Error())
+	}
+	// TODO deserialize this somewhere along the line and provide methods
+	// to mobile developers on the bindings to interact with the timestamps
+	msg.SetTimestamp(decryptedTimestamp)
+	// Decrypt e2e
+	decryptedPayload, err := e2e.Decrypt(grp, key.GetKey(), msg.SerializePayload())
+	if err != nil {
+		return errors.New("Failed to decrypt E2E message: " + err.Error())
+	}
+	if msg.SetSplitPayload(decryptedPayload) != len(decryptedPayload) {
+		jww.ERROR.Panicf("Error setting decrypted payload")
 	}
+	return nil
 }
diff --git a/crypto/encrypt.go b/crypto/encrypt.go
index cdc445d856f947a2b41e1c862f07832533117ed3..115a8f7dd6d39eec8156c1b9b8da8859ecfbd759 100644
--- a/crypto/encrypt.go
+++ b/crypto/encrypt.go
@@ -7,77 +7,77 @@
 package crypto
 
 import (
-	jww "github.com/spf13/jwalterweatherman"
+	"gitlab.com/elixxir/client/globals"
+	"gitlab.com/elixxir/client/keyStore"
+	"gitlab.com/elixxir/client/user"
+	"gitlab.com/elixxir/crypto/cmix"
 	"gitlab.com/elixxir/crypto/cyclic"
 	"gitlab.com/elixxir/crypto/e2e"
 	"gitlab.com/elixxir/crypto/hash"
 	"gitlab.com/elixxir/crypto/verification"
 	"gitlab.com/elixxir/primitives/format"
-	"time"
 )
 
-// Encrypt uses the encryption key to encrypt the passed message and populate
-// the associated data
-// You must also encrypt the message for the nodes
-func Encrypt(key *cyclic.Int, grp *cyclic.Group,
-	message *format.Message, e2eKey *cyclic.Int) (encryptedAssociatedData []byte,
-	encryptedPayload []byte) {
-	e2eKeyBytes := e2eKey.LeftpadBytes(uint64(format.TOTAL_LEN))
-	// Key fingerprint is 256 bits given by H(e2ekey)
-	// For now use Blake2B
-	h, _ := hash.NewCMixHash()
-	h.Write(e2eKeyBytes)
-	keyFp := format.NewFingerprint(h.Sum(nil))
-	message.SetKeyFingerprint(*keyFp)
+// CMIX Encrypt performs the encryption
+// of the msg to a team of nodes
+// It returns a new msg
+func CMIX_Encrypt(session user.Session,
+	salt []byte,
+	msg *format.Message) *format.Message {
+	// Generate the encryption key
+	nodeKeys := session.GetKeys()
+	baseKeys := make([]*cyclic.Int, len(nodeKeys))
+	for i, key := range nodeKeys {
+		baseKeys[i] = key.TransmissionKey
+		//TODO: Add KMAC generation here
+	}
+
+	fp := msg.GetKeyFingerprint()
+	// Calculate MIC
+	recipientMicList := [][]byte{
+		msg.GetRecipientID(),
+		fp[:],
+		msg.GetTimestamp(),
+		msg.GetMAC(),
+	}
+	mic := verification.GenerateMIC(recipientMicList, uint64(format.AD_RMIC_LEN))
+	msg.SetRecipientMIC(mic)
+	return cmix.ClientEncryptDecrypt(true, session.GetGroup(), msg, salt, baseKeys)
+}
+
+// E2E_Encrypt uses the E2E key to encrypt msg
+// to its intended recipient
+// It also properly populates the associated data
+// It modifies the passed msg instead of returning a new one
+func E2E_Encrypt(key *keyStore.E2EKey, grp *cyclic.Group,
+	msg *format.Message) {
+	keyFP := key.KeyFingerprint()
+	msg.SetKeyFingerprint(keyFP)
 
-	// Encrypt the timestamp using the e2ekey
-	// TODO BC: this will produce a 32 byte ciphertext, where the first 16 bytes
-	// is the IV internally generated AES. This is fine right now since there are 32 bytes
-	// of space in Associated Data for the timestamp.
-	// If we want to decrease that to 16 bytes, we need to use the key fingerprint
-	// as the IV for AES encryption
-	// TODO: timestamp like this is kinda hacky, maybe it should be set right here
-	// However, this would lead to parts of same message having potentially different timestamps
-	// Get relevant bytes from timestamp by unmarshalling and then marshalling again
-	timestamp := time.Time{}
-	timestamp.UnmarshalBinary(message.GetTimestamp())
-	timeBytes, _ := timestamp.MarshalBinary()
+	// Encrypt the timestamp using key
+	// Timestamp bytes were previously stored
+	// and GO only uses 15 bytes, so use those
 	var iv [e2e.AESBlockSize]byte
-	copy(iv[:], keyFp[:e2e.AESBlockSize])
-	encryptedTimestamp, err := e2e.EncryptAES256WithIV(e2eKeyBytes, iv, timeBytes)
+	copy(iv[:], keyFP[:e2e.AESBlockSize])
+	encryptedTimestamp, err :=
+		e2e.EncryptAES256WithIV(key.GetKey().Bytes(), iv,
+			msg.GetTimestamp()[:15])
+
 	// Make sure the encrypted timestamp fits
 	if len(encryptedTimestamp) != format.AD_TIMESTAMP_LEN || err != nil {
-		jww.ERROR.Panicf(err.Error())
+		globals.Log.ERROR.Panicf(err.Error())
 	}
-	message.SetTimestamp(encryptedTimestamp)
+	msg.SetTimestamp(encryptedTimestamp)
 
-	// E2E encrypt the message
-	encPayload, err := e2e.Encrypt(grp, e2eKey, message.GetPayload())
+	// E2E encrypt the msg
+	encPayload, err := e2e.Encrypt(grp, key.GetKey(), msg.GetPayload())
 	if len(encPayload) != format.TOTAL_LEN || err != nil {
-		jww.ERROR.Panicf(err.Error())
+		globals.Log.ERROR.Panicf(err.Error())
 	}
-	message.SetPayload(encPayload)
+	msg.SetPayload(encPayload)
 
 	// MAC is HMAC(key, ciphertext)
 	// Currently, the MAC doesn't include any of the associated data
-	MAC := hash.CreateHMAC(encPayload, e2eKeyBytes)
-	message.SetMAC(MAC)
-
-	recipientMicList := [][]byte{
-		message.AssociatedData.GetRecipientID(),
-		keyFp[:],
-		message.AssociatedData.GetTimestamp(),
-		message.AssociatedData.GetMAC(),
-	}
-	mic := verification.GenerateMIC(recipientMicList, uint64(format.AD_RMIC_LEN))
-	message.SetRecipientMIC(mic)
-
-	// perform the CMIX encryption
-	resultPayload := grp.NewIntFromBytes(message.SerializePayload())
-	resultAssociatedData := grp.NewIntFromBytes(message.SerializeAssociatedData())
-	grp.Mul(resultPayload, key, resultPayload)
-	grp.Mul(resultAssociatedData, key, resultAssociatedData)
-
-	return resultAssociatedData.LeftpadBytes(uint64(format.TOTAL_LEN)),
-		resultPayload.LeftpadBytes(uint64(format.TOTAL_LEN))
+	MAC := hash.CreateHMAC(encPayload, key.GetKey().Bytes())
+	msg.SetMAC(MAC)
 }
diff --git a/crypto/encryptdecrypt_test.go b/crypto/encryptdecrypt_test.go
index c7ce855dadf6050a2b8e6f47a52e33c67afb13f2..1d7e1659030217e071462d389877a3224166d17d 100644
--- a/crypto/encryptdecrypt_test.go
+++ b/crypto/encryptdecrypt_test.go
@@ -7,15 +7,9 @@
 package crypto_test
 
 import (
-	"bytes"
-	"gitlab.com/elixxir/client/crypto"
 	"gitlab.com/elixxir/client/user"
-	pb "gitlab.com/elixxir/comms/mixmessages"
-	"gitlab.com/elixxir/crypto/cmix"
 	"gitlab.com/elixxir/crypto/cyclic"
-	"gitlab.com/elixxir/crypto/e2e"
 	"gitlab.com/elixxir/crypto/large"
-	"gitlab.com/elixxir/primitives/format"
 	"gitlab.com/elixxir/primitives/id"
 	"testing"
 )
@@ -69,55 +63,3 @@ func setup(t *testing.T) {
 	session = user.NewSession(nil, u, "", nk,
 		nil, nil, grp)
 }
-
-func TestEncryptDecrypt(t *testing.T) {
-	setup(t)
-
-	grp := session.GetGroup()
-	sender := id.NewUserFromUint(38, t)
-	recipient := id.NewUserFromUint(29, t)
-	msg := format.NewMessage()
-	msg.SetSender(sender)
-	msg.SetRecipient(recipient)
-	msgPayload := []byte("help me, i'm stuck in an" +
-		" EnterpriseTextLabelDescriptorSetPipelineStateFactoryBeanFactory")
-	msg.SetPayloadData(msgPayload)
-
-	// Generate a compound encryption key
-	encryptionKey := grp.NewInt(1)
-	for _, key := range session.GetKeys() {
-		baseKey := key.TransmissionKey
-		partialEncryptionKey := cmix.NewEncryptionKey(salt, baseKey, grp)
-		grp.Mul(encryptionKey, encryptionKey, partialEncryptionKey)
-		//TODO: Add KMAC generation here
-	}
-
-	decryptionKey := grp.NewMaxInt()
-	grp.Inverse(encryptionKey, decryptionKey)
-
-	// do the encryption and the decryption
-	e2eKey := e2e.Keygen(grp, nil, nil)
-	assocData, payload := crypto.Encrypt(encryptionKey, grp, msg, e2eKey)
-	encryptedNet := &pb.CmixMessage{
-		SenderID:       sender.Bytes(),
-		MessagePayload: payload,
-		AssociatedData: assocData,
-	}
-	decrypted, err := crypto.Decrypt(decryptionKey, grp, encryptedNet)
-
-	if err != nil {
-		t.Fatalf("Couldn't decrypt message: %v", err.Error())
-	}
-	if *decrypted.GetSender() != *sender {
-		t.Errorf("Sender differed from expected: Got %q, expected %q",
-			decrypted.GetRecipient(), sender)
-	}
-	if *decrypted.GetRecipient() != *recipient {
-		t.Errorf("Recipient differed from expected: Got %q, expected %q",
-			decrypted.GetRecipient(), sender)
-	}
-	if !bytes.Equal(decrypted.GetPayloadData(), msgPayload) {
-		t.Errorf("Decrypted payload differed from expected: Got %q, "+
-			"expected %q", decrypted.GetPayloadData(), msgPayload)
-	}
-}
diff --git a/crypto/group.go b/globals/group.go
similarity index 99%
rename from crypto/group.go
rename to globals/group.go
index 30d00a0005477d8bc92539f3f1c96d59a605bca2..5f67d9e01be1f781ebadae1887885d19c3c09335 100644
--- a/crypto/group.go
+++ b/globals/group.go
@@ -3,7 +3,7 @@
 //                                                                             /
 // All rights reserved.                                                        /
 ////////////////////////////////////////////////////////////////////////////////
-package crypto
+package globals
 
 import (
 	"gitlab.com/elixxir/crypto/cyclic"
diff --git a/io/interface.go b/io/interface.go
index ae9f92897bb488c110992705fbadb6d6483568d1..53a72821a45db03425e6c2a3b1ca9e0780aca1db 100644
--- a/io/interface.go
+++ b/io/interface.go
@@ -9,6 +9,7 @@ package io
 
 import (
 	"gitlab.com/elixxir/client/user"
+	"gitlab.com/elixxir/primitives/format"
 	"gitlab.com/elixxir/primitives/id"
 	"time"
 )
@@ -16,7 +17,8 @@ import (
 // Communication interface implements send/receive functionality with the server
 type Communications interface {
 	// SendMessage to the server
-	SendMessage(session user.Session, recipientID *id.User, message []byte) error
+	SendMessage(session user.Session, recipientID *id.User,
+		cryptoType format.CryptoType, message []byte) error
 	// MessageReceiver thread to get new messages
 	MessageReceiver(session user.Session, delay time.Duration)
 }
diff --git a/io/messaging.go b/io/messaging.go
index b84264fefdc53dc20feb9bc31798e04d89afaaa8..fedc00f56d9517fb72419dd654dba5a4ed548c8c 100644
--- a/io/messaging.go
+++ b/io/messaging.go
@@ -13,13 +13,13 @@ import (
 	"fmt"
 	"gitlab.com/elixxir/client/crypto"
 	"gitlab.com/elixxir/client/globals"
+	"gitlab.com/elixxir/client/keyStore"
 	"gitlab.com/elixxir/client/parse"
 	"gitlab.com/elixxir/client/user"
 	"gitlab.com/elixxir/comms/client"
 	pb "gitlab.com/elixxir/comms/mixmessages"
 	"gitlab.com/elixxir/crypto/cmix"
 	"gitlab.com/elixxir/crypto/csprng"
-	"gitlab.com/elixxir/crypto/cyclic"
 	"gitlab.com/elixxir/crypto/e2e"
 	"gitlab.com/elixxir/primitives/format"
 	"gitlab.com/elixxir/primitives/id"
@@ -64,6 +64,7 @@ func NewMessenger() *Messaging {
 // w.r.t. generating message IDs for multi-part messages.)
 func (m *Messaging) SendMessage(session user.Session,
 	recipientID *id.User,
+	cryptoType format.CryptoType,
 	message []byte) error {
 	// FIXME: We should really bring the plaintext parts of the NewMessage logic
 	// into this module, then have an EncryptedMessage type that is sent to/from
@@ -75,7 +76,6 @@ func (m *Messaging) SendMessage(session user.Session,
 	// in this library? why not pass a sender object instead?
 	globals.Log.DEBUG.Printf("Sending message to %q: %q", *recipientID, message)
 	userID := session.GetCurrentUser().User
-	grp := session.GetGroup()
 	parts, err := parse.Partition([]byte(message),
 		m.nextId())
 	if err != nil {
@@ -83,17 +83,9 @@ func (m *Messaging) SendMessage(session user.Session,
 	}
 	// Every part should have the same timestamp
 	now := time.Now()
-	// TODO Is it better to use Golang's binary timestamp format, or
-	// use the 2 int64 technique with Unix seconds+nanoseconds?
-	// 2 int64s is 128 bits, which is as much as can fit in the timestamp field,
-	// but the binary serialization is 15 bytes, which is slightly smaller but
-	// not smaller enough to make a difference.
-	// The binary serialized timestamp also includes zone data, which could be
-	// a feature, but might compromise a little bit of anonymity.
-	// Using binary timestamp format for now.
-	// TODO BC: It is actually better to use the 15 byte version since this will
-	// allow the encrypted timestamp to fit in 16 bytes instead of 32, by using
-	// the key fingerprint as the IV for AES encryption
+	// GO Timestamp binary serialization is 15 bytes, which
+	// allows the encrypted timestamp to fit in 16 bytes
+	// using AES encryption
 	nowBytes, err := now.MarshalBinary()
 	if err != nil {
 		return fmt.Errorf("SendMessage MarshalBinary() error: %v", err.Error())
@@ -103,9 +95,10 @@ func (m *Messaging) SendMessage(session user.Session,
 		message.SetSender(userID)
 		message.SetRecipient(recipientID)
 		// The timestamp will be encrypted later
+		// NOTE: This sets 15 bytes, not 16
 		message.SetTimestamp(nowBytes)
 		message.SetPayloadData(parts[i])
-		err = m.send(session, userID, message, grp)
+		err = m.send(session, cryptoType, message)
 		if err != nil {
 			return fmt.Errorf("SendMessage send() error: %v", err.Error())
 		}
@@ -113,9 +106,51 @@ func (m *Messaging) SendMessage(session user.Session,
 	return nil
 }
 
+// Send Message without doing partitions
+// This function will be needed for example to send a Rekey
+// message, where a new public key will take up all the message
+func (m *Messaging) SendMessageNoPartition(session user.Session,
+	recipientID *id.User,
+	cryptoType format.CryptoType,
+	message []byte) error {
+	size := len(message)
+	if size > format.TOTAL_LEN {
+		return fmt.Errorf("SendMessageNoPartition() error: message to be sent is too big")
+	}
+	userID := session.GetCurrentUser().User
+	now := time.Now()
+	// GO Timestamp binary serialization is 15 bytes, which
+	// allows the encrypted timestamp to fit in 16 bytes
+	// using AES encryption
+	nowBytes, err := now.MarshalBinary()
+	if err != nil {
+		return fmt.Errorf("SendMessageNoPartition MarshalBinary() error: %v", err.Error())
+	}
+	msg := format.NewMessage()
+	msg.SetRecipient(recipientID)
+	// The timestamp will be encrypted later
+	// NOTE: This sets 15 bytes, not 16
+	msg.SetTimestamp(nowBytes)
+	// If message is bigger than payload size
+	// use SenderID space to send it
+	if size > format.MP_PAYLOAD_LEN {
+		msg.SetSenderID(message[:format.MP_SID_END])
+		msg.SetPayloadData(message[format.MP_SID_END:])
+	} else {
+		msg.SetSender(userID)
+		msg.SetPayloadData(message)
+	}
+	err = m.send(session, cryptoType, msg)
+	if err != nil {
+		return fmt.Errorf("SendMessageNoPartition send() error: %v", err.Error())
+	}
+	return nil
+}
+
 // send actually sends the message to the server
 func (m *Messaging) send(session user.Session,
-	senderID *id.User, message *format.Message, grp *cyclic.Group) error {
+	cryptoType format.CryptoType,
+	message *format.Message) error {
 	// Enable transmission blocking if enabled
 	if m.BlockTransmissions {
 		m.sendLock.Lock()
@@ -125,39 +160,54 @@ func (m *Messaging) send(session user.Session,
 		}()
 	}
 
-	salt := cmix.NewSalt(csprng.Source(&csprng.SystemRNG{}), 16)
-
-	// TBD: Add key macs to this message
-	macs := make([][]byte, 0)
-
-	// Generate a compound encryption key
-	encryptionKey := grp.NewInt(1)
-	for _, key := range session.GetKeys() {
-		baseKey := key.TransmissionKey
-		partialEncryptionKey := cmix.NewEncryptionKey(salt, baseKey, grp)
-		grp.Mul(encryptionKey, partialEncryptionKey, encryptionKey)
-		//TODO: Add KMAC generation here
+	// Check message type
+	if cryptoType == format.E2E {
+		handleE2ESending(session, message)
+	} else {
+		padded, err := e2e.Pad(message.GetPayload(), format.TOTAL_LEN)
+		if err != nil {
+			return err
+		}
+		message.SetPayload(padded)
+		e2e.SetUnencrypted(message)
 	}
 
-	// TBD: Is there a really good reason we have to specify the Grp and not a
-	// key? Should we even be doing the encryption here?
-	// TODO: Use salt here / generate n key map
-	e2eKey := e2e.Keygen(grp, nil, nil)
-	associatedData, payload := crypto.Encrypt(encryptionKey, grp,
-		message, e2eKey)
+	// CMIX Encryption
+	salt := cmix.NewSalt(csprng.Source(&csprng.SystemRNG{}), 16)
+	encMsg := crypto.CMIX_Encrypt(session, salt, message)
+
 	msgPacket := &pb.CmixMessage{
-		SenderID:       senderID.Bytes(),
-		MessagePayload: payload,
-		AssociatedData: associatedData,
+		SenderID:       session.GetCurrentUser().User.Bytes(),
+		MessagePayload: encMsg.SerializePayload(),
+		AssociatedData: encMsg.SerializeAssociatedData(),
 		Salt:           salt,
-		KMACs:          macs,
+		KMACs:          make([][]byte, 0),
 	}
 
-	var err error
 	globals.Log.INFO.Println("Sending put message to gateway")
-	err = client.SendPutMessage(m.SendAddress, msgPacket)
+	return client.SendPutMessage(m.SendAddress, msgPacket)
+}
 
-	return err
+func handleE2ESending(session user.Session,
+	message *format.Message) {
+	recipientID := message.GetRecipient()
+
+	// Get send key
+	sendKey, action := session.GetKeyStore().
+		TransmissionKeys.Pop(recipientID)
+
+	if sendKey == nil {
+		globals.Log.FATAL.Panicf("Couldn't get key to E2E encrypt message to" +
+			" user %v", *recipientID)
+	} else if action == keyStore.Deleted {
+		globals.Log.FATAL.Panicf("Key Manager is deleted when trying to get E2E Send Key")
+	}
+
+	if action == keyStore.Rekey {
+		// TODO handle Send Rekey message to SW
+	}
+
+	crypto.E2E_Encrypt(sendKey, session.GetGroup(), message)
 }
 
 // MessageReceiver is a polling thread for receiving messages -- again.. we
@@ -185,6 +235,7 @@ func (m *Messaging) MessageReceiver(session user.Session, delay time.Duration) {
 			decryptedMessages := m.receiveMessagesFromGateway(session, &pollingMessage)
 			if decryptedMessages != nil {
 				for i := range decryptedMessages {
+					// TODO Handle messages that do not need partitioning
 					assembledMessage := m.collator.AddMessage(
 						decryptedMessages[i], time.Minute)
 					if assembledMessage != nil {
@@ -197,6 +248,28 @@ func (m *Messaging) MessageReceiver(session user.Session, delay time.Duration) {
 	}
 }
 
+func handleE2EReceiving(session user.Session,
+	message *format.Message) error {
+	keyFingerprint := message.GetKeyFingerprint()
+
+	// Lookup reception key
+	recpKey := session.GetKeyStore().
+		ReceptionKeys.Pop(keyFingerprint)
+
+	if recpKey == nil {
+		// TODO Handle sending error message to SW
+		return fmt.Errorf("E2EKey for matching fingerprint not found, can't process message")
+	} else if recpKey.GetOuterType() == format.Rekey {
+		// TODO Handle Receiving Keys Rekey (partner rekey)
+	}
+
+	err := crypto.E2E_Decrypt(recpKey, session.GetGroup(), message)
+	if err != nil {
+		// TODO handle Garbled message to SW
+	}
+	return err
+}
+
 func (m *Messaging) receiveMessagesFromGateway(session user.Session,
 	pollingMessage *pb.ClientPollMessage) []*format.Message {
 	if session != nil {
@@ -212,7 +285,6 @@ func (m *Messaging) receiveMessagesFromGateway(session user.Session,
 		globals.Log.INFO.Printf("Checking novelty of %v messages", len(messages.MessageIDs))
 
 		results := make([]*format.Message, 0, len(messages.MessageIDs))
-		grp := session.GetGroup()
 		for _, messageID := range messages.MessageIDs {
 			// Get the first unseen message from the list of IDs
 			_, received := m.ReceivedMessages[messageID]
@@ -239,15 +311,28 @@ func (m *Messaging) receiveMessagesFromGateway(session user.Session,
 						continue
 					}
 
-					// Generate a compound decryption key
-					salt := newMessage.Salt
-					decryptionKey := grp.NewInt(1)
-					for _, key := range session.GetKeys() {
-						baseKey := key.ReceptionKey
-						partialDecryptionKey := cmix.NewDecryptionKey(salt, baseKey,
-							grp)
-						grp.Mul(decryptionKey, partialDecryptionKey, decryptionKey)
-						//TODO: Add KMAC verification here
+					// CMIX Decryption
+					decMsg := crypto.CMIX_Decrypt(session, newMessage)
+
+					var err error = nil
+					var unpadded []byte
+					// If message is E2E, handle decryption
+					if !e2e.IsUnencrypted(decMsg) {
+						err = handleE2EReceiving(session, decMsg)
+					} else {
+						// If message is non E2E, need to unpad payload
+						unpadded, err = e2e.Unpad(decMsg.SerializePayload())
+						if err == nil {
+							decMsg.SetSplitPayload(unpadded)
+						}
+					}
+
+					if err != nil {
+						globals.Log.WARN.Printf(
+							"Message did not decrypt properly, "+
+								"not adding to results array: %v", err.Error())
+					} else {
+						results = append(results, decMsg)
 					}
 
 					globals.Log.INFO.Printf(
@@ -255,16 +340,6 @@ func (m *Messaging) receiveMessagesFromGateway(session user.Session,
 					m.ReceivedMessages[messageID] = struct{}{}
 					session.SetLastMessageID(messageID)
 					session.StoreSession()
-
-					decryptedMsg, err2 := crypto.Decrypt(decryptionKey, grp,
-						newMessage)
-					if err2 != nil {
-						globals.Log.WARN.Printf(
-							"Message did not decrypt properly, "+
-								"not adding to results array: %v", err2.Error())
-					} else {
-						results = append(results, decryptedMsg)
-					}
 				}
 			}
 		}
diff --git a/user/user.go b/user/user.go
index 4f63125417fcf57db919e0d8727ea21bec3dda81..a65640cb12631b4a223fa89a3f735eee86f0d411 100644
--- a/user/user.go
+++ b/user/user.go
@@ -8,7 +8,6 @@ package user
 
 import (
 	"crypto/sha256"
-	"gitlab.com/elixxir/client/crypto"
 	"gitlab.com/elixxir/client/globals"
 	"gitlab.com/elixxir/primitives/id"
 )
@@ -58,7 +57,7 @@ func newRegistry() Registry {
 	nk := make(map[id.User]*NodeKeys)
 
 	// Initialize group object
-	grp := crypto.InitCrypto()
+	grp := globals.InitCrypto()
 
 	// Deterministically create NUM_DEMO_USERS users
 	// TODO Replace this with real user registration/discovery