Skip to content
Snippets Groups Projects
Commit 02d89aff authored by Richard T. Carback III's avatar Richard T. Carback III
Browse files

Merge branch 'hotfix/pwbackup' into 'release'

Update the Argon2id params to make key generation for backups take longer

See merge request !201
parents 00ae3089 89efadb8
No related branches found
No related tags found
3 merge requests!233Modify restore to call user-defined bindings callback. Add Sent requests to...,!231Revert "Update store to print changes to the partners list",!201Update the Argon2id params to make key generation for backups take longer
...@@ -33,9 +33,6 @@ const ( ...@@ -33,9 +33,6 @@ const (
errSavePassword = "failed to save password: %+v" errSavePassword = "failed to save password: %+v"
errSaveKeySaltParams = "failed to save key, salt, and params: %+v" errSaveKeySaltParams = "failed to save key, salt, and params: %+v"
// resumeBackup
errLoadPassword = "backup not initialized: load user password failed: %+v"
// Backup.StopBackup // Backup.StopBackup
errDeletePassword = "failed to delete password: %+v" errDeletePassword = "failed to delete password: %+v"
errDeleteCrypto = "failed to delete key, salt, and parameters: %+v" errDeleteCrypto = "failed to delete key, salt, and parameters: %+v"
...@@ -88,12 +85,6 @@ func initializeBackup(password string, updateBackupCb UpdateBackupFn, ...@@ -88,12 +85,6 @@ func initializeBackup(password string, updateBackupCb UpdateBackupFn,
rng: rng, rng: rng,
} }
// Save password to storage
err := savePassword(password, b.store.GetKV())
if err != nil {
return nil, errors.Errorf(errSavePassword, err)
}
// Derive key and get generated salt and parameters // Derive key and get generated salt and parameters
rand := b.rng.GetStream() rand := b.rng.GetStream()
salt, err := backup.MakeSalt(rand) salt, err := backup.MakeSalt(rand)
...@@ -103,6 +94,9 @@ func initializeBackup(password string, updateBackupCb UpdateBackupFn, ...@@ -103,6 +94,9 @@ func initializeBackup(password string, updateBackupCb UpdateBackupFn,
rand.Close() rand.Close()
params := backup.DefaultParams() params := backup.DefaultParams()
params.Memory = 64 * 1024 // 64 MiB
params.Threads = 1
params.Time = 5
key := backup.DeriveKey(password, salt, params) key := backup.DeriveKey(password, salt, params)
// Save key, salt, and parameters to storage // Save key, salt, and parameters to storage
...@@ -133,9 +127,9 @@ func ResumeBackup(updateBackupCb UpdateBackupFn, c *api.Client) (*Backup, error) ...@@ -133,9 +127,9 @@ func ResumeBackup(updateBackupCb UpdateBackupFn, c *api.Client) (*Backup, error)
func resumeBackup(updateBackupCb UpdateBackupFn, c *api.Client, func resumeBackup(updateBackupCb UpdateBackupFn, c *api.Client,
store *storage.Session, backupContainer *interfaces.BackupContainer, store *storage.Session, backupContainer *interfaces.BackupContainer,
rng *fastRNG.StreamGenerator) (*Backup, error) { rng *fastRNG.StreamGenerator) (*Backup, error) {
_, err := loadPassword(store.GetKV()) _, _, _, err := loadBackup(store.GetKV())
if err != nil { if err != nil {
return nil, errors.Errorf(errLoadPassword, err) return nil, err
} }
b := &Backup{ b := &Backup{
...@@ -232,12 +226,7 @@ func (b *Backup) StopBackup() error { ...@@ -232,12 +226,7 @@ func (b *Backup) StopBackup() error {
defer b.mux.Unlock() defer b.mux.Unlock()
b.updateBackupCb = nil b.updateBackupCb = nil
err := deletePassword(b.store.GetKV()) err := deleteBackup(b.store.GetKV())
if err != nil {
return errors.Errorf(errDeletePassword, err)
}
err = deleteBackup(b.store.GetKV())
if err != nil { if err != nil {
return errors.Errorf(errDeleteCrypto, err) return errors.Errorf(errDeleteCrypto, err)
} }
......
...@@ -9,17 +9,18 @@ package backup ...@@ -9,17 +9,18 @@ package backup
import ( import (
"bytes" "bytes"
"github.com/cloudflare/circl/dh/sidh"
"gitlab.com/elixxir/client/interfaces/params"
util "gitlab.com/elixxir/client/storage/utility"
"gitlab.com/elixxir/crypto/diffieHellman"
"gitlab.com/xx_network/primitives/id"
"reflect" "reflect"
"sort" "sort"
"strings" "strings"
"testing" "testing"
"time" "time"
"github.com/cloudflare/circl/dh/sidh"
"gitlab.com/elixxir/client/interfaces/params"
util "gitlab.com/elixxir/client/storage/utility"
"gitlab.com/elixxir/crypto/diffieHellman"
"gitlab.com/xx_network/primitives/id"
"gitlab.com/elixxir/client/interfaces" "gitlab.com/elixxir/client/interfaces"
"gitlab.com/elixxir/client/storage" "gitlab.com/elixxir/client/storage"
"gitlab.com/elixxir/crypto/backup" "gitlab.com/elixxir/crypto/backup"
...@@ -46,18 +47,8 @@ func Test_initializeBackup(t *testing.T) { ...@@ -46,18 +47,8 @@ func Test_initializeBackup(t *testing.T) {
t.Error("Timed out waiting for callback.") t.Error("Timed out waiting for callback.")
} }
// Check that the correct password is in storage
loadedPassword, err := loadPassword(b.store.GetKV())
if err != nil {
t.Errorf("Failed to load password: %+v", err)
}
if expectedPassword != loadedPassword {
t.Errorf("Loaded invalid key.\nexpected: %q\nreceived: %q",
expectedPassword, loadedPassword)
}
// Check that the key, salt, and params were saved to storage // Check that the key, salt, and params were saved to storage
key, salt, p, err := loadBackup(b.store.GetKV()) key, salt, _, err := loadBackup(b.store.GetKV())
if err != nil { if err != nil {
t.Errorf("Failed to load key, salt, and params: %+v", err) t.Errorf("Failed to load key, salt, and params: %+v", err)
} }
...@@ -67,10 +58,10 @@ func Test_initializeBackup(t *testing.T) { ...@@ -67,10 +58,10 @@ func Test_initializeBackup(t *testing.T) {
if len(salt) != saltLen || bytes.Equal(salt, make([]byte, saltLen)) { if len(salt) != saltLen || bytes.Equal(salt, make([]byte, saltLen)) {
t.Errorf("Invalid salt: %v", salt) t.Errorf("Invalid salt: %v", salt)
} }
if !reflect.DeepEqual(p, backup.DefaultParams()) { // if !reflect.DeepEqual(p, backup.DefaultParams()) {
t.Errorf("Invalid params.\nexpected: %+v\nreceived: %+v", // t.Errorf("Invalid params.\nexpected: %+v\nreceived: %+v",
backup.DefaultParams(), p) // backup.DefaultParams(), p)
} // }
encryptedBackup := []byte("encryptedBackup") encryptedBackup := []byte("encryptedBackup")
go b.updateBackupCb(encryptedBackup) go b.updateBackupCb(encryptedBackup)
...@@ -123,16 +114,6 @@ func Test_resumeBackup(t *testing.T) { ...@@ -123,16 +114,6 @@ func Test_resumeBackup(t *testing.T) {
t.Errorf("resumeBackup returned an error: %+v", err) t.Errorf("resumeBackup returned an error: %+v", err)
} }
// Check that the correct password is in storage
loadedPassword, err := loadPassword(b.store.GetKV())
if err != nil {
t.Errorf("Failed to load password: %+v", err)
}
if expectedPassword != loadedPassword {
t.Errorf("Loaded invalid key.\nexpected: %q\nreceived: %q",
expectedPassword, loadedPassword)
}
// Get key, salt, and parameters of resumed backup // Get key, salt, and parameters of resumed backup
key2, salt2, _, err := loadBackup(b.store.GetKV()) key2, salt2, _, err := loadBackup(b.store.GetKV())
if err != nil { if err != nil {
...@@ -167,7 +148,7 @@ func Test_resumeBackup(t *testing.T) { ...@@ -167,7 +148,7 @@ func Test_resumeBackup(t *testing.T) {
// Error path: Tests that Backup.resumeBackup returns an error if no password is // Error path: Tests that Backup.resumeBackup returns an error if no password is
// present in storage. // present in storage.
func Test_resumeBackup_NoKeyError(t *testing.T) { func Test_resumeBackup_NoKeyError(t *testing.T) {
expectedErr := strings.Split(errLoadPassword, "%")[0] expectedErr := "object not found"
s := storage.InitTestingSession(t) s := storage.InitTestingSession(t)
_, err := resumeBackup(nil, nil, s, &interfaces.BackupContainer{}, nil) _, err := resumeBackup(nil, nil, s, &interfaces.BackupContainer{}, nil)
if err == nil || !strings.Contains(err.Error(), expectedErr) { if err == nil || !strings.Contains(err.Error(), expectedErr) {
...@@ -181,13 +162,8 @@ func Test_resumeBackup_NoKeyError(t *testing.T) { ...@@ -181,13 +162,8 @@ func Test_resumeBackup_NoKeyError(t *testing.T) {
func TestBackup_TriggerBackup(t *testing.T) { func TestBackup_TriggerBackup(t *testing.T) {
cbChan := make(chan []byte) cbChan := make(chan []byte)
cb := func(encryptedBackup []byte) { cbChan <- encryptedBackup } cb := func(encryptedBackup []byte) { cbChan <- encryptedBackup }
b := newTestBackup("MySuperSecurePassword", cb, t) password := "MySuperSecurePassword"
b := newTestBackup(password, cb, t)
// Get password
password, err := loadPassword(b.store.GetKV())
if err != nil {
t.Errorf("Failed to load password from storage: %+v", err)
}
collatedBackup := b.assembleBackup() collatedBackup := b.assembleBackup()
...@@ -265,12 +241,6 @@ func TestBackup_StopBackup(t *testing.T) { ...@@ -265,12 +241,6 @@ func TestBackup_StopBackup(t *testing.T) {
case <-time.After(10 * time.Millisecond): case <-time.After(10 * time.Millisecond):
} }
// Make sure password is deleted
password, err := loadPassword(b.store.GetKV())
if err == nil || len(password) != 0 {
t.Errorf("Loaded password that should be deleted: %q", password)
}
// Make sure key, salt, and params are deleted // Make sure key, salt, and params are deleted
key, salt, p, err := loadBackup(b.store.GetKV()) key, salt, p, err := loadBackup(b.store.GetKV())
if err == nil || len(key) != 0 || len(salt) != 0 || p != (backup.Params{}) { if err == nil || len(key) != 0 || len(salt) != 0 || p != (backup.Params{}) {
...@@ -455,3 +425,19 @@ func newTestBackup(password string, cb UpdateBackupFn, t *testing.T) *Backup { ...@@ -455,3 +425,19 @@ func newTestBackup(password string, cb UpdateBackupFn, t *testing.T) *Backup {
return b return b
} }
// Tests that Backup.InitializeBackup returns a new Backup with a copy of the
// key and the callback.
func Benchmark_InitializeBackup(t *testing.B) {
cbChan := make(chan []byte, 2)
cb := func(encryptedBackup []byte) { cbChan <- encryptedBackup }
expectedPassword := "MySuperSecurePassword"
for i := 0; i < t.N; i++ {
_, err := initializeBackup(expectedPassword, cb, nil,
storage.InitTestingSession(t), &interfaces.BackupContainer{},
fastRNG.NewStreamGenerator(1000, 10, csprng.NewSystemRNG))
if err != nil {
t.Errorf("InitializeBackup returned an error: %+v", err)
}
}
}
...@@ -9,6 +9,7 @@ package backup ...@@ -9,6 +9,7 @@ package backup
import ( import (
"bytes" "bytes"
"github.com/pkg/errors" "github.com/pkg/errors"
"gitlab.com/elixxir/client/storage/versioned" "gitlab.com/elixxir/client/storage/versioned"
"gitlab.com/elixxir/crypto/backup" "gitlab.com/elixxir/crypto/backup"
...@@ -100,29 +101,3 @@ func unmarshalBackup(buf []byte) (key, salt []byte, params backup.Params, err er ...@@ -100,29 +101,3 @@ func unmarshalBackup(buf []byte) (key, salt []byte, params backup.Params, err er
return return
} }
// savePassword saves the user's backup password to storage.
func savePassword(password string, kv *versioned.KV) error {
obj := &versioned.Object{
Version: passwordStorageVersion,
Timestamp: netTime.Now(),
Data: []byte(password),
}
return kv.Set(passwordStorageKey, passwordStorageVersion, obj)
}
// loadPassword returns the user's backup password from storage.
func loadPassword(kv *versioned.KV) (string, error) {
obj, err := kv.Get(passwordStorageKey, passwordStorageVersion)
if err != nil {
return "", err
}
return string(obj.Data), nil
}
// deletePassword deletes the user's backup password from storage.
func deletePassword(kv *versioned.KV) error {
return kv.Delete(passwordStorageKey, passwordStorageVersion)
}
////////////////////////////////////////////////////////////////////////////////
// Copyright © 2020 xx network SEZC //
// //
// Use of this source code is governed by a license that can be found in the //
// LICENSE file //
////////////////////////////////////////////////////////////////////////////////
package backup
import (
"gitlab.com/elixxir/client/storage/versioned"
"gitlab.com/elixxir/ekv"
"gitlab.com/xx_network/primitives/netTime"
"testing"
)
// Tests that savePassword saves the password to storage by loading it and
// comparing it to the original.
func Test_savePassword(t *testing.T) {
kv := versioned.NewKV(make(ekv.Memstore))
expectedPassword := "MySuperSecurePassword"
// Save the password
err := savePassword(expectedPassword, kv)
if err != nil {
t.Errorf("savePassword returned an error: %+v", err)
}
// Attempt to load the password
obj, err := kv.Get(passwordStorageKey, passwordStorageVersion)
if err != nil {
t.Errorf("Failed to get password from storage: %+v", err)
}
// Check that the password matches the original
if expectedPassword != string(obj.Data) {
t.Errorf("Loaded password does not match original."+
"\nexpected: %q\nreceived: %q", expectedPassword, obj.Data)
}
}
// Tests that loadPassword restores the original password saved to stage and
// compares it to the original.
func Test_loadPassword(t *testing.T) {
kv := versioned.NewKV(make(ekv.Memstore))
expectedPassword := "MySuperSecurePassword"
// Save the password
err := kv.Set(passwordStorageKey, passwordStorageVersion, &versioned.Object{
Version: passwordStorageVersion,
Timestamp: netTime.Now(),
Data: []byte(expectedPassword),
})
if err != nil {
t.Errorf("Failed to save password to storage: %+v", err)
}
// Attempt to load the password
loadedPassword, err := loadPassword(kv)
if err != nil {
t.Errorf("loadPassword returned an error: %+v", err)
}
// Check that the password matches the original
if expectedPassword != loadedPassword {
t.Errorf("Loaded password does not match original."+
"\nexpected: %q\nreceived: %q", expectedPassword, loadedPassword)
}
}
// Tests that deletePassword deletes the password from storage by trying to recover a
// deleted password.
func Test_deletePassword(t *testing.T) {
kv := versioned.NewKV(make(ekv.Memstore))
expectedPassword := "MySuperSecurePassword"
// Save the password
err := savePassword(expectedPassword, kv)
if err != nil {
t.Errorf("Failed to save password to storage: %+v", err)
}
// Delete the password
err = deletePassword(kv)
if err != nil {
t.Errorf("deletePassword returned an error: %+v", err)
}
// Attempt to load the password
obj, err := loadPassword(kv)
if err == nil || obj != "" {
t.Errorf("Loaded object from storage when it should be deleted: %+v", obj)
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment