diff --git a/bindings/e2e.go b/bindings/e2e.go index dffc2560f4842e610a9eefe5f75f37d572776041..8820d59f9fed3ae4c3f120dec040b7c857ddfa94 100644 --- a/bindings/e2e.go +++ b/bindings/e2e.go @@ -7,15 +7,11 @@ package bindings import ( - "encoding/json" jww "github.com/spf13/jwalterweatherman" "gitlab.com/elixxir/client/cmix/identity/receptionID" "gitlab.com/elixxir/client/cmix/rounds" "gitlab.com/elixxir/client/xxdk" "gitlab.com/elixxir/crypto/contact" - "gitlab.com/elixxir/crypto/cyclic" - "gitlab.com/xx_network/crypto/signature/rsa" - "gitlab.com/xx_network/primitives/id" ) // e2eTrackerSingleton is used to track E2e objects so that @@ -46,7 +42,7 @@ func LoginE2e(cmixId int, callbacks AuthCallbacks, identity []byte) (*E2e, error return nil, err } - newIdentity, err := unmarshalIdentity(identity, cmix.api.GetStorage().GetE2EGroup()) + newIdentity, err := xxdk.UnmarshalReceptionIdentity(identity) if err != nil { return nil, err } @@ -75,7 +71,7 @@ func LoginE2eEphemeral(cmixId int, callbacks AuthCallbacks, identity []byte) (*E return nil, err } - newIdentity, err := unmarshalIdentity(identity, cmix.api.GetStorage().GetE2EGroup()) + newIdentity, err := xxdk.UnmarshalReceptionIdentity(identity) if err != nil { return nil, err } @@ -121,38 +117,7 @@ func LoginE2eLegacy(cmixId int, callbacks AuthCallbacks) (*E2e, error) { // GetContact returns a marshalled contact.Contact object for the E2e ReceptionIdentity func (e *E2e) GetContact() []byte { - return e.api.GetReceptionIdentity().GetContact(e.api.GetStorage().GetE2EGroup()).Marshal() -} - -// unmarshalIdentity is a helper function for taking in a marshalled xxdk.ReceptionIdentity and making it an object -func unmarshalIdentity(marshaled []byte, e2eGrp *cyclic.Group) (xxdk.ReceptionIdentity, error) { - newIdentity := xxdk.ReceptionIdentity{} - - // Unmarshal given identity into ReceptionIdentity object - givenIdentity := ReceptionIdentity{} - err := json.Unmarshal(marshaled, &givenIdentity) - if err != nil { - return xxdk.ReceptionIdentity{}, err - } - - newIdentity.ID, err = id.Unmarshal(givenIdentity.ID) - if err != nil { - return xxdk.ReceptionIdentity{}, err - } - - newIdentity.DHKeyPrivate = e2eGrp.NewInt(1) - err = newIdentity.DHKeyPrivate.UnmarshalJSON(givenIdentity.DHKeyPrivate) - if err != nil { - return xxdk.ReceptionIdentity{}, err - } - - newIdentity.RSAPrivatePem, err = rsa.LoadPrivateKeyFromPem(givenIdentity.RSAPrivatePem) - if err != nil { - return xxdk.ReceptionIdentity{}, err - } - - newIdentity.Salt = givenIdentity.Salt - return newIdentity, nil + return e.api.GetReceptionIdentity().GetContact().Marshal() } // AuthCallbacks is the bindings-specific interface for auth.Callbacks methods. diff --git a/bindings/contact.go b/bindings/identity.go similarity index 83% rename from bindings/contact.go rename to bindings/identity.go index 251c810f40c6e31a6212b8e2eaee770c86724d00..2718672f50b22b8017d84e9c1799eac4667905d6 100644 --- a/bindings/contact.go +++ b/bindings/identity.go @@ -5,7 +5,6 @@ import ( "gitlab.com/elixxir/client/xxdk" "gitlab.com/elixxir/crypto/contact" "gitlab.com/elixxir/primitives/fact" - "gitlab.com/xx_network/crypto/signature/rsa" ) // ReceptionIdentity struct @@ -27,23 +26,12 @@ type ReceptionIdentity struct { // MakeIdentity generates a new cryptographic identity for receiving messages func (c *Cmix) MakeIdentity() ([]byte, error) { - s := c.api.GetRng().GetStream() - defer s.Close() - ident, err := xxdk.MakeReceptionIdentity(s, c.api.GetStorage().GetE2EGroup()) - - dhPrivJson, err := ident.DHKeyPrivate.MarshalJSON() + ident, err := xxdk.MakeReceptionIdentity(c.api) if err != nil { return nil, err } - //create the identity object - I := ReceptionIdentity{ - ID: ident.ID.Marshal(), - RSAPrivatePem: rsa.CreatePrivateKeyPem(ident.RSAPrivatePem), - Salt: ident.Salt, - DHKeyPrivate: dhPrivJson, - } - return json.Marshal(&I) + return ident.Marshal() } // GetIDFromContact accepts a marshalled contact.Contact object & returns a marshalled id.ID object @@ -122,3 +110,32 @@ func GetFactsFromContact(marshaled []byte) ([]byte, error) { } return factsListMarshaled, nil } + +// StoreReceptionIdentity stores the given identity in Cmix storage with the given key +// This is the ideal way to securely store identities, as the caller of this function +// is only required to store the given key separately rather than the keying material +func StoreReceptionIdentity(key string, identity []byte, cmixId int) error { + cmix, err := cmixTrackerSingleton.get(cmixId) + if err != nil { + return err + } + receptionIdentity, err := xxdk.UnmarshalReceptionIdentity(identity) + if err != nil { + return err + } + return xxdk.StoreReceptionIdentity(key, receptionIdentity, cmix.api) +} + +// LoadReceptionIdentity loads the given identity in Cmix storage with the given key +func LoadReceptionIdentity(key string, cmixId int) ([]byte, error) { + cmix, err := cmixTrackerSingleton.get(cmixId) + if err != nil { + return nil, err + } + storageObj, err := cmix.api.GetStorage().Get(key) + if err != nil { + return nil, err + } + + return storageObj.Data, nil +} diff --git a/bindings/contact_test.go b/bindings/identity_test.go similarity index 100% rename from bindings/contact_test.go rename to bindings/identity_test.go diff --git a/cmd/broadcast.go b/cmd/broadcast.go index 8b9ae2358d5e4b6b51d2dd15bc6b6e22e74e5c05..1b4039dd54afbaca2ed87ae257c5c584fcb52a73 100644 --- a/cmd/broadcast.go +++ b/cmd/broadcast.go @@ -23,12 +23,11 @@ var broadcastCmd = &cobra.Command{ Short: "Send broadcast messages", Args: cobra.NoArgs, Run: func(cmd *cobra.Command, args []string) { - client := initClient() + client := initE2e() // Write user contact to file - user := client.GetUser() - jww.INFO.Printf("User: %s", user.ReceptionID) - jww.INFO.Printf("User Transmission: %s", user.TransmissionID) + user := client.GetReceptionIdentity() + jww.INFO.Printf("User: %s", user.ID) writeContact(user.GetContact()) err := client.StartNetworkFollower(5 * time.Second) @@ -39,8 +38,8 @@ var broadcastCmd = &cobra.Command{ // Wait until connected or crash on timeout connected := make(chan bool, 10) client.GetCmix().AddHealthCallback( - func(isconnected bool) { - connected <- isconnected + func(isConnected bool) { + connected <- isConnected }) waitUntilConnected(connected) @@ -69,10 +68,10 @@ var broadcastCmd = &cobra.Command{ jww.FATAL.Panicf("description cannot be empty") } - var channel *crypto.Channel + var cryptChannel *crypto.Channel if viper.GetBool("new") { // Create a new broadcast channel - channel, pk, err = crypto.NewChannel(name, desc, client.GetRng().GetStream()) + cryptChannel, pk, err = crypto.NewChannel(name, desc, client.GetRng().GetStream()) if err != nil { jww.FATAL.Panicf("Failed to create new channel: %+v", err) } @@ -99,7 +98,7 @@ var broadcastCmd = &cobra.Command{ jww.FATAL.Panicf("Failed to generate channel ID: %+v", err) } - channel = &crypto.Channel{ + cryptChannel = &crypto.Channel{ ReceptionID: rid, Name: name, Description: desc, @@ -126,7 +125,7 @@ var broadcastCmd = &cobra.Command{ } // Save channel to disk - cBytes, err := channel.Marshal() + cBytes, err := cryptChannel.Marshal() if err != nil { jww.ERROR.Printf("Failed to marshal channel to bytes: %+v", err) } diff --git a/cmd/fileTransfer.go b/cmd/fileTransfer.go index bdafb1edf63440c3f1109516f687a66ba2778b37..468bc50fe270ecc3a9114cc8aedf8627ddcd0f90 100644 --- a/cmd/fileTransfer.go +++ b/cmd/fileTransfer.go @@ -36,11 +36,11 @@ var ftCmd = &cobra.Command{ Run: func(cmd *cobra.Command, args []string) { // Initialise a new client - client := initClient() + client := initE2e() // Print user's reception ID and save contact file - user := client.GetUser() - jww.INFO.Printf("User: %s", user.ReceptionID) + user := client.GetReceptionIdentity() + jww.INFO.Printf("User: %s", user.ID) writeContact(user.GetContact()) // Start the network follower @@ -152,7 +152,7 @@ func initFileTransferManager(client *xxdk.E2e, maxThroughput int) ( // Create new manager manager, err := ft.NewManager(p, - client.GetUser().ReceptionID, + client.GetReceptionIdentity().ID, client.GetCmix(), client.GetStorage(), client.GetRng()) @@ -169,7 +169,7 @@ func initFileTransferManager(client *xxdk.E2e, maxThroughput int) ( e2eParams := ftE2e.DefaultParams() e2eFt, err := ftE2e.NewWrapper(receiveCB, e2eParams, manager, - client.GetUser().ReceptionID, client.GetE2E(), client.GetCmix()) + client.GetReceptionIdentity().ID, client.GetE2E(), client.GetCmix()) if err != nil { jww.FATAL.Panicf( "[FT] Failed to create new e2e file transfer wrapper: %+v", err) diff --git a/cmd/group.go b/cmd/group.go index 8ea7fd73870ec504605674be1f3c2817412abe75..9a718542250f5cc89977c02e45f87677e535c766 100644 --- a/cmd/group.go +++ b/cmd/group.go @@ -34,11 +34,11 @@ var groupCmd = &cobra.Command{ Args: cobra.NoArgs, Run: func(cmd *cobra.Command, args []string) { - client := initClient() + client := initE2e() // Print user's reception ID - user := client.GetUser() - jww.INFO.Printf("User: %s", user.ReceptionID) + user := client.GetReceptionIdentity() + jww.INFO.Printf("User: %s", user.ID) err := client.StartNetworkFollower(5 * time.Second) if err != nil { diff --git a/cmd/init.go b/cmd/init.go index 6c42b9cfc6a887d5f1dd3aacec85eb36ab47fb9e..75ea00e6c75bee432de3164d6f721291028ef97b 100644 --- a/cmd/init.go +++ b/cmd/init.go @@ -9,9 +9,6 @@ package cmd import ( - "fmt" - "gitlab.com/elixxir/client/xxdk" - "github.com/spf13/cobra" jww "github.com/spf13/jwalterweatherman" "github.com/spf13/viper" @@ -23,17 +20,10 @@ var initCmd = &cobra.Command{ Short: "Initialize a user ID but do not connect to the network", Args: cobra.NoArgs, Run: func(cmd *cobra.Command, args []string) { - client := createClient() - e2e, err := xxdk.LoadOrInitE2e(client) - if err != nil { - jww.FATAL.Panicf("%+v", err) - } - user := client.GetUser() - user.E2eDhPublicKey = e2e.GetHistoricalDHPubkey() + _, receptionIdentity := initCmix() - jww.INFO.Printf("User: %s", user.ReceptionID) - writeContact(user.GetContact()) - fmt.Printf("%s\n", user.ReceptionID) + jww.INFO.Printf("User: %s", receptionIdentity.ID) + writeContact(receptionIdentity.GetContact()) }, } diff --git a/cmd/root.go b/cmd/root.go index 0f0a42ad98fddb2791e659930573a752f639e555..e4b8d0155bac546096b637e76eb4ef65f51998c5 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -167,6 +167,9 @@ EnretBzQkeKeBwoB2u6NTiOmUjk= testNetCert = `` ) +// Key used for storing xxdk.ReceptionIdentity objects +const identityStorageKey = "identityStorageKey" + var authCbs *authCallbacks // Execute adds all child commands to the root command and sets flags @@ -194,14 +197,12 @@ var rootCmd = &cobra.Command{ pprof.StartCPUProfile(f) } - client := initClient() + client := initE2e() jww.INFO.Printf("Client Initialized...") - user := client.GetUser() - jww.INFO.Printf("USERPUBKEY: %s", - user.E2eDhPublicKey.TextVerbose(16, 0)) - jww.INFO.Printf("User: %s", user.ReceptionID) + user := client.GetReceptionIdentity() + jww.INFO.Printf("User: %s", user.ID) writeContact(user.GetContact()) // get Recipient and/or set it to myself @@ -216,13 +217,13 @@ var rootCmd = &cobra.Command{ } // Set it to myself - if recipientID == nil { + if recipientID == nil || recipientID.Cmp(user.ID) { jww.INFO.Printf("sending message to self") - recipientID = user.ReceptionID + recipientID = user.ID recipientContact = user.GetContact() } - jww.INFO.Printf("Client: %s, Partner: %s", user.ReceptionID, + jww.INFO.Printf("Client: %s, Partner: %s", user.ID, recipientID) client.GetE2E().EnableUnsafeReception() @@ -240,8 +241,8 @@ var rootCmd = &cobra.Command{ // Wait until connected or crash on timeout connected := make(chan bool, 10) client.GetCmix().AddHealthCallback( - func(isconnected bool) { - connected <- isconnected + func(isConnected bool) { + connected <- isConnected }) waitUntilConnected(connected) @@ -533,7 +534,8 @@ var rootCmd = &cobra.Command{ }, } -func createClient() *xxdk.Cmix { +// initCmix returns a newly-initialized xxdk.Cmix object and its stored xxdk.ReceptionIdentity +func initCmix() (*xxdk.Cmix, xxdk.ReceptionIdentity) { logLevel := viper.GetUint("logLevel") initLog(logLevel, viper.GetString("log")) jww.INFO.Printf(Version()) @@ -630,7 +632,21 @@ func createClient() *xxdk.Cmix { if err != nil { jww.FATAL.Panicf("%+v", err) } - return client + + // Attempt to load extant xxdk.ReceptionIdentity + identity, err := xxdk.LoadReceptionIdentity(identityStorageKey, client) + if err != nil { + // If no extant xxdk.ReceptionIdentity, generate and store a new one + identity, err = xxdk.MakeReceptionIdentity(client) + if err != nil { + jww.FATAL.Panicf("%+v", err) + } + err = xxdk.StoreReceptionIdentity(identityStorageKey, identity, client) + if err != nil { + jww.FATAL.Panicf("%+v", err) + } + } + return client, identity } func initParams() xxdk.Params { @@ -654,8 +670,9 @@ func initParams() xxdk.Params { return p } -func initClient() *xxdk.E2e { - createClient() +// initE2e returns a fully-formed xxdk.E2e object +func initE2e() *xxdk.E2e { + _, receptionIdentity := initCmix() pass := parsePassword(viper.GetString("password")) storeDir := viper.GetString("session") @@ -664,8 +681,7 @@ func initClient() *xxdk.E2e { params := initParams() // load the client - baseclient, err := xxdk.LoadCmix(storeDir, pass, params) - + baseClient, err := xxdk.LoadCmix(storeDir, pass, params) if err != nil { jww.FATAL.Panicf("%+v", err) } @@ -673,9 +689,20 @@ func initClient() *xxdk.E2e { authCbs = makeAuthCallbacks( viper.GetBool("unsafe-channel-creation")) - client, err := xxdk.LoginLegacy(baseclient, authCbs) - if err != nil { - jww.FATAL.Panicf("%+v", err) + // Force LoginLegacy for precanned senderID + var client *xxdk.E2e + if isPrecanned := viper.GetUint("sendid") != 0; isPrecanned { + jww.INFO.Printf("Using LoginLegacy for precan sender") + client, err = xxdk.LoginLegacy(baseClient, authCbs) + if err != nil { + jww.FATAL.Panicf("%+v", err) + } + } else { + jww.INFO.Printf("Using Login for non-precan sender") + client, err = xxdk.Login(baseClient, authCbs, receptionIdentity) + if err != nil { + jww.FATAL.Panicf("%+v", err) + } } if protoUser := viper.GetString("protoUserOut"); protoUser != "" { @@ -783,7 +810,7 @@ func addAuthenticatedChannel(client *xxdk.E2e, recipientID *id.ID, recipientContact := recipient if recipientContact.ID != nil && recipientContact.DhPubKey != nil { - me := client.GetUser().GetContact() + me := client.GetReceptionIdentity().GetContact() jww.INFO.Printf("Requesting auth channel from: %s", recipientID) diff --git a/cmd/single.go b/cmd/single.go index 2ce03e5c35162a909d3c502410ed35bede436c13..ed6939618864287668739abd0e6e258c02ae41f4 100644 --- a/cmd/single.go +++ b/cmd/single.go @@ -33,12 +33,11 @@ var singleCmd = &cobra.Command{ Args: cobra.NoArgs, Run: func(cmd *cobra.Command, args []string) { - client := initClient() + client := initE2e() // Write user contact to file - user := client.GetUser() - jww.INFO.Printf("User: %s", user.ReceptionID) - jww.INFO.Printf("User Transmission: %s", user.TransmissionID) + user := client.GetReceptionIdentity() + jww.INFO.Printf("User: %s", user.ID) writeContact(user.GetContact()) err := client.StartNetworkFollower(5 * time.Second) @@ -66,9 +65,14 @@ var singleCmd = &cobra.Command{ }), } - myID := client.GetUser().ReceptionID + dhKeyPriv, err := user.GetDHKeyPrivate() + if err != nil { + jww.FATAL.Panicf("%+v", err) + } + + myID := user.ID listener := single.Listen(tag, myID, - client.GetUser().E2eDhPrivateKey, + dhKeyPriv, client.GetCmix(), client.GetStorage().GetE2EGroup(), receiver) diff --git a/cmd/ud.go b/cmd/ud.go index 4666cba3fec19f620b0903e191c3955b2b42439a..94de6775c2a031dc37410fdc186dc4b090f1186c 100644 --- a/cmd/ud.go +++ b/cmd/ud.go @@ -33,11 +33,11 @@ var udCmd = &cobra.Command{ Short: "Register for and search users using the xx network user discovery service.", Args: cobra.NoArgs, Run: func(cmd *cobra.Command, args []string) { - client := initClient() + client := initE2e() // get user and save contact to file - user := client.GetUser() - jww.INFO.Printf("User: %s", user.ReceptionID) + user := client.GetReceptionIdentity() + jww.INFO.Printf("User: %s", user.ID) writeContact(user.GetContact()) // // Set up reception handler diff --git a/connect/authenticated.go b/connect/authenticated.go index 7fc0d0e7c6d15266f3c04b876cb46ff179123f5c..926cd15435d61883896117c98a5c370860365c27 100644 --- a/connect/authenticated.go +++ b/connect/authenticated.go @@ -66,7 +66,11 @@ func ConnectWithAuthentication(recipient contact.Contact, e2eClient *xxdk.E2e, // Build the authenticated connection and return identity := e2eClient.GetReceptionIdentity() - return connectWithAuthentication(conn, timeStart, recipient, identity.Salt, identity.RSAPrivatePem, + privKey, err := identity.GetRSAPrivatePem() + if err != nil { + return nil, err + } + return connectWithAuthentication(conn, timeStart, recipient, identity.Salt, privKey, e2eClient.GetRng(), e2eClient.GetCmix(), p) } diff --git a/groupChat/groupStore/store_test.go b/groupChat/groupStore/store_test.go index a41439b730f46285f39f9a960e6fe6bd94bbce77..e5549f06b1afadeceb44dd3a8bb3d2ac3c0ce7d1 100644 --- a/groupChat/groupStore/store_test.go +++ b/groupChat/groupStore/store_test.go @@ -558,7 +558,7 @@ func TestStore_GetUser(t *testing.T) { } if !user.Equal(store.GetUser()) { - t.Errorf("GetUser() failed to return the expected member."+ + t.Errorf("GetTransmissionIdentity() failed to return the expected member."+ "\nexpected: %#v\nreceived: %#v", user, store.GetUser()) } } diff --git a/groupChat/manager_test.go b/groupChat/manager_test.go index 374062ea83700854b222aaea55d70483304c8d30..de32491e49f2b7555783abc49d26d131c81a877e 100644 --- a/groupChat/manager_test.go +++ b/groupChat/manager_test.go @@ -170,26 +170,26 @@ func TestNewManager_LoadError(t *testing.T) { // m2, _ := newTestManagerWithStore(prng, 10, 0, requestFunc2, receiveFunc2, t) // m3, _ := newTestManagerWithStore(prng, 10, 0, requestFunc3, receiveFunc3, t) // -// membership, err := group.NewMembership(m1.store.GetUser().Contact(), -// m2.store.GetUser().Contact(), m3.store.GetUser().Contact()) +// membership, err := group.NewMembership(m1.store.GetTransmissionIdentity().Contact(), +// m2.store.GetTransmissionIdentity().Contact(), m3.store.GetTransmissionIdentity().Contact()) // if err != nil { // t.Errorf("Failed to generate new membership: %+v", err) // } // -// dhKeys := gs.GenerateDhKeyList(m1.gs.GetUser().ID, -// m1.store.GetUser().E2eDhPrivateKey, membership, m1.store.E2e().GetGroup()) +// dhKeys := gs.GenerateDhKeyList(m1.gs.GetTransmissionIdentity().ID, +// m1.store.GetTransmissionIdentity().E2eDhPrivateKey, membership, m1.store.E2e().GetGroup()) // -// grp1 := newTestGroup(m1.store.E2e().GetGroup(), m1.store.GetUser().E2eDhPrivateKey, prng, t) +// grp1 := newTestGroup(m1.store.E2e().GetGroup(), m1.store.GetTransmissionIdentity().E2eDhPrivateKey, prng, t) // grp1.Members = membership // grp1.DhKeys = dhKeys // grp1.ID = group.NewID(grp1.IdPreimage, grp1.Members) // grp1.Key = group.NewKey(grp1.KeyPreimage, grp1.Members) // grp2 := grp1.DeepCopy() -// grp2.DhKeys = gs.GenerateDhKeyList(m2.gs.GetUser().ID, -// m2.store.GetUser().E2eDhPrivateKey, membership, m2.store.E2e().GetGroup()) +// grp2.DhKeys = gs.GenerateDhKeyList(m2.gs.GetTransmissionIdentity().ID, +// m2.store.GetTransmissionIdentity().E2eDhPrivateKey, membership, m2.store.E2e().GetGroup()) // grp3 := grp1.DeepCopy() -// grp3.DhKeys = gs.GenerateDhKeyList(m3.gs.GetUser().ID, -// m3.store.GetUser().E2eDhPrivateKey, membership, m3.store.E2e().GetGroup()) +// grp3.DhKeys = gs.GenerateDhKeyList(m3.gs.GetTransmissionIdentity().ID, +// m3.store.GetTransmissionIdentity().E2eDhPrivateKey, membership, m3.store.E2e().GetGroup()) // // err = m1.gs.Add(grp1) // if err != nil { @@ -222,7 +222,7 @@ func TestNewManager_LoadError(t *testing.T) { // msg := message.Receive{ // Payload: requestMarshaled, // MessageType: message.GroupCreationRequest, -// Sender: m1.gs.GetUser().ID, +// Sender: m1.gs.GetTransmissionIdentity().ID, // } // // m2.swb.(*switchboard.Switchboard).Speak(msg) @@ -252,14 +252,14 @@ func TestNewManager_LoadError(t *testing.T) { // timestamp := netTime.Now() // // // Create cMix message and get public message -// cMixMsg, err := m1.newCmixMsg(grp1, contents, timestamp, m2.gs.GetUser(), prng) +// cMixMsg, err := m1.newCmixMsg(grp1, contents, timestamp, m2.gs.GetTransmissionIdentity(), prng) // if err != nil { // t.Errorf("Failed to create new cMix message: %+v", err) // } // // internalMsg, _ := newInternalMsg(cMixMsg.ContentsSize() - publicMinLen) // internalMsg.SetTimestamp(timestamp) -// internalMsg.SetSenderID(m1.gs.GetUser().ID) +// internalMsg.SetSenderID(m1.gs.GetTransmissionIdentity().ID) // internalMsg.SetPayload(contents) // expectedMsgID := group.NewMessageID(grp1.ID, internalMsg.Marshal()) // @@ -267,14 +267,14 @@ func TestNewManager_LoadError(t *testing.T) { // GroupID: grp1.ID, // ID: expectedMsgID, // Payload: contents, -// SenderID: m1.gs.GetUser().ID, +// SenderID: m1.gs.GetTransmissionIdentity().ID, // RoundTimestamp: timestamp.Local(), // } // // msg = message.Receive{ // Payload: cMixMsg.Marshal(), // MessageType: message.Raw, -// Sender: m1.gs.GetUser().ID, +// Sender: m1.gs.GetTransmissionIdentity().ID, // RoundTimestamp: timestamp.Local(), // } // m2.swb.(*switchboard.Switchboard).Speak(msg) diff --git a/storage/user/info.go b/storage/user/info.go index 62603c2225f0921f54684299f140fb33bfb6d182..3da77bb13935d863e382e26ad55aa529f1b63b6b 100644 --- a/storage/user/info.go +++ b/storage/user/info.go @@ -9,9 +9,7 @@ package user import ( "gitlab.com/elixxir/crypto/backup" - "gitlab.com/elixxir/crypto/contact" "gitlab.com/elixxir/crypto/cyclic" - "gitlab.com/elixxir/primitives/fact" "gitlab.com/xx_network/crypto/signature/rsa" "gitlab.com/xx_network/primitives/id" ) @@ -55,14 +53,6 @@ type Info struct { E2eDhPublicKey *cyclic.Int } -func (u Info) GetContact() contact.Contact { - return contact.Contact{ - ID: u.ReceptionID.DeepCopy(), - DhPubKey: u.E2eDhPublicKey, - Facts: make([]fact.Fact, 0), - } -} - func NewUserFromProto(proto *Proto) Info { return Info{ TransmissionID: proto.TransmissionID, diff --git a/xxdk/cmix.go b/xxdk/cmix.go index 059c9d061ffa8b83db87cf30db140f05d5311f7f..54aa051cbd8c22b0e7205e7e3c4d06822d5c5c39 100644 --- a/xxdk/cmix.go +++ b/xxdk/cmix.go @@ -392,7 +392,6 @@ func (c *Cmix) StopNetworkFollower() error { // NetworkFollowerStatus Gets the state of the network follower. Returns: // Stopped - 0 -// Starting - 1000 // Running - 2000 // Stopping - 3000 func (c *Cmix) NetworkFollowerStatus() Status { @@ -421,12 +420,11 @@ func (c *Cmix) AddService(sp Service) error { return c.followerServices.add(sp) } -// GetUser returns the current user Identity for this client. This -// can be serialized into a byte stream for out-of-band sharing. -func (c *Cmix) GetUser() user.Info { - jww.INFO.Printf("GetUser()") +// GetTransmissionIdentity returns the current TransmissionIdentity for this client +func (c *Cmix) GetTransmissionIdentity() TransmissionIdentity { + jww.INFO.Printf("GetTransmissionIdentity()") cMixUser := c.storage.PortableUserInfo() - return cMixUser + return buildTransmissionIdentity(cMixUser) } // GetComms returns the client comms object diff --git a/xxdk/e2e.go b/xxdk/e2e.go index e528c63352d167cc5b90016b56ae7200b0b921b4..34271b2092203b14feb7b8efe6d44499221a9597 100644 --- a/xxdk/e2e.go +++ b/xxdk/e2e.go @@ -76,7 +76,9 @@ func LoginLegacy(client *Cmix, callbacks AuthCallbacks) (m *E2e, err error) { if err != nil { return nil, err } - client.GetCmix().AddIdentity(client.GetUser().ReceptionID, time.Time{}, true) + + userInfo := client.GetStorage().PortableUserInfo() + client.GetCmix().AddIdentity(userInfo.ReceptionID, time.Time{}, true) err = client.AddService(m.e2e.StartProcesses) if err != nil { @@ -91,14 +93,7 @@ func LoginLegacy(client *Cmix, callbacks AuthCallbacks) (m *E2e, err error) { return nil, err } - u := m.Cmix.GetUser() - m.e2eIdentity = ReceptionIdentity{ - ID: u.TransmissionID, - RSAPrivatePem: u.TransmissionRSA, - Salt: u.TransmissionSalt, - DHKeyPrivate: u.E2eDhPrivateKey, - } - + m.e2eIdentity, err = buildReceptionIdentity(userInfo, m.e2e.GetGroup(), m.e2e.GetHistoricalDHPrivkey()) return m, err } @@ -183,12 +178,9 @@ func LoginWithProtoClient(storageDir string, password []byte, return nil, err } - return Login(c, callbacks, ReceptionIdentity{ - ID: protoUser.ReceptionID, - RSAPrivatePem: protoUser.ReceptionRSA, - Salt: protoUser.ReceptionSalt, - DHKeyPrivate: protoUser.E2eDhPrivateKey, - }) + userInfo := c.GetStorage().PortableUserInfo() + receptionIdentity, err := buildReceptionIdentity(userInfo, c.GetStorage().GetE2EGroup(), protoUser.E2eDhPrivateKey) + return Login(c, callbacks, receptionIdentity) } // login creates a new xxdk.E2e backed by the given versioned.KV @@ -196,7 +188,11 @@ func login(client *Cmix, callbacks AuthCallbacks, identity ReceptionIdentity, kv *versioned.KV) (m *E2e, err error) { // Verify the passed-in ReceptionIdentity matches its properties - generatedId, err := xx.NewID(identity.RSAPrivatePem.GetPublic(), identity.Salt, id.User) + privatePem, err := identity.GetRSAPrivatePem() + if err != nil { + return nil, err + } + generatedId, err := xx.NewID(privatePem.GetPublic(), identity.Salt, id.User) if err != nil { return nil, err } @@ -215,7 +211,11 @@ func login(client *Cmix, callbacks AuthCallbacks, client.network.AddIdentity(identity.ID, time.Time{}, true) //initialize the e2e storage - err = e2e.Init(kv, identity.ID, identity.DHKeyPrivate, e2eGrp, + dhPrivKey, err := identity.GetDHKeyPrivate() + if err != nil { + return nil, err + } + err = e2e.Init(kv, identity.ID, dhPrivKey, e2eGrp, rekey.GetDefaultEphemeralParams()) if err != nil { return nil, err @@ -250,7 +250,7 @@ func login(client *Cmix, callbacks AuthCallbacks, // e2e private key. It attempts to load via a legacy construction, then tries // to load the modern one, creating a new modern ID if neither can be found func LoadOrInitE2e(client *Cmix) (e2e.Handler, error) { - usr := client.GetUser() + usr := client.GetStorage().PortableUserInfo() e2eGrp := client.GetStorage().GetE2EGroup() kv := client.GetStorage().GetKV() @@ -314,15 +314,6 @@ func LoadOrInitE2e(client *Cmix) (e2e.Handler, error) { return e2eHandler, nil } -// GetUser replaces xxdk.Cmix's GetUser with one which includes the e2e dh -// private keys -func (m *E2e) GetUser() user.Info { - u := m.Cmix.GetUser() - u.E2eDhPrivateKey = m.e2e.GetHistoricalDHPrivkey() - u.E2eDhPublicKey = m.e2e.GetHistoricalDHPubkey() - return u -} - // GetReceptionIdentity returns a safe copy of the E2e ReceptionIdentity func (m *E2e) GetReceptionIdentity() ReceptionIdentity { return m.e2eIdentity.DeepCopy() @@ -339,15 +330,22 @@ func (m *E2e) ConstructProtoUserFile() ([]byte, error) { "permissioning") } + transIdentity := m.Cmix.GetTransmissionIdentity() + receptionIdentity := m.GetReceptionIdentity() + privatePem, err := receptionIdentity.GetRSAPrivatePem() + if err != nil { + return nil, err + } + Usr := user.Proto{ - TransmissionID: m.GetUser().TransmissionID, - TransmissionSalt: m.GetUser().TransmissionSalt, - TransmissionRSA: m.GetUser().TransmissionRSA, - ReceptionID: m.GetUser().ReceptionID, - ReceptionSalt: m.GetUser().ReceptionSalt, - ReceptionRSA: m.GetUser().ReceptionRSA, - Precanned: m.GetUser().Precanned, - RegistrationTimestamp: m.GetUser().RegistrationTimestamp, + TransmissionID: transIdentity.ID, + TransmissionSalt: transIdentity.Salt, + TransmissionRSA: transIdentity.RSAPrivatePem, + ReceptionID: receptionIdentity.ID, + ReceptionSalt: receptionIdentity.Salt, + ReceptionRSA: privatePem, + Precanned: m.GetStorage().IsPrecanned(), + RegistrationTimestamp: transIdentity.RegistrationTimestamp, RegCode: regCode, TransmissionRegValidationSig: m.GetStorage(). GetTransmissionRegistrationValidationSignature(), diff --git a/xxdk/identity.go b/xxdk/identity.go index 923bf3d5c6704284360d319c2d7e2483df77acd2..46caef778129618a8a07a2ebc5ba036fc5500718 100644 --- a/xxdk/identity.go +++ b/xxdk/identity.go @@ -7,26 +7,87 @@ package xxdk import ( + "encoding/json" + "gitlab.com/elixxir/client/storage/user" + "gitlab.com/elixxir/client/storage/versioned" "gitlab.com/elixxir/crypto/contact" "gitlab.com/elixxir/crypto/cyclic" "gitlab.com/elixxir/crypto/diffieHellman" - "gitlab.com/xx_network/crypto/csprng" "gitlab.com/xx_network/crypto/signature/rsa" "gitlab.com/xx_network/crypto/xx" "gitlab.com/xx_network/primitives/id" + "gitlab.com/xx_network/primitives/netTime" ) +const idVersion = 0 + +// ReceptionIdentity is used by the E2e object for managing +// identities used for message pickup type ReceptionIdentity struct { ID *id.ID - RSAPrivatePem *rsa.PrivateKey + RSAPrivatePem []byte Salt []byte - DHKeyPrivate *cyclic.Int + DHKeyPrivate []byte + E2eGrp []byte +} + +// StoreReceptionIdentity stores the given identity in Cmix storage with the given key +// This is the ideal way to securely store identities, as the caller of this function +// is only required to store the given key separately rather than the keying material +func StoreReceptionIdentity(key string, identity ReceptionIdentity, client *Cmix) error { + marshalledIdentity, err := identity.Marshal() + if err != nil { + return err + } + + return client.GetStorage().Set(key, &versioned.Object{ + Version: idVersion, + Timestamp: netTime.Now(), + Data: marshalledIdentity, + }) +} + +// LoadReceptionIdentity loads the given identity in Cmix storage with the given key +func LoadReceptionIdentity(key string, client *Cmix) (ReceptionIdentity, error) { + storageObj, err := client.GetStorage().Get(key) + if err != nil { + return ReceptionIdentity{}, err + } + + return UnmarshalReceptionIdentity(storageObj.Data) +} + +// Marshal returns the JSON representation of a ReceptionIdentity +func (r ReceptionIdentity) Marshal() ([]byte, error) { + return json.Marshal(&r) +} + +// UnmarshalReceptionIdentity takes in a marshalled ReceptionIdentity +// and converts it to an object +func UnmarshalReceptionIdentity(marshaled []byte) (ReceptionIdentity, error) { + newIdentity := ReceptionIdentity{} + return newIdentity, json.Unmarshal(marshaled, &newIdentity) +} + +// GetDHKeyPrivate returns the DHKeyPrivate in go format +func (r ReceptionIdentity) GetDHKeyPrivate() (*cyclic.Int, error) { + dhKeyPriv := &cyclic.Int{} + err := dhKeyPriv.UnmarshalJSON(r.DHKeyPrivate) + return dhKeyPriv, err +} + +// GetRSAPrivatePem returns the RSAPrivatePem in go format +func (r ReceptionIdentity) GetRSAPrivatePem() (*rsa.PrivateKey, error) { + return rsa.LoadPrivateKeyFromPem(r.RSAPrivatePem) } // MakeReceptionIdentity generates a new cryptographic identity // for receiving messages. -func MakeReceptionIdentity(rng csprng.Source, - grp *cyclic.Group) (ReceptionIdentity, error) { +func MakeReceptionIdentity(client *Cmix) (ReceptionIdentity, error) { + rng := client.GetRng().GetStream() + defer rng.Close() + grp := client.GetStorage().GetE2EGroup() + //make RSA Key rsaKey, err := rsa.GenerateKey(rng, rsa.DefaultRSABitLen) @@ -50,12 +111,24 @@ func MakeReceptionIdentity(rng csprng.Source, return ReceptionIdentity{}, err } + privKeyBytes, err := privKey.MarshalJSON() + if err != nil { + return ReceptionIdentity{}, err + } + + grpBytes, err := grp.MarshalJSON() + if err != nil { + return ReceptionIdentity{}, err + } + //create the identity object + rsaPem := rsa.CreatePrivateKeyPem(rsaKey) I := ReceptionIdentity{ ID: newId, - RSAPrivatePem: rsaKey, + RSAPrivatePem: rsaPem, Salt: salt, - DHKeyPrivate: privKey, + DHKeyPrivate: privKeyBytes, + E2eGrp: grpBytes, } return I, nil @@ -65,18 +138,28 @@ func MakeReceptionIdentity(rng csprng.Source, func (r ReceptionIdentity) DeepCopy() ReceptionIdentity { saltCopy := make([]byte, len(r.Salt)) copy(saltCopy, r.Salt) + + dhKeyCopy := make([]byte, len(r.DHKeyPrivate)) + copy(dhKeyCopy, r.DHKeyPrivate) + + grpCopy := make([]byte, len(r.E2eGrp)) + copy(grpCopy, r.E2eGrp) return ReceptionIdentity{ ID: r.ID.DeepCopy(), RSAPrivatePem: r.RSAPrivatePem, Salt: saltCopy, - DHKeyPrivate: r.DHKeyPrivate.DeepCopy(), + DHKeyPrivate: dhKeyCopy, + E2eGrp: grpCopy, } } // GetContact accepts a xxdk.ReceptionIdentity object and returns a contact.Contact object -func (r ReceptionIdentity) GetContact(grp *cyclic.Group) contact.Contact { - dhPub := grp.ExpG(r.DHKeyPrivate, grp.NewInt(1)) +func (r ReceptionIdentity) GetContact() contact.Contact { + grp := &cyclic.Group{} + _ = grp.UnmarshalJSON(r.E2eGrp) + dhKeyPriv, _ := r.GetDHKeyPrivate() + dhPub := grp.ExpG(dhKeyPriv, grp.NewInt(1)) ct := contact.Contact{ ID: r.ID, DhPubKey: dhPub, @@ -85,3 +168,62 @@ func (r ReceptionIdentity) GetContact(grp *cyclic.Group) contact.Contact { } return ct } + +// buildReceptionIdentity creates a new ReceptionIdentity +// from the given user.Info +func buildReceptionIdentity(userInfo user.Info, e2eGrp *cyclic.Group, dHPrivkey *cyclic.Int) (ReceptionIdentity, error) { + saltCopy := make([]byte, len(userInfo.TransmissionSalt)) + copy(saltCopy, userInfo.TransmissionSalt) + + grp, err := e2eGrp.MarshalJSON() + if err != nil { + return ReceptionIdentity{}, err + } + privKey, err := dHPrivkey.MarshalJSON() + if err != nil { + return ReceptionIdentity{}, err + } + + return ReceptionIdentity{ + ID: userInfo.ReceptionID.DeepCopy(), + RSAPrivatePem: rsa.CreatePrivateKeyPem(userInfo.ReceptionRSA), + Salt: saltCopy, + DHKeyPrivate: privKey, + E2eGrp: grp, + }, nil +} + +// TransmissionIdentity represents the identity +// used to transmit over the network via a specific Cmix object +type TransmissionIdentity struct { + ID *id.ID + RSAPrivatePem *rsa.PrivateKey + Salt []byte + // Timestamp in which user has registered with the network + RegistrationTimestamp int64 +} + +// DeepCopy produces a safe copy of a TransmissionIdentity +func (t TransmissionIdentity) DeepCopy() TransmissionIdentity { + saltCopy := make([]byte, len(t.Salt)) + copy(saltCopy, t.Salt) + return TransmissionIdentity{ + ID: t.ID.DeepCopy(), + RSAPrivatePem: t.RSAPrivatePem, + Salt: saltCopy, + RegistrationTimestamp: t.RegistrationTimestamp, + } +} + +// buildTransmissionIdentity creates a new TransmissionIdentity +// from the given user.Info +func buildTransmissionIdentity(userInfo user.Info) TransmissionIdentity { + saltCopy := make([]byte, len(userInfo.TransmissionSalt)) + copy(saltCopy, userInfo.TransmissionSalt) + return TransmissionIdentity{ + ID: userInfo.TransmissionID.DeepCopy(), + RSAPrivatePem: userInfo.TransmissionRSA, + Salt: saltCopy, + RegistrationTimestamp: userInfo.RegistrationTimestamp, + } +} diff --git a/xxdk/permissioning.go b/xxdk/permissioning.go index 2e1d735e1236c410bfb473e7d02bad87b6f73536..e3327d8a875c33885c3194013434e0b8d7037252 100644 --- a/xxdk/permissioning.go +++ b/xxdk/permissioning.go @@ -63,15 +63,16 @@ func (c *Cmix) ConstructProtoUserFile() ([]byte, error) { "permissioning") } + userInfo := c.GetStorage().PortableUserInfo() Usr := user.Proto{ - TransmissionID: c.GetUser().TransmissionID, - TransmissionSalt: c.GetUser().TransmissionSalt, - TransmissionRSA: c.GetUser().TransmissionRSA, - ReceptionID: c.GetUser().ReceptionID, - ReceptionSalt: c.GetUser().ReceptionSalt, - ReceptionRSA: c.GetUser().ReceptionRSA, - Precanned: c.GetUser().Precanned, - RegistrationTimestamp: c.GetUser().RegistrationTimestamp, + TransmissionID: userInfo.TransmissionID, + TransmissionSalt: userInfo.TransmissionSalt, + TransmissionRSA: userInfo.TransmissionRSA, + ReceptionID: userInfo.ReceptionID, + ReceptionSalt: userInfo.ReceptionSalt, + ReceptionRSA: userInfo.ReceptionRSA, + Precanned: userInfo.Precanned, + RegistrationTimestamp: userInfo.RegistrationTimestamp, RegCode: regCode, TransmissionRegValidationSig: c.storage.GetTransmissionRegistrationValidationSignature(), ReceptionRegValidationSig: c.storage.GetReceptionRegistrationValidationSignature(),