diff --git a/api/client.go b/api/client.go
index 2e5934be9b4db2784476bd7a8d87a44b2132edcf..86cb1775ceb94108ff86385a0ca0e601a4588b85 100644
--- a/api/client.go
+++ b/api/client.go
@@ -14,10 +14,16 @@ import (
 	"github.com/pkg/errors"
 	jww "github.com/spf13/jwalterweatherman"
 	"gitlab.com/elixxir/client/context"
+	"gitlab.com/elixxir/client/context/params"
 	"gitlab.com/elixxir/client/context/stoppable"
 	"gitlab.com/elixxir/client/context/switchboard"
+	"gitlab.com/elixxir/client/network"
 	"gitlab.com/elixxir/client/storage"
 	pb "gitlab.com/elixxir/comms/mixmessages"
+	"gitlab.com/elixxir/crypto/csprng"
+	"gitlab.com/elixxir/crypto/cyclic"
+	"gitlab.com/elixxir/crypto/fastRNG"
+	"gitlab.com/elixxir/crypto/large"
 	"gitlab.com/xx_network/crypto/signature/rsa"
 	"gitlab.com/xx_network/crypto/tls"
 	"gitlab.com/xx_network/primitives/id"
@@ -36,32 +42,68 @@ type Client struct {
 // with the network. Note that this does not register a username/identity, but
 // merely creates a new cryptographic identity for adding such information
 // at a later date.
-func NewClient(network, storageDir string, password []byte) (*Client, error) {
+func NewClient(netJSON, storageDir string, password []byte) (*Client, error) {
 	if clientStorageExists(storageDir) {
 		return nil, errors.Errorf("client already exists at %s",
 			storageDir)
 	}
 
+	// Use fastRNG for RNG ops (AES fortuna based RNG using system RNG)
+	rngStreamGen := fastRNG.NewStreamGenerator(12, 3, csprng.NewSystemRNG)
+	rngStream := rngStreamGen.GetStream()
+
 	// Parse the NDF
-	//ndf, err := parseNDF(network)
-	//if err != nil {
-	//	return nil, err
-	//}
+	ndf, err := parseNDF(netJSON)
+	if err != nil {
+		return nil, err
+	}
+	cmixGrp, e2eGrp := decodeGroups(ndf)
+
+	user := createNewUser(rngStream, cmixGrp, e2eGrp)
 
 	// Create Storage
+	passwordStr := string(password)
+	storageSess, err := storage.New(storageDir, passwordStr,
+		user.UID, user.Salt, user.RSAKey, user.IsPrecanned,
+		user.CMixKey, user.E2EKey, cmixGrp, e2eGrp, rngStreamGen)
+	if err != nil {
+		return nil, err
+	}
 
-	// Create network, context, switchboard
+	// Save NDF to be used in the future
+	err = storageSess.SetNDF(netJSON)
+	if err != nil {
+		return nil, err
+	}
 
-	// Generate Keys
+	// Set up a new context
+	ctx := &context.Context{
+		Session:     storageSess,
+		Switchboard: switchboard.New(),
+		Rng:         rngStreamGen,
+		Manager:     nil,
+	}
 
-	// Register with network
+	// Initialize network and link it to context
+	netman, err := network.NewManager(ctx, params.GetDefaultNetwork(), ndf)
+	if err != nil {
+		return nil, err
+	}
+	ctx.Manager = netman
 
 	client := &Client{
-		storage:     nil,
-		ctx:         nil,
-		switchboard: nil,
-		network:     nil,
+		storage:     storageSess,
+		ctx:         ctx,
+		switchboard: ctx.Switchboard,
+		network:     netman,
+	}
+
+	// Now register with network, note that regCode is no longer required
+	err = client.RegisterWithPermissioning("")
+	if err != nil {
+		return nil, err
 	}
+
 	return client, nil
 }
 
@@ -72,16 +114,47 @@ func LoadClient(storageDir string, password []byte) (*Client, error) {
 			storageDir)
 	}
 
+	// Use fastRNG for RNG ops (AES fortuna based RNG using system RNG)
+	rngStreamGen := fastRNG.NewStreamGenerator(12, 3, csprng.NewSystemRNG)
+
 	// Load Storage
+	passwordStr := string(password)
+	storageSess, err := storage.Load(storageDir, passwordStr, rngStreamGen)
+	if err != nil {
+		return nil, err
+	}
+
+	netJSON, err := storageSess.GetNDF()
+	if err != nil {
+		return nil, err
+	}
+	ndf, err := parseNDF(string(netJSON))
+	if err != nil {
+		return nil, err
+	}
 
-	// Load and create network, context, switchboard
+	// Set up a new context
+	ctx := &context.Context{
+		Session:     storageSess,
+		Switchboard: switchboard.New(),
+		Rng:         rngStreamGen,
+		Manager:     nil,
+	}
+
+	// Initialize network and link it to context
+	netman, err := network.NewManager(ctx, params.GetDefaultNetwork(), ndf)
+	if err != nil {
+		return nil, err
+	}
+	ctx.Manager = netman
 
 	client := &Client{
-		storage:     nil,
-		ctx:         nil,
-		switchboard: nil,
-		network:     nil,
+		storage:     storageSess,
+		ctx:         ctx,
+		switchboard: ctx.Switchboard,
+		network:     netman,
 	}
+
 	return client, nil
 }
 
@@ -372,3 +445,19 @@ func parseNDF(ndfString string) (*ndf.NetworkDefinition, error) {
 
 	return ndf, nil
 }
+
+// decodeGroups returns the e2e and cmix groups from the ndf
+func decodeGroups(ndf *ndf.NetworkDefinition) (cmixGrp, e2eGrp *cyclic.Group) {
+	largeIntBits := 16
+
+	//Generate the cmix group
+	cmixGrp = cyclic.NewGroup(
+		large.NewIntFromString(ndf.CMIX.Prime, largeIntBits),
+		large.NewIntFromString(ndf.CMIX.Generator, largeIntBits))
+	//Generate the e2e group
+	e2eGrp = cyclic.NewGroup(
+		large.NewIntFromString(ndf.E2E.Prime, largeIntBits),
+		large.NewIntFromString(ndf.E2E.Generator, largeIntBits))
+
+	return cmixGrp, e2eGrp
+}
diff --git a/api/user.go b/api/user.go
new file mode 100644
index 0000000000000000000000000000000000000000..bc190327736e958984ce9ce2bf2ef383730d5bfb
--- /dev/null
+++ b/api/user.go
@@ -0,0 +1,82 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2019 Privategrity Corporation                                   /
+//                                                                             /
+// All rights reserved.                                                        /
+////////////////////////////////////////////////////////////////////////////////
+
+package api
+
+import (
+	jww "github.com/spf13/jwalterweatherman"
+	"gitlab.com/elixxir/crypto/csprng"
+	"gitlab.com/elixxir/crypto/cyclic"
+	"gitlab.com/elixxir/crypto/xx"
+	"gitlab.com/xx_network/crypto/signature/rsa"
+	"gitlab.com/xx_network/primitives/id"
+)
+
+type user struct {
+	UID         *id.ID
+	Salt        []byte
+	RSAKey      *rsa.PrivateKey
+	CMixKey     *cyclic.Int
+	E2EKey      *cyclic.Int
+	IsPrecanned bool
+}
+
+const (
+	// SaltSize size of user salts
+	SaltSize = 32
+)
+
+// createNewUser generates an identity for cMix
+func createNewUser(rng csprng.Source, cmix, e2e *cyclic.Group) user {
+	// RSA Keygen (4096 bit defaults)
+	rsaKey, err := rsa.GenerateKey(rng, rsa.DefaultRSABitLen)
+	if err != nil {
+		jww.FATAL.Panicf(err.Error())
+	}
+
+	// CMIX Keygen
+	// FIXME: Why 256 bits? -- this is spec but not explained, it has
+	// to do with optimizing operations on one side and still preserves
+	// decent security -- cite this.
+	cMixKeyBytes, err := csprng.GenerateInGroup(cmix.GetPBytes(), 256, rng)
+	if err != nil {
+		jww.FATAL.Panicf(err.Error())
+	}
+
+	// DH Keygen
+	// FIXME: Why 256 bits? -- this is spec but not explained, it has
+	// to do with optimizing operations on one side and still preserves
+	// decent security -- cite this. Why valid for BOTH e2e and cmix?
+	e2eKeyBytes, err := csprng.GenerateInGroup(e2e.GetPBytes(), 256, rng)
+	if err != nil {
+		jww.FATAL.Panicf(err.Error())
+	}
+
+	// Salt, UID, etc gen
+	salt := make([]byte, SaltSize)
+	n, err := csprng.NewSystemRNG().Read(salt)
+	if err != nil {
+		jww.FATAL.Panicf(err.Error())
+	}
+	if n != SaltSize {
+		jww.FATAL.Panicf("salt size too small: %d", n)
+	}
+	userID, err := xx.NewID(rsaKey.GetPublic(), salt, id.User)
+	if err != nil {
+		jww.FATAL.Panicf(err.Error())
+	}
+
+	return user{
+		UID:         userID,
+		Salt:        salt,
+		RSAKey:      rsaKey,
+		CMixKey:     cmix.NewIntFromBytes(cMixKeyBytes),
+		E2EKey:      e2e.NewIntFromBytes(e2eKeyBytes),
+		IsPrecanned: false,
+	}
+}
+
+// TODO: Add precanned user code structures here.
diff --git a/go.sum b/go.sum
index 9a85c6d4f3ce3fe8b73412c9612227a9c57b1ad1..608d540ab0a7e9be922cde1dfd79a58e1ef4934b 100644
--- a/go.sum
+++ b/go.sum
@@ -254,6 +254,7 @@ gitlab.com/xx_network/comms v0.0.0-20200910173932-bd179f5fee4f h1:ExTCqEoro7VuS1
 gitlab.com/xx_network/comms v0.0.0-20200910173932-bd179f5fee4f/go.mod h1:+jEkDQKoK51WLl2ZZuxfAZkz6YFbUQ+oZfH0dt2wIF0=
 gitlab.com/xx_network/comms v0.0.0-20200915154643-d533291041b7 h1:lPx1wpkjNpwLaZ0pyd7/iCcdITjT+eCMmb0HXCVoIkk=
 gitlab.com/xx_network/comms v0.0.0-20200915154643-d533291041b7/go.mod h1:+jEkDQKoK51WLl2ZZuxfAZkz6YFbUQ+oZfH0dt2wIF0=
+gitlab.com/xx_network/crypto v0.0.0-20200805231039-4aa0e350ed0a h1:BlfWGPokU6yU69O+PGGsgc5iA/P9gERbHzYUvjoYbgM=
 gitlab.com/xx_network/crypto v0.0.0-20200806202113-978fa1984bbf/go.mod h1:i0df/q6dDCBiscgD51fMoS2U2TBrm6LcyN822JmB5Tw=
 gitlab.com/xx_network/crypto v0.0.0-20200806235322-ede3c15881ce h1:gypNBUl2guESEv4MDgH+miwYqR4jPoWM8dLt2Zs5gIs=
 gitlab.com/xx_network/crypto v0.0.0-20200806235322-ede3c15881ce/go.mod h1:i0df/q6dDCBiscgD51fMoS2U2TBrm6LcyN822JmB5Tw=
diff --git a/storage/session.go b/storage/session.go
index 3a9c8f51d77e39e5b825d1b3637b1e9869c76d41..5e093fff4052b995408417d1b78c8d22a1f741e4 100644
--- a/storage/session.go
+++ b/storage/session.go
@@ -19,13 +19,14 @@ import (
 	"gitlab.com/elixxir/client/storage/utility"
 	"gitlab.com/elixxir/client/storage/versioned"
 	"gitlab.com/elixxir/crypto/cyclic"
-	"gitlab.com/elixxir/crypto/large"
 	"gitlab.com/elixxir/crypto/fastRNG"
+	"gitlab.com/elixxir/crypto/large"
 	"gitlab.com/elixxir/ekv"
 	"gitlab.com/xx_network/crypto/signature/rsa"
 	"gitlab.com/xx_network/primitives/id"
 	"sync"
 	"testing"
+	"time"
 )
 
 // Number of rounds to store in the CheckedRound buffer
@@ -213,6 +214,25 @@ func (s *Session) Partition() *partition.Store {
 	return s.partition
 }
 
+// SetNDF stores a network definition json file
+func (s *Session) SetNDF(ndfJSON string) error {
+	return s.Set("NetworkDefinition",
+		&versioned.Object{
+			Version:   uint64(1),
+			Data:      []byte(ndfJSON),
+			Timestamp: time.Now(),
+		})
+}
+
+// Returns the stored network definition json file
+func (s *Session) GetNDF() (string, error) {
+	ndf, err := s.Get("NetworkDefinition")
+	if err != nil {
+		return "", err
+	}
+	return string(ndf.Data), nil
+}
+
 // Get an object from the session
 func (s *Session) Get(key string) (*versioned.Object, error) {
 	return s.kv.Get(key)