Skip to content
Snippets Groups Projects
Commit 18f59545 authored by Josh Brooks's avatar Josh Brooks
Browse files

Implement mnemonic in client

parent dc16e1e9
No related branches found
No related tags found
2 merge requests!23Release,!19Implement mnemonic in client
///////////////////////////////////////////////////////////////////////////////
// Copyright © 2020 xx network SEZC //
// //
// Use of this source code is governed by a license that can be found in the //
// LICENSE file //
///////////////////////////////////////////////////////////////////////////////
package api
import (
"github.com/pkg/errors"
"gitlab.com/elixxir/crypto/fastRNG"
"gitlab.com/xx_network/crypto/csprng"
xxMnemonic "gitlab.com/xx_network/crypto/mnemonic"
"golang.org/x/crypto/salsa20"
)
const (
nonceSize = 8
)
// StoreSecretWithMnemonic creates a mnemonic and uses it to encrypt the secret.
// This encrypted data saved in storage.
func (c *Client) StoreSecretWithMnemonic(secret []byte) (string, error) {
rng := c.rng.GetStream()
// Create a mnemonic
mnemonic, err := xxMnemonic.GenerateMnemonic(rng, 32)
if err != nil {
return "", errors.Errorf("Failed to generate mnemonic: %v", err)
}
// Encrypt secret with mnemonic as key
ciphertext, nonce, err := encryptWithMnemonic(mnemonic, secret, rng)
if err != nil {
return "", errors.Errorf("Failed to encrypt secret with mnemonic: %v", err)
}
// Concatenate ciphertext with nonce for storage
data := marshalMnemonicInformation(nonce, ciphertext)
// Save data to storage
err = c.storage.SaveMnemonicInformation(data)
if err != nil {
return "", errors.Errorf("Failed to store mnemonic information: %v", err)
}
return mnemonic, nil
}
// LoadSecretWithMnemonic loads the encrypted secret from storage and decrypts
// the secret using the given mnemonic.
func (c *Client) LoadSecretWithMnemonic(mnemonic string) (secret []byte, err error) {
data, err := c.storage.LoadMnemonicInformation()
if err != nil {
return nil, errors.Errorf("Failed to load mnemonic information: %v", err)
}
nonce, ciphertext := unmarshalMnemonicInformation(data)
secret = decryptWithMnemonic(nonce, ciphertext, mnemonic)
return secret, nil
}
// encryptWithMnemonic is a helper function which encrypts the given secret
// using the mnemonic as the key.
func encryptWithMnemonic(mnemonic string, secret []byte,
rng *fastRNG.Stream) (ciphertext, nonce []byte, err error) {
// Place the key into a 32 byte array for salsa 20
var keyArray [32]byte
copy(keyArray[:], mnemonic)
// Generate the nonce
nonce, err = csprng.Generate(nonceSize, rng)
if err != nil {
return nil, nil, errors.Errorf("Failed to generate nonce for encryption: %v", err)
}
// Encrypt the secret
ciphertext = make([]byte, len(secret))
salsa20.XORKeyStream(ciphertext, secret, nonce, &keyArray)
return ciphertext, nonce, nil
}
// decryptWithMnemonic is a helper function which decrypts the secret
// from storage, using the mnemonic as the key.
func decryptWithMnemonic(nonce, ciphertext []byte, mnemonic string) (secret []byte) {
// Place the key into a 32 byte array for salsa 20
var keyArray [32]byte
copy(keyArray[:], mnemonic)
// Decrypt the secret
secret = make([]byte, len(ciphertext))
salsa20.XORKeyStream(secret, ciphertext, nonce, &keyArray)
return secret
}
// marshalMnemonicInformation is a helper function which concatenates the nonce
// and ciphertext.
func marshalMnemonicInformation(nonce, ciphertext []byte) []byte {
return append(nonce, ciphertext...)
}
// unmarshalMnemonicInformation is a helper function which separates the
// concatenated data containing the nonce and ciphertext of the mnemonic
// handling. This is the inverse of marshalMnemonicInformation.
func unmarshalMnemonicInformation(data []byte) (nonce, ciphertext []byte) {
return data[:nonceSize], data[nonceSize:]
}
...@@ -22,7 +22,7 @@ require ( ...@@ -22,7 +22,7 @@ require (
gitlab.com/elixxir/ekv v0.1.5 gitlab.com/elixxir/ekv v0.1.5
gitlab.com/elixxir/primitives v0.0.3-0.20210803231939-7b924f78eaac gitlab.com/elixxir/primitives v0.0.3-0.20210803231939-7b924f78eaac
gitlab.com/xx_network/comms v0.0.4-0.20210813170223-ab758f0bbec5 gitlab.com/xx_network/comms v0.0.4-0.20210813170223-ab758f0bbec5
gitlab.com/xx_network/crypto v0.0.5-0.20210803231814-b18476a2257c gitlab.com/xx_network/crypto v0.0.5-0.20210909170042-07755821e8c5
gitlab.com/xx_network/primitives v0.0.4-0.20210803222745-e898d5e546e9 gitlab.com/xx_network/primitives v0.0.4-0.20210803222745-e898d5e546e9
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2
golang.org/x/net v0.0.0-20210525063256-abc453219eb5 golang.org/x/net v0.0.0-20210525063256-abc453219eb5
......
...@@ -239,6 +239,8 @@ github.com/ttacon/builder v0.0.0-20170518171403-c099f663e1c2 h1:5u+EJUQiosu3JFX0 ...@@ -239,6 +239,8 @@ github.com/ttacon/builder v0.0.0-20170518171403-c099f663e1c2 h1:5u+EJUQiosu3JFX0
github.com/ttacon/builder v0.0.0-20170518171403-c099f663e1c2/go.mod h1:4kyMkleCiLkgY6z8gK5BkI01ChBtxR0ro3I1ZDcGM3w= github.com/ttacon/builder v0.0.0-20170518171403-c099f663e1c2/go.mod h1:4kyMkleCiLkgY6z8gK5BkI01ChBtxR0ro3I1ZDcGM3w=
github.com/ttacon/libphonenumber v1.2.1 h1:fzOfY5zUADkCkbIafAed11gL1sW+bJ26p6zWLBMElR4= github.com/ttacon/libphonenumber v1.2.1 h1:fzOfY5zUADkCkbIafAed11gL1sW+bJ26p6zWLBMElR4=
github.com/ttacon/libphonenumber v1.2.1/go.mod h1:E0TpmdVMq5dyVlQ7oenAkhsLu86OkUl+yR4OAxyEg/M= github.com/ttacon/libphonenumber v1.2.1/go.mod h1:E0TpmdVMq5dyVlQ7oenAkhsLu86OkUl+yR4OAxyEg/M=
github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8=
github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/zeebo/assert v0.0.0-20181109011804-10f827ce2ed6/go.mod h1:yssERNPivllc1yU3BvpjYI5BUW+zglcz6QWqeVRL5t0= github.com/zeebo/assert v0.0.0-20181109011804-10f827ce2ed6/go.mod h1:yssERNPivllc1yU3BvpjYI5BUW+zglcz6QWqeVRL5t0=
github.com/zeebo/assert v1.1.0 h1:hU1L1vLTHsnO8x8c9KAR5GmM5QscxHg5RNU5z5qbUWY= github.com/zeebo/assert v1.1.0 h1:hU1L1vLTHsnO8x8c9KAR5GmM5QscxHg5RNU5z5qbUWY=
...@@ -272,6 +274,8 @@ gitlab.com/xx_network/crypto v0.0.3/go.mod h1:DF2HYvvCw9wkBybXcXAgQMzX+MiGbFPjwt ...@@ -272,6 +274,8 @@ gitlab.com/xx_network/crypto v0.0.3/go.mod h1:DF2HYvvCw9wkBybXcXAgQMzX+MiGbFPjwt
gitlab.com/xx_network/crypto v0.0.4/go.mod h1:+lcQEy+Th4eswFgQDwT0EXKp4AXrlubxalwQFH5O0Mk= gitlab.com/xx_network/crypto v0.0.4/go.mod h1:+lcQEy+Th4eswFgQDwT0EXKp4AXrlubxalwQFH5O0Mk=
gitlab.com/xx_network/crypto v0.0.5-0.20210803231814-b18476a2257c h1:pwP50UFdh68KPcP7VopsH34/d6rIuVDwXymgFXnCOjA= gitlab.com/xx_network/crypto v0.0.5-0.20210803231814-b18476a2257c h1:pwP50UFdh68KPcP7VopsH34/d6rIuVDwXymgFXnCOjA=
gitlab.com/xx_network/crypto v0.0.5-0.20210803231814-b18476a2257c/go.mod h1:e/5MGrKDQbCNJnskBeDscrolr2EK5iIatEgTQnEWmOg= gitlab.com/xx_network/crypto v0.0.5-0.20210803231814-b18476a2257c/go.mod h1:e/5MGrKDQbCNJnskBeDscrolr2EK5iIatEgTQnEWmOg=
gitlab.com/xx_network/crypto v0.0.5-0.20210909170042-07755821e8c5 h1:1K+FuxnlOTHI5H2OmoBokh/K9Pbmel8VBaCdP5RW9FU=
gitlab.com/xx_network/crypto v0.0.5-0.20210909170042-07755821e8c5/go.mod h1:hLNL8YCSiEMof0wgZHuRmN5C98TYZiLaz/rLqUYTdII=
gitlab.com/xx_network/primitives v0.0.0-20200803231956-9b192c57ea7c/go.mod h1:wtdCMr7DPePz9qwctNoAUzZtbOSHSedcK++3Df3psjA= gitlab.com/xx_network/primitives v0.0.0-20200803231956-9b192c57ea7c/go.mod h1:wtdCMr7DPePz9qwctNoAUzZtbOSHSedcK++3Df3psjA=
gitlab.com/xx_network/primitives v0.0.0-20200804183002-f99f7a7284da/go.mod h1:OK9xevzWCaPO7b1wiluVJGk7R5ZsuC7pHY5hteZFQug= gitlab.com/xx_network/primitives v0.0.0-20200804183002-f99f7a7284da/go.mod h1:OK9xevzWCaPO7b1wiluVJGk7R5ZsuC7pHY5hteZFQug=
gitlab.com/xx_network/primitives v0.0.2/go.mod h1:cs0QlFpdMDI6lAo61lDRH2JZz+3aVkHy+QogOB6F/qc= gitlab.com/xx_network/primitives v0.0.2/go.mod h1:cs0QlFpdMDI6lAo61lDRH2JZz+3aVkHy+QogOB6F/qc=
......
package storage
import (
"gitlab.com/elixxir/client/storage/versioned"
"gitlab.com/xx_network/primitives/netTime"
)
const (
mnemonicKvKey = "mnemonic"
mnemonicKvVersion = 0
mnemonicPath = "/.recovery"
)
func (s *Session) SaveMnemonicInformation(data []byte) error {
s.mnemonicMux.Lock()
defer s.mnemonicMux.Unlock()
vo := &versioned.Object{
Version: mnemonicKvVersion,
Timestamp: netTime.Now(),
Data: data,
}
return s.mnemonicKV.Set(mnemonicKvKey, mnemonicKvVersion, vo)
}
func (s *Session) LoadMnemonicInformation() ([]byte, error) {
s.mux.RLock()
defer s.mux.RUnlock()
vo, err := s.mnemonicKv.Get(mnemonicKvKey, mnemonicKvVersion)
if err != nil {
return nil, err
}
return vo.Data, err
}
...@@ -47,7 +47,11 @@ const currentSessionVersion = 0 ...@@ -47,7 +47,11 @@ const currentSessionVersion = 0
// Session object, backed by encrypted filestore // Session object, backed by encrypted filestore
type Session struct { type Session struct {
kv *versioned.KV kv *versioned.KV
mnemonicKV *versioned.KV
mnemonicKv *versioned.KV
mux sync.RWMutex mux sync.RWMutex
mnemonicMux sync.RWMutex
//memoized data //memoized data
regStatus RegistrationStatus regStatus RegistrationStatus
...@@ -78,8 +82,16 @@ func initStore(baseDir, password string) (*Session, error) { ...@@ -78,8 +82,16 @@ func initStore(baseDir, password string) (*Session, error) {
"Failed to create storage session") "Failed to create storage session")
} }
// Create a separate file store system for account recovery
mnemonicFS, err := ekv.NewFilestore(baseDir+mnemonicPath, password)
if err != nil {
return nil, errors.WithMessage(err,
"Failed to create mnemonic store")
}
s = &Session{ s = &Session{
kv: versioned.NewKV(fs), kv: versioned.NewKV(fs),
mnemonicKV: versioned.NewKV(mnemonicFS),
} }
return s, nil return s, nil
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment