diff --git a/user/regState.go b/user/regState.go deleted file mode 100644 index 62c88b2b59682c7bc6ea208efb232bd13c096530..0000000000000000000000000000000000000000 --- a/user/regState.go +++ /dev/null @@ -1,8 +0,0 @@ -package user - -const ( - NotStarted uint32 = iota // Set on session creation - KeyGenComplete = 1000 // Set upon generation of session information - PermissioningComplete = 2000 // Set upon completion of RegisterWithPermissioning - UDBComplete = 3000 // Set upon completion of RegisterWithUdb -) diff --git a/user/session.go b/user/session.go deleted file mode 100644 index 92cac7d0979e8a3912b27a0112cac6e4fb73416e..0000000000000000000000000000000000000000 --- a/user/session.go +++ /dev/null @@ -1,445 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright © 2020 Privategrity Corporation / -// / -// All rights reserved. / -//////////////////////////////////////////////////////////////////////////////// - -package user - -import ( - "bytes" - "crypto/aes" - "crypto/cipher" - "crypto/rand" - "crypto/sha256" - "encoding/gob" - "fmt" - "github.com/pkg/errors" - "gitlab.com/elixxir/client/globals" - "gitlab.com/elixxir/client/keyStore" - "gitlab.com/elixxir/crypto/cyclic" - "gitlab.com/elixxir/primitives/switchboard" - "gitlab.com/xx_network/primitives/id" - "io" - "sync" - "time" -) - -// Errors -var ErrQuery = errors.New("element not in map") - -// Interface for User Session operations -type Session interface { - StoreSession() error - Immolate() error - GetKeyStore() *keyStore.KeyStore - GetRekeyManager() *keyStore.RekeyManager - LockStorage() - UnlockStorage() - GetSessionData() ([]byte, error) - StorageIsEmpty() bool - GetSessionLocation() uint8 - LoadEncryptedSession(store globals.Storage) ([]byte, error) - SetE2EGrp(g *cyclic.Group) - SetUser(u *id.ID) -} - -type NodeKeys struct { - TransmissionKey *cyclic.Int - ReceptionKey *cyclic.Int -} - -// Creates a new Session interface for registration -func NewSession(store globals.Storage, - password string) Session { - // With an underlying Session data structure - return Session(&SessionObj{ - KeyMaps: keyStore.NewStore(), - RekeyManager: keyStore.NewRekeyManager(), - store: store, - password: password, - storageLocation: globals.LocationA, - }) -} - -//LoadSession loads the encrypted session from the storage location and processes it -// Returns a session object on success -func LoadSession(store globals.Storage, password string) (Session, error) { - if store == nil { - err := errors.New("LoadSession: Local Storage not available") - return nil, err - } - - wrappedSession, loadLocation, err := processSession(store, password) - if err != nil { - return nil, err - } - - for wrappedSession.Version != SessionVersion { - switch wrappedSession.Version { - case 1: - globals.Log.INFO.Println("Converting session file from V1 to V2") - wrappedSession, err = ConvertSessionV1toV2(wrappedSession) - default: - } - if err != nil { - return nil, err - } - } - - //extract the session from the wrapper - var sessionBytes bytes.Buffer - - sessionBytes.Write(wrappedSession.Session) - dec := gob.NewDecoder(&sessionBytes) - - session := SessionObj{} - - err = dec.Decode(&session) - if err != nil { - return nil, errors.Wrap(err, "Unable to decode session") - } - - session.storageLocation = loadLocation - - // Reconstruct Key maps - session.KeyMaps.ReconstructKeys(session.E2EGrp, - session.CurrentUser) - // Create switchboard - //session.listeners = switchboard.New() - // Create quit channel for reception runner - //session.quitReceptionRunner = make(chan struct{}) - - // Set storage pointer - session.store = store - session.password = password - - return &session, nil -} - -//processSession: gets the loadLocation and decrypted wrappedSession -func processSession(store globals.Storage, password string) (*SessionStorageWrapper, uint8, error) { - var wrappedSession *SessionStorageWrapper - loadLocation := globals.NoSave - //load sessions - wrappedSessionA, errA := processSessionWrapper(store.LoadA(), password) - wrappedSessionB, errB := processSessionWrapper(store.LoadB(), password) - - //figure out which session to use of the two locations - if errA != nil && errB != nil { - return nil, globals.NoSave, errors.Errorf("Loading both sessions errored: \n "+ - "SESSION A ERR: %s \n SESSION B ERR: %s", errA, errB) - } else if errA == nil && errB != nil { - loadLocation = globals.LocationA - wrappedSession = wrappedSessionA - } else if errA != nil && errB == nil { - loadLocation = globals.LocationB - wrappedSession = wrappedSessionB - } else { - if wrappedSessionA.Timestamp.After(wrappedSessionB.Timestamp) { - loadLocation = globals.LocationA - wrappedSession = wrappedSessionA - } else { - loadLocation = globals.LocationB - wrappedSession = wrappedSessionB - } - } - return wrappedSession, loadLocation, nil - -} - -//processSessionWrapper acts as a helper function for processSession -func processSessionWrapper(sessionGob []byte, password string) (*SessionStorageWrapper, error) { - - if sessionGob == nil || len(sessionGob) < 12 { - return nil, errors.New("No session file passed") - } - - decryptedSessionGob, err := decrypt(sessionGob, password) - - if err != nil { - return nil, errors.Wrap(err, "Could not decode the "+ - "session wrapper") - } - - var sessionBytes bytes.Buffer - - sessionBytes.Write(decryptedSessionGob) - dec := gob.NewDecoder(&sessionBytes) - - wrappedSession := SessionStorageWrapper{} - - err = dec.Decode(&wrappedSession) - if err != nil { - return nil, errors.Wrap(err, "Unable to decode session wrapper") - } - - return &wrappedSession, nil -} - -// Struct holding relevant session data -// When adding to this structure, ALWAYS ALWAYS -// consider if you want the data to be in the session file -type SessionObj struct { - // E2E KeyStore - KeyMaps *keyStore.KeyStore - - // do not touch until removing session, neeeded for keystores - E2EGrp *cyclic.Group - CurrentUser *id.ID - - // Rekey Manager - RekeyManager *keyStore.RekeyManager - - // Non exported fields (not GOB encoded/decoded) - // Local pointer to storage of this session - store globals.Storage - - lock sync.Mutex - - // The password used to encrypt this session when saved - password string - - storageLocation uint8 -} - -//WriteToSession: Writes to the location where session is being stored the arbitrary replacement string -// The replacement string is meant to be the output of a loadEncryptedSession -func WriteToSession(replacement []byte, store globals.Storage) error { - //Write to both - err := store.SaveA(replacement) - if err != nil { - return errors.Errorf("Failed to save to session A: %v", err) - } - err = store.SaveB(replacement) - if err != nil { - return errors.Errorf("Failed to save to session B: %v", err) - } - - return nil -} - -func (s *SessionObj) SetE2EGrp(g *cyclic.Group) { - s.E2EGrp = g -} - -func (s *SessionObj) SetUser(u *id.ID) { - s.CurrentUser = u -} - -//LoadEncryptedSession: gets the encrypted session file from storage -// Returns it as a base64 encoded string -func (s *SessionObj) LoadEncryptedSession(store globals.Storage) ([]byte, error) { - sessionData, _, err := processSession(store, s.password) - if err != nil { - return make([]byte, 0), err - } - encryptedSession := encrypt(sessionData.Session, s.password) - return encryptedSession, nil -} - -type SearchedUserRecord struct { - Id id.ID - Pk []byte -} - -func (s *SessionObj) StorageIsEmpty() bool { - s.LockStorage() - defer s.UnlockStorage() - return s.store.IsEmpty() -} - -type SessionStorageWrapper struct { - Version uint32 - Timestamp time.Time - Session []byte -} - -func (s *SessionObj) storeSession() error { - - if s.store == nil { - err := errors.New("StoreSession: Local Storage not available") - return err - } - - sessionData, err := s.getSessionData() - - encryptedSession := encrypt(sessionData, s.password) - if s.storageLocation == globals.LocationA { - err = s.store.SaveB(encryptedSession) - if err != nil { - err = errors.New(fmt.Sprintf("StoreSession: Could not save the encoded user"+ - " session in location B: %s", err.Error())) - } else { - s.storageLocation = globals.LocationB - } - } else if s.storageLocation == globals.LocationB { - err = s.store.SaveA(encryptedSession) - if err != nil { - err = errors.New(fmt.Sprintf("StoreSession: Could not save the encoded user"+ - " session in location A: %s", err.Error())) - } else { - s.storageLocation = globals.LocationA - } - } else { - err = errors.New("Could not store because no location is " + - "selected") - } - - return err - -} - -func (s *SessionObj) StoreSession() error { - s.LockStorage() - err := s.storeSession() - s.UnlockStorage() - return err -} - -// Immolate scrubs all cryptographic data from ram and logs out -// the ram overwriting can be improved -func (s *SessionObj) Immolate() error { - s.LockStorage() - if s == nil { - err := errors.New("immolate: Cannot immolate that which has no life") - return err - } - - globals.Log.WARN.Println("Immolate not implemented, did nothing") - - s.UnlockStorage() - - return nil -} - -func (s *SessionObj) GetSessionData() ([]byte, error) { - s.LockStorage() - defer s.UnlockStorage() - return s.getSessionData() -} - -func (s *SessionObj) GetKeyStore() *keyStore.KeyStore { - return s.KeyMaps -} - -func (s *SessionObj) GetRekeyManager() *keyStore.RekeyManager { - return s.RekeyManager -} - -func (s *SessionObj) GetSwitchboard() *switchboard.Switchboard { - return nil //s.listeners -} - -func (s *SessionObj) GetQuitChan() chan struct{} { - return nil //s.quitReceptionRunner -} - -func (s *SessionObj) getSessionData() ([]byte, error) { - var sessionBuffer bytes.Buffer - - enc := gob.NewEncoder(&sessionBuffer) - - err := enc.Encode(s) - - if err != nil { - err = errors.New(fmt.Sprintf("StoreSession: Could not encode user"+ - " session: %s", err.Error())) - return nil, err - } - - sw := SessionStorageWrapper{ - Version: SessionVersion, - Session: sessionBuffer.Bytes(), - Timestamp: time.Now(), - } - - var wrapperBuffer bytes.Buffer - - enc = gob.NewEncoder(&wrapperBuffer) - - err = enc.Encode(&sw) - - if err != nil { - err = errors.New(fmt.Sprintf("StoreSession: Could not encode user"+ - " session wrapper: %s", err.Error())) - return nil, err - } - - return wrapperBuffer.Bytes(), nil -} - -// Locking a mutex that belongs to the session object makes the locking -// independent of the implementation of the storage, which is probably good. -func (s *SessionObj) LockStorage() { - s.lock.Lock() -} - -func (s *SessionObj) UnlockStorage() { - s.lock.Unlock() -} - -func clearCyclicInt(c *cyclic.Int) { - c.Reset() - //c.Set(cyclic.NewMaxInt()) - //c.SetInt64(0) -} - -// FIXME Shouldn't we just be putting pseudorandom bytes in to obscure the mem? -func burntString(length int) string { - b := make([]byte, length) - - rand.Read(b) - - return string(b) -} - -// Internal crypto helper functions below - -func hashPassword(password string) []byte { - hasher := sha256.New() - hasher.Write([]byte(password)) - return hasher.Sum(nil) -} - -func initAESGCM(password string) cipher.AEAD { - aesCipher, _ := aes.NewCipher(hashPassword(password)) - // NOTE: We use gcm as it's authenticated and simplest to set up - aesGCM, err := cipher.NewGCM(aesCipher) - if err != nil { - globals.Log.FATAL.Panicf("Could not init AES GCM mode: %s", - err.Error()) - } - return aesGCM -} - -func encrypt(data []byte, password string) []byte { - aesGCM := initAESGCM(password) - nonce := make([]byte, aesGCM.NonceSize()) - if _, err := io.ReadFull(rand.Reader, nonce); err != nil { - globals.Log.FATAL.Panicf("Could not generate nonce: %s", - err.Error()) - } - ciphertext := aesGCM.Seal(nonce, nonce, data, nil) - return ciphertext -} - -func decrypt(data []byte, password string) ([]byte, error) { - aesGCM := initAESGCM(password) - nonceLen := aesGCM.NonceSize() - nonce, ciphertext := data[:nonceLen], data[nonceLen:] - plaintext, err := aesGCM.Open(nil, nonce, ciphertext, nil) - if err != nil { - return nil, errors.Wrap(err, "Cannot decrypt with password!") - } - return plaintext, nil -} - -func (s *SessionObj) GetSessionLocation() uint8 { - if s.storageLocation == globals.LocationA { - return globals.LocationA - } else if s.storageLocation == globals.LocationB { - return globals.LocationB - } - return globals.NoSave -} diff --git a/user/sessionVersion.go b/user/sessionVersion.go deleted file mode 100644 index 79d18a4790e83d0d65337bc09bc0f077976aae38..0000000000000000000000000000000000000000 --- a/user/sessionVersion.go +++ /dev/null @@ -1,3 +0,0 @@ -package user - -const SessionVersion = 2 diff --git a/user/session_test.go b/user/session_test.go deleted file mode 100644 index b45c59fc895ff58a0d947b201bf076bc06db2143..0000000000000000000000000000000000000000 --- a/user/session_test.go +++ /dev/null @@ -1,146 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright © 2019 Privategrity Corporation / -// / -// All rights reserved. / -//////////////////////////////////////////////////////////////////////////////// - -package user - -import ( - "crypto/sha256" - "gitlab.com/elixxir/client/globals" - "gitlab.com/elixxir/crypto/cyclic" - "gitlab.com/elixxir/crypto/large" - "math/rand" - "testing" -) - -// TestUserRegistry tests the constructors/getters/setters -// surrounding the User struct and the Registry interface -func TestUserSession(t *testing.T) { - - pass := 0 - - // Storage - storage := &globals.RamStorage{} - - rng := rand.New(rand.NewSource(42)) - - ses := NewSession(storage, "password") - - regSignature := make([]byte, 768) - rng.Read(regSignature) - - err := ses.StoreSession() - - if err != nil { - t.Errorf("Session not stored correctly: %s", err.Error()) - } - - ses.Immolate() - - //TODO: write test which validates the immolation - - ses, err = LoadSession(storage, "password") - - if err != nil { - t.Errorf("Unable to login with valid user: %v", - err.Error()) - } else { - pass++ - } - - //Logout - ses.Immolate() - - // Error tests - - // Test nil LocalStorage - - _, err = LoadSession(nil, "password") - - if err == nil { - t.Errorf("Error did not catch a nil LocalStorage") - } - - // Test invalid / corrupted LocalStorage - h := sha256.New() - h.Write([]byte(string(20000))) - randBytes := h.Sum(nil) - storage.SaveA(randBytes) - storage.SaveB(randBytes) - - defer func() { - recover() - }() - - _, err = LoadSession(storage, "password") - if err == nil { - t.Errorf("LoadSession should error on bad decrypt!") - } -} - -//Tests the isEmpty function before and after StoreSession -func TestSessionObj_StorageIsEmpty(t *testing.T) { - // Storage - storage := &globals.RamStorage{} - - //Keys - rng := rand.New(rand.NewSource(42)) - - ses := NewSession(storage, "password") - - regSignature := make([]byte, 768) - rng.Read(regSignature) - - //Test that the session is empty before the StoreSession call - if !ses.StorageIsEmpty() { - t.Errorf("session should be empty before the StoreSession call") - } - err := ses.StoreSession() - if err != nil { - t.Errorf("Failed to store session: %v", err) - } - - //Test that the session is not empty after the StoreSession call - if ses.StorageIsEmpty() { - t.Errorf("session should not be empty after a StoreSession call") - } - -} - -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)) - - e2eGrp := cyclic.NewGroup( - large.NewIntFromString("E2EE983D031DC1DB6F1A7A67DF0E9A8E5561DB8E8D49413394C049B"+ - "7A8ACCEDC298708F121951D9CF920EC5D146727AA4AE535B0922C688B55B3DD2AE"+ - "DF6C01C94764DAB937935AA83BE36E67760713AB44A6337C20E7861575E745D31F"+ - "8B9E9AD8412118C62A3E2E29DF46B0864D0C951C394A5CBBDC6ADC718DD2A3E041"+ - "023DBB5AB23EBB4742DE9C1687B5B34FA48C3521632C4A530E8FFB1BC51DADDF45"+ - "3B0B2717C2BC6669ED76B4BDD5C9FF558E88F26E5785302BEDBCA23EAC5ACE9209"+ - "6EE8A60642FB61E8F3D24990B8CB12EE448EEF78E184C7242DD161C7738F32BF29"+ - "A841698978825B4111B4BC3E1E198455095958333D776D8B2BEEED3A1A1A221A6E"+ - "37E664A64B83981C46FFDDC1A45E3D5211AAF8BFBC072768C4F50D7D7803D2D4F2"+ - "78DE8014A47323631D7E064DE81C0C6BFA43EF0E6998860F1390B5D3FEACAF1696"+ - "015CB79C3F9C2D93D961120CD0E5F12CBB687EAB045241F96789C38E89D796138E"+ - "6319BE62E35D87B1048CA28BE389B575E994DCA755471584A09EC723742DC35873"+ - "847AEF49F66E43873", 16), - large.NewIntFromString("2", 16)) - - return cmixGrp, e2eGrp - -} diff --git a/user/sessionv1.go b/user/sessionv1.go deleted file mode 100644 index c50da2670c7cb834276bc7e56d25ff5dc19f5e60..0000000000000000000000000000000000000000 --- a/user/sessionv1.go +++ /dev/null @@ -1,133 +0,0 @@ -package user - -import ( - "bytes" - "encoding/gob" - "fmt" - "github.com/pkg/errors" - "gitlab.com/elixxir/client/globals" - "gitlab.com/elixxir/client/keyStore" - "gitlab.com/elixxir/crypto/cyclic" - "gitlab.com/elixxir/primitives/format" - "gitlab.com/elixxir/primitives/switchboard" - "gitlab.com/xx_network/crypto/signature/rsa" - "gitlab.com/xx_network/primitives/id" - "sync" -) - -// Struct holding relevant session data -type SessionObjV1 struct { - // Currently authenticated user - CurrentUser *UserV1 - - Keys map[id.ID]NodeKeys - RSAPrivateKey *rsa.PrivateKey - RSAPublicKey *rsa.PublicKey - CMIXDHPrivateKey *cyclic.Int - CMIXDHPublicKey *cyclic.Int - E2EDHPrivateKey *cyclic.Int - E2EDHPublicKey *cyclic.Int - CmixGrp *cyclic.Group - E2EGrp *cyclic.Group - Salt []byte - - // Last received message ID. Check messages after this on the gateway. - LastMessageID string - - //Interface map for random data storage - InterfaceMap map[string]interface{} - - // E2E KeyStore - KeyMaps *keyStore.KeyStore - - // Rekey Manager - RekeyManager *keyStore.RekeyManager - - // Non exported fields (not GOB encoded/decoded) - // Local pointer to storage of this session - store globals.Storage - - // Switchboard - listeners *switchboard.Switchboard - - // Quit channel for message reception runner - quitReceptionRunner chan struct{} - - lock sync.Mutex - - // The password used to encrypt this session when saved - password string - - //The validation signature provided by permissioning - regValidationSignature []byte - - // Buffer of messages that cannot be decrypted - garbledMessages []*format.Message - - RegState *uint32 - - storageLocation uint8 - - ContactsByValue map[string]SearchedUserRecord -} - -// Struct representing a User in the system -type UserV1 struct { - User *id.ID - Nick string - Email string -} - -// ConvertSessionV1toV2 converts the session object from version 1 to version 2. -// This conversion includes: -// 1. Changing the RegState values to the new integer values (1 to 2000, and 2 -// to 3000). -func ConvertSessionV1toV2(inputWrappedSession *SessionStorageWrapper) (*SessionStorageWrapper, error) { - //extract teh session from the wrapper - var sessionBytes bytes.Buffer - - //get the old session object - sessionBytes.Write(inputWrappedSession.Session) - dec := gob.NewDecoder(&sessionBytes) - - sessionV1 := SessionObjV1{} - - err := dec.Decode(&sessionV1) - if err != nil { - return nil, errors.Wrap(err, "Unable to decode session") - } - - sessionV2 := SessionObj{} - - // Convert RegState to new values - if *sessionV1.RegState == 1 { - *sessionV1.RegState = 2000 - } else if *sessionV1.RegState == 2 { - *sessionV1.RegState = 3000 - } - - sessionV2.KeyMaps = sessionV1.KeyMaps - sessionV2.RekeyManager = sessionV1.RekeyManager - - //re encode the session - var sessionBuffer bytes.Buffer - - enc := gob.NewEncoder(&sessionBuffer) - - err = enc.Encode(sessionV2) - - if err != nil { - err = errors.New(fmt.Sprintf("ConvertSessionV1toV2: Could not "+ - " store session v2: %s", err.Error())) - return nil, err - } - - //build the session wrapper - ssw := SessionStorageWrapper{ - Version: 2, - Timestamp: inputWrappedSession.Timestamp, - Session: sessionBuffer.Bytes(), - } - - return &ssw, nil -}