diff --git a/README.md b/README.md index d546e85140536803b657303fad068a9d9436dfdd..c89b714f0330336fac8c1bc6dbe88eb0587fef53 100644 --- a/README.md +++ b/README.md @@ -48,7 +48,6 @@ Optional args: |--version|-V|Show the generated version information. Run `$ go generate cmd/version.go` if the information is out of date.|--version| |--sessionfile|-f|File path for storing the session. If not specified, the session will be stored in RAM and won't persist.|-f mySuperCoolSessionFile| |--noBlockingTransmission| |Disables transmission rate limiting (useful for dummy client)|--noBlockingTransmission| -|--mint| |Creates some coins for this user for testing and demos|--mint| |--help|-h|Prints a help message with all of these flags|-h| |--gwcertpath|-c|Enables TLS by passing in path to the gateway certificate file|-c "~/Documents/gateway.cert"| |--registrationcertpath|-r|Enables TLS by passing in path to the registration server certificate file|-r "~/Documents/registration.cert"| @@ -56,6 +55,13 @@ Optional args: |--dummyfrequency| |How often dummy messages should be sent per second. This flag is likely to be replaced when we implement better dummy message sending.|--dummyfrequency 0.5| |--end2end| |Send messages with E2E encryption to destination user|--end2end| |--keyParams| |Set E2E key generation parameters. Pass values in comma separated list, with the following order: MinKeys,MaxKeys,NumRekeys,TTLScalar,MinNumKeys|--keyParams 100,200,32,1.2,50| +|--email|-E|Email to register for User Discovery (default "default@default.com")|| +|--nick| |Nickname to register for User Discovery (default "Default")|| +|--ndfPubKey|-p|Path to the public key for the network definition JSON file| +|--ndf|-n|Path to the network definition JSON file| +|--ndfVerifySignature| |Specifies if the NDF should be loaded without the signature. defaults to true| +|--ndfRegistration| |Overwrite the Registration values for the NDF| +|--ndfUDB| |Overwrite the UDB values for the NDF| ##Project Structure @@ -84,9 +90,7 @@ the client's part of the cipher. without seriously considering the alternatives. Most important is the Log variable: -```go globals.Log.ERROR.Println("this is an error") -``` Using this global Log variable allows external users of jww logging, like the console UI, to see and print log messages from the client library if they need diff --git a/api/client.go b/api/client.go index 40c45875eb79c7809ee9fa9621622dd4881704e5..0a770a2162f3beca0408765ebe297ecc4178041a 100644 --- a/api/client.go +++ b/api/client.go @@ -31,8 +31,10 @@ import ( "gitlab.com/elixxir/crypto/large" "gitlab.com/elixxir/crypto/registration" "gitlab.com/elixxir/crypto/signature" - "gitlab.com/elixxir/primitives/format" + "gitlab.com/elixxir/crypto/signature/rsa" + "gitlab.com/elixxir/primitives/circuit" "gitlab.com/elixxir/primitives/id" + "gitlab.com/elixxir/primitives/ndf" "gitlab.com/elixxir/primitives/switchboard" "google.golang.org/grpc/credentials" goio "io" @@ -40,11 +42,11 @@ import ( ) type Client struct { - storage globals.Storage - sess user.Session - comm io.Communications - gwAddresses []io.ConnAddr - regAddress io.ConnAddr + storage globals.Storage + session user.Session + comm io.Communications + ndf *ndf.NetworkDefinition + topology *circuit.Circuit } // Populates a text message and returns its wire representation @@ -55,15 +57,55 @@ func FormatTextMessage(message string) []byte { Message: message, Time: time.Now().Unix(), } + wireRepresentation, _ := proto.Marshal(&textMessage) return wireRepresentation } +// VerifyNDF verifies the signature of the network definition file (NDF) and +// returns the structure. Panics when the NDF string cannot be decoded and when +// the signature cannot be verified. If the NDF public key is empty, then the +// signature verification is skipped and warning is printed. +func VerifyNDF(ndfString, ndfPub string) *ndf.NetworkDefinition { + // Decode NDF string to a NetworkDefinition and its signature + ndfJSON, ndfSignature, err := ndf.DecodeNDF(ndfString) + if err != nil { + globals.Log.FATAL.Panicf("Could not decode NDF: %v", err) + } + + // If there is no public key, then skip verification and print warning + if ndfPub == "" { + globals.Log.WARN.Printf("Running without signed network " + + "definition file") + } else { + // Get public key + pubKey, err := rsa.LoadPublicKeyFromPem([]byte(ndfPub)) + if err != nil { + globals.Log.FATAL.Panicf("Could not load public key: %v", err) + } + + // Hash NDF JSON + opts := rsa.NewDefaultOptions() + rsaHash := opts.Hash.New() + rsaHash.Write(ndfJSON.Serialize()) + + // Verify signature + err = rsa.Verify( + pubKey, opts.Hash, rsaHash.Sum(nil), ndfSignature, nil) + + if err != nil { + globals.Log.FATAL.Panicf("Could not verify NDF: %v", err) + } + } + + return ndfJSON +} + // Creates a new Client using the storage mechanism provided. // If none is provided, a default storage using OS file access // is created // returns a new Client object, and an error if it fails -func NewClient(s globals.Storage, loc string) (*Client, error) { +func NewClient(s globals.Storage, loc string, ndfJSON *ndf.NetworkDefinition) (*Client, error) { var store globals.Storage if s == nil { globals.Log.INFO.Printf("No storage provided," + @@ -81,72 +123,104 @@ func NewClient(s globals.Storage, loc string) (*Client, error) { return nil, err } + cmixGrp := cyclic.NewGroup( + large.NewIntFromString(ndfJSON.CMIX.Prime, 16), + large.NewIntFromString(ndfJSON.CMIX.Generator, 16), + large.NewIntFromString(ndfJSON.CMIX.SmallPrime, 16)) + + user.InitUserRegistry(cmixGrp) + cl := new(Client) cl.storage = store cl.comm = io.NewMessenger() - cl.gwAddresses = make([]io.ConnAddr, 0) + cl.ndf = ndfJSON + + //build the topology + nodeIDs := make([]*id.Node, len(cl.ndf.Nodes)) + for i, node := range cl.ndf.Nodes { + nodeIDs[i] = id.NewNodeFromBytes(node.ID) + } + + cl.topology = circuit.New(nodeIDs) + return cl, nil } // Connects to gateways and registration server (if needed) // using TLS filepaths to create credential information // for connection establishment -func (cl *Client) Connect(gwAddresses []string, gwCertPath, - regAddr, regCertPath string) error { - if len(gwAddresses) < 1 { +func (cl *Client) Connect() error { + if len(cl.ndf.Gateways) < 1 { globals.Log.ERROR.Printf("Connect: Invalid number of nodes") return errors.New("could not connect due to invalid number of nodes") } - var gwCreds credentials.TransportCredentials = nil - if gwCertPath != "" { - gwCreds = connect.NewCredentialsFromFile(gwCertPath, "") - } - - for _, gw := range gwAddresses { - addr := io.ConnAddr(gw) - (cl.comm).(*io.Messaging).Comms.ConnectToGateway(addr, gw, gwCreds) - cl.gwAddresses = append(cl.gwAddresses, addr) + //connect to all gateways + for _, gateway := range cl.ndf.Gateways { + var gwCreds credentials.TransportCredentials + if gateway.TlsCertificate != "" { + gwCreds = connect.NewCredentialsFromPEM(gateway.TlsCertificate, "") + } + addr := io.ConnAddr(gateway.Address) + (cl.comm).(*io.Messaging).Comms.ConnectToGateway(addr, gateway.Address, gwCreds) } - if regAddr != "" { - var regCreds credentials.TransportCredentials = nil - if regCertPath != "" { - regCreds = connect.NewCredentialsFromFile(regCertPath, "") + //connect to the registration server + if cl.ndf.Registration.Address != "" { + var regCreds credentials.TransportCredentials + if cl.ndf.Registration.TlsCertificate != "" { + regCreds = connect.NewCredentialsFromPEM(cl.ndf.Registration.TlsCertificate, "") } - addr := io.ConnAddr(regAddr) - (cl.comm).(*io.Messaging).Comms.ConnectToRegistration(addr, regAddr, regCreds) - cl.regAddress = addr + addr := io.ConnAddr(cl.ndf.Registration.Address) + (cl.comm).(*io.Messaging).Comms.ConnectToRegistration(addr, cl.ndf.Registration.Address, regCreds) + } else { + globals.Log.WARN.Printf("No registration server found to connect to") } return nil } // Registers user and returns the User ID. // Returns an error if registration fails. -func (cl *Client) Register(preCan bool, registrationCode, nick string, - mint bool, grp *cyclic.Group) (*id.User, error) { +func (cl *Client) Register(preCan bool, registrationCode, nick, email string) (*id.User, error) { var err error var u *user.User var UID *id.User + + cmixGrp := cyclic.NewGroup( + large.NewIntFromString(cl.ndf.CMIX.Prime, 16), + large.NewIntFromString(cl.ndf.CMIX.Generator, 16), + large.NewIntFromString(cl.ndf.CMIX.SmallPrime, 16)) + + e2eGrp := cyclic.NewGroup( + large.NewIntFromString(cl.ndf.E2E.Prime, 16), + large.NewIntFromString(cl.ndf.E2E.Generator, 16), + large.NewIntFromString(cl.ndf.E2E.SmallPrime, 16)) + // Make CMIX keys array - nk := make([]user.NodeKeys, len(cl.gwAddresses)) + nk := make(map[id.Node]user.NodeKeys) // Generate DSA keypair even for precanned users as it will probably // be needed for the new UDB flow - params := signature.GetDefaultDSAParams() + params := signature.CustomDSAParams( + cmixGrp.GetP(), + cmixGrp.GetQ(), + cmixGrp.GetG()) privateKey := params.PrivateKeyGen(rand.Reader) publicKey := privateKey.PublicKeyGen() + fmt.Println("gened private keys") + // Handle precanned registration if preCan { var successLook bool globals.Log.DEBUG.Printf("Registering precanned user") UID, successLook = user.Users.LookupUser(registrationCode) + fmt.Println("UID:", UID, "success:", successLook) + if !successLook { globals.Log.ERROR.Printf("Register: HUID does not match") - err = errors.New("could not register due to invalid HUID") - return id.ZeroID, err + return id.ZeroID, errors.New("could not register due to invalid HUID") } var successGet bool @@ -162,6 +236,10 @@ func (cl *Client) Register(preCan bool, registrationCode, nick string, u.Nick = nick } + if email != "" { + u.Email = email + } + nodekeys, successKeys := user.Users.LookupKeys(u.User) if !successKeys { @@ -170,8 +248,8 @@ func (cl *Client) Register(preCan bool, registrationCode, nick string, return id.ZeroID, err } - for i := 0; i < len(cl.gwAddresses); i++ { - nk[i] = *nodekeys + for i := 0; i < len(cl.ndf.Gateways); i++ { + nk[*cl.topology.GetNodeAtIndex(i)] = *nodekeys } } else { // Generate salt for UserID @@ -191,10 +269,10 @@ func (cl *Client) Register(preCan bool, registrationCode, nick string, // If Registration Server is specified, contact it // Only if registrationCode is set - if cl.regAddress != "" && registrationCode != "" { + if cl.ndf.Registration.Address != "" && registrationCode != "" { // Send registration code and public key to RegistrationServer response, err := (cl.comm).(*io.Messaging).Comms. - SendRegistrationMessage(cl.regAddress, + SendRegistrationMessage(io.ConnAddr(cl.ndf.Registration.Address), &pb.UserRegistration{ RegistrationCode: registrationCode, Client: &pb.DSAPublicKey{ @@ -217,12 +295,13 @@ func (cl *Client) Register(preCan bool, registrationCode, nick string, regR = response.ClientSignedByServer.R regS = response.ClientSignedByServer.S // Disconnect from regServer here since it will not be needed - (cl.comm).(*io.Messaging).Comms.Disconnect(cl.regAddress.String()) - cl.regAddress = "" + (cl.comm).(*io.Messaging).Comms.Disconnect(cl.ndf.Registration.Address) } - + fmt.Println("passed reg") // Loop over all Servers - for _, gwAddr := range cl.gwAddresses { + for _, gateway := range cl.ndf.Gateways { + + gwAddr := io.ConnAddr(gateway.Address) // Send signed public key and salt for UserID to Server nonceResponse, err := (cl.comm).(*io.Messaging).Comms. @@ -300,18 +379,17 @@ func (cl *Client) Register(preCan bool, registrationCode, nick string, // Loop through all the server public keys for itr, publicKey := range serverPublicKeys { - // Generate the base keys - nk[itr].TransmissionKey = registration.GenerateBaseKey( - grp, publicKey, privateKey, transmissionHash, - ) - - transmissionHash.Reset() + nodeID := *cl.topology.GetNodeAtIndex(itr) - nk[itr].ReceptionKey = registration.GenerateBaseKey( - grp, publicKey, privateKey, receptionHash, - ) + nk[nodeID] = user.NodeKeys{ + TransmissionKey: registration.GenerateBaseKey(cmixGrp, + publicKey, privateKey, transmissionHash), + ReceptionKey: registration.GenerateBaseKey(cmixGrp, publicKey, + privateKey, receptionHash), + } receptionHash.Reset() + transmissionHash.Reset() } var actualNick string @@ -325,7 +403,7 @@ func (cl *Client) Register(preCan bool, registrationCode, nick string, } // Create the user session - nus := user.NewSession(cl.storage, u, nk, publicKey, privateKey, grp) + nus := user.NewSession(cl.storage, u, nk, publicKey, privateKey, cmixGrp, e2eGrp) // Store the user session errStore := nus.StoreSession() @@ -340,7 +418,10 @@ func (cl *Client) Register(preCan bool, registrationCode, nick string, return id.ZeroID, err } - nus.Immolate() + err = nus.Immolate() + if err != nil { + globals.Log.ERROR.Printf("Error on immolate: %+v", err) + } nus = nil return UID, nil @@ -348,16 +429,16 @@ func (cl *Client) Register(preCan bool, registrationCode, nick string, // Logs in user and sets session on client object // returns the nickname or error if login fails -func (cl *Client) Login(UID *id.User, email string) (string, error) { +func (cl *Client) Login(UID *id.User) (string, error) { session, err := user.LoadSession(cl.storage, UID) if session == nil { return "", errors.New("Unable to load session: " + err.Error()) } - (cl.comm).(*io.Messaging).SendAddress = cl.gwAddresses[0] + (cl.comm).(*io.Messaging).SendAddress = io.ConnAddr(cl.ndf.Gateways[0].Address) (cl.comm).(*io.Messaging).ReceiveAddress = - cl.gwAddresses[len(cl.gwAddresses)-1] + io.ConnAddr(cl.ndf.Gateways[len(cl.ndf.Gateways)-1].Address) if err != nil { err = errors.New(fmt.Sprintf("Login: Could not login: %s", @@ -366,7 +447,7 @@ func (cl *Client) Login(UID *id.User, email string) (string, error) { return "", err } - cl.sess = session + cl.session = session pollWaitTimeMillis := 1000 * time.Millisecond // TODO Don't start the message receiver if it's already started. @@ -374,9 +455,11 @@ func (cl *Client) Login(UID *id.User, email string) (string, error) { go cl.comm.MessageReceiver(session, pollWaitTimeMillis) // Initialize UDB and nickname "bot" stuff here - bots.InitBots(cl.sess, cl.comm) + bots.InitBots(cl.session, cl.comm, cl.topology) // Initialize Rekey listeners - rekey.InitRekey(cl.sess, cl.comm) + rekey.InitRekey(cl.session, cl.comm, cl.topology) + + email := session.GetCurrentUser().Email if email != "" { err = cl.registerForUserDiscovery(email) @@ -396,7 +479,7 @@ 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() cryptoType := message.GetCryptoType() - return cl.comm.SendMessage(cl.sess, recipientID, cryptoType, message.Pack()) + return cl.comm.SendMessage(cl.session, cl.topology, recipientID, cryptoType, message.Pack()) } // DisableBlockingTransmission turns off blocking transmission, for @@ -411,50 +494,49 @@ func (cl *Client) SetRateLimiting(limit uint32) { (cl.comm).(*io.Messaging).TransmitDelay = time.Duration(limit) * time.Millisecond } -func (cl *Client) Listen(user *id.User, outerType format.CryptoType, - messageType int32, newListener switchboard.Listener) string { - listenerId := cl.sess.GetSwitchboard(). - Register(user, outerType, messageType, newListener) +func (cl *Client) Listen(user *id.User, messageType int32, newListener switchboard.Listener) string { + listenerId := cl.session.GetSwitchboard(). + Register(user, messageType, newListener) globals.Log.INFO.Printf("Listening now: user %v, message type %v, id %v", user, messageType, listenerId) return listenerId } func (cl *Client) StopListening(listenerHandle string) { - cl.sess.GetSwitchboard().Unregister(listenerHandle) + cl.session.GetSwitchboard().Unregister(listenerHandle) } func (cl *Client) GetSwitchboard() *switchboard.Switchboard { - return cl.sess.GetSwitchboard() + return cl.session.GetSwitchboard() } func (cl *Client) GetCurrentUser() *id.User { - return cl.sess.GetCurrentUser().User + return cl.session.GetCurrentUser().User } func (cl *Client) GetKeyParams() *keyStore.KeyParams { - return cl.sess.GetKeyStore().GetKeyParams() + return cl.session.GetKeyStore().GetKeyParams() } // Logout closes the connection to the server at this time and does // nothing with the user id. In the future this will release resources // and safely release any sensitive memory. func (cl *Client) Logout() error { - if cl.sess == nil { + if cl.session == nil { err := errors.New("Logout: Cannot Logout when you are not logged in") globals.Log.ERROR.Printf(err.Error()) return err } // Stop reception runner goroutine - cl.sess.GetQuitChan() <- true + cl.session.GetQuitChan() <- true // Disconnect from the gateways - for _, gw := range cl.gwAddresses { - (cl.comm).(*io.Messaging).Comms.Disconnect(gw.String()) + for _, gateway := range cl.ndf.Gateways { + (cl.comm).(*io.Messaging).Comms.Disconnect(gateway.Address) } - errStore := cl.sess.StoreSession() + errStore := cl.session.StoreSession() if errStore != nil { err := errors.New(fmt.Sprintf("Logout: Store Failed: %s" + @@ -463,8 +545,8 @@ func (cl *Client) Logout() error { return err } - errImmolate := cl.sess.Immolate() - cl.sess = nil + errImmolate := cl.session.Immolate() + cl.session = nil if errImmolate != nil { err := errors.New(fmt.Sprintf("Logout: Immolation Failed: %s" + @@ -488,7 +570,7 @@ func (cl *Client) registerForUserDiscovery(emailAddress string) error { return err } - publicKey := cl.sess.GetPublicKey() + publicKey := cl.session.GetPublicKey() publicKeyBytes := publicKey.GetKey().LeftpadBytes(256) return bots.Register(valueType, emailAddress, publicKeyBytes) } @@ -531,12 +613,12 @@ func (cl *Client) LookupNick(user *id.User, func (cl *Client) registerUserE2E(partnerID *id.User, partnerPubKey []byte) { // Get needed variables from session - grp := cl.sess.GetGroup() - userID := cl.sess.GetCurrentUser().User + grp := cl.session.GetCmixGroup() + userID := cl.session.GetCurrentUser().User // Create user private key and partner public key // in the group - privKey := cl.sess.GetPrivateKey() + privKey := cl.session.GetPrivateKey() privKeyCyclic := grp.NewIntFromLargeInt(privKey.GetKey()) partnerPubKeyCyclic := grp.NewIntFromBytes(partnerPubKey) @@ -547,7 +629,7 @@ func (cl *Client) registerUserE2E(partnerID *id.User, grp) // Generate key TTL and number of keys - params := cl.sess.GetKeyStore().GetKeyParams() + params := cl.session.GetKeyStore().GetKeyParams() keysTTL, numKeys := e2e.GenerateKeyTTL(baseKey.GetLargeInt(), params.MinKeys, params.MaxKeys, params.TTLParams) @@ -557,7 +639,7 @@ func (cl *Client) registerUserE2E(partnerID *id.User, numKeys, keysTTL, params.NumRekeys) // Generate Send Keys - km.GenerateKeys(grp, userID, cl.sess.GetKeyStore()) + km.GenerateKeys(grp, userID, cl.session.GetKeyStore()) // Create Receive KeyManager km = keyStore.NewManager(baseKey, privKeyCyclic, @@ -565,10 +647,10 @@ func (cl *Client) registerUserE2E(partnerID *id.User, numKeys, keysTTL, params.NumRekeys) // Generate Receive Keys - km.GenerateKeys(grp, userID, cl.sess.GetKeyStore()) + km.GenerateKeys(grp, userID, cl.session.GetKeyStore()) // Create RekeyKeys and add to RekeyManager - rkm := cl.sess.GetRekeyManager() + rkm := cl.session.GetRekeyManager() keys := &keyStore.RekeyKeys{ CurrPrivKey: privKeyCyclic, @@ -618,7 +700,7 @@ func ParseMessage(message []byte) (ParsedMessage, error) { } func (cl *Client) GetSessionData() ([]byte, error) { - return cl.sess.GetSessionData() + return cl.session.GetSessionData() } // Set the output of the diff --git a/api/client_test.go b/api/client_test.go index 0a3531d3d9efd0e604ff9e4bd2511460de6c4465..508da9cf8e98a9a18b00d10f4810c594a0d63546 100644 --- a/api/client_test.go +++ b/api/client_test.go @@ -10,6 +10,7 @@ import ( "bytes" "crypto/sha256" "encoding/gob" + "fmt" "github.com/golang/protobuf/proto" "gitlab.com/elixxir/client/cmixproto" "gitlab.com/elixxir/client/globals" @@ -17,10 +18,13 @@ import ( "gitlab.com/elixxir/client/parse" "gitlab.com/elixxir/client/user" "gitlab.com/elixxir/crypto/csprng" + "gitlab.com/elixxir/crypto/cyclic" "gitlab.com/elixxir/crypto/diffieHellman" "gitlab.com/elixxir/crypto/e2e" "gitlab.com/elixxir/crypto/hash" + "gitlab.com/elixxir/crypto/large" "gitlab.com/elixxir/crypto/signature" + "gitlab.com/elixxir/primitives/circuit" "gitlab.com/elixxir/primitives/format" "gitlab.com/elixxir/primitives/id" "reflect" @@ -28,21 +32,20 @@ import ( "time" ) -var testClient *Client - func TestRegistrationGob(t *testing.T) { // Get a Client - var err error - testClient, err = NewClient(&globals.RamStorage{}, "") + testClient, err := NewClient(&globals.RamStorage{}, "", def) if err != nil { t.Error(err) } - testClient.Connect(RegGWAddresses[:], "", "", "") + err = testClient.Connect() + if err != nil { + t.Error(err) + } // populate a gob in the store - grp := getGroup() - _, err = testClient.Register(true, "UAV6IWD6", "", false, grp) + _, err = testClient.Register(true, "UAV6IWD6", "", "") if err != nil { t.Error(err) } @@ -52,41 +55,45 @@ func TestRegistrationGob(t *testing.T) { var sessionBytes bytes.Buffer sessionBytes.Write(sessionGob) dec := gob.NewDecoder(&sessionBytes) - Session = user.SessionObj{} + Session := user.SessionObj{} err = dec.Decode(&Session) if err != nil { t.Error(err) } - VerifyRegisterGobKeys(t) - VerifyRegisterGobUser(t) + VerifyRegisterGobUser(&Session, t) + VerifyRegisterGobKeys(&Session, testClient.topology, t) } -func VerifyRegisterGobUser(t *testing.T) { - if *Session.GetCurrentUser().User != *id.NewUserFromUint(5, t) { - t.Errorf("User's ID was %q, expected %v", - Session.GetCurrentUser().User, 5) +func VerifyRegisterGobUser(session user.Session, t *testing.T) { + + expectedUser := id.NewUserFromUint(5, t) + + if reflect.DeepEqual(session.GetCurrentUser().User, &expectedUser) { + t.Errorf("Incorrect User ID; \n expected %q \n recieved: %q", + expectedUser, session.GetCurrentUser().User) } } -func VerifyRegisterGobKeys(t *testing.T) { - grp := getGroup() +func VerifyRegisterGobKeys(session user.Session, topology *circuit.Circuit, t *testing.T) { + cmixGrp, _ := getGroups() h := sha256.New() h.Write([]byte(string(20005))) - expectedTransmissionBaseKey := grp.NewIntFromBytes(h.Sum(nil)) - if Session.GetKeys()[0].TransmissionKey.Cmp( + expectedTransmissionBaseKey := cmixGrp.NewIntFromBytes(h.Sum(nil)) + + if session.GetKeys(topology)[0].TransmissionKey.Cmp( expectedTransmissionBaseKey) != 0 { t.Errorf("Transmission base key was %v, expected %v", - Session.GetKeys()[0].TransmissionKey.Text(16), + session.GetKeys(topology)[0].TransmissionKey.Text(16), expectedTransmissionBaseKey.Text(16)) } h = sha256.New() h.Write([]byte(string(40005))) - expectedReceptionBaseKey := grp.NewIntFromBytes(h.Sum(nil)) - if Session.GetKeys()[0].ReceptionKey.Cmp( + expectedReceptionBaseKey := cmixGrp.NewIntFromBytes(h.Sum(nil)) + if session.GetKeys(topology)[0].ReceptionKey.Cmp( expectedReceptionBaseKey) != 0 { t.Errorf("Reception base key was %v, expected %v", - Session.GetKeys()[0].ReceptionKey.Text(16), + session.GetKeys(topology)[0].ReceptionKey.Text(16), expectedReceptionBaseKey.Text(16)) } } @@ -184,29 +191,34 @@ func TestParse(t *testing.T) { // Test that registerUserE2E correctly creates keys and adds them to maps func TestRegisterUserE2E(t *testing.T) { - grp := getGroup() + testClient, err := NewClient(&globals.RamStorage{}, "", def) + if err != nil { + t.Error(err) + } + + cmixGrp, e2eGrp := getGroups() userID := id.NewUserFromUint(18, t) partner := id.NewUserFromUint(14, t) params := signature.CustomDSAParams( - grp.GetP(), - grp.GetG(), - grp.GetQ()) + cmixGrp.GetP(), + cmixGrp.GetQ(), + cmixGrp.GetG()) rng := csprng.NewSystemRNG() myPrivKey := params.PrivateKeyGen(rng) - myPrivKeyCyclic := grp.NewIntFromLargeInt(myPrivKey.GetKey()) + myPrivKeyCyclic := cmixGrp.NewIntFromLargeInt(myPrivKey.GetKey()) myPubKey := myPrivKey.PublicKeyGen() partnerPrivKey := params.PrivateKeyGen(rng) partnerPubKey := partnerPrivKey.PublicKeyGen() - partnerPubKeyCyclic := grp.NewIntFromLargeInt(partnerPubKey.GetKey()) + partnerPubKeyCyclic := cmixGrp.NewIntFromLargeInt(partnerPubKey.GetKey()) myUser := &user.User{User: userID, Nick: "test"} session := user.NewSession(testClient.storage, - myUser, []user.NodeKeys{}, myPubKey, myPrivKey, grp) - - testClient.sess = session + myUser, make(map[id.Node]user.NodeKeys), myPubKey, myPrivKey, cmixGrp, e2eGrp) + testClient.session = session + fmt.Println("runn") testClient.registerUserE2E(partner, partnerPubKeyCyclic.Bytes()) - + fmt.Println("dunn") // Confirm we can get all types of keys km := session.GetKeyStore().GetSendManager(partner) if km == nil { @@ -215,7 +227,7 @@ func TestRegisterUserE2E(t *testing.T) { key, action := km.PopKey() if key == nil { t.Errorf("TransmissionKeys map returned nil") - } else if key.GetOuterType() != format.E2E { + } else if key.GetOuterType() != parse.E2E { t.Errorf("Key type expected 'E2E', got %s", key.GetOuterType()) } else if action != keyStore.None { @@ -226,7 +238,7 @@ func TestRegisterUserE2E(t *testing.T) { key, action = km.PopRekey() if key == nil { t.Errorf("TransmissionReKeys map returned nil") - } else if key.GetOuterType() != format.Rekey { + } else if key.GetOuterType() != parse.Rekey { t.Errorf("Key type expected 'Rekey', got %s", key.GetOuterType()) } else if action != keyStore.None { @@ -236,9 +248,9 @@ func TestRegisterUserE2E(t *testing.T) { // Generate one reception key of each type to test // fingerprint map - baseKey, _ := diffieHellman.CreateDHSessionKey(partnerPubKeyCyclic, myPrivKeyCyclic, grp) - recvKeys := e2e.DeriveKeys(grp, baseKey, partner, uint(1)) - recvReKeys := e2e.DeriveEmergencyKeys(grp, baseKey, partner, uint(1)) + baseKey, _ := diffieHellman.CreateDHSessionKey(partnerPubKeyCyclic, myPrivKeyCyclic, cmixGrp) + recvKeys := e2e.DeriveKeys(cmixGrp, baseKey, partner, uint(1)) + recvReKeys := e2e.DeriveEmergencyKeys(cmixGrp, baseKey, partner, uint(1)) h, _ := hash.NewCMixHash() h.Write(recvKeys[0].Bytes()) @@ -248,7 +260,7 @@ func TestRegisterUserE2E(t *testing.T) { key = session.GetKeyStore().GetRecvKey(fp) if key == nil { t.Errorf("ReceptionKeys map returned nil for Key") - } else if key.GetOuterType() != format.E2E { + } else if key.GetOuterType() != parse.E2E { t.Errorf("Key type expected 'E2E', got %s", key.GetOuterType()) } @@ -260,7 +272,7 @@ func TestRegisterUserE2E(t *testing.T) { key = session.GetKeyStore().GetRecvKey(fp) if key == nil { t.Errorf("ReceptionKeys map returned nil for ReKey") - } else if key.GetOuterType() != format.Rekey { + } else if key.GetOuterType() != parse.Rekey { t.Errorf("Key type expected 'Rekey', got %s", key.GetOuterType()) } @@ -268,41 +280,46 @@ func TestRegisterUserE2E(t *testing.T) { // Test all keys created with registerUserE2E match what is expected func TestRegisterUserE2E_CheckAllKeys(t *testing.T) { - grp := getGroup() + testClient, err := NewClient(&globals.RamStorage{}, "", def) + if err != nil { + t.Error(err) + } + + cmixGrp, e2eGrp := getGroups() userID := id.NewUserFromUint(18, t) partner := id.NewUserFromUint(14, t) params := signature.CustomDSAParams( - grp.GetP(), - grp.GetG(), - grp.GetQ()) + cmixGrp.GetP(), + cmixGrp.GetQ(), + cmixGrp.GetG()) rng := csprng.NewSystemRNG() myPrivKey := params.PrivateKeyGen(rng) - myPrivKeyCyclic := grp.NewIntFromLargeInt(myPrivKey.GetKey()) + myPrivKeyCyclic := cmixGrp.NewIntFromLargeInt(myPrivKey.GetKey()) myPubKey := myPrivKey.PublicKeyGen() partnerPrivKey := params.PrivateKeyGen(rng) partnerPubKey := partnerPrivKey.PublicKeyGen() - partnerPubKeyCyclic := grp.NewIntFromLargeInt(partnerPubKey.GetKey()) + partnerPubKeyCyclic := cmixGrp.NewIntFromLargeInt(partnerPubKey.GetKey()) myUser := &user.User{User: userID, Nick: "test"} session := user.NewSession(testClient.storage, - myUser, []user.NodeKeys{}, myPubKey, - myPrivKey, grp) + myUser, make(map[id.Node]user.NodeKeys), myPubKey, + myPrivKey, cmixGrp, e2eGrp) - testClient.sess = session + testClient.session = session testClient.registerUserE2E(partner, partnerPubKeyCyclic.Bytes()) // Generate all keys and confirm they all match keyParams := testClient.GetKeyParams() - baseKey, _ := diffieHellman.CreateDHSessionKey(partnerPubKeyCyclic, myPrivKeyCyclic, grp) + baseKey, _ := diffieHellman.CreateDHSessionKey(partnerPubKeyCyclic, myPrivKeyCyclic, cmixGrp) keyTTL, numKeys := e2e.GenerateKeyTTL(baseKey.GetLargeInt(), keyParams.MinKeys, keyParams.MaxKeys, keyParams.TTLParams) - sendKeys := e2e.DeriveKeys(grp, baseKey, userID, uint(numKeys)) - sendReKeys := e2e.DeriveEmergencyKeys(grp, baseKey, + sendKeys := e2e.DeriveKeys(cmixGrp, baseKey, userID, uint(numKeys)) + sendReKeys := e2e.DeriveEmergencyKeys(cmixGrp, baseKey, userID, uint(keyParams.NumRekeys)) - recvKeys := e2e.DeriveKeys(grp, baseKey, partner, uint(numKeys)) - recvReKeys := e2e.DeriveEmergencyKeys(grp, baseKey, + recvKeys := e2e.DeriveKeys(cmixGrp, baseKey, partner, uint(numKeys)) + recvReKeys := e2e.DeriveEmergencyKeys(cmixGrp, baseKey, partner, uint(keyParams.NumRekeys)) // Confirm all keys @@ -314,7 +331,7 @@ func TestRegisterUserE2E_CheckAllKeys(t *testing.T) { key, action := km.PopKey() if key == nil { t.Errorf("TransmissionKeys map returned nil") - } else if key.GetOuterType() != format.E2E { + } else if key.GetOuterType() != parse.E2E { t.Errorf("Key type expected 'E2E', got %s", key.GetOuterType()) } @@ -342,7 +359,7 @@ func TestRegisterUserE2E_CheckAllKeys(t *testing.T) { key, action := km.PopRekey() if key == nil { t.Errorf("TransmissionReKeys map returned nil") - } else if key.GetOuterType() != format.Rekey { + } else if key.GetOuterType() != parse.Rekey { t.Errorf("Key type expected 'Rekey', got %s", key.GetOuterType()) } @@ -376,7 +393,7 @@ func TestRegisterUserE2E_CheckAllKeys(t *testing.T) { key := session.GetKeyStore().GetRecvKey(fp) if key == nil { t.Errorf("ReceptionKeys map returned nil for Key") - } else if key.GetOuterType() != format.E2E { + } else if key.GetOuterType() != parse.E2E { t.Errorf("Key type expected 'E2E', got %s", key.GetOuterType()) } @@ -395,7 +412,7 @@ func TestRegisterUserE2E_CheckAllKeys(t *testing.T) { key := session.GetKeyStore().GetRecvKey(fp) if key == nil { t.Errorf("ReceptionKeys map returned nil for Rekey") - } else if key.GetOuterType() != format.Rekey { + } else if key.GetOuterType() != parse.Rekey { t.Errorf("Key type expected 'Rekey', got %s", key.GetOuterType()) } @@ -482,3 +499,45 @@ func TestRegisterUserE2E_CheckAllKeys(t *testing.T) { // t.Errorf("Message wrong length: %d v. expected 81", len(lastmsg)) // } //} + +func getGroups() (*cyclic.Group, *cyclic.Group) { + + cmixGrp := cyclic.NewGroup( + large.NewIntFromString("9DB6FB5951B66BB6FE1E140F1D2CE5502374161FD6538DF1648218642F0B5C48"+ + "C8F7A41AADFA187324B87674FA1822B00F1ECF8136943D7C55757264E5A1A44F"+ + "FE012E9936E00C1D3E9310B01C7D179805D3058B2A9F4BB6F9716BFE6117C6B5"+ + "B3CC4D9BE341104AD4A80AD6C94E005F4B993E14F091EB51743BF33050C38DE2"+ + "35567E1B34C3D6A5C0CEAA1A0F368213C3D19843D0B4B09DCB9FC72D39C8DE41"+ + "F1BF14D4BB4563CA28371621CAD3324B6A2D392145BEBFAC748805236F5CA2FE"+ + "92B871CD8F9C36D3292B5509CA8CAA77A2ADFC7BFD77DDA6F71125A7456FEA15"+ + "3E433256A2261C6A06ED3693797E7995FAD5AABBCFBE3EDA2741E375404AE25B", 16), + large.NewIntFromString("5C7FF6B06F8F143FE8288433493E4769C4D988ACE5BE25A0E24809670716C613"+ + "D7B0CEE6932F8FAA7C44D2CB24523DA53FBE4F6EC3595892D1AA58C4328A06C4"+ + "6A15662E7EAA703A1DECF8BBB2D05DBE2EB956C142A338661D10461C0D135472"+ + "085057F3494309FFA73C611F78B32ADBB5740C361C9F35BE90997DB2014E2EF5"+ + "AA61782F52ABEB8BD6432C4DD097BC5423B285DAFB60DC364E8161F4A2A35ACA"+ + "3A10B1C4D203CC76A470A33AFDCBDD92959859ABD8B56E1725252D78EAC66E71"+ + "BA9AE3F1DD2487199874393CD4D832186800654760E1E34C09E4D155179F9EC0"+ + "DC4473F996BDCE6EED1CABED8B6F116F7AD9CF505DF0F998E34AB27514B0FFE7", 16), + large.NewIntFromString("F2C3119374CE76C9356990B465374A17F23F9ED35089BD969F61C6DDE9998C1F", 16)) + + e2eGrp := cyclic.NewGroup( + large.NewIntFromString("E2EE983D031DC1DB6F1A7A67DF0E9A8E5561DB8E8D49413394C049B"+ + "7A8ACCEDC298708F121951D9CF920EC5D146727AA4AE535B0922C688B55B3DD2AE"+ + "DF6C01C94764DAB937935AA83BE36E67760713AB44A6337C20E7861575E745D31F"+ + "8B9E9AD8412118C62A3E2E29DF46B0864D0C951C394A5CBBDC6ADC718DD2A3E041"+ + "023DBB5AB23EBB4742DE9C1687B5B34FA48C3521632C4A530E8FFB1BC51DADDF45"+ + "3B0B2717C2BC6669ED76B4BDD5C9FF558E88F26E5785302BEDBCA23EAC5ACE9209"+ + "6EE8A60642FB61E8F3D24990B8CB12EE448EEF78E184C7242DD161C7738F32BF29"+ + "A841698978825B4111B4BC3E1E198455095958333D776D8B2BEEED3A1A1A221A6E"+ + "37E664A64B83981C46FFDDC1A45E3D5211AAF8BFBC072768C4F50D7D7803D2D4F2"+ + "78DE8014A47323631D7E064DE81C0C6BFA43EF0E6998860F1390B5D3FEACAF1696"+ + "015CB79C3F9C2D93D961120CD0E5F12CBB687EAB045241F96789C38E89D796138E"+ + "6319BE62E35D87B1048CA28BE389B575E994DCA755471584A09EC723742DC35873"+ + "847AEF49F66E43873", 16), + large.NewIntFromString("2", 16), + large.NewIntFromString("2", 16)) + + return cmixGrp, e2eGrp + +} diff --git a/api/mockserver.go b/api/mockserver.go index 9ff19efa84bb6cc5cbe1c420485484c6e657ffb3..abeb89278e4ee7f74f9bac3dad43b70efd3c19a6 100644 --- a/api/mockserver.go +++ b/api/mockserver.go @@ -9,9 +9,9 @@ package api import ( "gitlab.com/elixxir/client/cmixproto" + "gitlab.com/elixxir/client/parse" pb "gitlab.com/elixxir/comms/mixmessages" "gitlab.com/elixxir/crypto/large" - "gitlab.com/elixxir/primitives/format" "gitlab.com/elixxir/primitives/id" "sync" ) @@ -40,8 +40,8 @@ func (m APIMessage) GetMessageType() int32 { return int32(cmixproto.Type_NO_TYPE) } -func (m APIMessage) GetCryptoType() format.CryptoType { - return format.None +func (m APIMessage) GetCryptoType() parse.CryptoType { + return parse.None } func (m APIMessage) Pack() []byte { @@ -96,7 +96,7 @@ type MockRegistration struct { } func (s *MockRegistration) RegisterNode(ID []byte, - NodeTLSCert, GatewayTLSCert, RegistrationCode string) error { + NodeTLSCert, GatewayTLSCert, RegistrationCode, Addr string) error { return nil } diff --git a/api/mockserver_test.go b/api/mockserver_test.go index f99d87d3bd593658d64095b20b8469ef3b60c02e..5d91c396368a321cfc87a5bb138f3999d672c32e 100644 --- a/api/mockserver_test.go +++ b/api/mockserver_test.go @@ -10,42 +10,37 @@ package api import ( "fmt" jww "github.com/spf13/jwalterweatherman" - "gitlab.com/elixxir/client/globals" "gitlab.com/elixxir/client/user" "gitlab.com/elixxir/comms/gateway" pb "gitlab.com/elixxir/comms/mixmessages" "gitlab.com/elixxir/comms/registration" - "gitlab.com/elixxir/crypto/cyclic" "gitlab.com/elixxir/primitives/id" + "gitlab.com/elixxir/primitives/ndf" + "math/rand" "os" "testing" + "time" ) -const NumGWs = 3 +const NumNodes = 3 +const NumGWs = NumNodes const RegPort = 5000 -const RegGWsStartPort = 10000 -const SessionGWPort = 15000 +const GWsStartPort = 10000 -var RegAddress = fmtAddress(RegPort) -var RegGWAddresses [NumGWs]string -var SessionGWAddress = fmtAddress(SessionGWPort) -var RegGWComms [NumGWs]*gateway.GatewayComms +var RegHandler = MockRegistration{} var RegComms *registration.RegistrationComms -var SessionGWComms *gateway.GatewayComms const ValidRegCode = "UAV6IWD6" -const InvalidRegCode = "INVALID_REG_CODE" +const InvalidRegCode = "INVALID_REG_CODE_" -var RegGWHandlers = [NumGWs]*TestInterface{ +var RegGWHandlers [3]*TestInterface = [NumGWs]*TestInterface{ {LastReceivedMessage: pb.Slot{}}, {LastReceivedMessage: pb.Slot{}}, {LastReceivedMessage: pb.Slot{}}, } +var GWComms [NumGWs]*gateway.GatewayComms -var RegHandler = MockRegistration{} - -var SessionGWHandler = TestInterface{LastReceivedMessage: pb.Slot{}} -var Session user.SessionObj +var def *ndf.NetworkDefinition // Setups general testing params and calls test wrapper func TestMain(m *testing.M) { @@ -62,17 +57,21 @@ func TestRegister_ValidPrecannedRegCodeReturnsZeroID(t *testing.T) { // Initialize client with dummy storage storage := DummyStorage{Location: "Blah", LastSave: []byte{'a', 'b', 'c'}} - client, err := NewClient(&storage, "hello") + client, err := NewClient(&storage, "hello", def) if err != nil { t.Errorf("Failed to initialize dummy client: %s", err.Error()) } // Connect to gateways and reg server - client.Connect(RegGWAddresses[:], "", "", "") + err = client.Connect() + + if err != nil { + t.Errorf("Client failed of connect: %+v", err) + } // Register precanned user with all gateways regRes, err := client.Register(true, ValidRegCode, - "", false, getGroup()) + "", "") // Verify registration succeeds with valid precanned registration code if err != nil { @@ -89,23 +88,26 @@ func TestRegister_ValidRegParams___(t *testing.T) { // Initialize client with dummy storage storage := DummyStorage{Location: "Blah", LastSave: []byte{'a', 'b', 'c'}} - client, err := NewClient(&storage, "hello") + client, err := NewClient(&storage, "hello", def) if err != nil { t.Errorf("Failed to initialize dummy client: %s", err.Error()) } // Connect to gateways and reg server - client.Connect(RegGWAddresses[:], "", RegAddress, "") + err = client.Connect() + + if err != nil { + t.Errorf("Client failed of connect: %+v", err) + } // Register precanned user with all gateways - regRes, err := client.Register(false, ValidRegCode, - "", false, getGroup()) + regRes, err := client.Register(false, ValidRegCode, "", "") if err != nil { t.Errorf("Registration failed: %s", err.Error()) } if *regRes == *id.ZeroID { - t.Errorf("Invalid registration number received: %v", *regRes) + t.Errorf("Invalid registration number received: %+v", *regRes) } } @@ -114,19 +116,22 @@ func TestRegister_InvalidPrecannedRegCodeReturnsError(t *testing.T) { // Initialize client with dummy storage storage := DummyStorage{Location: "Blah", LastSave: []byte{'a', 'b', 'c'}} - client, err := NewClient(&storage, "hello") + client, err := NewClient(&storage, "hello", def) if err != nil { t.Errorf("Failed to initialize dummy client: %s", err.Error()) } // Connect to gateways and reg server - client.Connect(RegGWAddresses[:], "", "", "") + err = client.Connect() + + if err != nil { + t.Errorf("Client failed of connect: %+v", err) + } // Register with invalid reg code - _, err = client.Register(true, InvalidRegCode, - "", false, getGroup()) + uid, err := client.Register(true, InvalidRegCode, "", "") if err == nil { - t.Error("Registration worked with invalid registration code!") + t.Errorf("Registration worked with invalid registration code! UID: %v", uid) } } @@ -134,21 +139,24 @@ func TestRegister_DeletedUserReturnsErr(t *testing.T) { // Initialize client with dummy storage storage := DummyStorage{Location: "Blah", LastSave: []byte{'a', 'b', 'c'}} - client, err := NewClient(&storage, "hello") + client, err := NewClient(&storage, "hello", def) if err != nil { t.Errorf("Failed to initialize dummy client: %s", err.Error()) } // Connect to gateways and reg server - client.Connect(RegGWAddresses[:], "", "", "") + err = client.Connect() + + if err != nil { + t.Errorf("Client failed of connect: %+v", err) + } // ... tempUser, _ := user.Users.GetUser(id.NewUserFromUint(5, t)) user.Users.DeleteUser(id.NewUserFromUint(5, t)) // Register - _, err = client.Register(true, ValidRegCode, - "", false, getGroup()) + _, err = client.Register(true, ValidRegCode, "", "") if err == nil { t.Errorf("Registration worked with a deleted user: %s", err.Error()) } @@ -160,24 +168,27 @@ func TestRegister_DeletedUserReturnsErr(t *testing.T) { func TestSend(t *testing.T) { // Initialize client with dummy storage storage := DummyStorage{Location: "Blah", LastSave: []byte{'a', 'b', 'c'}} - client, err := NewClient(&storage, "hello") + client, err := NewClient(&storage, "hello", def) if err != nil { t.Errorf("Failed to initialize dummy client: %s", err.Error()) } // Connect to gateways and reg server - client.Connect(RegGWAddresses[:], "", "", "") + err = client.Connect() + + if err != nil { + t.Errorf("Client failed of connect: %+v", err) + } // Register with a valid registration code - userID, err := client.Register(true, ValidRegCode, - "", false, getGroup()) + userID, err := client.Register(true, ValidRegCode, "", "") if err != nil { t.Errorf("Register failed: %s", err.Error()) } // Login to gateway - _, err = client.Login(userID, "") + _, err = client.Login(userID) if err != nil { t.Errorf("Login failed: %s", err.Error()) @@ -195,7 +206,7 @@ func TestSend(t *testing.T) { if err != nil { // TODO: would be nice to catch the sender but we // don't have the interface/mocking for that. - t.Errorf("error on first message send: %v", err) + t.Errorf("error on first message send: %+v", err) } // Test send with valid inputs @@ -217,13 +228,17 @@ func TestLogout(t *testing.T) { // Initialize client with dummy storage storage := DummyStorage{Location: "Blah", LastSave: []byte{'a', 'b', 'c'}} - client, err := NewClient(&storage, "hello") + client, err := NewClient(&storage, "hello", def) if err != nil { t.Errorf("Failed to initialize dummy client: %s", err.Error()) } // Connect to gateways and reg server - client.Connect(RegGWAddresses[:], "", "", "") + err = client.Connect() + + if err != nil { + t.Errorf("Client failed of connect: %+v", err) + } // Logout before logging in should return an error err = client.Logout() @@ -234,15 +249,14 @@ func TestLogout(t *testing.T) { } // Register with a valid registration code - userID, err := client.Register(true, ValidRegCode, - "", false, getGroup()) + userID, err := client.Register(true, ValidRegCode, "", "") if err != nil { t.Errorf("Register failed: %s", err.Error()) } // Login to gateway - _, err = client.Login(userID, "") + _, err = client.Login(userID) if err != nil { t.Errorf("Login failed: %s", err.Error()) @@ -267,36 +281,91 @@ func TestLogout(t *testing.T) { // gateways used for registration and gateway used for session func testMainWrapper(m *testing.M) int { + rng := rand.New(rand.NewSource(time.Now().UnixNano())) + + rndPort := int(rng.Uint64() % 10000) + + def = getNDF() + // Start mock gateways used by registration and defer their shutdown (may not be needed) for i, handler := range RegGWHandlers { - RegGWAddresses[i] = fmtAddress(RegGWsStartPort + i) - gw := gateway.StartGateway(RegGWAddresses[i], + + gw := ndf.Gateway{ + Address: fmtAddress(GWsStartPort + i + rndPort), + } + + def.Gateways = append(def.Gateways, gw) + + GWComms[i] = gateway.StartGateway(gw.Address, handler, "", "") - RegGWComms[i] = gw } // Start mock registration server and defer its shutdown - RegComms = registration.StartRegistrationServer(RegAddress, + def.Registration = ndf.Registration{ + Address: fmtAddress(RegPort + rndPort), + } + RegComms = registration.StartRegistrationServer(def.Registration.Address, &RegHandler, "", "") - // Start session gateway and defer its shutdown - SessionGWComms = gateway.StartGateway(SessionGWAddress, - &SessionGWHandler, "", "") + for i := 0; i < NumNodes; i++ { + nIdBytes := make([]byte, id.NodeIdLen) + nIdBytes[0] = byte(i) + n := ndf.Node{ + ID: nIdBytes, + } + def.Nodes = append(def.Nodes, n) + } defer testWrapperShutdown() return m.Run() } func testWrapperShutdown() { - for _, gw := range RegGWComms { + for _, gw := range GWComms { gw.Shutdown() } RegComms.Shutdown() - SessionGWComms.Shutdown() -} - -func getGroup() *cyclic.Group { - return globals.InitCrypto() } func fmtAddress(port int) string { return fmt.Sprintf("localhost:%d", port) } + +func getNDF() *ndf.NetworkDefinition { + return &ndf.NetworkDefinition{ + E2E: ndf.Group{ + Prime: "E2EE983D031DC1DB6F1A7A67DF0E9A8E5561DB8E8D49413394C049B" + + "7A8ACCEDC298708F121951D9CF920EC5D146727AA4AE535B0922C688B55B3DD2AE" + + "DF6C01C94764DAB937935AA83BE36E67760713AB44A6337C20E7861575E745D31F" + + "8B9E9AD8412118C62A3E2E29DF46B0864D0C951C394A5CBBDC6ADC718DD2A3E041" + + "023DBB5AB23EBB4742DE9C1687B5B34FA48C3521632C4A530E8FFB1BC51DADDF45" + + "3B0B2717C2BC6669ED76B4BDD5C9FF558E88F26E5785302BEDBCA23EAC5ACE9209" + + "6EE8A60642FB61E8F3D24990B8CB12EE448EEF78E184C7242DD161C7738F32BF29" + + "A841698978825B4111B4BC3E1E198455095958333D776D8B2BEEED3A1A1A221A6E" + + "37E664A64B83981C46FFDDC1A45E3D5211AAF8BFBC072768C4F50D7D7803D2D4F2" + + "78DE8014A47323631D7E064DE81C0C6BFA43EF0E6998860F1390B5D3FEACAF1696" + + "015CB79C3F9C2D93D961120CD0E5F12CBB687EAB045241F96789C38E89D796138E" + + "6319BE62E35D87B1048CA28BE389B575E994DCA755471584A09EC723742DC35873" + + "847AEF49F66E43873", + SmallPrime: "2", + Generator: "2", + }, + CMIX: ndf.Group{ + Prime: "9DB6FB5951B66BB6FE1E140F1D2CE5502374161FD6538DF1648218642F0B5C48" + + "C8F7A41AADFA187324B87674FA1822B00F1ECF8136943D7C55757264E5A1A44F" + + "FE012E9936E00C1D3E9310B01C7D179805D3058B2A9F4BB6F9716BFE6117C6B5" + + "B3CC4D9BE341104AD4A80AD6C94E005F4B993E14F091EB51743BF33050C38DE2" + + "35567E1B34C3D6A5C0CEAA1A0F368213C3D19843D0B4B09DCB9FC72D39C8DE41" + + "F1BF14D4BB4563CA28371621CAD3324B6A2D392145BEBFAC748805236F5CA2FE" + + "92B871CD8F9C36D3292B5509CA8CAA77A2ADFC7BFD77DDA6F71125A7456FEA15" + + "3E433256A2261C6A06ED3693797E7995FAD5AABBCFBE3EDA2741E375404AE25B", + SmallPrime: "F2C3119374CE76C9356990B465374A17F23F9ED35089BD969F61C6DDE9998C1F", + Generator: "5C7FF6B06F8F143FE8288433493E4769C4D988ACE5BE25A0E24809670716C613" + + "D7B0CEE6932F8FAA7C44D2CB24523DA53FBE4F6EC3595892D1AA58C4328A06C4" + + "6A15662E7EAA703A1DECF8BBB2D05DBE2EB956C142A338661D10461C0D135472" + + "085057F3494309FFA73C611F78B32ADBB5740C361C9F35BE90997DB2014E2EF5" + + "AA61782F52ABEB8BD6432C4DD097BC5423B285DAFB60DC364E8161F4A2A35ACA" + + "3A10B1C4D203CC76A470A33AFDCBDD92959859ABD8B56E1725252D78EAC66E71" + + "BA9AE3F1DD2487199874393CD4D832186800654760E1E34C09E4D155179F9EC0" + + "DC4473F996BDCE6EED1CABED8B6F116F7AD9CF505DF0F998E34AB27514B0FFE7", + }, + } +} diff --git a/api/ndf_test.go b/api/ndf_test.go new file mode 100644 index 0000000000000000000000000000000000000000..b2185a149af7662b762bb6e5592525d2cfcc8740 --- /dev/null +++ b/api/ndf_test.go @@ -0,0 +1,160 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright © 2019 Privategrity Corporation / +// / +// All rights reserved. / +//////////////////////////////////////////////////////////////////////////////// + +package api + +import ( + "crypto/rand" + "encoding/base64" + "fmt" + "gitlab.com/elixxir/crypto/signature/rsa" + "gitlab.com/elixxir/primitives/ndf" + "reflect" + "testing" +) + +var ExampleJSON = `{"Timestamp": "2019-06-04T20:48:48-07:00", "gateways": [{"Address": "52.25.135.52", "Tls_certificate": "-----BEGIN CERTIFICATE-----\nMIIDgTCCAmmgAwIBAgIJAKLdZ8UigIAeMA0GCSqGSIb3DQEBBQUAMG8xCzAJBgNV\nBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRIwEAYDVQQHDAlDbGFyZW1vbnQx\nGzAZBgNVBAoMElByaXZhdGVncml0eSBDb3JwLjEaMBgGA1UEAwwRZ2F0ZXdheSou\nY21peC5yaXAwHhcNMTkwMzA1MTgzNTU0WhcNMjkwMzAyMTgzNTU0WjBvMQswCQYD\nVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTESMBAGA1UEBwwJQ2xhcmVtb250\nMRswGQYDVQQKDBJQcml2YXRlZ3JpdHkgQ29ycC4xGjAYBgNVBAMMEWdhdGV3YXkq\nLmNtaXgucmlwMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA9+AaxwDP\nxHbhLmn4HoZu0oUM48Qufc6T5XEZTrpMrqJAouXk+61Jc0EFH96/sbj7VyvnXPRo\ngIENbk2Y84BkB9SkRMIXya/gh9dOEDSgnvj/yg24l3bdKFqBMKiFg00PYB30fU+A\nbe3OI/le0I+v++RwH2AV0BMq+T6PcAGjCC1Q1ZB0wP9/VqNMWq5lbK9wD46IQiSi\n+SgIQeE7HoiAZXrGO0Y7l9P3+VRoXjRQbqfn3ETNL9ZvQuarwAYC9Ix5MxUrS5ag\nOmfjc8bfkpYDFAXRXmdKNISJmtCebX2kDrpP8Bdasx7Fzsx59cEUHCl2aJOWXc7R\n5m3juOVL1HUxjQIDAQABoyAwHjAcBgNVHREEFTATghFnYXRld2F5Ki5jbWl4LnJp\ncDANBgkqhkiG9w0BAQUFAAOCAQEAMu3xoc2LW2UExAAIYYWEETggLNrlGonxteSu\njuJjOR+ik5SVLn0lEu22+z+FCA7gSk9FkWu+v9qnfOfm2Am+WKYWv3dJ5RypW/hD\nNXkOYxVJNYFxeShnHohNqq4eDKpdqSxEcuErFXJdLbZP1uNs4WIOKnThgzhkpuy7\ntZRosvOF1X5uL1frVJzHN5jASEDAa7hJNmQ24kh+ds/Ge39fGD8pK31CWhnIXeDo\nvKD7wivi/gSOBtcRWWLvU8SizZkS3hgTw0lSOf5geuzvasCEYlqrKFssj6cTzbCB\nxy3ra3WazRTNTW4TmkHlCUC9I3oWTTxw5iQxF/I2kQQnwR7L3w==\n-----END CERTIFICATE-----"}, {"Address": "52.25.219.38", "Tls_certificate": "-----BEGIN CERTIFICATE-----\nMIIDgTCCAmmgAwIBAgIJAKLdZ8UigIAeMA0GCSqGSIb3DQEBBQUAMG8xCzAJBgNV\nBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRIwEAYDVQQHDAlDbGFyZW1vbnQx\nGzAZBgNVBAoMElByaXZhdGVncml0eSBDb3JwLjEaMBgGA1UEAwwRZ2F0ZXdheSou\nY21peC5yaXAwHhcNMTkwMzA1MTgzNTU0WhcNMjkwMzAyMTgzNTU0WjBvMQswCQYD\nVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTESMBAGA1UEBwwJQ2xhcmVtb250\nMRswGQYDVQQKDBJQcml2YXRlZ3JpdHkgQ29ycC4xGjAYBgNVBAMMEWdhdGV3YXkq\nLmNtaXgucmlwMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA9+AaxwDP\nxHbhLmn4HoZu0oUM48Qufc6T5XEZTrpMrqJAouXk+61Jc0EFH96/sbj7VyvnXPRo\ngIENbk2Y84BkB9SkRMIXya/gh9dOEDSgnvj/yg24l3bdKFqBMKiFg00PYB30fU+A\nbe3OI/le0I+v++RwH2AV0BMq+T6PcAGjCC1Q1ZB0wP9/VqNMWq5lbK9wD46IQiSi\n+SgIQeE7HoiAZXrGO0Y7l9P3+VRoXjRQbqfn3ETNL9ZvQuarwAYC9Ix5MxUrS5ag\nOmfjc8bfkpYDFAXRXmdKNISJmtCebX2kDrpP8Bdasx7Fzsx59cEUHCl2aJOWXc7R\n5m3juOVL1HUxjQIDAQABoyAwHjAcBgNVHREEFTATghFnYXRld2F5Ki5jbWl4LnJp\ncDANBgkqhkiG9w0BAQUFAAOCAQEAMu3xoc2LW2UExAAIYYWEETggLNrlGonxteSu\njuJjOR+ik5SVLn0lEu22+z+FCA7gSk9FkWu+v9qnfOfm2Am+WKYWv3dJ5RypW/hD\nNXkOYxVJNYFxeShnHohNqq4eDKpdqSxEcuErFXJdLbZP1uNs4WIOKnThgzhkpuy7\ntZRosvOF1X5uL1frVJzHN5jASEDAa7hJNmQ24kh+ds/Ge39fGD8pK31CWhnIXeDo\nvKD7wivi/gSOBtcRWWLvU8SizZkS3hgTw0lSOf5geuzvasCEYlqrKFssj6cTzbCB\nxy3ra3WazRTNTW4TmkHlCUC9I3oWTTxw5iQxF/I2kQQnwR7L3w==\n-----END CERTIFICATE-----"}, {"Address": "52.41.80.104", "Tls_certificate": "-----BEGIN CERTIFICATE-----\nMIIDgTCCAmmgAwIBAgIJAKLdZ8UigIAeMA0GCSqGSIb3DQEBBQUAMG8xCzAJBgNV\nBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRIwEAYDVQQHDAlDbGFyZW1vbnQx\nGzAZBgNVBAoMElByaXZhdGVncml0eSBDb3JwLjEaMBgGA1UEAwwRZ2F0ZXdheSou\nY21peC5yaXAwHhcNMTkwMzA1MTgzNTU0WhcNMjkwMzAyMTgzNTU0WjBvMQswCQYD\nVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTESMBAGA1UEBwwJQ2xhcmVtb250\nMRswGQYDVQQKDBJQcml2YXRlZ3JpdHkgQ29ycC4xGjAYBgNVBAMMEWdhdGV3YXkq\nLmNtaXgucmlwMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA9+AaxwDP\nxHbhLmn4HoZu0oUM48Qufc6T5XEZTrpMrqJAouXk+61Jc0EFH96/sbj7VyvnXPRo\ngIENbk2Y84BkB9SkRMIXya/gh9dOEDSgnvj/yg24l3bdKFqBMKiFg00PYB30fU+A\nbe3OI/le0I+v++RwH2AV0BMq+T6PcAGjCC1Q1ZB0wP9/VqNMWq5lbK9wD46IQiSi\n+SgIQeE7HoiAZXrGO0Y7l9P3+VRoXjRQbqfn3ETNL9ZvQuarwAYC9Ix5MxUrS5ag\nOmfjc8bfkpYDFAXRXmdKNISJmtCebX2kDrpP8Bdasx7Fzsx59cEUHCl2aJOWXc7R\n5m3juOVL1HUxjQIDAQABoyAwHjAcBgNVHREEFTATghFnYXRld2F5Ki5jbWl4LnJp\ncDANBgkqhkiG9w0BAQUFAAOCAQEAMu3xoc2LW2UExAAIYYWEETggLNrlGonxteSu\njuJjOR+ik5SVLn0lEu22+z+FCA7gSk9FkWu+v9qnfOfm2Am+WKYWv3dJ5RypW/hD\nNXkOYxVJNYFxeShnHohNqq4eDKpdqSxEcuErFXJdLbZP1uNs4WIOKnThgzhkpuy7\ntZRosvOF1X5uL1frVJzHN5jASEDAa7hJNmQ24kh+ds/Ge39fGD8pK31CWhnIXeDo\nvKD7wivi/gSOBtcRWWLvU8SizZkS3hgTw0lSOf5geuzvasCEYlqrKFssj6cTzbCB\nxy3ra3WazRTNTW4TmkHlCUC9I3oWTTxw5iQxF/I2kQQnwR7L3w==\n-----END CERTIFICATE-----"}], "nodes": [{"Id": [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], "Dsa_public_key": "-----BEGIN PUBLIC KEY-----\nMIIDNDCCAiwCggEBAJ22+1lRtmu2/h4UDx0s5VAjdBYf1lON8WSCGGQvC1xIyPek\nGq36GHMkuHZ0+hgisA8ez4E2lD18VXVyZOWhpE/+AS6ZNuAMHT6TELAcfReYBdMF\niyqfS7b5cWv+YRfGtbPMTZvjQRBK1KgK1slOAF9LmT4U8JHrUXQ78zBQw43iNVZ+\nGzTD1qXAzqoaDzaCE8PRmEPQtLCdy5/HLTnI3kHxvxTUu0Vjyig3FiHK0zJLai05\nIUW+v6x0iAUjb1yi/pK4cc2PnDbTKStVCcqMqneirfx7/XfdpvcRJadFb+oVPkMy\nVqImHGoG7TaTeX55lfrVqrvPvj7aJ0HjdUBK4lsCIQDywxGTdM52yTVpkLRlN0oX\n8j+e01CJvZafYcbd6ZmMHwKCAQBcf/awb48UP+gohDNJPkdpxNmIrOW+JaDiSAln\nBxbGE9ewzuaTL4+qfETSyyRSPaU/vk9uw1lYktGqWMQyigbEahVmLn6qcDod7Pi7\nstBdvi65VsFCozhmHRBGHA0TVHIIUFfzSUMJ/6c8YR94syrbtXQMNhyfNb6QmX2y\nAU4u9apheC9Sq+uL1kMsTdCXvFQjsoXa+2DcNk6BYfSio1rKOhCxxNIDzHakcKM6\n/cvdkpWYWavYtW4XJSUteOrGbnG6muPx3SSHGZh0OTzU2DIYaABlR2Dh40wJ5NFV\nF5+ewNxEc/mWvc5u7Ryr7YtvEW962c9QXfD5mONKsnUUsP/nAoIBAERwUmUlL9YP\nq6MSn+bUr6qNZPsVYoQAo8nTjZWiuSjJa2XWnh7sftnISWkwkiiRxo7qfq3sAiD5\nB8+tM6kONeICBXukldXJerxoVBspYa+RiPuDWy2pwGRDBpfty3QqJOpu5g2ThYFJ\nD5Xu0yCuX8ZJRj33nliI8dQgKdQQva6p2VuXzyRT8LwXMfRwLuSB6Schc9mF8C\nkWCb4m0ujlEKe1xKoKt2zG9b1o7XyaVhxguSUAuEznifMzsEUfuONJOy+XoQELex\nF0wvLzNzABcyxkM3lx52uG41mKgJiV6Z0ZyuBRvt+V3VL/38tPn9lsTaFi8N6/IH\nRyy0bWP5s44=\n-----END PUBLIC KEY-----\n", "Address": "18.237.147.105", "Tls_certificate": "-----BEGIN CERTIFICATE-----MIIDbDCCAlSgAwIBAgIJAOUNtZneIYECMA0GCSqGSIb3DQEBBQUAMGgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRIwEAYDVQQHDAlDbGFyZW1vbnQxGzAZBgNVBAoMElByaXZhdGVncml0eSBDb3JwLjETMBEGA1UEAwwKKi5jbWl4LnJpcDAeFwOTAzMDUxODM1NDNaFw0yOTAzMDIxODM1NDNaMGgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRIwEAYDVQQHDAlDbGFyZW1vbnQxGzAZBgNVBAoMElByaXZhdGVncml0eSBDb3JwLjETMBEGA1UEAwwKKi5jbWl4LnJpcDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAPP0WyVkfZA/CEd2DgKpcudn0oDhDwsjmx8LBDWsUgQzyLrFiVigfUmUefknUH3dTJjmiJtGqLsayCnWdqWLHPJYvFfsWYW0IGF93UG/4N5UAWO4okC3CYgKSi4ekpfw2zgZq0gmbzTnXcHF9gfmQ7jJUKSEtJPSNzXq+PZeJTC9zJAb4Lj8QzH18rDM8DaL2y1ns0Y2Hu0edBFn/OqavBJKb/uAm3AEjqeOhC7EQUjVamWlTBPt40+B/6aFJX5BYm2JFkRsGBIyBVL46MvC02MgzTT9bJIJfwqmBaTruwemNgzGu7Jk03hqqS1TUEvSI6/x8bVoba3orcKkf9HsDjECAwEAAaMZMBcwFQYDVR0RBA4wDIIKKi5jbWl4LnJpcDANBgkqhkiG9w0BAQUFAAOCAQEAneUocN4AbcQAC1+b3To8u5UGdaGxhcGyZBlAoenRVdjXK3lTjsMdMWb4QctgNfIfU/zuUn2mxTmF/ekP0gCCgtleZr9+DYKU5hlXk8K10uKxGD6EvoiXZzlfeUuotgp2qvI3ysOm/hvCfyEkqhfHtbxjV7j7v7eQFPbvNaXbLa0yr4C4vMK/Z09Ui9JrZ/Z4cyIkxfC6/rOqAirSdIp09EGiw7GM8guHyggE4IiZrDslT8V3xIl985cbCxSxeW1RtgH4rdEXuVe9+31oJhmXOE9ux2jCop9tEJMgWg7HStrJ5plPbb+HmjoX3nBO04E56m52PyzMNV+2N21IPppKwA==-----END CERTIFICATE-----"}, {"Id": [2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], "Dsa_public_key": "-----BEGIN PUBLIC KEY-----\nMIIDNDCCAiwCggEBAJ22+1lRtmu2/h4UDx0s5VAjdBYf1lON8WSCGGQvC1xIyPek\nGq36GHMkuHZ0+hgisA8ez4E2lD18VXVyZOWhpE/+AS6ZNuAMHT6TELAcfReYBdMF\niyqfS7b5cWv+YRfGtbPMTZvjQRBK1KgK1slOAF9LmT4U8JHrUXQ78zBQw43iNVZ+\nGzTD1qXAzqoaDzaCE8PRmEPQtLCdy5/HLTnI3kHxvxTUu0Vjyig3FiHK0zJLai05\nIUW+v6x0iAUjb1yi/pK4cc2PnDbTKStVCcqMqneirfx7/XfdpvcRJadFb+oVPkMy\nVqImHGoG7TaTeX55lfrVqrvPvj7aJ0HjdUBK4lsCIQDywxGTdM52yTVpkLRlN0oX\n8j+e01CJvZafYcbd6ZmMHwKCAQBcf/awb48UP+gohDNJPkdpxNmIrOW+JaDiSAln\nBxbGE9ewzuaTL4+qfETSyyRSPaU/vk9uw1lYktGqWMQyigbEahVmLn6qcDod7Pi7\nstBdvi65VsFCozhmHRBGHA0TVHIIUFfzSUMJ/6c8YR94syrbtXQMNhyfNb6QmX2y\nAU4u9apheC9Sq+uL1kMsTdCXvFQjsoXa+2DcNk6BYfSio1rKOhCxxNIDzHakcKM6\n/cvdkpWYWavYtW4XJSUteOrGbnG6muPx3SSHGZh0OTzU2DIYaABlR2Dh40wJ5NFV\nF5+ewNxEc/mWvc5u7Ryr7YtvEW962c9QXfD5mONKsnUUsP/nAoIBAFbADcqA8KQh\nxzgylW6VS1dYYelO5DjPZVVSjfdcbj1twu4ZHDNZLOexpv4nGY8xS6vesELXcVOR\n/CHXgh/3byBZYm0zkrBi/FsJJ3nP2uZ1+QCRldI2KzqcLOWH/CAYj8koork9k1Dp\nFq7rMSDgw4pktqvFj9Eev8dSZuRnoCfZbt/6vxi1r30AYAjDYOwcysqcVyUa1tPa\nLEh3JksttXUCd5cvfqatWedTs5Vxo7ICW1toGBHABYvSJkwK0YFfi5RLw+Oda1sA\njJ+aLcIxQjrpoRC2alXCdwmZXVb+O6zluQctw6LJjt4J704ueSvR4VNNhr0uLYGW\nk7e+WoQCS98=\n-----END PUBLIC KEY-----\n", "Address": "52.11.136.238", "Tls_certificate": "-----BEGIN CERTIFICATE-----MIIDbDCCAlSgAwIBAgIJAOUNtZneIYECMA0GCSqGSIb3DQEBBQUAMGgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRIwEAYDVQQHDAlDbGFyZW1vbnQxGzAZBgNVBAoMElByaXZhdGVncml0eSBDb3JwLjETMBEGA1UEAwwKKi5jbWl4LnJpcDAeFwOTAzMDUxODM1NDNaFw0yOTAzMDIxODM1NDNaMGgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRIwEAYDVQQHDAlDbGFyZW1vbnQxGzAZBgNVBAoMElByaXZhdGVncml0eSBDb3JwLjETMBEGA1UEAwwKKi5jbWl4LnJpcDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAPP0WyVkfZA/CEd2DgKpcudn0oDhDwsjmx8LBDWsUgQzyLrFiVigfUmUefknUH3dTJjmiJtGqLsayCnWdqWLHPJYvFfsWYW0IGF93UG/4N5UAWO4okC3CYgKSi4ekpfw2zgZq0gmbzTnXcHF9gfmQ7jJUKSEtJPSNzXq+PZeJTC9zJAb4Lj8QzH18rDM8DaL2y1ns0Y2Hu0edBFn/OqavBJKb/uAm3AEjqeOhC7EQUjVamWlTBPt40+B/6aFJX5BYm2JFkRsGBIyBVL46MvC02MgzTT9bJIJfwqmBaTruwemNgzGu7Jk03hqqS1TUEvSI6/x8bVoba3orcKkf9HsDjECAwEAAaMZMBcwFQYDVR0RBA4wDIIKKi5jbWl4LnJpcDANBgkqhkiG9w0BAQUFAAOCAQEAneUocN4AbcQAC1+b3To8u5UGdaGxhcGyZBlAoenRVdjXK3lTjsMdMWb4QctgNfIfU/zuUn2mxTmF/ekP0gCCgtleZr9+DYKU5hlXk8K10uKxGD6EvoiXZzlfeUuotgp2qvI3ysOm/hvCfyEkqhfHtbxjV7j7v7eQFPbvNaXbLa0yr4C4vMK/Z09Ui9JrZ/Z4cyIkxfC6/rOqAirSdIp09EGiw7GM8guHyggE4IiZrDslT8V3xIl985cbCxSxeW1RtgH4rdEXuVe9+31oJhmXOE9ux2jCop9tEJMgWg7HStrJ5plPbb+HmjoX3nBO04E56m52PyzMNV+2N21IPppKwA==-----END CERTIFICATE-----"}, {"Id": [3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], "Dsa_public_key": "-----BEGIN PUBLIC KEY-----\nMIIDNTCCAiwCggEBAJ22+1lRtmu2/h4UDx0s5VAjdBYf1lON8WSCGGQvC1xIyPek\nGq36GHMkuHZ0+hgisA8ez4E2lD18VXVyZOWhpE/+AS6ZNuAMHT6TELAcfReYBdMF\niyqfS7b5cWv+YRfGtbPMTZvjQRBK1KgK1slOAF9LmT4U8JHrUXQ78zBQw43iNVZ+\nGzTD1qXAzqoaDzaCE8PRmEPQtLCdy5/HLTnI3kHxvxTUu0Vjyig3FiHK0zJLai05\nIUW+v6x0iAUjb1yi/pK4cc2PnDbTKStVCcqMqneirfx7/XfdpvcRJadFb+oVPkMy\nVqImHGoG7TaTeX55lfrVqrvPvj7aJ0HjdUBK4lsCIQDywxGTdM52yTVpkLRlN0oX\n8j+e01CJvZafYcbd6ZmMHwKCAQBcf/awb48UP+gohDNJPkdpxNmIrOW+JaDiSAln\nBxbGE9ewzuaTL4+qfETSyyRSPaU/vk9uw1lYktGqWMQyigbEahVmLn6qcDod7Pi7\nstBdvi65VsFCozhmHRBGHA0TVHIIUFfzSUMJ/6c8YR94syrbtXQMNhyfNb6QmX2y\nAU4u9apheC9Sq+uL1kMsTdCXvFQjsoXa+2DcNk6BYfSio1rKOhCxxNIDzHakcKM6\n/cvdkpWYWavYtW4XJSUteOrGbnG6muPx3SSHGZh0OTzU2DIYaABlR2Dh40wJ5NFV\nF5+ewNxEc/mWvc5u7Ryr7YtvEW962c9QXfD5mONKsnUUsP/nAoIBAQCN19tTnkS3\nitBQXXR/h8OKl+rliFBLgO6h6GvZL4yQDZFtBAOmkrs3wLoDroJRGCeqz/IUb+JF\njslEr/mpm2kcmK77hr535dq7HsWz1fFl9YyGTaOH055FLSV9QEPAV9j3zWADdQ1v\nuSQll+QfWi6lIibWV4HNQ2ywRFoOY8OBLCJB90UXLeJpaPanpqiM8hjda2VGRDbi\nIixEE2lCOWITydiz2DmvXrLhVGF49+g5MDwbWO65dmasCe//Ff6Z4bJ6n049xv\nVtac8nX6FO3eBsV5d+rG6HZXSG3brCKRCSKYCTX1IkTSiutYxYqvwaluoCjOakh0\nKkqvQ8IeVZ+B\n-----END PUBLIC KEY-----\n", "Address": "34.213.79.31", "Tls_certificate": "-----BEGIN CERTIFICATE-----MIIDbDCCAlSgAwIBAgIJAOUNtZneIYECMA0GCSqGSIb3DQEBBQUAMGgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRIwEAYDVQQHDAlDbGFyZW1vbnQxGzAZBgNVBAoMElByaXZhdGVncml0eSBDb3JwLjETMBEGA1UEAwwKKi5jbWl4LnJpcDAeFwOTAzMDUxODM1NDNaFw0yOTAzMDIxODM1NDNaMGgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRIwEAYDVQQHDAlDbGFyZW1vbnQxGzAZBgNVBAoMElByaXZhdGVncml0eSBDb3JwLjETMBEGA1UEAwwKKi5jbWl4LnJpcDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAPP0WyVkfZA/CEd2DgKpcudn0oDhDwsjmx8LBDWsUgQzyLrFiVigfUmUefknUH3dTJjmiJtGqLsayCnWdqWLHPJYvFfsWYW0IGF93UG/4N5UAWO4okC3CYgKSi4ekpfw2zgZq0gmbzTnXcHF9gfmQ7jJUKSEtJPSNzXq+PZeJTC9zJAb4Lj8QzH18rDM8DaL2y1ns0Y2Hu0edBFn/OqavBJKb/uAm3AEjqeOhC7EQUjVamWlTBPt40+B/6aFJX5BYm2JFkRsGBIyBVL46MvC02MgzTT9bJIJfwqmBaTruwemNgzGu7Jk03hqqS1TUEvSI6/x8bVoba3orcKkf9HsDjECAwEAAaMZMBcwFQYDVR0RBA4wDIIKKi5jbWl4LnJpcDANBgkqhkiG9w0BAQUFAAOCAQEAneUocN4AbcQAC1+b3To8u5UGdaGxhcGyZBlAoenRVdjXK3lTjsMdMWb4QctgNfIfU/zuUn2mxTmF/ekP0gCCgtleZr9+DYKU5hlXk8K10uKxGD6EvoiXZzlfeUuotgp2qvI3ysOm/hvCfyEkqhfHtbxjV7j7v7eQFPbvNaXbLa0yr4C4vMK/Z09Ui9JrZ/Z4cyIkxfC6/rOqAirSdIp09EGiw7GM8guHyggE4IiZrDslT8V3xIl985cbCxSxeW1RtgH4rdEXuVe9+31oJhmXOE9ux2jCop9tEJMgWg7HStrJ5plPbb+HmjoX3nBO04E56m52PyzMNV+2N21IPppKwA==-----END CERTIFICATE-----"}], "registration": {"Dsa_public_key": "-----BEGIN PUBLIC KEY-----\nMIIDNDCCAiwCggEBAJ22+1lRtmu2/h4UDx0s5VAjdBYf1lON8WSCGGQvC1xIyPek\nGq36GHMkuHZ0+hgisA8ez4E2lD18VXVyZOWhpE/+AS6ZNuAMHT6TELAcfReYBdMF\niyqfS7b5cWv+YRfGtbPMTZvjQRBK1KgK1slOAF9LmT4U8JHrUXQ78zBQw43iNVZ+\nGzTD1qXAzqoaDzaCE8PRmEPQtLCdy5/HLTnI3kHxvxTUu0Vjyig3FiHK0zJLai05\nIUW+v6x0iAUjb1yi/pK4cc2PnDbTKStVCcqMqneirfx7/XfdpvcRJadFb+oVPkMy\nVqImHGoG7TaTeX55lfrVqrvPvj7aJ0HjdUBK4lsCIQDywxGTdM52yTVpkLRlN0oX\n8j+e01CJvZafYcbd6ZmMHwKCAQBcf/awb48UP+gohDNJPkdpxNmIrOW+JaDiSAln\nBxbGE9ewzuaTL4+qfETSyyRSPaU/vk9uw1lYktGqWMQyigbEahVmLn6qcDod7Pi7\nstBdvi65VsFCozhmHRBGHA0TVHIIUFfzSUMJ/6c8YR94syrbtXQMNhyfNb6QmX2y\nAU4u9apheC9Sq+uL1kMsTdCXvFQjsoXa+2DcNk6BYfSio1rKOhCxxNIDzHakcKM6\n/cvdkpWYWavYtW4XJSUteOrGbnG6muPx3SSHGZh0OTzU2DIYaABlR2Dh40wJ5NFV\nF5+ewNxEc/mWvc5u7Ryr7YtvEW962c9QXfD5mONKsnUUsP/nAoIBAAlELnrXLG0s\n4yAAn7IsVWwY7swDnbBcsIF2cnef4tjm/nNwrFKp5AxYqgeXCiJM8VkyJrotWG50\nnXQwMCR6BsvYrlVt/RmQvR8BSrir62uSLK7hMKm7dXnFvtyFtjp91UwTRbIjxhUQ\nGYnhAzrkCDWo1m54ysqXEGlrVwvRXrCAXiLKPiTEIS+B4GFH9W26SwBxhFLNYSUk\nZZ7+4qwMf9aTu7kIpXTP3hNIyRCjtuZvo5SnymtbLARwTP943hW8MOj0+Ege+m1P\ntey6rkMUGQ86cgK9/7+7Jb+EwW5UxdQtFPUFeNKdQ6zDPS6qbliecUrsc12tdgeg\nhQyuMbyKUuo=\n-----END PUBLIC KEY-----\n", "Address": "registration.default.cmix.rip", "Tls_certificate": "-----BEGIN CERTIFICATE-----MIIDkDCCAnigAwIBAgIJAJnjosuSsP7gMA0GCSqGSIb3DQEBBQUAMHQxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRIwEAYDVQQHDAlDbGFyZW1vbnQxGzAZBgNVBAoMElByaXZhdGVncml0eSBDb3JwLjEfMB0GA1UEAwwWcmVnaXN0cmF0aW9uKi5jbWl4LnJpcDAeFwOTAzMDUyMTQ5NTZaFw0yOTAzMDIyMTQ5NTZaMHQxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRIwEAYDVQQHDAlDbGFyZW1vbnQxGzAZBgNVBAoMElByaXZhdGVncml0eSBDb3JwLjEfMB0GA1UEAwwWcmVnaXN0cmF0aW9uKi5jbWl4LnJpcDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOQKvqjdh35o+MECBhCwopJzPlQNmq2iPbewRNtI02bUNK3kLQUbFlYdzNGZS4GYXGc5O+jdi8Slx82r1kdjz5PPCNFBARIsOP/L8r3DGeW+yeJdgBZjm1s3ylkamt4Ajiq/bNjysS6L/WSOp+sVumDxtBEzO/UTU1O6QRnzUphLaiWENmErGvsH0CZVq38Ia58k/QjCAzpUcYi4j2l1fb07xqFcQD8H6SmUM297UyQosDrp8ukdIo31Koxr4XDnnNNsYStC26tzHMeKuJ2Wl+3YzsSyflfM2YEcKE31sqB9DS36UkJ8J84eLsHNImGg3WodFAviDB67+jXDbB30NkMCAwEAAaMlMCMwIQYDVR0RBBowGIIWcmVnaXN0cmF0aW9uKi5jbWl4LnJpcDANBgkqhkiG9w0BAQUFAAOCAQEAF9mNzk+g+o626Rllt3f3/1qIyYQrYJ0BjSWCKYEFMCgZ4JibAJjAvIajhVYERtltffM+YKcdE2kTpdzJ0YJuUnRfuv6sVnXlVVugUUnd4IOigmjbCdM32k170CYMm0aiwGxl4FrNa8ei7AIax/s1n+sqWq3HeW5LXjnoVb+s3HeCWIuLfcgrurfye8FnNhy14HFzxVYYefIKmL+DPlcGGGm/PPYt3u4a2+rP3xaihc65dTa0u5tf/XPXtPxTDPFj2JeQDFxo7QRREbPD89CtYnwuP937CrkvCKrL0GkW1FViXKqZY9F5uhxrvLIpzhbNrs/EbtweY35XGLDCCMkg==-----END CERTIFICATE-----"}, "udb": {"Id": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3], "Dsa_public_key": "-----BEGIN PUBLIC KEY-----\nMIIDNDCCAiwCggEBAJ22+1lRtmu2/h4UDx0s5VAjdBYf1lON8WSCGGQvC1xIyPek\nGq36GHMkuHZ0+hgisA8ez4E2lD18VXVyZOWhpE/+AS6ZNuAMHT6TELAcfReYBdMF\niyqfS7b5cWv+YRfGtbPMTZvjQRBK1KgK1slOAF9LmT4U8JHrUXQ78zBQw43iNVZ+\nGzTD1qXAzqoaDzaCE8PRmEPQtLCdy5/HLTnI3kHxvxTUu0Vjyig3FiHK0zJLai05\nIUW+v6x0iAUjb1yi/pK4cc2PnDbTKStVCcqMqneirfx7/XfdpvcRJadFb+oVPkMy\nVqImHGoG7TaTeX55lfrVqrvPvj7aJ0HjdUBK4lsCIQDywxGTdM52yTVpkLRlN0oX\n8j+e01CJvZafYcbd6ZmMHwKCAQBcf/awb48UP+gohDNJPkdpxNmIrOW+JaDiSAln\nBxbGE9ewzuaTL4+qfETSyyRSPaU/vk9uw1lYktGqWMQyigbEahVmLn6qcDod7Pi7\nstBdvi65VsFCozhmHRBGHA0TVHIIUFfzSUMJ/6c8YR94syrbtXQMNhyfNb6QmX2y\nAU4u9apheC9Sq+uL1kMsTdCXvFQjsoXa+2DcNk6BYfSio1rKOhCxxNIDzHakcKM6\n/cvdkpWYWavYtW4XJSUteOrGbnG6muPx3SSHGZh0OTzU2DIYaABlR2Dh40wJ5NFV\nF5+ewNxEc/mWvc5u7Ryr7YtvEW962c9QXfD5mONKsnUUsP/nAoIBACvR2lUslz3D\nB/MUo0rHVIHVkhVJCxNjtgTOYgJ9ckArSXQbYzr/fcigcNGjUO2LbK5NFp9GK43C\nrLxMUnJ9nkyIVPaWvquJFZItjcDK3NiNGyD4XyM0eRj4dYeSxQM48hvFbmtbjlXn\n9SQTnGIlr1XnTI4RVHZSQOL6kFJIaLw6wYrQ4w08Ng+p45brp5ercAHnLiftNUWP\nqROhQkdSEpS9LEwfotUSY1jP2AhQfaIMxaeXsZuTU1IYvdhMFRL3DR0r5Ww2Upf8\ng0Ace0mtnsUQ2OG+7MTh2jYIEWRjvuoe3RCz603ujW6g7BfQ1H7f4YFwc5xOOJ3u\nr4dj49dCCjc=\n-----END PUBLIC KEY-----\n"}, "E2e": {"Prime": "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF", "Small_prime": "7FFFFFFFFFFFFFFFE487ED5110B4611A62633145C06E0E68948127044533E63A0105DF531D89CD9128A5043CC71A026EF7CA8CD9E69D218D98158536F92F8A1BA7F09AB6B6A8E122F242DABB312F3F637A262174D31BF6B585FFAE5B7A035BF6F71C35FDAD44CFD2D74F9208BE258FF324943328F6722D9EE1003E5C50B1DF82CC6D241B0E2AE9CD348B1FD47E9267AFC1B2AE91EE51D6CB0E3179AB1042A95DCF6A9483B84B4B36B3861AA7255E4C0278BA3604650C10BE19482F23171B671DF1CF3B960C074301CD93C1D17603D147DAE2AEF837A62964EF15E5FB4AAC0B8C1CCAA4BE754AB5728AE9130C4C7D02880AB9472D455655347FFFFFFFFFFFFFFF", "Generator": "02"}, "CMIX": {"Prime": "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF", "Small_prime": "7FFFFFFFFFFFFFFFE487ED5110B4611A62633145C06E0E68948127044533E63A0105DF531D89CD9128A5043CC71A026EF7CA8CD9E69D218D98158536F92F8A1BA7F09AB6B6A8E122F242DABB312F3F637A262174D31BF6B585FFAE5B7A035BF6F71C35FDAD44CFD2D74F9208BE258FF324943328F6722D9EE1003E5C50B1DF82CC6D241B0E2AE9CD348B1FD47E9267AFC1B2AE91EE51D6CB0E3179AB1042A95DCF6A9483B84B4B36B3861AA7255E4C0278BA3604650C10BE19482F23171B671DF1CF3B960C074301CD93C1D17603D147DAE2AEF837A62964EF15E5FB4AAC0B8C1CCAA4BE754AB5728AE9130C4C7D02880AB9472D455655347FFFFFFFFFFFFFFF", "Generator": "02"}}` + +// Tests that VerifyNDF() correctly verifies the NDF signature. +func TestVerifyNDF(t *testing.T) { + // Generate RSA private and public keys + // Size of 768 is unsafe, but allows the test to run faster + privateKey, _ := rsa.GenerateKey(rand.Reader, 768) + publicKey := &rsa.PublicKey{PublicKey: privateKey.PublicKey} + publicKeyBytes := rsa.CreatePublicKeyPem(publicKey) + + // Sign the NDF + ndfJSON, _, _ := ndf.DecodeNDF(ExampleJSON + "\n") + opts := rsa.NewDefaultOptions() + rsaHash := opts.Hash.New() + rsaHash.Write(ndfJSON.Serialize()) + signature, _ := rsa.Sign( + rand.Reader, privateKey, opts.Hash, rsaHash.Sum(nil), nil) + + // Print error on panic + defer func() { + if r := recover(); r != nil { + t.Errorf("VerifyNDF() panicked when it was not supposed to"+ + "\n\treceived: %#v\n\texpected: %#v", r, nil) + } + }() + + // Compose network definition string + ndfString := ExampleJSON + "\n" + base64.StdEncoding.EncodeToString(signature) + + // Run VerifyNDF() + fmt.Println(string(publicKeyBytes)) + fmt.Println(ndfString) + ndfJSONOutput := VerifyNDF(ndfString, string(publicKeyBytes)) + + // Check that the output is the expected NetworkDefinition structure + if !reflect.DeepEqual(ndfJSONOutput, ndfJSON) { + t.Errorf("VerifyNDF() did not output the correct "+ + "NetworkDefinition structure"+ + "\n\treceived: %#v\n\texpected: %#v", + ndfJSONOutput, ndfJSON) + } +} + +// Tests that VerifyNDF() panics when given the incorrect RSA public key. +func TestVerifyNDF_ErrPublicKey(t *testing.T) { + // Generate RSA private key and fake RSA public key + // Size of 768 is unsafe, but allows the test to run faster + privateKey, _ := rsa.GenerateKey(rand.Reader, 768) + + privateKey2, _ := rsa.GenerateKey(rand.Reader, 768) + publicKey := &rsa.PublicKey{PublicKey: privateKey2.PublicKey} + publicKeyBytes := rsa.CreatePublicKeyPem(publicKey) + + // Sign the NDF + ndfJSON, _, _ := ndf.DecodeNDF(ExampleJSON + "\n") + opts := rsa.NewDefaultOptions() + rsaHash := opts.Hash.New() + rsaHash.Write(ndfJSON.Serialize()) + signature, _ := rsa.Sign( + rand.Reader, privateKey, opts.Hash, rsaHash.Sum(nil), nil) + + // Print error on no panic + defer func() { + if r := recover(); r == nil { + t.Errorf("VerifyNDF() did not panic when expected when the "+ + "public key is invalid"+ + "\n\treceived: %#v\n\texpected: %#v", + r, "Could not verify NDF: crypto/rsa: verification error") + } + }() + + // Compose network definition string + ndfString := ExampleJSON + "\n" + base64.StdEncoding.EncodeToString(signature) + + // Run VerifyNDF() + VerifyNDF(ndfString, string(publicKeyBytes)) +} + +// Tests that VerifyNDF() panics when given an invalid NDF string. +func TestVerifyNDF_ErrInvalidNDF(t *testing.T) { + // Generate RSA private key and fake RSA public key + // Size of 768 is unsafe, but allows the test to run faster + privateKey, _ := rsa.GenerateKey(rand.Reader, 768) + + privateKey2, _ := rsa.GenerateKey(rand.Reader, 768) + publicKey := &rsa.PublicKey{PublicKey: privateKey2.PublicKey} + publicKeyBytes := rsa.CreatePublicKeyPem(publicKey) + + // Sign the NDF + ndfJSON, _, _ := ndf.DecodeNDF(ExampleJSON + "\n") + opts := rsa.NewDefaultOptions() + rsaHash := opts.Hash.New() + rsaHash.Write(ndfJSON.Serialize()) + signature, _ := rsa.Sign( + rand.Reader, privateKey, opts.Hash, rsaHash.Sum(nil), nil) + + // Print error on no panic + defer func() { + if r := recover(); r == nil { + t.Errorf("VerifyNDF() did not panic when expected when given "+ + "invalid NDF"+ + "\n\treceived: %#v\n\texpected: %#v", + r, "Could not decode NDF: unexpected end of JSON input") + } + }() + + // Compose network definition string + ndfString := " \n" + base64.StdEncoding.EncodeToString(signature) + + // Run VerifyNDF() + VerifyNDF(ndfString, string(publicKeyBytes)) +} + +// Tests that VerifyNDF() correctly outputs a NetworkDefinition structure and +// skips verifying the signature when the public key is empty. +func TestVerifyNDF_EmptyPublicKey(t *testing.T) { + // Generate RSA private and public keys + // Size of 768 is unsafe, but allows the test to run faster + privateKey, _ := rsa.GenerateKey(rand.Reader, 768) + + // Sign the NDF + ndfJSON, _, _ := ndf.DecodeNDF(ExampleJSON + "\n") + opts := rsa.NewDefaultOptions() + rsaHash := opts.Hash.New() + rsaHash.Write(ndfJSON.Serialize()) + signature, _ := rsa.Sign( + rand.Reader, privateKey, opts.Hash, rsaHash.Sum(nil), nil) + + // Compose network definition string + ndfString := ExampleJSON + "\n" + base64.StdEncoding.EncodeToString(signature) + + // Run VerifyNDF() + ndfJSONOutput := VerifyNDF(ndfString, "") + + // Check that the output is the expected NetworkDefinition structure + if !reflect.DeepEqual(ndfJSONOutput, ndfJSON) { + t.Errorf("VerifyNDF() did not output the correct "+ + "NetworkDefinition structure"+ + "\n\treceived: %#v\n\texpected: %#v", + ndfJSONOutput, ndfJSON) + } +} diff --git a/bindings/client.go b/bindings/client.go index d4437fdbb746237c5de4f18675a7e50c4376804b..4db478d73201f9e6e608063783d5fe72abedd8ee 100644 --- a/bindings/client.go +++ b/bindings/client.go @@ -8,15 +8,13 @@ package bindings import ( "errors" + "fmt" "gitlab.com/elixxir/client/api" "gitlab.com/elixxir/client/globals" "gitlab.com/elixxir/client/parse" - "gitlab.com/elixxir/crypto/cyclic" - "gitlab.com/elixxir/primitives/format" "gitlab.com/elixxir/primitives/id" "gitlab.com/elixxir/primitives/switchboard" "io" - "strings" ) type Client struct { @@ -73,7 +71,7 @@ func (cl *Client) Listen(userId []byte, messageType int32, newListener Listener) listener := &listenerProxy{proxy: newListener} - return cl.client.Listen(typedUserId, format.None, messageType, listener) + return cl.client.Listen(typedUserId, messageType, listener) } // Pass the listener handle that Listen() returned to delete the listener @@ -98,13 +96,15 @@ func FormatTextMessage(message string) []byte { // loc is a string. If you're using DefaultStorage for your storage, // this would be the filename of the file that you're storing the user // session in. -func NewClient(storage Storage, loc string) (*Client, error) { +func NewClient(storage Storage, loc string, ndfStr, ndfPubKey string) (*Client, error) { if storage == nil { return nil, errors.New("could not init client: Storage was nil") } + ndf := api.VerifyNDF(ndfStr, ndfPubKey) + proxy := &storageProxy{boundStorage: storage} - cl, err := api.NewClient(globals.Storage(proxy), loc) + cl, err := api.NewClient(globals.Storage(proxy), loc, ndf) return &Client{client: cl}, err } @@ -112,15 +112,8 @@ func NewClient(storage Storage, loc string) (*Client, error) { // Connects to gateways and registration server (if needed) // using TLS filepaths to create credential information // for connection establishment -func (cl *Client) Connect(gwAddressesList, gwCertPath, - regAddr, regCertPath string) error { - - if gwAddressesList == "" { - return errors.New("invalid number of nodes") - } - - gwList := strings.Split(gwAddressesList, ",") - return cl.client.Connect(gwList, gwCertPath, regAddr, regCertPath) +func (cl *Client) Connect() error { + return cl.client.Connect() } // Registers user and returns the User ID bytes. @@ -130,17 +123,9 @@ func (cl *Client) Connect(gwAddressesList, gwCertPath, // registrationAddr is the address of the registration server // gwAddressesList is CSV of gateway addresses // grp is the CMIX group needed for keys generation in JSON string format -func (cl *Client) Register(preCan bool, registrationCode, nick string, - mint bool, grpJSON string) ([]byte, error) { - - // Unmarshal group JSON - var grp cyclic.Group - err := grp.UnmarshalJSON([]byte(grpJSON)) - if err != nil { - return id.ZeroID[:], err - } - - UID, err := cl.client.Register(preCan, registrationCode, nick, mint, &grp) +func (cl *Client) Register(preCan bool, registrationCode, nick, email string) ([]byte, error) { + fmt.Println("calling client reg") + UID, err := cl.client.Register(preCan, registrationCode, nick, email) if err != nil { return id.ZeroID[:], err @@ -158,9 +143,9 @@ func (cl *Client) Register(preCan bool, registrationCode, nick string, // certificate string to "default", the bindings will use that certificate. // If you leave it empty, the Client will try to connect to the GW without TLS // This should only ever be used for testing purposes -func (cl *Client) Login(UID []byte, email string) (string, error) { +func (cl *Client) Login(UID []byte) (string, error) { userID := id.NewUserFromBytes(UID) - return cl.client.Login(userID, email) + return cl.client.Login(userID) } // Sends a message structured via the message interface @@ -170,11 +155,11 @@ func (cl *Client) Send(m Message, encrypt bool) error { sender := id.NewUserFromBytes(m.GetSender()) recipient := id.NewUserFromBytes(m.GetRecipient()) - var cryptoType format.CryptoType + var cryptoType parse.CryptoType if encrypt { - cryptoType = format.E2E + cryptoType = parse.E2E } else { - cryptoType = format.Unencrypted + cryptoType = parse.Unencrypted } return cl.client.Send(&parse.Message{ @@ -182,9 +167,9 @@ func (cl *Client) Send(m Message, encrypt bool) error { MessageType: m.GetMessageType(), Body: m.GetPayload(), }, - CryptoType: cryptoType, - Sender: sender, - Receiver: recipient, + InferredType: cryptoType, + Sender: sender, + Receiver: recipient, }) } diff --git a/bindings/client_test.go b/bindings/client_test.go index 3b57f8330c3bd59d88ab14d9349ed2be384c371c..13c90eb54ead7b4f84e65c7d0e1dcaa6b7d628b2 100644 --- a/bindings/client_test.go +++ b/bindings/client_test.go @@ -8,38 +8,52 @@ package bindings import ( "bytes" + crand "crypto/rand" + "encoding/base64" + "encoding/json" + "fmt" "gitlab.com/elixxir/client/api" "gitlab.com/elixxir/client/cmixproto" "gitlab.com/elixxir/client/globals" "gitlab.com/elixxir/client/parse" "gitlab.com/elixxir/comms/gateway" - "gitlab.com/elixxir/crypto/cyclic" - "gitlab.com/elixxir/crypto/large" + "gitlab.com/elixxir/crypto/signature/rsa" "gitlab.com/elixxir/primitives/id" + "gitlab.com/elixxir/primitives/ndf" + "math/rand" "os" "reflect" "testing" "time" ) -const gwAddress = "localhost:5557" +const NumNodes = 1 +const NumGWs = NumNodes +const GWsStartPort = 10000 +const ValidRegCode = "UAV6IWD6" + +var GWComms [NumGWs]*gateway.GatewayComms + +var def *ndf.NetworkDefinition + +// Setups general testing params and calls test wrapper func TestMain(m *testing.M) { - gwShutDown := gateway.StartGateway(gwAddress, - gateway.NewImplementation(), "", "") - time.Sleep(100 * time.Millisecond) - defer gwShutDown.Shutdown() - os.Exit(m.Run()) + + os.Exit(testMainWrapper(m)) } // Make sure NewClient returns an error when called incorrectly. func TestNewClientNil(t *testing.T) { - _, err := NewClient(nil, "") + + ndfStr, pubKey := getNDFJSONStr(def, t) + + _, err := NewClient(nil, "", ndfStr, pubKey) if err == nil { t.Errorf("NewClient returned nil on invalid (nil, nil) input!") } - _, err = NewClient(nil, "hello") + _, err = NewClient(nil, "hello", "", "") if err == nil { t.Errorf("NewClient returned nil on invalid (nil, 'hello') input!") } @@ -47,7 +61,10 @@ func TestNewClientNil(t *testing.T) { func TestNewClient(t *testing.T) { d := api.DummyStorage{Location: "Blah", LastSave: []byte{'a', 'b', 'c'}} - client, err := NewClient(&d, "hello") + + ndfStr, pubKey := getNDFJSONStr(def, t) + + client, err := NewClient(&d, "hello", ndfStr, pubKey) if err != nil { t.Errorf("NewClient returned error: %v", err) } else if client == nil { @@ -55,52 +72,26 @@ func TestNewClient(t *testing.T) { } } -// BytesReceiver receives the last message and puts the data it received into -// byte slices -type BytesReceiver struct { - receptionBuffer []byte - lastSID []byte - lastRID []byte -} +func TestRegister(t *testing.T) { -// This is the method that globals.Receive calls when you set a BytesReceiver -// as the global receiver -func (br *BytesReceiver) Receive(message Message) { - br.receptionBuffer = append(br.receptionBuffer, message.GetPayload()...) - br.lastRID = message.GetRecipient() - br.lastSID = message.GetSender() -} + ndfStr, pubKey := getNDFJSONStr(def, t) -func TestRegister(t *testing.T) { - registrationCode := "UAV6IWD6" d := api.DummyStorage{Location: "Blah", LastSave: []byte{'a', 'b', 'c'}} - client, err := NewClient(&d, "hello") - primeString := "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" + - "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + - "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" + - "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" + - "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" + - "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" + - "83655D23DCA3AD961C62F356208552BB9ED529077096966D" + - "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" + - "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" + - "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" + - "15728E5A8AACAA68FFFFFFFFFFFFFFFF" - p := large.NewInt(1) - p.SetString(primeString, 16) - g := large.NewInt(2) - q := large.NewInt(3) - grp := cyclic.NewGroup(p, g, q) - grpJSON, err := grp.MarshalJSON() + client, err := NewClient(&d, "hello", ndfStr, pubKey) + if err != nil { t.Errorf("Failed to marshal group JSON: %s", err) } // Connect to gateway - client.Connect(gwAddress, "", "", "") + err = client.Connect() + + if err != nil { + t.Errorf("Could not connect: %+v", err) + } - regRes, err := client.Register(true, registrationCode, - "", false, string(grpJSON)) + regRes, err := client.Register(true, ValidRegCode, + "", "") if err != nil { t.Errorf("Registration failed: %s", err.Error()) } @@ -110,11 +101,18 @@ func TestRegister(t *testing.T) { } func TestConnectBadNumNodes(t *testing.T) { + + newDef := *def + + newDef.Gateways = make([]ndf.Gateway, 0) + + ndfStr, pubKey := getNDFJSONStr(&newDef, t) + d := api.DummyStorage{Location: "Blah", LastSave: []byte{'a', 'b', 'c'}} - client, err := NewClient(&d, "hello") + client, err := NewClient(&d, "hello", ndfStr, pubKey) // Connect to empty gw - err = client.Connect("", "", "", "") + err = client.Connect() if err == nil { t.Errorf("Connect should have returned an error when no gateway is passed") @@ -122,38 +120,23 @@ func TestConnectBadNumNodes(t *testing.T) { } func TestLoginLogout(t *testing.T) { - registrationCode := "UAV6IWD6" + + ndfStr, pubKey := getNDFJSONStr(def, t) + d := api.DummyStorage{Location: "Blah", LastSave: []byte{'a', 'b', 'c'}} - client, err := NewClient(&d, "hello") - primeString := "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" + - "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + - "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" + - "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" + - "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" + - "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" + - "83655D23DCA3AD961C62F356208552BB9ED529077096966D" + - "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" + - "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" + - "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" + - "15728E5A8AACAA68FFFFFFFFFFFFFFFF" - p := large.NewInt(1) - p.SetString(primeString, 16) - g := large.NewInt(2) - q := large.NewInt(3) - grp := cyclic.NewGroup(p, g, q) - grpJSON, err := grp.MarshalJSON() - if err != nil { - t.Errorf("Failed to marshal group JSON: %s", err) - } + client, err := NewClient(&d, "hello", ndfStr, pubKey) // Connect to gateway - client.Connect(gwAddress, "", "", "") + err = client.Connect() + if err != nil { + t.Errorf("Could not connect: %+v", err) + } - regRes, err := client.Register(true, registrationCode, - "", false, string(grpJSON)) - loginRes, err2 := client.Login(regRes, "") + regRes, err := client.Register(true, ValidRegCode, + "", "") + loginRes, err2 := client.Login(regRes) if err2 != nil { - t.Errorf("Login failed: %s", err.Error()) + t.Errorf("Login failed: %s", err2.Error()) } if len(loginRes) == 0 { t.Errorf("Invalid login received: %v", loginRes) @@ -161,7 +144,7 @@ func TestLoginLogout(t *testing.T) { time.Sleep(2000 * time.Millisecond) err3 := client.Logout() if err3 != nil { - t.Errorf("Logoutfailed: %s", err.Error()) + t.Errorf("Logoutfailed: %s", err3.Error()) } } @@ -173,36 +156,27 @@ func (m *MockListener) Hear(msg Message, isHeardElsewhere bool) { // Proves that a message can be received by a listener added with the bindings func TestListen(t *testing.T) { - registrationCode := "UAV6IWD6" + + ndfStr, pubKey := getNDFJSONStr(def, t) + d := api.DummyStorage{Location: "Blah", LastSave: []byte{'a', 'b', 'c'}} - client, err := NewClient(&d, "hello") - primeString := "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" + - "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + - "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" + - "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" + - "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" + - "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" + - "83655D23DCA3AD961C62F356208552BB9ED529077096966D" + - "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" + - "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" + - "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" + - "15728E5A8AACAA68FFFFFFFFFFFFFFFF" - p := large.NewInt(1) - p.SetString(primeString, 16) - g := large.NewInt(2) - q := large.NewInt(3) - grp := cyclic.NewGroup(p, g, q) - grpJSON, err := grp.MarshalJSON() + client, err := NewClient(&d, "hello", ndfStr, pubKey) + + // Connect to gateway + err = client.Connect() + if err != nil { - t.Errorf("Failed to marshal group JSON: %s", err) + t.Errorf("Could not connect: %+v", err) } - // Connect to gateway - client.Connect(gwAddress, "", "", "") + regRes, _ := client.Register(true, ValidRegCode, + "", "") + _, err = client.Login(regRes) + + if err != nil { + t.Errorf("Could not log in: %+v", err) + } - regRes, _ := client.Register(true, registrationCode, - "", false, string(grpJSON)) - client.Login(regRes, "") listener := MockListener(false) client.Listen(id.ZeroID[:], int32(cmixproto.Type_NO_TYPE), &listener) client.client.GetSwitchboard().Speak(&parse.Message{ @@ -219,36 +193,28 @@ func TestListen(t *testing.T) { } func TestStopListening(t *testing.T) { - registrationCode := "UAV6IWD6" + + ndfStr, pubKey := getNDFJSONStr(def, t) + d := api.DummyStorage{Location: "Blah", LastSave: []byte{'a', 'b', 'c'}} - client, err := NewClient(&d, "hello") - primeString := "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" + - "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + - "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" + - "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" + - "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" + - "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" + - "83655D23DCA3AD961C62F356208552BB9ED529077096966D" + - "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" + - "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" + - "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" + - "15728E5A8AACAA68FFFFFFFFFFFFFFFF" - p := large.NewInt(1) - p.SetString(primeString, 16) - g := large.NewInt(2) - q := large.NewInt(3) - grp := cyclic.NewGroup(p, g, q) - grpJSON, err := grp.MarshalJSON() + client, err := NewClient(&d, "hello", ndfStr, pubKey) + + // Connect to gateway + err = client.Connect() + if err != nil { - t.Errorf("Failed to marshal group JSON: %s", err) + t.Errorf("Could not connect: %+v", err) } - // Connect to gateway - client.Connect(gwAddress, "", "", "") + regRes, _ := client.Register(true, ValidRegCode, + "", "") + + _, err = client.Login(regRes) + + if err != nil { + t.Errorf("Could not log in: %+v", err) + } - regRes, _ := client.Register(true, registrationCode, - "", false, string(grpJSON)) - client.Login(regRes, "") listener := MockListener(false) handle := client.Listen(id.ZeroID[:], int32(cmixproto.Type_NO_TYPE), &listener) client.StopListening(handle) @@ -308,3 +274,112 @@ func TestParse(t *testing.T) { } } + +func getNDFJSONStr(netDef *ndf.NetworkDefinition, t *testing.T) (string, string) { + ndfBytes, err := json.Marshal(netDef) + + if err != nil { + t.Errorf("Could not JSON the NDF: %+v", err) + } + + privateKey, _ := rsa.GenerateKey(crand.Reader, 768) + publicKey := &rsa.PublicKey{PublicKey: privateKey.PublicKey} + publicKeyPem := string(rsa.CreatePublicKeyPem(publicKey)) + + // Sign the NDF + opts := rsa.NewDefaultOptions() + rsaHash := opts.Hash.New() + rsaHash.Write(netDef.Serialize()) + signature, _ := rsa.Sign( + crand.Reader, privateKey, opts.Hash, rsaHash.Sum(nil), nil) + + // Compose network definition string + ndfStr := string(ndfBytes) + "\n" + base64.StdEncoding.EncodeToString(signature) + + return ndfStr, publicKeyPem +} + +// Handles initialization of mock registration server, +// gateways used for registration and gateway used for session +func testMainWrapper(m *testing.M) int { + + rng := rand.New(rand.NewSource(time.Now().UnixNano())) + + rndPort := int(rng.Uint64() % 10000) + + def = getNDF() + + // Start mock gateways used by registration and defer their shutdown (may not be needed) + for i := 0; i < NumGWs; i++ { + + gw := ndf.Gateway{ + Address: fmtAddress(GWsStartPort + i + rndPort), + } + + def.Gateways = append(def.Gateways, gw) + + GWComms[i] = gateway.StartGateway(gw.Address, + gateway.NewImplementation(), "", "") + } + + for i := 0; i < NumNodes; i++ { + nIdBytes := make([]byte, id.NodeIdLen) + nIdBytes[0] = byte(i) + n := ndf.Node{ + ID: nIdBytes, + } + def.Nodes = append(def.Nodes, n) + } + + defer testWrapperShutdown() + return m.Run() +} + +func testWrapperShutdown() { + for _, gw := range GWComms { + gw.Shutdown() + } +} + +func fmtAddress(port int) string { return fmt.Sprintf("localhost:%d", port) } + +func getNDF() *ndf.NetworkDefinition { + return &ndf.NetworkDefinition{ + E2E: ndf.Group{ + Prime: "E2EE983D031DC1DB6F1A7A67DF0E9A8E5561DB8E8D49413394C049B" + + "7A8ACCEDC298708F121951D9CF920EC5D146727AA4AE535B0922C688B55B3DD2AE" + + "DF6C01C94764DAB937935AA83BE36E67760713AB44A6337C20E7861575E745D31F" + + "8B9E9AD8412118C62A3E2E29DF46B0864D0C951C394A5CBBDC6ADC718DD2A3E041" + + "023DBB5AB23EBB4742DE9C1687B5B34FA48C3521632C4A530E8FFB1BC51DADDF45" + + "3B0B2717C2BC6669ED76B4BDD5C9FF558E88F26E5785302BEDBCA23EAC5ACE9209" + + "6EE8A60642FB61E8F3D24990B8CB12EE448EEF78E184C7242DD161C7738F32BF29" + + "A841698978825B4111B4BC3E1E198455095958333D776D8B2BEEED3A1A1A221A6E" + + "37E664A64B83981C46FFDDC1A45E3D5211AAF8BFBC072768C4F50D7D7803D2D4F2" + + "78DE8014A47323631D7E064DE81C0C6BFA43EF0E6998860F1390B5D3FEACAF1696" + + "015CB79C3F9C2D93D961120CD0E5F12CBB687EAB045241F96789C38E89D796138E" + + "6319BE62E35D87B1048CA28BE389B575E994DCA755471584A09EC723742DC35873" + + "847AEF49F66E43873", + SmallPrime: "2", + Generator: "2", + }, + CMIX: ndf.Group{ + Prime: "9DB6FB5951B66BB6FE1E140F1D2CE5502374161FD6538DF1648218642F0B5C48" + + "C8F7A41AADFA187324B87674FA1822B00F1ECF8136943D7C55757264E5A1A44F" + + "FE012E9936E00C1D3E9310B01C7D179805D3058B2A9F4BB6F9716BFE6117C6B5" + + "B3CC4D9BE341104AD4A80AD6C94E005F4B993E14F091EB51743BF33050C38DE2" + + "35567E1B34C3D6A5C0CEAA1A0F368213C3D19843D0B4B09DCB9FC72D39C8DE41" + + "F1BF14D4BB4563CA28371621CAD3324B6A2D392145BEBFAC748805236F5CA2FE" + + "92B871CD8F9C36D3292B5509CA8CAA77A2ADFC7BFD77DDA6F71125A7456FEA15" + + "3E433256A2261C6A06ED3693797E7995FAD5AABBCFBE3EDA2741E375404AE25B", + SmallPrime: "F2C3119374CE76C9356990B465374A17F23F9ED35089BD969F61C6DDE9998C1F", + Generator: "5C7FF6B06F8F143FE8288433493E4769C4D988ACE5BE25A0E24809670716C613" + + "D7B0CEE6932F8FAA7C44D2CB24523DA53FBE4F6EC3595892D1AA58C4328A06C4" + + "6A15662E7EAA703A1DECF8BBB2D05DBE2EB956C142A338661D10461C0D135472" + + "085057F3494309FFA73C611F78B32ADBB5740C361C9F35BE90997DB2014E2EF5" + + "AA61782F52ABEB8BD6432C4DD097BC5423B285DAFB60DC364E8161F4A2A35ACA" + + "3A10B1C4D203CC76A470A33AFDCBDD92959859ABD8B56E1725252D78EAC66E71" + + "BA9AE3F1DD2487199874393CD4D832186800654760E1E34C09E4D155179F9EC0" + + "DC4473F996BDCE6EED1CABED8B6F116F7AD9CF505DF0F998E34AB27514B0FFE7", + }, + } +} diff --git a/bots/bots.go b/bots/bots.go index 2db7183ef951b41b1632279554587b7d1d80575c..e001f0125206fa6bd665e5d7493e5b18e6f840d4 100644 --- a/bots/bots.go +++ b/bots/bots.go @@ -6,12 +6,13 @@ import ( "gitlab.com/elixxir/client/io" "gitlab.com/elixxir/client/parse" "gitlab.com/elixxir/client/user" - "gitlab.com/elixxir/primitives/format" + "gitlab.com/elixxir/primitives/circuit" "gitlab.com/elixxir/primitives/id" "gitlab.com/elixxir/primitives/switchboard" ) var session user.Session +var topology *circuit.Circuit var messaging io.Communications // UdbID is the ID of the user discovery bot, which is always 3 @@ -48,7 +49,7 @@ func (l *nickReqListener) Hear(msg switchboard.Item, isHeardElsewhere bool) { var nicknameRequestListener nickReqListener // InitBots is called internally by the Login API -func InitBots(s user.Session, m io.Communications) { +func InitBots(s user.Session, m io.Communications, top *circuit.Circuit) { UdbID = id.NewUserFromUints(&[4]uint64{0, 0, 0, 3}) pushKeyResponseListener = make(channelResponseListener) @@ -59,39 +60,33 @@ func InitBots(s user.Session, m io.Communications) { nicknameResponseListener = make(channelResponseListener) session = s + topology = top messaging = m l := session.GetSwitchboard() - l.Register(UdbID, - format.None, int32(cmixproto.Type_UDB_PUSH_KEY_RESPONSE), + l.Register(UdbID, int32(cmixproto.Type_UDB_PUSH_KEY_RESPONSE), &pushKeyResponseListener) - l.Register(UdbID, - format.None, int32(cmixproto.Type_UDB_GET_KEY_RESPONSE), + l.Register(UdbID, int32(cmixproto.Type_UDB_GET_KEY_RESPONSE), &getKeyResponseListener) - l.Register(UdbID, - format.None, int32(cmixproto.Type_UDB_REGISTER_RESPONSE), + l.Register(UdbID, int32(cmixproto.Type_UDB_REGISTER_RESPONSE), ®isterResponseListener) - l.Register(UdbID, - format.None, int32(cmixproto.Type_UDB_SEARCH_RESPONSE), + l.Register(UdbID, int32(cmixproto.Type_UDB_SEARCH_RESPONSE), &searchResponseListener) l.Register(id.ZeroID, - format.None, int32(cmixproto.Type_NICKNAME_REQUEST), - &nicknameRequestListener) + int32(cmixproto.Type_NICKNAME_REQUEST), &nicknameRequestListener) l.Register(id.ZeroID, - format.None, int32(cmixproto.Type_NICKNAME_RESPONSE), - &nicknameResponseListener) + int32(cmixproto.Type_NICKNAME_RESPONSE), &nicknameResponseListener) } // sendCommand sends a command to the udb. This doesn't block. // 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, - format.Unencrypted, command) + return messaging.SendMessage(session, topology, botID, + parse.Unencrypted, command) } // Nickname Lookup function - func LookupNick(user *id.User) (string, error) { globals.Log.DEBUG.Printf("Sending nickname request to user %v", *user) msg := parse.Pack(&parse.TypedBody{ diff --git a/bots/bots_test.go b/bots/bots_test.go index 1cb0b512771352983b1a9a8ef0d650961b624c21..88a7bafc0ba67a78dcd002d0fd05cfb016f2c9ad 100644 --- a/bots/bots_test.go +++ b/bots/bots_test.go @@ -16,6 +16,9 @@ import ( "gitlab.com/elixxir/client/globals" "gitlab.com/elixxir/client/parse" "gitlab.com/elixxir/client/user" + "gitlab.com/elixxir/crypto/cyclic" + "gitlab.com/elixxir/crypto/large" + "gitlab.com/elixxir/primitives/circuit" "gitlab.com/elixxir/primitives/format" "gitlab.com/elixxir/primitives/id" "os" @@ -31,8 +34,9 @@ type dummyMessaging struct { // SendMessage to the server func (d *dummyMessaging) SendMessage(sess user.Session, + topology *circuit.Circuit, recipientID *id.User, - cryptoType format.CryptoType, + cryptoType parse.CryptoType, message []byte) error { jww.INFO.Printf("Sending: %s", string(message)) return nil @@ -40,8 +44,9 @@ func (d *dummyMessaging) SendMessage(sess user.Session, // SendMessage without partitions to the server func (d *dummyMessaging) SendMessageNoPartition(sess user.Session, + topology *circuit.Circuit, recipientID *id.User, - cryptoType format.CryptoType, + cryptoType parse.CryptoType, message []byte) error { jww.INFO.Printf("Sending: %s", string(message)) return nil @@ -61,12 +66,18 @@ func TestMain(m *testing.M) { User: id.NewUserFromUints(&[4]uint64{0, 0, 0, 18}), Nick: "Bernie", } + + cmixGrp, e2eGrp := getGroups() + fakeSession := user.NewSession(&globals.RamStorage{}, - u, nil, nil, nil, nil) + u, nil, nil, nil, cmixGrp, e2eGrp) fakeComm := &dummyMessaging{ listener: ListenCh, } - InitBots(fakeSession, fakeComm) + + topology := circuit.New([]*id.Node{id.NewNodeFromBytes(make([]byte, id.NodeIdLen))}) + + InitBots(fakeSession, fakeComm, topology) // Make the reception channels buffered for this test // which overwrites the channels registered in InitBots @@ -127,8 +138,8 @@ func TestNicknameFunctions(t *testing.T) { MessageType: int32(cmixproto.Type_NICKNAME_REQUEST), Body: []byte{}, }, - CryptoType: format.Unencrypted, - Receiver: session.GetCurrentUser().User, + InferredType: parse.Unencrypted, + Receiver: session.GetCurrentUser().User, } session.GetSwitchboard().Speak(msg) @@ -153,8 +164,8 @@ func TestNicknameFunctions(t *testing.T) { MessageType: int32(cmixproto.Type_NICKNAME_RESPONSE), Body: []byte(session.GetCurrentUser().Nick), }, - CryptoType: format.Unencrypted, - Receiver: session.GetCurrentUser().User, + InferredType: parse.Unencrypted, + Receiver: session.GetCurrentUser().User, } session.GetSwitchboard().Speak(msg) } @@ -163,16 +174,18 @@ type errorMessaging struct{} // SendMessage that just errors out func (e *errorMessaging) SendMessage(sess user.Session, + topology *circuit.Circuit, recipientID *id.User, - cryptoType format.CryptoType, + cryptoType parse.CryptoType, message []byte) error { return errors.New("This is an error") } // SendMessage no partition that just errors out func (e *errorMessaging) SendMessageNoPartition(sess user.Session, + topology *circuit.Circuit, recipientID *id.User, - cryptoType format.CryptoType, + cryptoType parse.CryptoType, message []byte) error { return errors.New("This is an error") } @@ -191,3 +204,40 @@ func TestLookupNick_error(t *testing.T) { t.Errorf("LookupNick should have returned an error") } } + +func getGroups() (cmixGrp *cyclic.Group, e2eGrp *cyclic.Group) { + + cmixPrime := "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" + + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" + + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" + + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" + + "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" + + "83655D23DCA3AD961C62F356208552BB9ED529077096966D" + + "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" + + "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" + + "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" + + "15728E5A8AACAA68FFFFFFFFFFFFFFFF" + + e2ePrime := "E2EE983D031DC1DB6F1A7A67DF0E9A8E5561DB8E8D49413394C049B" + + "7A8ACCEDC298708F121951D9CF920EC5D146727AA4AE535B0922C688B55B3DD2AE" + + "DF6C01C94764DAB937935AA83BE36E67760713AB44A6337C20E7861575E745D31F" + + "8B9E9AD8412118C62A3E2E29DF46B0864D0C951C394A5CBBDC6ADC718DD2A3E041" + + "023DBB5AB23EBB4742DE9C1687B5B34FA48C3521632C4A530E8FFB1BC51DADDF45" + + "3B0B2717C2BC6669ED76B4BDD5C9FF558E88F26E5785302BEDBCA23EAC5ACE9209" + + "6EE8A60642FB61E8F3D24990B8CB12EE448EEF78E184C7242DD161C7738F32BF29" + + "A841698978825B4111B4BC3E1E198455095958333D776D8B2BEEED3A1A1A221A6E" + + "37E664A64B83981C46FFDDC1A45E3D5211AAF8BFBC072768C4F50D7D7803D2D4F2" + + "78DE8014A47323631D7E064DE81C0C6BFA43EF0E6998860F1390B5D3FEACAF1696" + + "015CB79C3F9C2D93D961120CD0E5F12CBB687EAB045241F96789C38E89D796138E" + + "6319BE62E35D87B1048CA28BE389B575E994DCA755471584A09EC723742DC35873" + + "847AEF49F66E43873" + + cmixGrp = cyclic.NewGroup(large.NewIntFromString(cmixPrime, 16), + large.NewIntFromUInt(2), large.NewIntFromUInt(2)) + + e2eGrp = cyclic.NewGroup(large.NewIntFromString(e2ePrime, 16), + large.NewIntFromUInt(2), large.NewIntFromUInt(2)) + + return +} diff --git a/cmd/root.go b/cmd/root.go index fecac877ff26a91d884837296ca9a0c3aacc52f6..0e009b221cc504b0547cd03a20d8ba44d93a5e77 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -21,8 +21,8 @@ import ( "gitlab.com/elixxir/client/user" "gitlab.com/elixxir/crypto/cyclic" "gitlab.com/elixxir/crypto/large" - "gitlab.com/elixxir/primitives/format" "gitlab.com/elixxir/primitives/id" + "gitlab.com/elixxir/primitives/ndf" "gitlab.com/elixxir/primitives/switchboard" "io/ioutil" "log" @@ -41,7 +41,6 @@ var message string var sessionFile string var dummyFrequency float64 var noBlockingTransmission bool -var mint bool var rateLimiting uint32 var showVer bool var gwCertPath string @@ -49,9 +48,15 @@ var registrationCertPath string var registrationAddr string var registrationCode string var userEmail string +var userNick string var end2end bool var keyParams []string var client *api.Client +var ndfPath string +var ndfVerifySignature bool +var ndfRegistration []string +var ndfUDB []string +var ndfPubKey string // Execute adds all child commands to the root command and sets flags // appropriately. This is called by main.main(). It only needs to @@ -67,9 +72,29 @@ func sessionInitialization() *id.User { var err error register := false + // Read in the network definition file and save as string + ndfBytes, err := ioutil.ReadFile(ndfPath) + if err != nil { + globals.Log.FATAL.Panicf("Could not read network definition file: %v", err) + } + + // Check if the NDF verify flag is set + if !ndfVerifySignature { + ndfPubKey = "" + globals.Log.WARN.Println("Skipping NDF verification") + } else if ndfPubKey == "" { + globals.Log.FATAL.Panicln("No public key for NDF found") + } + + // Verify the signature + ndfJSON := api.VerifyNDF(string(ndfBytes), ndfPubKey) + + // Overwrite the network definition with any specified flags + overwriteNDF(ndfJSON) + //If no session file is passed initialize with RAM Storage if sessionFile == "" { - client, err = api.NewClient(&globals.RamStorage{}, "") + client, err = api.NewClient(&globals.RamStorage{}, "", ndfJSON) if err != nil { globals.Log.ERROR.Printf("Could Not Initialize Ram Storage: %s\n", err.Error()) @@ -93,7 +118,7 @@ func sessionInitialization() *id.User { } //Initialize client with OS Storage - client, err = api.NewClient(nil, sessionFile) + client, err = api.NewClient(nil, sessionFile, ndfJSON) if err != nil { globals.Log.ERROR.Printf("Could Not Initialize OS Storage: %s\n", err.Error()) @@ -123,8 +148,11 @@ func sessionInitialization() *id.User { } // Connect to gateways and reg server - client.Connect(gateways, gwCertPath, - registrationAddr, registrationCertPath) + err = client.Connect() + + if err != nil { + globals.Log.FATAL.Panicf("Could not call connect on client: %+v", err) + } // Holds the User ID var uid *id.User @@ -148,7 +176,7 @@ func sessionInitialization() *id.User { globals.Log.INFO.Printf("Attempting to register with code %s...", regCode) - uid, err = client.Register(userId != 0, regCode, "", mint, &grp) + uid, err = client.Register(userId != 0, regCode, userNick, userEmail) if err != nil { globals.Log.ERROR.Printf("Could Not Register User: %s\n", err.Error()) return id.ZeroID @@ -166,7 +194,7 @@ func sessionInitialization() *id.User { // Log the user in, for now using the first gateway specified // This will also register the user email with UDB - _, err = client.Login(uid, userEmail) + _, err = client.Login(uid) if err != nil { globals.Log.ERROR.Printf("Could Not Log In: %s\n", err) return id.ZeroID @@ -272,7 +300,12 @@ func (l *ChannelListener) Hear(item switchboard.Item, isHeardElsewhere bool) { message := item.(*parse.Message) globals.Log.INFO.Println("Hearing a channel message") result := cmixproto.ChannelMessage{} - proto.Unmarshal(message.Body, &result) + err := proto.Unmarshal(message.Body, &result) + + if err != nil { + globals.Log.ERROR.Printf("Could not unmarhsal message, message "+ + "not processed: %+v", err) + } sender, ok := user.Users.GetUser(message.Sender) var senderNick string @@ -319,15 +352,15 @@ var rootCmd = &cobra.Command{ // the integration test // Normal text messages text := TextListener{} - client.Listen(id.ZeroID, format.None, int32(cmixproto.Type_TEXT_MESSAGE), + client.Listen(id.ZeroID, int32(cmixproto.Type_TEXT_MESSAGE), &text) // Channel messages channel := ChannelListener{} - client.Listen(id.ZeroID, format.None, + client.Listen(id.ZeroID, int32(cmixproto.Type_CHANNEL_MESSAGE), &channel) // All other messages fallback := FallbackListener{} - client.Listen(id.ZeroID, format.None, int32(cmixproto.Type_NO_TYPE), + client.Listen(id.ZeroID, int32(cmixproto.Type_NO_TYPE), &fallback) // Do calculation for dummy messages if the flag is set @@ -336,9 +369,9 @@ var rootCmd = &cobra.Command{ (time.Duration(float64(1000000000) * (float64(1.0) / dummyFrequency))) } - cryptoType := format.Unencrypted + cryptoType := parse.Unencrypted if end2end { - cryptoType = format.E2E + cryptoType = parse.E2E } // Only send a message if we have a message to send (except dummy messages) @@ -362,15 +395,18 @@ var rootCmd = &cobra.Command{ recipientNick, message) // Send the message - client.Send(&parse.Message{ + err := client.Send(&parse.Message{ Sender: userID, TypedBody: parse.TypedBody{ MessageType: int32(cmixproto.Type_TEXT_MESSAGE), Body: wireOut, }, - CryptoType: cryptoType, - Receiver: recipientId, + InferredType: cryptoType, + Receiver: recipientId, }) + if err != nil { + globals.Log.ERROR.Printf("Error sending message: %+v", err) + } } } @@ -397,9 +433,12 @@ var rootCmd = &cobra.Command{ MessageType: int32(cmixproto.Type_TEXT_MESSAGE), Body: api.FormatTextMessage(message), }, - CryptoType: cryptoType, - Receiver: recipientId} - client.Send(message) + InferredType: cryptoType, + Receiver: recipientId} + err := client.Send(message) + if err != nil { + globals.Log.ERROR.Printf("Error sending message: %+v", err) + } timer = time.NewTimer(dummyPeriod) } @@ -439,9 +478,6 @@ func init() { rootCmd.PersistentFlags().BoolVarP(&noBlockingTransmission, "noBlockingTransmission", "", false, "Sets if transmitting messages blocks or not. "+ "Defaults to true if unset.") - rootCmd.PersistentFlags().BoolVarP(&mint, "mint", "", false, - "Mint some coins for testing") - rootCmd.PersistentFlags().Uint32VarP(&rateLimiting, "rateLimiting", "", 1000, "Sets the amount of time, in ms, "+ "that the client waits between sending messages. "+ @@ -472,15 +508,47 @@ func init() { rootCmd.PersistentFlags().StringVarP(&userEmail, "email", "E", - "", + "default@default.com", "Email to register for User Discovery") + rootCmd.PersistentFlags().StringVar(&userNick, + "nick", + "Default", + "Nickname to register for User Discovery") + rootCmd.PersistentFlags().StringVarP(&sessionFile, "sessionfile", "f", "", "Passes a file path for loading a session. "+ "If the file doesn't exist the code will register the user and"+ " store it there. If not passed the session will be stored"+ " to ram and lost when the cli finishes") + rootCmd.PersistentFlags().StringVarP(&ndfPubKey, + "ndfPubKey", + "p", + "", + "Path to the public key for the network definition JSON file") + + rootCmd.PersistentFlags().StringVarP(&ndfPath, + "ndf", + "n", + "ndf.json", + "Path to the network definition JSON file") + + rootCmd.PersistentFlags().BoolVar(&ndfVerifySignature, + "ndfVerifySignature", + true, + "Specifies if the NDF should be loaded without the signature") + + rootCmd.PersistentFlags().StringSliceVar(&ndfRegistration, + "ndfRegistration", + nil, + "Overwrite the Registration values for the NDF") + + rootCmd.PersistentFlags().StringSliceVar(&ndfUDB, + "ndfUDB", + nil, + "Overwrite the UDB values for the NDF") + // Cobra also supports local flags, which will only run // when this action is called directly. rootCmd.Flags().StringVarP(&message, "message", "m", "", "Message to send") @@ -502,14 +570,7 @@ func init() { } // initConfig reads in config file and ENV variables if set. -func initConfig() { - // Temporarily need to get group as JSON data into viper - json, err := globals.InitCrypto().MarshalJSON() - if err != nil { - // panic - } - viper.Set("group", string(json)) -} +func initConfig() {} // initLog initializes logging thresholds and the log path. func initLog() { @@ -535,3 +596,29 @@ func initLog() { } } } + +// overwriteNDF replaces fields in the NetworkDefinition structure with values +// specified from the commandline. +func overwriteNDF(n *ndf.NetworkDefinition) { + if len(ndfRegistration) == 3 { + n.Registration.DsaPublicKey = ndfRegistration[0] + n.Registration.Address = ndfRegistration[1] + n.Registration.TlsCertificate = ndfRegistration[2] + + globals.Log.WARN.Println("Overwrote Registration values in the " + + "NetworkDefinition from the commandline") + } + + if len(ndfUDB) == 2 { + udbIdString, err := base64.StdEncoding.DecodeString(ndfUDB[0]) + if err != nil { + globals.Log.WARN.Printf("Could not decode USB ID: %v", err) + } + + n.UDB.ID = udbIdString + n.UDB.DsaPublicKey = ndfUDB[1] + + globals.Log.WARN.Println("Overwrote UDB values in the " + + "NetworkDefinition from the commandline") + } +} diff --git a/crypto/decrypt.go b/crypto/decrypt.go index 9b5e62ca9ee48a14802ad31c08ce8324bececb93..515ca745163cb05442381c8489767c799a183395 100644 --- a/crypto/decrypt.go +++ b/crypto/decrypt.go @@ -21,12 +21,11 @@ import ( func E2EDecrypt(grp *cyclic.Group, key *cyclic.Int, msg *format.Message) error { // First thing to do is check MAC - if !hash.VerifyHMAC(msg.SerializePayload(), - msg.GetMAC(), key.Bytes()) { + if !hash.VerifyHMAC(msg.Contents.Get(), msg.GetMAC(), key.Bytes()) { return errors.New("HMAC verification failed for E2E message") } var iv [e2e.AESBlockSize]byte - fp := msg.GetKeyFingerprint() + fp := msg.GetKeyFP() copy(iv[:], fp[:e2e.AESBlockSize]) // decrypt the timestamp in the associated data decryptedTimestamp, err := e2e.DecryptAES256WithIV( @@ -36,13 +35,15 @@ func E2EDecrypt(grp *cyclic.Group, key *cyclic.Int, } // TODO deserialize this somewhere along the line and provide methods // to mobile developers on the bindings to interact with the timestamps + decryptedTimestamp = append(decryptedTimestamp, 0) msg.SetTimestamp(decryptedTimestamp) // Decrypt e2e - decryptedPayload, err := e2e.Decrypt(grp, key, msg.SerializePayload()) + decryptedPayload, err := e2e.Decrypt(grp, key, msg.Contents.Get()) + if err != nil { return errors.New("Failed to decrypt E2E message: " + err.Error()) } - msg.SetSplitPayload(decryptedPayload) + msg.Contents.SetRightAligned(decryptedPayload) return nil } @@ -53,12 +54,11 @@ func E2EDecrypt(grp *cyclic.Group, key *cyclic.Int, func E2EDecryptUnsafe(grp *cyclic.Group, key *cyclic.Int, msg *format.Message) error { // First thing to do is check MAC - if !hash.VerifyHMAC(msg.SerializePayload(), - msg.GetMAC(), key.Bytes()) { + if !hash.VerifyHMAC(msg.Contents.Get(), msg.GetMAC(), key.Bytes()) { return errors.New("HMAC verification failed for E2E message") } var iv [e2e.AESBlockSize]byte - fp := msg.GetKeyFingerprint() + fp := msg.GetKeyFP() copy(iv[:], fp[:e2e.AESBlockSize]) // decrypt the timestamp in the associated data decryptedTimestamp, err := e2e.DecryptAES256WithIV( @@ -68,9 +68,10 @@ func E2EDecryptUnsafe(grp *cyclic.Group, key *cyclic.Int, } // TODO deserialize this somewhere along the line and provide methods // to mobile developers on the bindings to interact with the timestamps + decryptedTimestamp = append(decryptedTimestamp, 0) msg.SetTimestamp(decryptedTimestamp) // Decrypt e2e - decryptedPayload := e2e.DecryptUnsafe(grp, key, msg.SerializePayload()) - msg.SetSplitPayload(decryptedPayload) + decryptedPayload := e2e.DecryptUnsafe(grp, key, msg.Contents.Get()) + msg.Contents.Set(decryptedPayload) return nil } diff --git a/crypto/encrypt.go b/crypto/encrypt.go index 0324491a12ec0b13903b46df61f81f649643d93d..295209ce272a7acc1da3e21c344d1ee9730bba4d 100644 --- a/crypto/encrypt.go +++ b/crypto/encrypt.go @@ -13,35 +13,24 @@ import ( "gitlab.com/elixxir/crypto/cyclic" "gitlab.com/elixxir/crypto/e2e" "gitlab.com/elixxir/crypto/hash" - "gitlab.com/elixxir/crypto/verification" + "gitlab.com/elixxir/primitives/circuit" "gitlab.com/elixxir/primitives/format" ) // CMIX Encrypt performs the encryption // of the msg to a team of nodes // It returns a new msg -func CMIXEncrypt(session user.Session, - salt []byte, +func CMIXEncrypt(session user.Session, topology *circuit.Circuit, salt []byte, msg *format.Message) *format.Message { // Generate the encryption key - nodeKeys := session.GetKeys() + nodeKeys := session.GetKeys(topology) 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) + return cmix.ClientEncrypt(session.GetCmixGroup(), msg, salt, baseKeys) } // E2EEncrypt uses the E2E key to encrypt msg @@ -51,24 +40,27 @@ func CMIXEncrypt(session user.Session, func E2EEncrypt(grp *cyclic.Group, key *cyclic.Int, keyFP format.Fingerprint, msg *format.Message) { - msg.SetKeyFingerprint(keyFP) + msg.SetKeyFP(keyFP) // 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, _ := + encryptedTimestamp, err := e2e.EncryptAES256WithIV(key.Bytes(), iv, msg.GetTimestamp()[:15]) + if err != nil { + panic(err) + } msg.SetTimestamp(encryptedTimestamp) // E2E encrypt the msg - encPayload, err := e2e.Encrypt(grp, key, msg.GetPayload()) + encPayload, err := e2e.Encrypt(grp, key, msg.Contents.GetRightAligned()) if err != nil { globals.Log.ERROR.Panicf(err.Error()) } - msg.SetPayload(encPayload) + msg.Contents.Set(encPayload) // MAC is HMAC(key, ciphertext) // Currently, the MAC doesn't include any of the associated data @@ -85,21 +77,24 @@ func E2EEncrypt(grp *cyclic.Group, func E2EEncryptUnsafe(grp *cyclic.Group, key *cyclic.Int, keyFP format.Fingerprint, msg *format.Message) { - msg.SetKeyFingerprint(keyFP) + msg.SetKeyFP(keyFP) // 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, _ := + encryptedTimestamp, err := e2e.EncryptAES256WithIV(key.Bytes(), iv, msg.GetTimestamp()[:15]) + if err != nil { + panic(err) + } msg.SetTimestamp(encryptedTimestamp) // E2E encrypt the msg - encPayload := e2e.EncryptUnsafe(grp, key, msg.GetPayload()) - msg.SetPayload(encPayload) + encPayload := e2e.EncryptUnsafe(grp, key, msg.Contents.Get()) + msg.Contents.Set(encPayload) // MAC is HMAC(key, ciphertext) // Currently, the MAC doesn't include any of the associated data diff --git a/crypto/encryptdecrypt_test.go b/crypto/encryptdecrypt_test.go index 6b0bf119b37085bd916b66d893f7baf5750cb785..d0f4c511653ee92802a31eabf0a402fdd7cbab4a 100644 --- a/crypto/encryptdecrypt_test.go +++ b/crypto/encryptdecrypt_test.go @@ -14,69 +14,74 @@ import ( "gitlab.com/elixxir/crypto/cyclic" "gitlab.com/elixxir/crypto/hash" "gitlab.com/elixxir/crypto/large" + "gitlab.com/elixxir/primitives/circuit" "gitlab.com/elixxir/primitives/format" "gitlab.com/elixxir/primitives/id" + "golang.org/x/crypto/blake2b" "os" "testing" "time" ) +const numNodes = 5 + var salt = []byte( "fdecfa52a8ad1688dbfa7d16df74ebf27e535903c469cefc007ebbe1ee895064") var session user.Session -var serverTransmissionKey *cyclic.Int -var serverReceptionKey *cyclic.Int +var serverPayloadAKey *cyclic.Int +var serverPayloadBKey *cyclic.Int + +var topology *circuit.Circuit func setup() { - base := 16 - - pString := "9DB6FB5951B66BB6FE1E140F1D2CE5502374161FD6538DF1648218642F0B5C48" + - "C8F7A41AADFA187324B87674FA1822B00F1ECF8136943D7C55757264E5A1A44F" + - "FE012E9936E00C1D3E9310B01C7D179805D3058B2A9F4BB6F9716BFE6117C6B5" + - "B3CC4D9BE341104AD4A80AD6C94E005F4B993E14F091EB51743BF33050C38DE2" + - "35567E1B34C3D6A5C0CEAA1A0F368213C3D19843D0B4B09DCB9FC72D39C8DE41" + - "F1BF14D4BB4563CA28371621CAD3324B6A2D392145BEBFAC748805236F5CA2FE" + - "92B871CD8F9C36D3292B5509CA8CAA77A2ADFC7BFD77DDA6F71125A7456FEA15" + - "3E433256A2261C6A06ED3693797E7995FAD5AABBCFBE3EDA2741E375404AE25B" - - gString := "5C7FF6B06F8F143FE8288433493E4769C4D988ACE5BE25A0E24809670716C613" + - "D7B0CEE6932F8FAA7C44D2CB24523DA53FBE4F6EC3595892D1AA58C4328A06C4" + - "6A15662E7EAA703A1DECF8BBB2D05DBE2EB956C142A338661D10461C0D135472" + - "085057F3494309FFA73C611F78B32ADBB5740C361C9F35BE90997DB2014E2EF5" + - "AA61782F52ABEB8BD6432C4DD097BC5423B285DAFB60DC364E8161F4A2A35ACA" + - "3A10B1C4D203CC76A470A33AFDCBDD92959859ABD8B56E1725252D78EAC66E71" + - "BA9AE3F1DD2487199874393CD4D832186800654760E1E34C09E4D155179F9EC0" + - "DC4473F996BDCE6EED1CABED8B6F116F7AD9CF505DF0F998E34AB27514B0FFE7" - - qString := "F2C3119374CE76C9356990B465374A17F23F9ED35089BD969F61C6DDE9998C1F" - - p := large.NewIntFromString(pString, base) - g := large.NewIntFromString(gString, base) - q := large.NewIntFromString(qString, base) - - grp := cyclic.NewGroup(p, g, q) + + cmixGrp, e2eGrp := getGroups() + + user.InitUserRegistry(cmixGrp) UID := id.NewUserFromUints(&[4]uint64{0, 0, 0, 18}) u, _ := user.Users.GetUser(UID) - nk := make([]user.NodeKeys, 5) + var nodeSlice []*id.Node + + //build topology + for i := 0; i < numNodes; i++ { + nodeBytes := make([]byte, id.NodeIdLen) + nodeBytes[0] = byte(i) + nodeId := id.NewNodeFromBytes(nodeBytes) + nodeSlice = append(nodeSlice, nodeId) + } + + topology = circuit.New(nodeSlice) + + nkMap := make(map[id.Node]user.NodeKeys) + + tempKey := cmixGrp.NewInt(1) + serverPayloadAKey = cmixGrp.NewInt(1) + serverPayloadBKey = cmixGrp.NewInt(1) + + h, _ := blake2b.New256(nil) + + for i := 0; i < numNodes; i++ { + + nk := user.NodeKeys{} - baseKey := grp.NewInt(1) - serverTransmissionKey = grp.NewInt(1) - serverReceptionKey = grp.NewInt(1) + h.Reset() + h.Write(salt) - for i := range nk { + nk.TransmissionKey = cmixGrp.NewInt(int64(2 + i)) + cmix.NodeKeyGen(cmixGrp, salt, nk.TransmissionKey, tempKey) + cmixGrp.Mul(serverPayloadAKey, tempKey, serverPayloadAKey) - nk[i].TransmissionKey = grp.NewInt(int64(2 + i)) - cmix.NodeKeyGen(grp, salt, nk[i].TransmissionKey, baseKey) - grp.Mul(serverTransmissionKey, baseKey, serverTransmissionKey) - nk[i].ReceptionKey = grp.NewInt(int64(1000 + i)) - cmix.NodeKeyGen(grp, salt, nk[i].ReceptionKey, baseKey) - grp.Mul(serverReceptionKey, baseKey, serverReceptionKey) + cmix.NodeKeyGen(cmixGrp, h.Sum(nil), nk.TransmissionKey, tempKey) + cmixGrp.Mul(serverPayloadBKey, tempKey, serverPayloadBKey) + + nkMap[*topology.GetNodeAtIndex(i)] = nk } - session = user.NewSession(nil, u, nk, - nil, nil, grp) + + session = user.NewSession(nil, u, nkMap, + nil, nil, cmixGrp, e2eGrp) } func TestMain(m *testing.M) { @@ -85,130 +90,122 @@ func TestMain(m *testing.M) { } func TestFullEncryptDecrypt(t *testing.T) { - grp := session.GetGroup() + cmixGrp, e2eGrp := getGroups() + 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) + // Normally, msgPayload would be the right length due to padding + //msgPayload = append(msgPayload, make([]byte, + // format.ContentsLen-len(msgPayload)-format.PadMinLen)...) + msg.Contents.SetRightAligned(msgPayload) now := time.Now() nowBytes, _ := now.MarshalBinary() + // Normally, nowBytes would be the right length due to AES encryption + nowBytes = append(nowBytes, make([]byte, format.TimestampLen-len(nowBytes))...) msg.SetTimestamp(nowBytes) - key := grp.NewInt(42) + key := e2eGrp.NewInt(42) h, _ := hash.NewCMixHash() h.Write(key.Bytes()) fp := format.Fingerprint{} copy(fp[:], h.Sum(nil)) // E2E Encryption - E2EEncrypt(grp, key, fp, msg) + E2EEncrypt(e2eGrp, key, fp, msg) // CMIX Encryption - encMsg := CMIXEncrypt(session, salt, msg) + encMsg := CMIXEncrypt(session, topology, salt, msg) // Server will decrypt payload (which is OK because the payload is now e2e) // This block imitates what the server does during the realtime - var encryptedNet *pb.Slot - { - payload := grp.NewIntFromBytes(encMsg.SerializePayload()) - assocData := grp.NewIntFromBytes(encMsg.SerializeAssociatedData()) - // Multiply payload and associated data by transmission key only - grp.Mul(payload, serverTransmissionKey, payload) - // Multiply associated data only by transmission key - grp.Mul(assocData, serverTransmissionKey, assocData) - encryptedNet = &pb.Slot{ - SenderID: sender.Bytes(), - Salt: salt, - MessagePayload: payload.LeftpadBytes(uint64(format.TOTAL_LEN)), - AssociatedData: assocData.LeftpadBytes(uint64(format.TOTAL_LEN)), - } - } + payloadA := cmixGrp.NewIntFromBytes(encMsg.GetPayloadA()) + payloadB := cmixGrp.NewIntFromBytes(encMsg.GetPayloadB()) + // Multiply payloadA and associated data by serverPayloadBkey + cmixGrp.Mul(payloadA, serverPayloadAKey, payloadA) + // Multiply payloadB data only by serverPayloadAkey + cmixGrp.Mul(payloadB, serverPayloadBKey, payloadB) decMsg := format.NewMessage() - decMsg.Payload = format.DeserializePayload(encryptedNet.MessagePayload) - decMsg.AssociatedData = format.DeserializeAssociatedData(encryptedNet.AssociatedData) + decMsg.SetPayloadA(payloadA.LeftpadBytes(uint64(format.PayloadLen))) + decMsg.SetDecryptedPayloadB(payloadB.LeftpadBytes(uint64(format.PayloadLen))) // E2E Decryption - err := E2EDecrypt(grp, key, decMsg) + err := E2EDecrypt(e2eGrp, key, decMsg) if err != nil { t.Errorf("E2EDecrypt returned error: %v", err.Error()) } - if *decMsg.GetSender() != *sender { - t.Errorf("Sender differed from expected: Got %q, expected %q", - decMsg.GetRecipient(), sender) - } if *decMsg.GetRecipient() != *recipient { t.Errorf("Recipient differed from expected: Got %q, expected %q", decMsg.GetRecipient(), sender) } - if !bytes.Equal(decMsg.GetPayloadData(), msgPayload) { + if !bytes.Equal(decMsg.Contents.GetRightAligned(), msgPayload) { t.Errorf("Decrypted payload differed from expected: Got %q, "+ - "expected %q", decMsg.GetPayloadData(), msgPayload) + "expected %q", decMsg.Contents.Get(), msgPayload) } } // E2E unsafe functions should only be used when the payload // to be sent occupies the whole payload structure, i.e. 256 bytes func TestFullEncryptDecrypt_Unsafe(t *testing.T) { - grp := session.GetGroup() + cmixGrp, e2eGrp := getGroups() sender := id.NewUserFromUint(38, t) recipient := id.NewUserFromUint(29, t) msg := format.NewMessage() msg.SetRecipient(recipient) msgPayload := []byte( " EnterpriseTextLabelDescriptorSetPipelineStateFactoryBeanFactory" + + " EnterpriseTextLabelDescriptorSetPipelineStateFactoryBeanFactory" + + " EnterpriseTextLabelDescriptorSetPipelineStateFactoryBeanFactory" + + " EnterpriseTextLabelDescriptorSetPipelineStateFactoryBeanFactory" + " EnterpriseTextLabelDescriptorSetPipelineStateFactoryBeanFactory" + " EnterpriseTextLabelDescriptorSetPipelineStateFactoryBeanFactory" + " EnterpriseTextLabelDescriptorSetPipelineStateFactoryBeanFactory") - // Need to take up space of SenderID - msg.SetSenderID(msgPayload[:format.MP_SID_LEN]) - msg.SetPayloadData(msgPayload[format.MP_SID_LEN:]) - now := time.Now() - nowBytes, _ := now.MarshalBinary() - msg.SetTimestamp(nowBytes) + msg.Contents.Set(msgPayload[:format.ContentsLen]) + + msg.SetTimestamp(make([]byte, 16)) - key := grp.NewInt(42) + key := e2eGrp.NewInt(42) h, _ := hash.NewCMixHash() h.Write(key.Bytes()) fp := format.Fingerprint{} copy(fp[:], h.Sum(nil)) // E2E Encryption without padding - E2EEncryptUnsafe(grp, key, fp, msg) + E2EEncryptUnsafe(e2eGrp, key, fp, msg) // CMIX Encryption - encMsg := CMIXEncrypt(session, salt, msg) + encMsg := CMIXEncrypt(session, topology, salt, msg) // Server will decrypt payload (which is OK because the payload is now e2e) // This block imitates what the server does during the realtime var encryptedNet *pb.Slot { - payload := grp.NewIntFromBytes(encMsg.SerializePayload()) - assocData := grp.NewIntFromBytes(encMsg.SerializeAssociatedData()) + payload := cmixGrp.NewIntFromBytes(encMsg.GetPayloadA()) + assocData := cmixGrp.NewIntFromBytes(encMsg.GetPayloadB()) // Multiply payload and associated data by transmission key only - grp.Mul(payload, serverTransmissionKey, payload) + cmixGrp.Mul(payload, serverPayloadAKey, payload) // Multiply associated data only by transmission key - grp.Mul(assocData, serverTransmissionKey, assocData) + cmixGrp.Mul(assocData, serverPayloadBKey, assocData) encryptedNet = &pb.Slot{ SenderID: sender.Bytes(), Salt: salt, - MessagePayload: payload.LeftpadBytes(uint64(format.TOTAL_LEN)), - AssociatedData: assocData.LeftpadBytes(uint64(format.TOTAL_LEN)), + MessagePayload: payload.LeftpadBytes(uint64(format.PayloadLen)), + AssociatedData: assocData.LeftpadBytes(uint64(format.PayloadLen)), } } decMsg := format.NewMessage() - decMsg.AssociatedData = format.DeserializeAssociatedData(encryptedNet.AssociatedData) - decMsg.Payload = format.DeserializePayload(encryptedNet.MessagePayload) + decMsg.SetPayloadA(encryptedNet.MessagePayload) + decMsg.SetDecryptedPayloadB(encryptedNet.AssociatedData) // E2E Decryption - err := E2EDecryptUnsafe(grp, key, decMsg) + err := E2EDecryptUnsafe(e2eGrp, key, decMsg) if err != nil { t.Errorf("E2EDecryptUnsafe returned error: %v", err.Error()) @@ -218,31 +215,30 @@ func TestFullEncryptDecrypt_Unsafe(t *testing.T) { t.Errorf("Recipient differed from expected: Got %q, expected %q", decMsg.GetRecipient(), sender) } - if !bytes.Equal(decMsg.GetPayload(), msgPayload) { + if !bytes.Equal(decMsg.Contents.Get(), msgPayload[:format.ContentsLen]) { t.Errorf("Decrypted payload differed from expected: Got %q, "+ - "expected %q", decMsg.GetPayload(), msgPayload) + "expected %q", decMsg.Contents.Get(), msgPayload[:format.ContentsLen]) } } // Test that E2EEncrypt panics if the payload is too big (can't be padded) func TestE2EEncrypt_Panic(t *testing.T) { - grp := session.GetGroup() - sender := id.NewUserFromUint(38, t) + _, e2eGrp := getGroups() recipient := id.NewUserFromUint(29, t) msg := format.NewMessage() - msg.SetSender(sender) msg.SetRecipient(recipient) msgPayload := []byte("help me, i'm stuck in an" + + " EnterpriseTextLabelDescriptorSetPipelineStateFactoryBeanFactory" + + " EnterpriseTextLabelDescriptorSetPipelineStateFactoryBeanFactory" + " EnterpriseTextLabelDescriptorSetPipelineStateFactoryBeanFactory" + " EnterpriseTextLabelDescriptorSetPipelineStateFactoryBeanFactory" + " EnterpriseTextLabelDescriptorSetPipelineStateFactoryBeanFactory" + " EnterpriseTextLabelDescriptorSetPipelineStateFactoryBeanFactory") - msg.SetPayloadData(msgPayload) - now := time.Now() - nowBytes, _ := now.MarshalBinary() - msg.SetTimestamp(nowBytes) + msgPayload = msgPayload[:format.ContentsLen] + msg.Contents.Set(msgPayload) + msg.SetTimestamp(make([]byte, 16)) - key := grp.NewInt(42) + key := e2eGrp.NewInt(42) h, _ := hash.NewCMixHash() h.Write(key.Bytes()) fp := format.Fingerprint{} @@ -255,43 +251,38 @@ func TestE2EEncrypt_Panic(t *testing.T) { }() // E2E Encryption Panics - E2EEncrypt(grp, key, fp, msg) + E2EEncrypt(e2eGrp, key, fp, msg) } // Test that E2EDecrypt and E2EDecryptUnsafe handle errors correctly func TestE2EDecrypt_Errors(t *testing.T) { - grp := session.GetGroup() - sender := id.NewUserFromUint(38, t) + _, e2eGrp := getGroups() 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) - now := time.Now() - nowBytes, _ := now.MarshalBinary() - msg.SetTimestamp(nowBytes) + msgPayload := []byte("help me, i'm stuck in an EnterpriseTextLabelDescriptorSetPipelineStateFactoryBeanFactory ") + msg.Contents.SetRightAligned(msgPayload) + msg.SetTimestamp(make([]byte, 16)) - key := grp.NewInt(42) + key := e2eGrp.NewInt(42) h, _ := hash.NewCMixHash() h.Write(key.Bytes()) fp := format.Fingerprint{} copy(fp[:], h.Sum(nil)) // E2E Encryption - E2EEncrypt(grp, key, fp, msg) + E2EEncrypt(e2eGrp, key, fp, msg) // Copy message badMsg := format.NewMessage() - badMsg.Payload = format.DeserializePayload(msg.SerializePayload()) - badMsg.AssociatedData = format.DeserializeAssociatedData(msg.SerializeAssociatedData()) + badMsg.SetPayloadA(msg.GetPayloadA()) + badMsg.SetPayloadB(msg.GetPayloadB()) // Corrupt MAC to make decryption fail - badMsg.SetMAC([]byte("sakfaskfajskasfkkaskfanjjnaf")) + badMsg.SetMAC([]byte("sakfaskfajskasfkkaskfanjffffjnaf")) // E2E Decryption returns error - err := E2EDecrypt(grp, key, badMsg) + err := E2EDecrypt(e2eGrp, key, badMsg) if err == nil { t.Errorf("E2EDecrypt should have returned error") @@ -300,7 +291,7 @@ func TestE2EDecrypt_Errors(t *testing.T) { } // Unsafe E2E Decryption returns error - err = E2EDecryptUnsafe(grp, key, badMsg) + err = E2EDecryptUnsafe(e2eGrp, key, badMsg) if err == nil { t.Errorf("E2EDecryptUnsafe should have returned error") @@ -315,7 +306,7 @@ func TestE2EDecrypt_Errors(t *testing.T) { badMsg.SetTimestamp([]byte("ABCDEF1234567890")) // E2E Decryption returns error - err = E2EDecrypt(grp, key, badMsg) + err = E2EDecrypt(e2eGrp, key, badMsg) if err == nil { t.Errorf("E2EDecrypt should have returned error") @@ -324,7 +315,7 @@ func TestE2EDecrypt_Errors(t *testing.T) { } // Unsafe E2E Decryption returns error - err = E2EDecryptUnsafe(grp, key, badMsg) + err = E2EDecryptUnsafe(e2eGrp, key, badMsg) if err == nil { t.Errorf("E2EDecryptUnsafe should have returned error") @@ -336,14 +327,15 @@ func TestE2EDecrypt_Errors(t *testing.T) { badMsg.SetTimestamp(msg.GetTimestamp()) // Corrupt payload to make decryption fail - badMsg.SetPayload([]byte("sakomnsfjeiknheuijhgfyaistuajhfaiuojfkhufijsahufiaij")) + badMsg.Contents.SetRightAligned([]byte( + "sakomnsfjeiknheuijhgfyaistuajhfaiuojfkhufijsahufiaij")) // Calculate new MAC to avoid failing on that verification again - newMAC := hash.CreateHMAC(badMsg.SerializePayload(), key.Bytes()) + newMAC := hash.CreateHMAC(badMsg.Contents.Get(), key.Bytes()) badMsg.SetMAC(newMAC) // E2E Decryption returns error - err = E2EDecrypt(grp, key, badMsg) + err = E2EDecrypt(e2eGrp, key, badMsg) if err == nil { t.Errorf("E2EDecrypt should have returned error") @@ -351,3 +343,41 @@ func TestE2EDecrypt_Errors(t *testing.T) { t.Logf("E2EDecrypt error: %v", err.Error()) } } + +func getGroups() (*cyclic.Group, *cyclic.Group) { + + cmixGrp := cyclic.NewGroup( + large.NewIntFromString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"+ + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"+ + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"+ + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"+ + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"+ + "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"+ + "83655D23DCA3AD961C62F356208552BB9ED529077096966D"+ + "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B"+ + "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"+ + "DE2BCBF6955817183995497CEA956AE515D2261898FA0510"+ + "15728E5A8AACAA68FFFFFFFFFFFFFFFF", 16), + large.NewIntFromString("2", 16), + large.NewIntFromString("2", 16)) + + e2eGrp := cyclic.NewGroup( + large.NewIntFromString("E2EE983D031DC1DB6F1A7A67DF0E9A8E5561DB8E8D49413394C049B"+ + "7A8ACCEDC298708F121951D9CF920EC5D146727AA4AE535B0922C688B55B3DD2AE"+ + "DF6C01C94764DAB937935AA83BE36E67760713AB44A6337C20E7861575E745D31F"+ + "8B9E9AD8412118C62A3E2E29DF46B0864D0C951C394A5CBBDC6ADC718DD2A3E041"+ + "023DBB5AB23EBB4742DE9C1687B5B34FA48C3521632C4A530E8FFB1BC51DADDF45"+ + "3B0B2717C2BC6669ED76B4BDD5C9FF558E88F26E5785302BEDBCA23EAC5ACE9209"+ + "6EE8A60642FB61E8F3D24990B8CB12EE448EEF78E184C7242DD161C7738F32BF29"+ + "A841698978825B4111B4BC3E1E198455095958333D776D8B2BEEED3A1A1A221A6E"+ + "37E664A64B83981C46FFDDC1A45E3D5211AAF8BFBC072768C4F50D7D7803D2D4F2"+ + "78DE8014A47323631D7E064DE81C0C6BFA43EF0E6998860F1390B5D3FEACAF1696"+ + "015CB79C3F9C2D93D961120CD0E5F12CBB687EAB045241F96789C38E89D796138E"+ + "6319BE62E35D87B1048CA28BE389B575E994DCA755471584A09EC723742DC35873"+ + "847AEF49F66E43873", 16), + large.NewIntFromString("2", 16), + large.NewIntFromString("2", 16)) + + return cmixGrp, e2eGrp + +} diff --git a/glide.yaml b/glide.yaml index 049ea320ff65c1816adcb4eedd1110e692d8fd8e..7d86dcd0d2e663ace9bd0bd5f1e5ae2280a478b1 100644 --- a/glide.yaml +++ b/glide.yaml @@ -4,7 +4,7 @@ import: version: master vcs: git - package: gitlab.com/elixxir/crypto - version: master + version: updateMessageFormat repo: git@gitlab.com:elixxir/crypto vcs: git - package: gitlab.com/elixxir/comms @@ -12,7 +12,7 @@ import: repo: git@gitlab.com:elixxir/comms vcs: git - package: gitlab.com/elixxir/primitives - version: master + version: newMessageFormat repo: git@gitlab.com:elixxir/primitives vcs: git - package: github.com/mitchellh/go-homedir diff --git a/globals/group.go b/globals/group.go deleted file mode 100644 index 490a421b3cb1adf559119192443805e5525596c5..0000000000000000000000000000000000000000 --- a/globals/group.go +++ /dev/null @@ -1,45 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright © 2018 Privategrity Corporation / -// / -// All rights reserved. / -//////////////////////////////////////////////////////////////////////////////// -package globals - -import ( - "gitlab.com/elixxir/crypto/cyclic" - "gitlab.com/elixxir/crypto/large" -) - -// InitCrypto sets up the cryptographic constants for cMix -func InitCrypto() *cyclic.Group { - - base := 16 - - pString := "9DB6FB5951B66BB6FE1E140F1D2CE5502374161FD6538DF1648218642F0B5C48" + - "C8F7A41AADFA187324B87674FA1822B00F1ECF8136943D7C55757264E5A1A44F" + - "FE012E9936E00C1D3E9310B01C7D179805D3058B2A9F4BB6F9716BFE6117C6B5" + - "B3CC4D9BE341104AD4A80AD6C94E005F4B993E14F091EB51743BF33050C38DE2" + - "35567E1B34C3D6A5C0CEAA1A0F368213C3D19843D0B4B09DCB9FC72D39C8DE41" + - "F1BF14D4BB4563CA28371621CAD3324B6A2D392145BEBFAC748805236F5CA2FE" + - "92B871CD8F9C36D3292B5509CA8CAA77A2ADFC7BFD77DDA6F71125A7456FEA15" + - "3E433256A2261C6A06ED3693797E7995FAD5AABBCFBE3EDA2741E375404AE25B" - - gString := "5C7FF6B06F8F143FE8288433493E4769C4D988ACE5BE25A0E24809670716C613" + - "D7B0CEE6932F8FAA7C44D2CB24523DA53FBE4F6EC3595892D1AA58C4328A06C4" + - "6A15662E7EAA703A1DECF8BBB2D05DBE2EB956C142A338661D10461C0D135472" + - "085057F3494309FFA73C611F78B32ADBB5740C361C9F35BE90997DB2014E2EF5" + - "AA61782F52ABEB8BD6432C4DD097BC5423B285DAFB60DC364E8161F4A2A35ACA" + - "3A10B1C4D203CC76A470A33AFDCBDD92959859ABD8B56E1725252D78EAC66E71" + - "BA9AE3F1DD2487199874393CD4D832186800654760E1E34C09E4D155179F9EC0" + - "DC4473F996BDCE6EED1CABED8B6F116F7AD9CF505DF0F998E34AB27514B0FFE7" - - qString := "F2C3119374CE76C9356990B465374A17F23F9ED35089BD969F61C6DDE9998C1F" - - p := large.NewIntFromString(pString, base) - g := large.NewIntFromString(gString, base) - q := large.NewIntFromString(qString, base) - - grp := cyclic.NewGroup(p, g, q) - - return grp -} diff --git a/io/collate.go b/io/collate.go index 99a538a23a80d85715da08527555e522aedbdd1c..86ae0a5536154a03aef58ce6d1f2a9a61e2d131c 100644 --- a/io/collate.go +++ b/io/collate.go @@ -12,6 +12,7 @@ import ( "gitlab.com/elixxir/client/globals" "gitlab.com/elixxir/client/parse" "gitlab.com/elixxir/primitives/format" + "gitlab.com/elixxir/primitives/id" "sync" "time" ) @@ -48,8 +49,11 @@ func NewCollator() *Collator { func (mb *Collator) AddMessage(message *format.Message, timeout time.Duration) *parse.Message { - payload := message.GetPayloadData() - sender := message.GetSender() + payload := message.Contents.GetRightAligned() + // There's currently no mechanism for knowing who sent an unencrypted + // message, I think? + // Let's just try ZeroID for now... + sender := id.ZeroID recipient := message.GetRecipient() partition, err := parse.ValidatePartition(payload) @@ -66,10 +70,10 @@ func (mb *Collator) AddMessage(message *format.Message, } msg := parse.Message{ - TypedBody: *typedBody, - CryptoType: format.Unencrypted, - Sender: sender, - Receiver: recipient, + TypedBody: *typedBody, + InferredType: parse.Unencrypted, + Sender: sender, + Receiver: recipient, } return &msg @@ -131,10 +135,10 @@ func (mb *Collator) AddMessage(message *format.Message, } msg := parse.Message{ - TypedBody: *typedBody, - CryptoType: format.Unencrypted, - Sender: sender, - Receiver: recipient, + TypedBody: *typedBody, + InferredType: parse.Unencrypted, + Sender: sender, + Receiver: recipient, } delete(mb.pendingMessages, key) diff --git a/io/collate_test.go b/io/collate_test.go index 34c424f07fdb7507f8767c2b2bd1adf01fef1f94..40790998f6b1587c9704ae46d75f648dbe33a264 100644 --- a/io/collate_test.go +++ b/io/collate_test.go @@ -22,7 +22,7 @@ func TestCollator_AddMessage(t *testing.T) { pendingMessages: make(map[PendingMessageKey]*multiPartMessage), } var bodies [][]byte - for length := 5; length < 20*format.MP_PAYLOAD_LEN; length += 20 { + for length := 5; length < 20*format.TotalLen; length += 20 { newBody := make([]byte, length) _, err := rand.Read(newBody) if err != nil { @@ -40,9 +40,8 @@ func TestCollator_AddMessage(t *testing.T) { for j := range partitions { fm := format.NewMessage() - fm.SetSender(id.NewUserFromUint(5, t)) fm.SetRecipient(id.NewUserFromUint(6, t)) - fm.SetPayloadData(partitions[j]) + fm.Contents.SetRightAligned(partitions[j]) result = collator.AddMessage(fm, time.Minute) } @@ -54,7 +53,7 @@ func TestCollator_AddMessage(t *testing.T) { // already, and strings should respect null terminators, // so it's probably not actually that much of a problem. if !bytes.Contains(result.Body, typedBody.Body) { - t.Errorf("Input didn't match output for %v. Got: %v, expected %v", + t.Errorf("Input didn't match output for %v. \n Got: %v\n Expected %v", i, hex.EncodeToString(result.Body), hex.EncodeToString(typedBody.Body)) } @@ -66,7 +65,7 @@ func TestCollator_AddMessage_Timeout(t *testing.T) { pendingMessages: make(map[PendingMessageKey]*multiPartMessage), } //enough for four partitions, probably - body := make([]byte, 3*format.MP_PAYLOAD_LEN) + body := make([]byte, 3*format.ContentsLen) partitions, err := parse.Partition(body, []byte{88}) if err != nil { t.Errorf("Error partitioning messages: %v", err.Error()) @@ -74,9 +73,8 @@ func TestCollator_AddMessage_Timeout(t *testing.T) { var result *parse.Message for i := range partitions { fm := format.NewMessage() - fm.SetSender(id.NewUserFromUint(5, t)) fm.SetRecipient(id.NewUserFromUint(6, t)) - fm.SetPayload(partitions[i]) + fm.Contents.SetRightAligned(partitions[i]) result = collator.AddMessage(fm, 80*time.Millisecond) if result != nil { diff --git a/io/interface.go b/io/interface.go index 043e3ceb07e15c813c75b6e41c3b99a771c73bdb..d8130f15fd2c216d4c760c6f715b9f16e465121b 100644 --- a/io/interface.go +++ b/io/interface.go @@ -8,8 +8,9 @@ package io import ( + "gitlab.com/elixxir/client/parse" "gitlab.com/elixxir/client/user" - "gitlab.com/elixxir/primitives/format" + "gitlab.com/elixxir/primitives/circuit" "gitlab.com/elixxir/primitives/id" "time" ) @@ -17,12 +18,13 @@ import ( // Communication interface implements send/receive functionality with the server type Communications interface { // SendMessage to the server - SendMessage(session user.Session, recipientID *id.User, - cryptoType format.CryptoType, message []byte) error + // TODO(nen) Can we get rid of the crypto type param here? + SendMessage(session user.Session, topology *circuit.Circuit, + recipientID *id.User, cryptoType parse.CryptoType, message []byte) error // SendMessage without partitions to the server // This is used to send rekey messages - SendMessageNoPartition(session user.Session, recipientID *id.User, - cryptoType format.CryptoType, message []byte) error + SendMessageNoPartition(session user.Session, topology *circuit.Circuit, + recipientID *id.User, cryptoType parse.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 04a137678e6280472b47152157906da354730443..b68a0a6f50bbe53216080da91c9a07bef0714c6b 100644 --- a/io/messaging.go +++ b/io/messaging.go @@ -22,6 +22,7 @@ import ( "gitlab.com/elixxir/crypto/cmix" "gitlab.com/elixxir/crypto/csprng" "gitlab.com/elixxir/crypto/e2e" + "gitlab.com/elixxir/primitives/circuit" "gitlab.com/elixxir/primitives/format" "gitlab.com/elixxir/primitives/id" "gitlab.com/elixxir/primitives/switchboard" @@ -72,9 +73,9 @@ func NewMessenger() *Messaging { // the keys) here. I won't touch crypto at this time, though... // TODO This method would be cleaner if it took a parse.Message (particularly // w.r.t. generating message IDs for multi-part messages.) -func (m *Messaging) SendMessage(session user.Session, +func (m *Messaging) SendMessage(session user.Session, topology *circuit.Circuit, recipientID *id.User, - cryptoType format.CryptoType, + cryptoType parse.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 @@ -85,7 +86,6 @@ func (m *Messaging) SendMessage(session user.Session, // TBD: Is there a really good reason why we'd ever have more than one user // 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 parts, err := parse.Partition([]byte(message), m.nextId()) if err != nil { @@ -100,15 +100,15 @@ func (m *Messaging) SendMessage(session user.Session, if err != nil { return fmt.Errorf("SendMessage MarshalBinary() error: %v", err.Error()) } + extendedNowBytes := append(nowBytes, 0) for i := range parts { message := format.NewMessage() - 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, cryptoType, message, false) + message.SetTimestamp(extendedNowBytes) + message.Contents.SetRightAligned(parts[i]) + err = m.send(session, topology, cryptoType, message, false) if err != nil { return fmt.Errorf("SendMessage send() error: %v", err.Error()) } @@ -120,14 +120,12 @@ func (m *Messaging) SendMessage(session user.Session, // This function will be needed for example to send a Rekey // message, where a new public key will take up the whole message func (m *Messaging) SendMessageNoPartition(session user.Session, - recipientID *id.User, - cryptoType format.CryptoType, + topology *circuit.Circuit, recipientID *id.User, cryptoType parse.CryptoType, message []byte) error { size := len(message) - if size > format.TOTAL_LEN { + if size > format.TotalLen { 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 @@ -141,17 +139,9 @@ func (m *Messaging) SendMessageNoPartition(session user.Session, // 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) - } + msg.Contents.Set(message) globals.Log.DEBUG.Printf("Sending message to %v: %x", *recipientID, message) - err = m.send(session, cryptoType, msg, true) + err = m.send(session, topology, cryptoType, msg, true) if err != nil { return fmt.Errorf("SendMessageNoPartition send() error: %v", err.Error()) } @@ -159,8 +149,8 @@ func (m *Messaging) SendMessageNoPartition(session user.Session, } // send actually sends the message to the server -func (m *Messaging) send(session user.Session, - cryptoType format.CryptoType, +func (m *Messaging) send(session user.Session, topology *circuit.Circuit, + cryptoType parse.CryptoType, message *format.Message, rekey bool) error { // Enable transmission blocking if enabled @@ -173,25 +163,25 @@ func (m *Messaging) send(session user.Session, } // Check message type - if cryptoType == format.E2E { + if cryptoType == parse.E2E { handleE2ESending(session, message, rekey) } else { - padded, err := e2e.Pad(message.GetPayload(), format.TOTAL_LEN) + padded, err := e2e.Pad(message.Contents.GetRightAligned(), format.ContentsLen) if err != nil { return err } - message.SetPayload(padded) + message.Contents.Set(padded) e2e.SetUnencrypted(message) } // CMIX Encryption salt := cmix.NewSalt(csprng.Source(&csprng.SystemRNG{}), 16) - encMsg := crypto.CMIXEncrypt(session, salt, message) + encMsg := crypto.CMIXEncrypt(session, topology, salt, message) msgPacket := &pb.Slot{ SenderID: session.GetCurrentUser().User.Bytes(), - MessagePayload: encMsg.SerializePayload(), - AssociatedData: encMsg.SerializeAssociatedData(), + MessagePayload: encMsg.GetPayloadA(), + AssociatedData: encMsg.GetPayloadB(), Salt: salt, KMACs: make([][]byte, 0), } @@ -242,20 +232,20 @@ func handleE2ESending(session user.Session, MessageType: int32(cmixproto.Type_REKEY_TRIGGER), Body: []byte{}, }, - CryptoType: format.None, - Receiver: recipientID, + InferredType: parse.None, + Receiver: recipientID, } go session.GetSwitchboard().Speak(rekeyMsg) } globals.Log.DEBUG.Printf("E2E encrypting message") if rekey { - crypto.E2EEncryptUnsafe(session.GetGroup(), + crypto.E2EEncryptUnsafe(session.GetE2EGroup(), key.GetKey(), key.KeyFingerprint(), message) } else { - crypto.E2EEncrypt(session.GetGroup(), + crypto.E2EEncrypt(session.GetE2EGroup(), key.GetKey(), key.KeyFingerprint(), message) @@ -302,7 +292,7 @@ func (m *Messaging) MessageReceiver(session user.Session, delay time.Duration) { func handleE2EReceiving(session user.Session, message *format.Message) (bool, error) { - keyFingerprint := message.GetKeyFingerprint() + keyFingerprint := message.GetKeyFP() // Lookup reception key recpKey := session.GetKeyStore(). @@ -312,7 +302,7 @@ func handleE2EReceiving(session user.Session, if recpKey == nil { // TODO Handle sending error message to SW return rekey, fmt.Errorf("E2EKey for matching fingerprint not found, can't process message") - } else if recpKey.GetOuterType() == format.Rekey { + } else if recpKey.GetOuterType() == parse.Rekey { // If key type is rekey, the message is a rekey from partner rekey = true } @@ -320,9 +310,9 @@ func handleE2EReceiving(session user.Session, globals.Log.DEBUG.Printf("E2E decrypting message") var err error if rekey { - err = crypto.E2EDecryptUnsafe(session.GetGroup(), recpKey.GetKey(), message) + err = crypto.E2EDecryptUnsafe(session.GetE2EGroup(), recpKey.GetKey(), message) } else { - err = crypto.E2EDecrypt(session.GetGroup(), recpKey.GetKey(), message) + err = crypto.E2EDecrypt(session.GetE2EGroup(), recpKey.GetKey(), message) } if err != nil { @@ -335,15 +325,15 @@ func handleE2EReceiving(session user.Session, // Send rekey message to switchboard if rekey { partner := recpKey.GetManager().GetPartner() - partnerPubKey := message.SerializePayload() + partnerPubKey := message.Contents.Get() rekeyMsg := &parse.Message{ Sender: partner, TypedBody: parse.TypedBody{ MessageType: int32(cmixproto.Type_NO_TYPE), Body: partnerPubKey, }, - CryptoType: format.Rekey, - Receiver: session.GetCurrentUser().User, + InferredType: parse.Rekey, + Receiver: session.GetCurrentUser().User, } go session.GetSwitchboard().Speak(rekeyMsg) } @@ -392,10 +382,8 @@ func (m *Messaging) receiveMessagesFromGateway(session user.Session, } msg := format.NewMessage() - msg.AssociatedData = format.DeserializeAssociatedData( - newMessage.AssociatedData) - msg.Payload = format.DeserializePayload(newMessage. - MessagePayload) + msg.SetPayloadA(newMessage.MessagePayload) + msg.SetPayloadB(newMessage.AssociatedData) var err error = nil var rekey bool @@ -405,9 +393,9 @@ func (m *Messaging) receiveMessagesFromGateway(session user.Session, rekey, err = handleE2EReceiving(session, msg) } else { // If message is non E2E, need to unpad payload - unpadded, err = e2e.Unpad(msg.SerializePayload()) + unpadded, err = e2e.Unpad(msg.Contents.Get()) if err == nil { - msg.SetSplitPayload(unpadded) + msg.Contents.Set(unpadded) } } diff --git a/keyStore/e2eKey.go b/keyStore/e2eKey.go index d45808f60b83187848180c84899fb2ec36cf84ce..3c6226477ab86bd3bc34d30786eea663abe00e29 100644 --- a/keyStore/e2eKey.go +++ b/keyStore/e2eKey.go @@ -1,6 +1,7 @@ package keyStore import ( + "gitlab.com/elixxir/client/parse" "gitlab.com/elixxir/crypto/cyclic" "gitlab.com/elixxir/crypto/hash" "gitlab.com/elixxir/primitives/format" @@ -14,7 +15,7 @@ type E2EKey struct { key *cyclic.Int // Designation of crypto type - outer format.CryptoType + outer parse.CryptoType // keyNum is needed by Key Manager // to keep track of which receiving keys @@ -33,7 +34,7 @@ func (e2ekey *E2EKey) GetKey() *cyclic.Int { } // Get key type, E2E or Rekey -func (e2ekey *E2EKey) GetOuterType() format.CryptoType { +func (e2ekey *E2EKey) GetOuterType() parse.CryptoType { return e2ekey.outer } diff --git a/keyStore/keyManager.go b/keyStore/keyManager.go index e34eb4646a7230976012d623745cfa1b05124f6c..669e72d9f87304d91d759bacb052306d8eec37a9 100644 --- a/keyStore/keyManager.go +++ b/keyStore/keyManager.go @@ -4,6 +4,7 @@ import ( "bytes" "encoding/binary" "encoding/gob" + "gitlab.com/elixxir/client/parse" "gitlab.com/elixxir/crypto/cyclic" "gitlab.com/elixxir/crypto/e2e" "gitlab.com/elixxir/primitives/format" @@ -88,11 +89,11 @@ func NewManager(baseKey *cyclic.Int, km.ttl = ttl km.numKeys = numKeys km.numReKeys = numReKeys - for i, _ := range km.recvKeysState { + for i := range km.recvKeysState { km.recvKeysState[i] = new(uint64) *km.recvKeysState[i] = 0 } - for i, _ := range km.recvReKeysState { + for i := range km.recvReKeysState { km.recvReKeysState[i] = new(uint64) *km.recvReKeysState[i] = 0 } @@ -283,7 +284,7 @@ func (km *KeyManager) GenerateKeys(grp *cyclic.Group, userID *id.User, e2ekey := new(E2EKey) e2ekey.key = key e2ekey.manager = km - e2ekey.outer = format.E2E + e2ekey.outer = parse.E2E km.sendKeys.Push(e2ekey) } @@ -295,7 +296,7 @@ func (km *KeyManager) GenerateKeys(grp *cyclic.Group, userID *id.User, e2ekey := new(E2EKey) e2ekey.key = key e2ekey.manager = km - e2ekey.outer = format.Rekey + e2ekey.outer = parse.Rekey km.sendReKeys.Push(e2ekey) } // Add KeyManager to KeyStore map @@ -317,7 +318,7 @@ func (km *KeyManager) GenerateKeys(grp *cyclic.Group, userID *id.User, e2ekey := new(E2EKey) e2ekey.key = key e2ekey.manager = km - e2ekey.outer = format.E2E + e2ekey.outer = parse.E2E e2ekey.keyNum = uint32(i) keyFP := e2ekey.KeyFingerprint() km.recvKeysFingerprint = append(km.recvKeysFingerprint, keyFP) @@ -333,7 +334,7 @@ func (km *KeyManager) GenerateKeys(grp *cyclic.Group, userID *id.User, e2ekey := new(E2EKey) e2ekey.key = key e2ekey.manager = km - e2ekey.outer = format.Rekey + e2ekey.outer = parse.Rekey e2ekey.keyNum = uint32(i) keyFP := e2ekey.KeyFingerprint() km.recvReKeysFingerprint = append(km.recvReKeysFingerprint, keyFP) diff --git a/keyStore/keyStack_test.go b/keyStore/keyStack_test.go index a61db9971da30dea9a37624a35c07d91eb77f670..8d4085f8749dd0804a0ddd3df1d21e635c84845d 100644 --- a/keyStore/keyStack_test.go +++ b/keyStore/keyStack_test.go @@ -1,9 +1,9 @@ package keyStore import ( + "gitlab.com/elixxir/client/parse" "gitlab.com/elixxir/crypto/cyclic" "gitlab.com/elixxir/crypto/large" - "gitlab.com/elixxir/primitives/format" "testing" "time" ) @@ -32,7 +32,7 @@ func TestKeyStack(t *testing.T) { for i := 0; i < 100; i++ { key := new(E2EKey) - key.outer = format.E2E + key.outer = parse.E2E key.key = grp.NewInt(int64(i + 2)) key.manager = nil expectedKeys[99-i] = key @@ -57,7 +57,7 @@ func TestKeyStack_Panic(t *testing.T) { for i := 0; i < 10; i++ { key := new(E2EKey) - key.outer = format.E2E + key.outer = parse.E2E key.key = grp.NewInt(int64(i + 2)) key.manager = nil expectedKeys[9-i] = key @@ -88,7 +88,7 @@ func TestKeyStack_Delete(t *testing.T) { for i := 0; i < 100; i++ { key := new(E2EKey) - key.outer = format.E2E + key.outer = parse.E2E key.key = grp.NewInt(int64(i + 2)) key.manager = nil expectedKeys[99-i] = key @@ -123,7 +123,7 @@ func TestKeyStack_Concurrent(t *testing.T) { for i := 0; i < 100; i++ { key := new(E2EKey) - key.outer = format.E2E + key.outer = parse.E2E key.key = grp.NewInt(int64(i + 2)) key.manager = nil expectedKeys[99-i] = key diff --git a/keyStore/keyStore.go b/keyStore/keyStore.go index 85392d0e3257ba15b4ca90ce15f85dfd1a26f392..8c92dccc6afb12c5226e7c30b8d43ba8fc3924fd 100644 --- a/keyStore/keyStore.go +++ b/keyStore/keyStore.go @@ -3,6 +3,7 @@ package keyStore import ( "bytes" "encoding/gob" + "gitlab.com/elixxir/client/parse" "gitlab.com/elixxir/crypto/cyclic" "gitlab.com/elixxir/crypto/e2e" "gitlab.com/elixxir/primitives/format" @@ -68,7 +69,7 @@ func (m *inKeyMap) Pop(fingerprint format.Fingerprint) *E2EKey { m.Delete(fingerprint) // Update Key Manager Receiving State key.GetManager().updateRecvState( - key.GetOuterType() == format.Rekey, + key.GetOuterType() == parse.Rekey, key.keyNum) return key } diff --git a/parse/message.go b/parse/message.go index fd34ef7a1a3c4e950886be313c8b87b59817baa5..b19f121e0bff039b5afac1cf6b6136edf2df6ca9 100644 --- a/parse/message.go +++ b/parse/message.go @@ -8,7 +8,6 @@ package parse import ( "crypto/sha256" - "gitlab.com/elixxir/primitives/format" "gitlab.com/elixxir/primitives/id" ) @@ -19,10 +18,26 @@ type MessageHash [MessageHashLen]byte type Message struct { TypedBody - CryptoType format.CryptoType - Sender *id.User - Receiver *id.User - Nonce []byte + // The crypto type is inferred from the message's contents + InferredType CryptoType + Sender *id.User + Receiver *id.User + Nonce []byte +} + +type CryptoType int32 + +const ( + None CryptoType = iota + Unencrypted + Rekey + E2E +) + +var cryptoTypeStrArr = []string{"None", "Unencrypted", "Rekey", "E2E"} + +func (ct CryptoType) String() string { + return cryptoTypeStrArr[ct] } // Interface used to standardize message definitions @@ -38,7 +53,7 @@ type MessageInterface interface { // Return the message's inner type GetMessageType() int32 // Returns the message's outer type - GetCryptoType() format.CryptoType + GetCryptoType() CryptoType // Return the message fully serialized including the type prefix // Does this really belong in the interface? Pack() []byte @@ -78,8 +93,8 @@ func (m *Message) GetMessageType() int32 { return m.MessageType } -func (m *Message) GetCryptoType() format.CryptoType { - return m.CryptoType +func (m *Message) GetCryptoType() CryptoType { + return m.InferredType } func (m *Message) Pack() []byte { diff --git a/parse/partition.go b/parse/partition.go index 23afa2467c5cd34e2f2e8154c6572c63376fc7d1..2036f307c4f4758504ace962f27aa744f0699fe9 100644 --- a/parse/partition.go +++ b/parse/partition.go @@ -11,12 +11,15 @@ import ( "errors" "fmt" "gitlab.com/elixxir/client/globals" - "gitlab.com/elixxir/crypto/e2e" "gitlab.com/elixxir/primitives/format" "math" "sync" ) +func getMaxMessageLength() int { + return format.ContentsLen - format.PadMinLen +} + // TODO is there a better way to generate unique message IDs locally? func IDCounter() func() []byte { // 32 bits to put a smaller upper bound on the varint size on the wire @@ -52,7 +55,7 @@ func GetMaxIndex(body []byte, id []byte) int32 { if bodyLen > 0 { bodyLen-- } - maxIndex := bodyLen / (format.MP_PAYLOAD_LEN - e2e.MinPaddingLen - len(id) - IndexLength) + maxIndex := bodyLen / (getMaxMessageLength() - len(id) - IndexLength) return int32(maxIndex) } @@ -75,7 +78,7 @@ func Partition(body []byte, id []byte) ([][]byte, error) { var lastPartitionLength int partitionReadIdx := 0 for i := range partitions { - maxPartitionLength := format.MP_PAYLOAD_LEN - e2e.MinPaddingLen + maxPartitionLength := getMaxMessageLength() partitions[i], lastPartitionLength = makePartition(maxPartitionLength, body[partitionReadIdx:], id, byte(i), byte(maxIndex)) partitionReadIdx += lastPartitionLength @@ -128,7 +131,8 @@ func makePartition(maxLength int, body []byte, id []byte, i byte, func Assemble(partitions [][]byte) ([]byte, error) { // this will allocate a bit more capacity than needed but not so much that // it breaks the bank - result := make([]byte, 0, int(format.MP_PAYLOAD_LEN)*len(partitions)) + result := make([]byte, 0, int(format.ContentsLen-format.PadMinLen)* + len(partitions)) for i := range partitions { result = append(result, partitions[i]...) diff --git a/parse/partition_test.go b/parse/partition_test.go index d6dec915fc02a1d2a5ad58292002cc6e6eb5f088..349ad3c75da2cae06d696afdce1d76a4f5f17163 100644 --- a/parse/partition_test.go +++ b/parse/partition_test.go @@ -8,8 +8,6 @@ package parse import ( "bytes" - "gitlab.com/elixxir/crypto/e2e" - "gitlab.com/elixxir/primitives/format" "math/rand" "testing" ) @@ -61,7 +59,9 @@ func TestPartitionShort(t *testing.T) { // in sum, contains the whole message. func TestPartitionLong(t *testing.T) { id := []byte{0xa2, 0x54} - randomBytes := randomString(0, 300) + // This should be about the right length + // With the other length, the test panicked with out of bounds + randomBytes := randomString(0, getMaxMessageLength()*2-12) actual, err := Partition(randomBytes, id) if err != nil { @@ -75,7 +75,7 @@ func TestPartitionLong(t *testing.T) { expected[0] = append(expected[0], 0, 1) // part of random string expected[0] = append(expected[0], - randomBytes[:format.MP_PAYLOAD_LEN-4-e2e.MinPaddingLen]...) + randomBytes[:getMaxMessageLength()-4]...) // id expected[1] = append(expected[1], id...) @@ -83,7 +83,7 @@ func TestPartitionLong(t *testing.T) { expected[1] = append(expected[1], 1, 1) // other part of random string expected[1] = append(expected[1], - randomBytes[format.MP_PAYLOAD_LEN-4-e2e.MinPaddingLen:]...) + randomBytes[getMaxMessageLength()-4:]...) for i := range actual { if !bytes.Equal(actual[i], expected[i]) { @@ -106,7 +106,7 @@ func TestPartitionLongest(t *testing.T) { t.Fatalf(err.Error()) } - expectedNumberOfPartitions := 256 + expectedNumberOfPartitions := 139 if len(actual) != expectedNumberOfPartitions { t.Errorf("Expected a 52480-byte message to split into %v partitions, got %v instead", @@ -116,7 +116,7 @@ func TestPartitionLongest(t *testing.T) { // check the index and max index of the last partition lastIndex := len(actual) - 1 - expectedIdx := byte(255) + expectedIdx := byte(138) idxLocation := len(id) maxIdxLocation := len(id) + 1 actualIdx := actual[lastIndex][idxLocation] @@ -135,7 +135,7 @@ func TestPartitionLongest(t *testing.T) { // message that's too long to partition func TestPartitionTooLong(t *testing.T) { id := []byte{0x1f, 0x2f, 0x3f, 0x4f, 0x5f} - _, err := Partition(randomString(0, 57856), id) + _, err := Partition(randomString(0, 257856), id) if err == nil { t.Error("Partition() processed a message that was too long to be" + @@ -155,8 +155,7 @@ func TestOnlyAssemble(t *testing.T) { partitions := make([][]byte, len(messageChunks)) for i := range partitions { - e2e.Pad([]byte(messageChunks[i]), format.MP_PAYLOAD_LEN) - partitions[i] = append(partitions[i], messageChunks[i]...) + partitions[i] = append(partitions[i], []byte(messageChunks[i])...) } assembled, err := Assemble(partitions) @@ -164,7 +163,7 @@ func TestOnlyAssemble(t *testing.T) { t.Error(err.Error()) } if completeMessage != string(assembled) { - t.Errorf("TestOnlyAssemble: got \"%v\"; expected \"%v\".", + t.Errorf("TestOnlyAssemble: got \"%v\";\n expected \"%v\".", string(assembled), completeMessage) } } @@ -449,7 +448,8 @@ func TestValidatePartition(t *testing.T) { for i := range validPayloads { result, err := ValidatePartition(validPayloads[i]) if err != nil { - t.Errorf("Payload %v was incorrectly invalidated: %v", i, err.Error()) + t.Fatalf("Payload %v was incorrectly invalidated: %v", i, + err.Error()) } if !bytes.Equal(result.ID, expectedIDs[i]) { t.Errorf("Payload %v's ID was parsed incorrectly. Got %v, "+ diff --git a/rekey/rekey.go b/rekey/rekey.go index 7caffa0018849fae237b61999a609442eca3f624..c4e8c9636ec82b4e3209def90e602a26711ed59a 100644 --- a/rekey/rekey.go +++ b/rekey/rekey.go @@ -15,12 +15,14 @@ import ( "gitlab.com/elixxir/crypto/e2e" "gitlab.com/elixxir/crypto/hash" "gitlab.com/elixxir/crypto/signature" + "gitlab.com/elixxir/primitives/circuit" "gitlab.com/elixxir/primitives/format" "gitlab.com/elixxir/primitives/id" "gitlab.com/elixxir/primitives/switchboard" ) var session user.Session +var topology *circuit.Circuit var messaging io.Communications var rekeyTriggerList rekeyTriggerListener @@ -52,6 +54,10 @@ func (l *rekeyListener) Hear(msg switchboard.Item, isHeardElsewhere bool) { m := msg.(*parse.Message) partner := m.GetSender() partnerPubKey := m.GetPayload() + if m.GetCryptoType() != parse.Rekey { + globals.Log.WARN.Printf("Received message with NO_TYPE but not Rekey CryptoType, needs to be fixed!") + return + } globals.Log.DEBUG.Printf("Received Rekey message from user %v", *partner) err := rekeyProcess(Rekey, partner, partnerPubKey) if err != nil { @@ -81,24 +87,30 @@ func (l *rekeyConfirmListener) Hear(msg switchboard.Item, isHeardElsewhere bool) } // InitRekey is called internally by the Login API -func InitRekey(s user.Session, m io.Communications) { +func InitRekey(s user.Session, m io.Communications, t *circuit.Circuit) { rekeyTriggerList = rekeyTriggerListener{} rekeyList = rekeyListener{} rekeyConfirmList = rekeyConfirmListener{} session = s + topology = t messaging = m l := session.GetSwitchboard() l.Register(s.GetCurrentUser().User, - format.None, int32(cmixproto.Type_REKEY_TRIGGER), + int32(cmixproto.Type_REKEY_TRIGGER), &rekeyTriggerList) + // TODO(nen) Wouldn't it be possible to register these listeners based + // solely on the inner type? maybe the switchboard can rebroadcast + // messages that have a type that includes the outer type if that's not + // possible + // in short, switchboard should be the package that includes outer l.Register(id.ZeroID, - format.Rekey, int32(cmixproto.Type_NO_TYPE), + int32(cmixproto.Type_NO_TYPE), &rekeyList) l.Register(id.ZeroID, - format.None, int32(cmixproto.Type_REKEY_CONFIRM), + int32(cmixproto.Type_REKEY_CONFIRM), &rekeyConfirmList) } @@ -113,7 +125,7 @@ const ( func rekeyProcess(rt rekeyType, partner *id.User, data []byte) error { rkm := session.GetRekeyManager() - grp := session.GetGroup() + grp := session.GetCmixGroup() // Error handling according to Rekey Message Type var ctx *keyStore.RekeyContext @@ -236,17 +248,18 @@ func rekeyProcess(rt rekeyType, partner *id.User, data []byte) error { // Directly send raw publicKey bytes, without any message type // This ensures that the publicKey fits in a single message, which // is sent with E2E encryption using a send Rekey, and without padding - return messaging.SendMessageNoPartition(session, partner, format.E2E, - pubKey.GetKey().LeftpadBytes(uint64(format.TOTAL_LEN))) + return messaging.SendMessageNoPartition(session, topology, partner, parse.E2E, + pubKey.GetKey().LeftpadBytes(uint64(format.TotalLen))) case Rekey: // Send rekey confirm message with hash of the baseKey h, _ := hash.NewCMixHash() h.Write(ctx.BaseKey.Bytes()) + baseKeyHash := h.Sum(nil) msg := parse.Pack(&parse.TypedBody{ MessageType: int32(cmixproto.Type_REKEY_CONFIRM), - Body: h.Sum(nil), + Body: baseKeyHash, }) - return messaging.SendMessage(session, partner, format.None, msg) + return messaging.SendMessage(session, topology, partner, parse.None, msg) } return nil } diff --git a/rekey/rekey_test.go b/rekey/rekey_test.go index 6dacf9d2c37918fbf3c9836209cc6e298ed15044..3e770747176348930859f02bdbaff44f5921dd11 100644 --- a/rekey/rekey_test.go +++ b/rekey/rekey_test.go @@ -8,11 +8,13 @@ import ( "gitlab.com/elixxir/client/parse" "gitlab.com/elixxir/client/user" "gitlab.com/elixxir/crypto/csprng" + "gitlab.com/elixxir/crypto/cyclic" "gitlab.com/elixxir/crypto/diffieHellman" "gitlab.com/elixxir/crypto/e2e" "gitlab.com/elixxir/crypto/hash" + "gitlab.com/elixxir/crypto/large" "gitlab.com/elixxir/crypto/signature" - "gitlab.com/elixxir/primitives/format" + "gitlab.com/elixxir/primitives/circuit" "gitlab.com/elixxir/primitives/id" "os" "testing" @@ -27,8 +29,9 @@ type dummyMessaging struct { // SendMessage to the server func (d *dummyMessaging) SendMessage(sess user.Session, + topology *circuit.Circuit, recipientID *id.User, - cryptoType format.CryptoType, + cryptoType parse.CryptoType, message []byte) error { d.listener <- message return nil @@ -36,8 +39,9 @@ func (d *dummyMessaging) SendMessage(sess user.Session, // SendMessage without partitions to the server func (d *dummyMessaging) SendMessageNoPartition(sess user.Session, + topology *circuit.Circuit, recipientID *id.User, - cryptoType format.CryptoType, + cryptoType parse.CryptoType, message []byte) error { d.listener <- message return nil @@ -49,11 +53,13 @@ func (d *dummyMessaging) MessageReceiver(session user.Session, } func TestMain(m *testing.M) { - grp := globals.InitCrypto() + + grp, e2eGrp := getGroups() + user.InitUserRegistry(grp) params := signature.CustomDSAParams( grp.GetP(), - grp.GetG(), - grp.GetQ()) + grp.GetQ(), + grp.GetG()) rng := csprng.NewSystemRNG() u := &user.User{ User: id.NewUserFromUints(&[4]uint64{0, 0, 0, 18}), @@ -68,12 +74,12 @@ func TestMain(m *testing.M) { partnerPubKeyCyclic := grp.NewIntFromLargeInt(partnerPubKey.GetKey()) session := user.NewSession(&globals.RamStorage{}, - u, nil, myPubKey, myPrivKey, grp) + u, nil, myPubKey, myPrivKey, grp, e2eGrp) ListenCh = make(chan []byte, 100) fakeComm := &dummyMessaging{ listener: ListenCh, } - InitRekey(session, fakeComm) + InitRekey(session, fakeComm, circuit.New([]*id.Node{id.NewNodeFromBytes(make([]byte, id.NodeIdLen))})) // Create E2E relationship with partner // Generate baseKey @@ -125,8 +131,8 @@ func TestRekeyTrigger(t *testing.T) { MessageType: int32(cmixproto.Type_REKEY_TRIGGER), Body: partnerPubKey.Bytes(), }, - CryptoType: format.None, - Receiver: partnerID, + InferredType: parse.None, + Receiver: partnerID, } session.GetSwitchboard().Speak(msg) @@ -137,7 +143,7 @@ func TestRekeyTrigger(t *testing.T) { // Get new PubKey from Rekey message and confirm value matches // with PubKey created from privKey in Rekey Context value := <-ListenCh - grp := session.GetGroup() + grp := session.GetCmixGroup() actualPubKey := grp.NewIntFromBytes(value) privKey := session.GetRekeyManager().GetCtx(partnerID).PrivKey expectedPubKey := grp.NewInt(1) @@ -156,8 +162,8 @@ func TestRekeyTrigger(t *testing.T) { MessageType: int32(cmixproto.Type_REKEY_TRIGGER), Body: partnerPubKey.Bytes(), }, - CryptoType: format.None, - Receiver: partnerID, + InferredType: parse.None, + Receiver: partnerID, } session.GetSwitchboard().Speak(msg) @@ -179,8 +185,8 @@ func TestRekeyConfirm(t *testing.T) { MessageType: int32(cmixproto.Type_REKEY_CONFIRM), Body: baseKey.Bytes(), }, - CryptoType: format.None, - Receiver: session.GetCurrentUser().User, + InferredType: parse.None, + Receiver: session.GetCurrentUser().User, } session.GetSwitchboard().Speak(msg) @@ -198,8 +204,8 @@ func TestRekeyConfirm(t *testing.T) { MessageType: int32(cmixproto.Type_REKEY_CONFIRM), Body: h.Sum(nil), }, - CryptoType: format.None, - Receiver: session.GetCurrentUser().User, + InferredType: parse.None, + Receiver: session.GetCurrentUser().User, } session.GetSwitchboard().Speak(msg) @@ -224,8 +230,8 @@ func TestRekeyConfirm(t *testing.T) { MessageType: int32(cmixproto.Type_REKEY_CONFIRM), Body: h.Sum(nil), }, - CryptoType: format.None, - Receiver: session.GetCurrentUser().User, + InferredType: parse.None, + Receiver: session.GetCurrentUser().User, } session.GetSwitchboard().Speak(msg) @@ -240,11 +246,11 @@ func TestRekey(t *testing.T) { partnerID := id.NewUserFromUints(&[4]uint64{0, 0, 0, 12}) km := session.GetKeyStore().GetSendManager(partnerID) // Generate new partner public key - grp := globals.InitCrypto() + grp, _ := getGroups() params := signature.CustomDSAParams( grp.GetP(), - grp.GetG(), - grp.GetQ()) + grp.GetQ(), + grp.GetG()) rng := csprng.NewSystemRNG() partnerPrivKey := params.PrivateKeyGen(rng) partnerPubKey := partnerPrivKey.PublicKeyGen() @@ -255,8 +261,8 @@ func TestRekey(t *testing.T) { MessageType: int32(cmixproto.Type_NO_TYPE), Body: partnerPubKey.GetKey().Bytes(), }, - CryptoType: format.Rekey, - Receiver: session.GetCurrentUser().User, + InferredType: parse.Rekey, + Receiver: session.GetCurrentUser().User, } session.GetSwitchboard().Speak(msg) @@ -309,8 +315,8 @@ func TestRekey_Errors(t *testing.T) { MessageType: int32(cmixproto.Type_REKEY_TRIGGER), Body: partnerPubKey.Bytes(), }, - CryptoType: format.None, - Receiver: partnerID, + InferredType: parse.None, + Receiver: partnerID, } session.GetSwitchboard().Speak(msg) @@ -326,8 +332,8 @@ func TestRekey_Errors(t *testing.T) { MessageType: int32(cmixproto.Type_NO_TYPE), Body: []byte{}, }, - CryptoType: format.Rekey, - Receiver: session.GetCurrentUser().User, + InferredType: parse.Rekey, + Receiver: session.GetCurrentUser().User, } session.GetSwitchboard().Speak(msg) @@ -336,3 +342,45 @@ func TestRekey_Errors(t *testing.T) { t.Errorf("Rekey should have returned error") } } + +func getGroups() (*cyclic.Group, *cyclic.Group) { + + cmixGrp := cyclic.NewGroup( + large.NewIntFromString("9DB6FB5951B66BB6FE1E140F1D2CE5502374161FD6538DF1648218642F0B5C48"+ + "C8F7A41AADFA187324B87674FA1822B00F1ECF8136943D7C55757264E5A1A44F"+ + "FE012E9936E00C1D3E9310B01C7D179805D3058B2A9F4BB6F9716BFE6117C6B5"+ + "B3CC4D9BE341104AD4A80AD6C94E005F4B993E14F091EB51743BF33050C38DE2"+ + "35567E1B34C3D6A5C0CEAA1A0F368213C3D19843D0B4B09DCB9FC72D39C8DE41"+ + "F1BF14D4BB4563CA28371621CAD3324B6A2D392145BEBFAC748805236F5CA2FE"+ + "92B871CD8F9C36D3292B5509CA8CAA77A2ADFC7BFD77DDA6F71125A7456FEA15"+ + "3E433256A2261C6A06ED3693797E7995FAD5AABBCFBE3EDA2741E375404AE25B", 16), + large.NewIntFromString("5C7FF6B06F8F143FE8288433493E4769C4D988ACE5BE25A0E24809670716C613"+ + "D7B0CEE6932F8FAA7C44D2CB24523DA53FBE4F6EC3595892D1AA58C4328A06C4"+ + "6A15662E7EAA703A1DECF8BBB2D05DBE2EB956C142A338661D10461C0D135472"+ + "085057F3494309FFA73C611F78B32ADBB5740C361C9F35BE90997DB2014E2EF5"+ + "AA61782F52ABEB8BD6432C4DD097BC5423B285DAFB60DC364E8161F4A2A35ACA"+ + "3A10B1C4D203CC76A470A33AFDCBDD92959859ABD8B56E1725252D78EAC66E71"+ + "BA9AE3F1DD2487199874393CD4D832186800654760E1E34C09E4D155179F9EC0"+ + "DC4473F996BDCE6EED1CABED8B6F116F7AD9CF505DF0F998E34AB27514B0FFE7", 16), + large.NewIntFromString("F2C3119374CE76C9356990B465374A17F23F9ED35089BD969F61C6DDE9998C1F", 16)) + + e2eGrp := cyclic.NewGroup( + large.NewIntFromString("E2EE983D031DC1DB6F1A7A67DF0E9A8E5561DB8E8D49413394C049B"+ + "7A8ACCEDC298708F121951D9CF920EC5D146727AA4AE535B0922C688B55B3DD2AE"+ + "DF6C01C94764DAB937935AA83BE36E67760713AB44A6337C20E7861575E745D31F"+ + "8B9E9AD8412118C62A3E2E29DF46B0864D0C951C394A5CBBDC6ADC718DD2A3E041"+ + "023DBB5AB23EBB4742DE9C1687B5B34FA48C3521632C4A530E8FFB1BC51DADDF45"+ + "3B0B2717C2BC6669ED76B4BDD5C9FF558E88F26E5785302BEDBCA23EAC5ACE9209"+ + "6EE8A60642FB61E8F3D24990B8CB12EE448EEF78E184C7242DD161C7738F32BF29"+ + "A841698978825B4111B4BC3E1E198455095958333D776D8B2BEEED3A1A1A221A6E"+ + "37E664A64B83981C46FFDDC1A45E3D5211AAF8BFBC072768C4F50D7D7803D2D4F2"+ + "78DE8014A47323631D7E064DE81C0C6BFA43EF0E6998860F1390B5D3FEACAF1696"+ + "015CB79C3F9C2D93D961120CD0E5F12CBB687EAB045241F96789C38E89D796138E"+ + "6319BE62E35D87B1048CA28BE389B575E994DCA755471584A09EC723742DC35873"+ + "847AEF49F66E43873", 16), + large.NewIntFromString("2", 16), + large.NewIntFromString("2", 16)) + + return cmixGrp, e2eGrp + +} diff --git a/user/regPrime.go b/user/regPrime.go new file mode 100644 index 0000000000000000000000000000000000000000..30278c7e99857f64377c5c4036146a383987173a --- /dev/null +++ b/user/regPrime.go @@ -0,0 +1,61 @@ +package user + +var pString = "F0032FB15A40F9397B63481527D1" + + "80BAF55F8562824EF02139016E6335" + + "ABC78784A6CB263B0CDB0FA4763485" + + "0E9A500EE529F68550D57F70C22BF4" + + "D6735D764376A535AB7DF31B06B372" + + "C193090478E64387AA712A11D2BE51" + + "3189AC7E2B2CA392D29087FE5922D8" + + "F196765DA84CCE827E47126865FA5F" + + "A37FC019598889C0FD93DB1B23549C" + + "EDA7E01F250827F405638DADFDCED2" + + "3C918DB4C2BA43CC7F9310181B7CCB" + + "865C0180437705F3B20DC20641B56D" + + "96C4EB66B312EFCCD38E1B8E25AD44" + + "21B1CC94C3E885FC2DEB238BB377CF" + + "041797D83166EBEA2445C7E71C7111" + + "246340B4A97036108A76FD666A6DC9" + + "7C834256D9C03505C6EC4F39D25F38" + + "5B69D564EC49AD6C7B26DDCA4ED919" + + "DC3B1DA56E6F092F72AD6E8C13F278" + + "71026D09651939A5824EB2AA7E7D1C" + + "DFA833FBE79E77CE5CBB131A95CD62" + + "6B68E7F885533E101BD5738FE6B2B1" + + "E14350E986CDDB70C74591618DEA31" + + "77151E6ACEC74F7FB44A4DE0453C3C" + + "F23C307C3D47E61DD3BDD6FDE041EB" + + "77D80C2F957CB5CA93BE246AC79E4F" + + "498F2420766452BA1256F5" + +var qString = "8ACA238243784F3571ED3FC1A259" + + "58981ADA4F187A61AA0543C2AC6230" + + "A56267" + +var gString = "BB3428DCAB4CF726195626EB6B04" + + "26FC7BB310C43A3C959AF4D30898B6" + + "F60A2649DC4DF17BA9EE1A503B2DD1" + + "373A644648946305EB924458E62140" + + "98A59A71AB43BE31F2E8B51B039EF6" + + "6B8B94BC8D60B788A738CC77220546" + + "B8C68FA345CAA946183E3D8D139C3C" + + "8F62CC2DE7B022B51022A2301780E8" + + "A869809F25EECB1FCB41583B68E5A9" + + "D019CCE5279708F65C9222FFAB88A3" + + "16A8BECDB80AB6C7EB44D8E9596BCA" + + "1DBCA9D5B57240C9EAD6C6BBBE09D1" + + "025D017B257F3B6B9DDB4155F2A93B" + + "52CCEA17158295F1AB8B3A2BEF18D6" + + "B73802C9F030054B4628CA1FF6A8BC" + + "66F5CD19772039B231FE0B4508569A" + + "ABF34367ED033E1B3CC523AB0DD0E2" + + "EAB189596DFD31EEF0A51AF7792321" + + "FDDAF0722B1970388F958069DF4646" + + "AA45C28CF2AB981E8FA8F6202A54E4" + + "21A4D2DF742EAC1479A558A09ED8E4" + + "6DB76B85132DA0E648548E86440A4F" + + "5C1DBB175B1003B1EE3119E443590B" + + "1FD3EE96E132D545CB08C9E7598BB6" + + "9A4F65B3CF985DBB1F97C294C6096C" + + "3AF318A3CE836222253C3AB72EC253" + + "5886C7F84E8828DCE79095" diff --git a/user/session.go b/user/session.go index 7815f30aff44108d986c9cfa73f6d8b26d0b5548..33affb1523c01482278c5205f3c932b1fe889084 100644 --- a/user/session.go +++ b/user/session.go @@ -16,6 +16,7 @@ import ( "gitlab.com/elixxir/client/keyStore" "gitlab.com/elixxir/crypto/cyclic" "gitlab.com/elixxir/crypto/signature" + "gitlab.com/elixxir/primitives/circuit" "gitlab.com/elixxir/primitives/id" "gitlab.com/elixxir/primitives/switchboard" "math/rand" @@ -29,10 +30,11 @@ var ErrQuery = errors.New("element not in map") // Interface for User Session operations type Session interface { GetCurrentUser() (currentUser *User) - GetKeys() []NodeKeys + GetKeys(topology *circuit.Circuit) []NodeKeys GetPrivateKey() *signature.DSAPrivateKey GetPublicKey() *signature.DSAPublicKey - GetGroup() *cyclic.Group + GetCmixGroup() *cyclic.Group + GetE2EGroup() *cyclic.Group GetLastMessageID() string SetLastMessageID(id string) StoreSession() error @@ -56,10 +58,10 @@ type NodeKeys struct { // Creates a new Session interface for registration func NewSession(store globals.Storage, - u *User, nk []NodeKeys, + u *User, nk map[id.Node]NodeKeys, publicKey *signature.DSAPublicKey, privateKey *signature.DSAPrivateKey, - grp *cyclic.Group) Session { + cmixGrp, e2eGrp *cyclic.Group) Session { // With an underlying Session data structure return Session(&SessionObj{ @@ -67,7 +69,8 @@ func NewSession(store globals.Storage, Keys: nk, PrivateKey: privateKey, PublicKey: publicKey, - Grp: grp, + CmixGrp: cmixGrp, + E2EGrp: e2eGrp, InterfaceMap: make(map[string]interface{}), KeyMaps: keyStore.NewStore(), RekeyManager: keyStore.NewRekeyManager(), @@ -127,7 +130,7 @@ func LoadSession(store globals.Storage, } // Reconstruct Key maps - session.KeyMaps.ReconstructKeys(session.Grp, UID) + session.KeyMaps.ReconstructKeys(session.E2EGrp, UID) // Create switchboard session.listeners = switchboard.NewSwitchboard() @@ -144,10 +147,11 @@ type SessionObj struct { // Currently authenticated user CurrentUser *User - Keys []NodeKeys + Keys map[id.Node]NodeKeys PrivateKey *signature.DSAPrivateKey PublicKey *signature.DSAPublicKey - Grp *cyclic.Group + CmixGrp *cyclic.Group + E2EGrp *cyclic.Group // Last received message ID. Check messages after this on the gateway. LastMessageID string @@ -186,10 +190,17 @@ func (s *SessionObj) SetLastMessageID(id string) { s.UnlockStorage() } -func (s *SessionObj) GetKeys() []NodeKeys { +func (s *SessionObj) GetKeys(topology *circuit.Circuit) []NodeKeys { s.LockStorage() defer s.UnlockStorage() - return s.Keys + + keys := make([]NodeKeys, topology.Len()) + + for i := 0; i < topology.Len(); i++ { + keys[i] = s.Keys[*topology.GetNodeAtIndex(i)] + } + + return keys } func (s *SessionObj) GetPrivateKey() *signature.DSAPrivateKey { @@ -204,10 +215,16 @@ func (s *SessionObj) GetPublicKey() *signature.DSAPublicKey { return s.PublicKey } -func (s *SessionObj) GetGroup() *cyclic.Group { +func (s *SessionObj) GetCmixGroup() *cyclic.Group { + s.LockStorage() + defer s.UnlockStorage() + return s.CmixGrp +} + +func (s *SessionObj) GetE2EGroup() *cyclic.Group { s.LockStorage() defer s.UnlockStorage() - return s.Grp + return s.E2EGrp } // Return a copy of the current user diff --git a/user/session_test.go b/user/session_test.go index a79a198748cef7627cc5d4b9e7add42140ea683e..a54f6beb2e59caa674ed7b792a3fcd980966adce 100644 --- a/user/session_test.go +++ b/user/session_test.go @@ -12,6 +12,7 @@ import ( "gitlab.com/elixxir/crypto/cyclic" "gitlab.com/elixxir/crypto/large" "gitlab.com/elixxir/crypto/signature" + "gitlab.com/elixxir/primitives/circuit" "gitlab.com/elixxir/primitives/id" "math/rand" "reflect" @@ -35,12 +36,17 @@ func TestUserSession(t *testing.T) { grp := cyclic.NewGroup(large.NewInt(107), large.NewInt(2), large.NewInt(5)) - keys := make([]NodeKeys, 1) - keys[0] = NodeKeys{ + keys := make(map[id.Node]NodeKeys) + + nodeID := id.NewNodeFromUInt(1, t) + + keys[*nodeID] = NodeKeys{ TransmissionKey: grp.NewInt(2), ReceptionKey: grp.NewInt(2), } + topology := circuit.New([]*id.Node{nodeID}) + // Storage storage := &globals.RamStorage{} @@ -48,8 +54,11 @@ func TestUserSession(t *testing.T) { params := signature.NewDSAParams(rng, signature.L1024N160) privateKey := params.PrivateKeyGen(rng) publicKey := privateKey.PublicKeyGen() + + cmixGrp, e2eGrp := getGroups() + ses := NewSession(storage, - u, keys, publicKey, privateKey, grp) + u, keys, publicKey, privateKey, cmixGrp, e2eGrp) ses.SetLastMessageID("totally unique ID") @@ -101,22 +110,22 @@ func TestUserSession(t *testing.T) { pass++ } - if ses.GetKeys() == nil { + if ses.GetKeys(topology) == nil { t.Errorf("Error: Keys not set correctly!") } else { - test += len(ses.GetKeys()) + test += len(ses.GetKeys(topology)) - for i := 0; i < len(ses.GetKeys()); i++ { + for i := 0; i < len(ses.GetKeys(topology)); i++ { if !reflect.DeepEqual(*ses.GetPublicKey(), *publicKey) { t.Errorf("Error: Public key not set correctly!") } else if !reflect.DeepEqual(*ses.GetPrivateKey(), *privateKey) { t.Errorf("Error: Private key not set correctly!") - } else if ses.GetKeys()[i].ReceptionKey.Cmp(grp. + } else if ses.GetKeys(topology)[i].ReceptionKey.Cmp(grp. NewInt(2)) != 0 { t.Errorf("Error: Reception key not set correctly!") - } else if ses.GetKeys()[i].TransmissionKey.Cmp(grp. + } else if ses.GetKeys(topology)[i].TransmissionKey.Cmp(grp. NewInt(2)) != 0 { t.Errorf("Error: Transmission key not set correctly!") } @@ -195,8 +204,9 @@ func TestGetPubKey(t *testing.T) { grp := cyclic.NewGroup(large.NewInt(107), large.NewInt(2), large.NewInt(5)) - keys := make([]NodeKeys, 1) - keys[0] = NodeKeys{ + keys := make(map[id.Node]NodeKeys) + + keys[*id.NewNodeFromUInt(1, t)] = NodeKeys{ TransmissionKey: grp.NewInt(2), ReceptionKey: grp.NewInt(2), } @@ -205,7 +215,10 @@ func TestGetPubKey(t *testing.T) { params := signature.NewDSAParams(rng, signature.L1024N160) privateKey := params.PrivateKeyGen(rng) publicKey := privateKey.PublicKeyGen() - ses := NewSession(nil, u, keys, publicKey, privateKey, grp) + + cmixGrp, e2eGrp := getGroups() + + ses := NewSession(nil, u, keys, publicKey, privateKey, cmixGrp, e2eGrp) pubKey := ses.GetPublicKey() if !reflect.DeepEqual(pubKey, publicKey) { @@ -222,8 +235,9 @@ func TestGetPrivKey(t *testing.T) { grp := cyclic.NewGroup(large.NewInt(107), large.NewInt(2), large.NewInt(5)) - keys := make([]NodeKeys, 1) - keys[0] = NodeKeys{ + keys := make(map[id.Node]NodeKeys) + + keys[*id.NewNodeFromUInt(1, t)] = NodeKeys{ TransmissionKey: grp.NewInt(2), ReceptionKey: grp.NewInt(2), } @@ -232,7 +246,10 @@ func TestGetPrivKey(t *testing.T) { params := signature.NewDSAParams(rng, signature.L1024N160) privateKey := params.PrivateKeyGen(rng) publicKey := privateKey.PublicKeyGen() - ses := NewSession(nil, u, keys, publicKey, privateKey, grp) + + cmixGrp, e2eGrp := getGroups() + + ses := NewSession(nil, u, keys, publicKey, privateKey, cmixGrp, e2eGrp) privKey := ses.GetPrivateKey() if !reflect.DeepEqual(*privKey, *privateKey) { @@ -259,4 +276,42 @@ func TestBruntString(t *testing.T) { if preBurnPointer != postBurnPointer { t.Errorf("Pointer values are not the same") } -} \ No newline at end of file +} + +func getGroups() (*cyclic.Group, *cyclic.Group) { + + cmixGrp := cyclic.NewGroup( + large.NewIntFromString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"+ + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"+ + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"+ + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"+ + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"+ + "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"+ + "83655D23DCA3AD961C62F356208552BB9ED529077096966D"+ + "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B"+ + "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"+ + "DE2BCBF6955817183995497CEA956AE515D2261898FA0510"+ + "15728E5A8AACAA68FFFFFFFFFFFFFFFF", 16), + large.NewIntFromString("2", 16), + large.NewIntFromString("2", 16)) + + e2eGrp := cyclic.NewGroup( + large.NewIntFromString("E2EE983D031DC1DB6F1A7A67DF0E9A8E5561DB8E8D49413394C049B"+ + "7A8ACCEDC298708F121951D9CF920EC5D146727AA4AE535B0922C688B55B3DD2AE"+ + "DF6C01C94764DAB937935AA83BE36E67760713AB44A6337C20E7861575E745D31F"+ + "8B9E9AD8412118C62A3E2E29DF46B0864D0C951C394A5CBBDC6ADC718DD2A3E041"+ + "023DBB5AB23EBB4742DE9C1687B5B34FA48C3521632C4A530E8FFB1BC51DADDF45"+ + "3B0B2717C2BC6669ED76B4BDD5C9FF558E88F26E5785302BEDBCA23EAC5ACE9209"+ + "6EE8A60642FB61E8F3D24990B8CB12EE448EEF78E184C7242DD161C7738F32BF29"+ + "A841698978825B4111B4BC3E1E198455095958333D776D8B2BEEED3A1A1A221A6E"+ + "37E664A64B83981C46FFDDC1A45E3D5211AAF8BFBC072768C4F50D7D7803D2D4F2"+ + "78DE8014A47323631D7E064DE81C0C6BFA43EF0E6998860F1390B5D3FEACAF1696"+ + "015CB79C3F9C2D93D961120CD0E5F12CBB687EAB045241F96789C38E89D796138E"+ + "6319BE62E35D87B1048CA28BE389B575E994DCA755471584A09EC723742DC35873"+ + "847AEF49F66E43873", 16), + large.NewIntFromString("2", 16), + large.NewIntFromString("2", 16)) + + return cmixGrp, e2eGrp + +} diff --git a/user/user.go b/user/user.go index 9b4da05e6fb569a61b0d6fa4d15b7ab545cd58d7..c48b94f5097e9480c9656906eb2b5850c64a2cb8 100644 --- a/user/user.go +++ b/user/user.go @@ -9,13 +9,14 @@ package user import ( "crypto/sha256" "gitlab.com/elixxir/client/globals" + "gitlab.com/elixxir/crypto/cyclic" "gitlab.com/elixxir/primitives/id" ) // Globally instantiated Registry -var Users = newRegistry() +var Users Registry -const NUM_DEMO_USERS = 40 +const NumDemoUsers = 40 var DemoUserNicks = []string{"David", "Payments", "UDB", "Jim", "Ben", "Steph", "Rick", "Jake", "Spencer", "Stephanie", "Mario", "Jono", "Amanda", @@ -24,6 +25,10 @@ var DemoUserNicks = []string{"David", "Payments", "UDB", "Jim", "Ben", "Steph", var DemoChannelNames = []string{"#General", "#Engineering", "#Lunch", "#Random"} +func InitUserRegistry(grp *cyclic.Group) { + Users = newRegistry(grp) +} + // Interface for User Registry operations type Registry interface { NewUser(id *id.User, nickname string) *User @@ -48,7 +53,7 @@ type UserMap struct { } // newRegistry creates a new Registry interface -func newRegistry() Registry { +func newRegistry(grp *cyclic.Group) Registry { if len(DemoChannelNames) > 10 || len(DemoUserNicks) > 30 { globals.Log.ERROR.Print("Not enough demo users have been hardcoded.") } @@ -56,12 +61,9 @@ func newRegistry() Registry { ul := make(map[string]*id.User) nk := make(map[id.User]*NodeKeys) - // Initialize group object - grp := globals.InitCrypto() - - // Deterministically create NUM_DEMO_USERS users + // Deterministically create NumDemoUsers users // TODO Replace this with real user registration/discovery - for i := uint64(1); i <= NUM_DEMO_USERS; i++ { + for i := uint64(1); i <= NumDemoUsers; i++ { currentID := id.NewUserFromUints(&[4]uint64{0, 0, 0, i}) t := new(User) k := new(NodeKeys) @@ -102,15 +104,16 @@ func newRegistry() Registry { // With an underlying UserMap data structure return Registry(&UserMap{userCollection: uc, - idCounter: uint64(NUM_DEMO_USERS), + idCounter: uint64(NumDemoUsers), userLookup: ul, keysLookup: nk}) } // Struct representing a User in the system type User struct { - User *id.User - Nick string + User *id.User + Nick string + Email string } // DeepCopy performs a deep copy of a user and returns a pointer to the new copy diff --git a/user/user_test.go b/user/user_test.go index 2bd573b94b30717656bdc31a4a7da105d64aad10..4de0d3cbf2049b3dcae955276554dd982d1027b1 100644 --- a/user/user_test.go +++ b/user/user_test.go @@ -14,45 +14,12 @@ import ( "testing" ) -// InitGroup sets up the cryptographic constants for cMix -func InitGroup() *cyclic.Group { - - base := 16 - - pString := "9DB6FB5951B66BB6FE1E140F1D2CE5502374161FD6538DF1648218642F0B5C48" + - "C8F7A41AADFA187324B87674FA1822B00F1ECF8136943D7C55757264E5A1A44F" + - "FE012E9936E00C1D3E9310B01C7D179805D3058B2A9F4BB6F9716BFE6117C6B5" + - "B3CC4D9BE341104AD4A80AD6C94E005F4B993E14F091EB51743BF33050C38DE2" + - "35567E1B34C3D6A5C0CEAA1A0F368213C3D19843D0B4B09DCB9FC72D39C8DE41" + - "F1BF14D4BB4563CA28371621CAD3324B6A2D392145BEBFAC748805236F5CA2FE" + - "92B871CD8F9C36D3292B5509CA8CAA77A2ADFC7BFD77DDA6F71125A7456FEA15" + - "3E433256A2261C6A06ED3693797E7995FAD5AABBCFBE3EDA2741E375404AE25B" - - gString := "5C7FF6B06F8F143FE8288433493E4769C4D988ACE5BE25A0E24809670716C613" + - "D7B0CEE6932F8FAA7C44D2CB24523DA53FBE4F6EC3595892D1AA58C4328A06C4" + - "6A15662E7EAA703A1DECF8BBB2D05DBE2EB956C142A338661D10461C0D135472" + - "085057F3494309FFA73C611F78B32ADBB5740C361C9F35BE90997DB2014E2EF5" + - "AA61782F52ABEB8BD6432C4DD097BC5423B285DAFB60DC364E8161F4A2A35ACA" + - "3A10B1C4D203CC76A470A33AFDCBDD92959859ABD8B56E1725252D78EAC66E71" + - "BA9AE3F1DD2487199874393CD4D832186800654760E1E34C09E4D155179F9EC0" + - "DC4473F996BDCE6EED1CABED8B6F116F7AD9CF505DF0F998E34AB27514B0FFE7" - - qString := "F2C3119374CE76C9356990B465374A17F23F9ED35089BD969F61C6DDE9998C1F" - - p := large.NewIntFromString(pString, base) - g := large.NewIntFromString(gString, base) - q := large.NewIntFromString(qString, base) - - grp := cyclic.NewGroup(p, g, q) - - return grp -} - // TestUserRegistry tests the constructors/getters/setters // surrounding the User struct and the Registry interface func TestUserRegistry(t *testing.T) { + InitUserRegistry(InitGroup()) // Test if CountUsers correctly counts the hard-coded demo users - if Users.CountUsers() != NUM_DEMO_USERS { + if Users.CountUsers() != NumDemoUsers { t.Errorf("CountUsers: Start size of userRegistry not zero!") } // Test the integration of the LookupUser, UserHash and GetUser functions @@ -138,8 +105,42 @@ func TestUserRegistry(t *testing.T) { // Doesn't actually do any testing, but can print the registration codes for // the first several users func TestPrintRegCodes(t *testing.T) { - for i := 1; i <= NUM_DEMO_USERS; i++ { + for i := 1; i <= NumDemoUsers; i++ { currentID := id.NewUserFromUint(uint64(i), t) t.Logf("%v:\t%v", i, currentID.RegistrationCode()) } } + +// InitGroup sets up the cryptographic constants for cMix +func InitGroup() *cyclic.Group { + + base := 16 + + pString := "9DB6FB5951B66BB6FE1E140F1D2CE5502374161FD6538DF1648218642F0B5C48" + + "C8F7A41AADFA187324B87674FA1822B00F1ECF8136943D7C55757264E5A1A44F" + + "FE012E9936E00C1D3E9310B01C7D179805D3058B2A9F4BB6F9716BFE6117C6B5" + + "B3CC4D9BE341104AD4A80AD6C94E005F4B993E14F091EB51743BF33050C38DE2" + + "35567E1B34C3D6A5C0CEAA1A0F368213C3D19843D0B4B09DCB9FC72D39C8DE41" + + "F1BF14D4BB4563CA28371621CAD3324B6A2D392145BEBFAC748805236F5CA2FE" + + "92B871CD8F9C36D3292B5509CA8CAA77A2ADFC7BFD77DDA6F71125A7456FEA15" + + "3E433256A2261C6A06ED3693797E7995FAD5AABBCFBE3EDA2741E375404AE25B" + + gString := "5C7FF6B06F8F143FE8288433493E4769C4D988ACE5BE25A0E24809670716C613" + + "D7B0CEE6932F8FAA7C44D2CB24523DA53FBE4F6EC3595892D1AA58C4328A06C4" + + "6A15662E7EAA703A1DECF8BBB2D05DBE2EB956C142A338661D10461C0D135472" + + "085057F3494309FFA73C611F78B32ADBB5740C361C9F35BE90997DB2014E2EF5" + + "AA61782F52ABEB8BD6432C4DD097BC5423B285DAFB60DC364E8161F4A2A35ACA" + + "3A10B1C4D203CC76A470A33AFDCBDD92959859ABD8B56E1725252D78EAC66E71" + + "BA9AE3F1DD2487199874393CD4D832186800654760E1E34C09E4D155179F9EC0" + + "DC4473F996BDCE6EED1CABED8B6F116F7AD9CF505DF0F998E34AB27514B0FFE7" + + qString := "F2C3119374CE76C9356990B465374A17F23F9ED35089BD969F61C6DDE9998C1F" + + p := large.NewIntFromString(pString, base) + g := large.NewIntFromString(gString, base) + q := large.NewIntFromString(qString, base) + + grp := cyclic.NewGroup(p, g, q) + + return grp +}