wallet: remove public passphrase prompt

1. Remove passphrase support for public keys.
2. Rename privPassphrase to passphrase to avoid confusion.

Note:

There has been a bug in the prompt, which prevents users from
specifying a custom public passphrase. So, most wallet databases
have been using the default password for the public keys, anyway.
This commit is contained in:
Roy Lee 2022-09-28 15:16:15 -07:00
parent 9c20f19d23
commit 79da868c74
14 changed files with 243 additions and 513 deletions

View file

@ -266,11 +266,11 @@ func sweep() error {
sourceOutputs[unspentOutput.Address] = append(sourceAddressOutputs, unspentOutput)
}
var privatePassphrase string
var passphrase string
if len(sourceOutputs) != 0 {
privatePassphrase, err = promptSecret("Wallet private passphrase")
passphrase, err = promptSecret("Wallet passphrase")
if err != nil {
return errContext(err, "failed to read private passphrase")
return errContext(err, "failed to read passphrase")
}
}
@ -294,7 +294,7 @@ func sweep() error {
}
// Unlock the wallet, sign the transaction, and immediately lock.
err = rpcClient.WalletPassphrase(privatePassphrase, 60)
err = rpcClient.WalletPassphrase(passphrase, 60)
if err != nil {
reportError("Failed to unlock wallet: %v", err)
continue

View file

@ -265,7 +265,6 @@ func loadConfig() (*config, []string, error) {
ConfigFile: cfgutil.NewExplicitString(defaultConfigFile),
AppDataDir: cfgutil.NewExplicitString(defaultAppDataDir),
LogDir: defaultLogDir,
WalletPass: wallet.InsecurePubPassphrase,
CAFile: cfgutil.NewExplicitString(""),
RPCKey: cfgutil.NewExplicitString(defaultRPCKeyFile),
RPCCert: cfgutil.NewExplicitString(defaultRPCCertFile),

View file

@ -52,10 +52,10 @@ func provideSeed(reader *bufio.Reader) ([]byte, error) {
}
}
// ProvidePrivPassphrase is used to prompt for the private passphrase which
// maybe required during upgrades.
func ProvidePrivPassphrase() ([]byte, error) {
prompt := "Enter the private passphrase of your wallet: "
// ProvidePassphrase is used to prompt for the passphrase which maybe required
// during upgrades.
func ProvidePassphrase() ([]byte, error) {
prompt := "Enter the passphrase of your wallet: "
for {
fmt.Print(prompt)
pass, err := terminal.ReadPassword(int(os.Stdin.Fd()))
@ -147,10 +147,10 @@ func promptUnixTimestamp(reader *bufio.Reader, prefix string,
}
}
// promptPass prompts the user for a passphrase with the given prefix. The
// function will ask the user to confirm the passphrase and will repeat the
// prompts until they enter a matching response.
func promptPass(_ *bufio.Reader, prefix string, confirm bool) ([]byte, error) {
// promptPassphrase prompts the user for a passphrase with the given prefix.
// The function will ask the user to confirm the passphrase and will repeat
// the prompts until they enter a matching response.
func promptPassphrase(_ *bufio.Reader, prefix string, confirm bool) ([]byte, error) {
// Prompt the user until they enter a passphrase.
prompt := fmt.Sprintf("%s: ", prefix)
for {
@ -191,56 +191,11 @@ func birthday(reader *bufio.Reader) (time.Time, error) {
return promptUnixTimestamp(reader, prompt, "0")
}
// PrivatePass prompts the user for a private passphrase. The user is prompted
// for a new private passphrase. All prompts are repeated until the user
// enters a valid response.
func PrivatePass(reader *bufio.Reader) ([]byte, error) {
return promptPass(reader, "Enter the private "+
"passphrase for your new wallet", true)
}
// PublicPass prompts the user whether they want to add an additional layer of
// encryption to the wallet. When the user answers yes and there is already a
// public passphrase provided via the passed config, it prompts them whether or
// not to use that configured passphrase. It will also detect when the same
// passphrase is used for the private and public passphrase and prompt the user
// if they are sure they want to use the same passphrase for both. Finally, all
// prompts are repeated until the user enters a valid response.
func PublicPass(reader *bufio.Reader, privPass []byte,
defaultPubPassphrase, configPubPassphrase []byte) ([]byte, error) {
pubPass := defaultPubPassphrase
usePubPass, err := promptListBool(reader, "Do you want "+
"to add an additional layer of encryption for public "+
"data?", "no")
if err != nil {
return nil, err
}
if !usePubPass {
return pubPass, nil
}
if !bytes.Equal(configPubPassphrase, pubPass) {
useExisting, err := promptListBool(reader, "Use the "+
"existing configured public passphrase for encryption "+
"of public data?", "no")
if err != nil {
return nil, err
}
if useExisting {
return configPubPassphrase, nil
}
}
pubPass, err = provideSeed(reader)
if err != nil {
return nil, err
}
fmt.Println("NOTE: Use the --walletpass option to configure your " +
"public passphrase.")
return pubPass, nil
// Passphrase prompts the user for a passphrase.
// All prompts are repeated until the user enters a valid response.
func Passphrase(reader *bufio.Reader) ([]byte, error) {
return promptPassphrase(reader, "Enter the passphrase "+
"for your new wallet", true)
}
// Seed prompts the user whether they want to use an existing wallet generation

View file

@ -1,30 +0,0 @@
// Copyright (c) 2015-2021 The btcsuite developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package prompt
import (
"bufio"
"fmt"
)
func ProvideSeed() ([]byte, error) {
return nil, fmt.Errorf("prompt not supported in WebAssembly")
}
func ProvidePrivPassphrase() ([]byte, error) {
return nil, fmt.Errorf("prompt not supported in WebAssembly")
}
func PrivatePass(_ *bufio.Reader) ([]byte, error) {
return nil, fmt.Errorf("prompt not supported in WebAssembly")
}
func PublicPass(_ *bufio.Reader, _, _, _ []byte) ([]byte, error) {
return nil, fmt.Errorf("prompt not supported in WebAssembly")
}
func Seed(_ *bufio.Reader) ([]byte, error) {
return nil, fmt.Errorf("prompt not supported in WebAssembly")
}

View file

@ -94,7 +94,7 @@ func walletMain() error {
if !cfg.NoInitialLoad {
// Load the wallet database. It must have been created already
// or this will return an appropriate error.
_, err = loader.OpenExistingWallet([]byte(cfg.WalletPass), true)
_, err = loader.OpenExistingWallet(true)
if err != nil {
log.Error(err)
return err

View file

@ -2154,7 +2154,7 @@ func walletPassphrase(icmd interface{}, w *wallet.Wallet) (interface{}, error) {
func walletPassphraseChange(icmd interface{}, w *wallet.Wallet) (interface{}, error) {
cmd := icmd.(*btcjson.WalletPassphraseChangeCmd)
err := w.ChangePrivatePassphrase([]byte(cmd.OldPassphrase),
err := w.ChangePassphrase([]byte(cmd.OldPassphrase),
[]byte(cmd.NewPassphrase))
if waddrmgr.IsError(err, waddrmgr.ErrWrongPassphrase) {
return nil, &btcjson.RPCError{

View file

@ -29,9 +29,7 @@ var (
rootKey, _ = hdkeychain.NewMaster(seed, &chaincfg.MainNetParams)
pubPassphrase = []byte("_DJr{fL4H0O}*-0\n:V1izc)(6BomK")
privPassphrase = []byte("81lUHXnOMZ@?XXd7O9xyDIWIbXX-lj")
pubPassphrase2 = []byte("-0NV4P~VSJBWbunw}%<Z]fuGpbN[ZI")
passphrase = []byte("81lUHXnOMZ@?XXd7O9xyDIWIbXX-lj")
privPassphrase2 = []byte("~{<]08%6!-?2s<$(8$8:f(5[4/!/{Y")
// fastScrypt are parameters used throughout the tests to speed up the
@ -287,13 +285,13 @@ func setupManager(t *testing.T) (tearDownFunc func(), db walletdb.DB, mgr *Manag
return err
}
err = Create(
ns, rootKey, pubPassphrase, privPassphrase,
&chaincfg.MainNetParams, fastScrypt, time.Time{},
ns, rootKey, passphrase, &chaincfg.MainNetParams,
fastScrypt, time.Time{},
)
if err != nil {
return err
}
mgr, err = Open(ns, pubPassphrase, &chaincfg.MainNetParams)
mgr, err = Open(ns, &chaincfg.MainNetParams)
return err
})
if err != nil {

View file

@ -34,7 +34,7 @@ var (
// ObtainUserInputFunc is a function that reads a user input and returns it as
// a byte stream. It is used to accept data required during upgrades, for e.g.
// wallet seed and private passphrase.
// wallet seed and passphrase.
type ObtainUserInputFunc func() ([]byte, error)
// maybeConvertDbError converts the passed error to a ManagerError with an

View file

@ -81,7 +81,7 @@ const (
InternalBranch uint32 = 1
// saltSize is the number of bytes of the salt used when hashing
// private passphrases.
// passphrases.
saltSize = 32
)
@ -113,11 +113,11 @@ type OpenCallbacks struct {
// from the user (or any other mechanism the caller deems fit).
ObtainSeed ObtainUserInputFunc
// ObtainPrivatePass is a callback function that is potentially invoked
// ObtainPassphrase is a callback function that is potentially invoked
// during upgrades. It is intended to be used to request the wallet
// private passphrase from the user (or any other mechanism the caller
// deems fit).
ObtainPrivatePass ObtainUserInputFunc
// passphrase from the user (or any other mechanism the caller deems
// fit).
ObtainPassphrase ObtainUserInputFunc
}
// DefaultScryptOptions is the default options used with scrypt.
@ -373,11 +373,11 @@ type Manager struct {
cryptoKeyScriptEncrypted []byte
cryptoKeyScript EncryptorDecryptor
// privPassphraseSalt and hashedPrivPassphrase allow for the secure
// detection of a correct passphrase on manager unlock when the
// manager is already unlocked. The hash is zeroed each lock.
privPassphraseSalt [saltSize]byte
hashedPrivPassphrase [sha512.Size]byte
// pssphraseSalt and hashedPassphrase allow for the secure detection
// of a correct passphrase on manager unlock when the manager is already
// unlocked. The hash is zeroed each lock.
passphraseSalt [saltSize]byte
hashedPassphrase [sha512.Size]byte
}
// lock performs a best try effort to remove and zero all secret keys associated
@ -413,7 +413,7 @@ func (m *Manager) lock() {
m.masterKeyPriv.Zero()
// Zero the hashed passphrase.
zero.Bytea64(&m.hashedPrivPassphrase)
zero.Bytea64(&m.hashedPassphrase)
// NOTE: m.cryptoKeyPub is intentionally not cleared here as the address
// manager needs to be able to continue to read and decrypt public data
@ -825,13 +825,12 @@ func (m *Manager) ChainParams() *chaincfg.Params {
return m.chainParams
}
// ChangePassphrase changes either the public or private passphrase to the
// provided value depending on the private flag. The new passphrase keys are
// derived using the scrypt parameters in the options, so changing the
// passphrase may be used to bump the computational difficulty needed to brute
// force the passphrase.
// ChangePassphrase changes passphrase to the provided value. The new
// passphrase keys are derived using the scrypt parameters in the options, so
// changing the passphrase may be used to bump the computational difficulty
// needed to brute force the passphrase.
func (m *Manager) ChangePassphrase(ns walletdb.ReadWriteBucket, oldPassphrase,
newPassphrase []byte, private bool, config *ScryptOptions) error {
newPassphrase []byte, config *ScryptOptions) error {
m.mtx.Lock()
defer m.mtx.Unlock()
@ -842,13 +841,9 @@ func (m *Manager) ChangePassphrase(ns walletdb.ReadWriteBucket, oldPassphrase,
// cleared when done to avoid leaving a copy in memory.
var keyName string
secretKey := snacl.SecretKey{Key: &snacl.CryptoKey{}}
if private {
keyName = "private"
secretKey.Parameters = m.masterKeyPriv.Parameters
} else {
keyName = "public"
secretKey.Parameters = m.masterKeyPub.Parameters
}
keyName = "private"
secretKey.Parameters = m.masterKeyPriv.Parameters
if err := secretKey.DeriveKey(&oldPassphrase); err != nil {
if err == snacl.ErrInvalidPassword {
str := fmt.Sprintf("invalid passphrase for %s master "+
@ -870,112 +865,85 @@ func (m *Manager) ChangePassphrase(ns walletdb.ReadWriteBucket, oldPassphrase,
}
newKeyParams := newMasterKey.Marshal()
if private {
// Technically, the locked state could be checked here to only
// do the decrypts when the address manager is locked as the
// clear text keys are already available in memory when it is
// unlocked, but this is not a hot path, decryption is quite
// fast, and it's less cyclomatic complexity to simply decrypt
// in either case.
// Technically, the locked state could be checked here to only
// do the decrypts when the address manager is locked as the
// clear text keys are already available in memory when it is
// unlocked, but this is not a hot path, decryption is quite
// fast, and it's less cyclomatic complexity to simply decrypt
// in either case.
// Create a new salt that will be used for hashing the new
// passphrase each unlock.
var passphraseSalt [saltSize]byte
_, err := rand.Read(passphraseSalt[:])
if err != nil {
str := "failed to read random source for passhprase salt"
return managerError(ErrCrypto, str, err)
}
// Re-encrypt the crypto private key using the new master
// private key.
decPriv, err := secretKey.Decrypt(m.cryptoKeyPrivEncrypted)
if err != nil {
str := "failed to decrypt crypto private key"
return managerError(ErrCrypto, str, err)
}
encPriv, err := newMasterKey.Encrypt(decPriv)
zero.Bytes(decPriv)
if err != nil {
str := "failed to encrypt crypto private key"
return managerError(ErrCrypto, str, err)
}
// Re-encrypt the crypto script key using the new master
// private key.
decScript, err := secretKey.Decrypt(m.cryptoKeyScriptEncrypted)
if err != nil {
str := "failed to decrypt crypto script key"
return managerError(ErrCrypto, str, err)
}
encScript, err := newMasterKey.Encrypt(decScript)
zero.Bytes(decScript)
if err != nil {
str := "failed to encrypt crypto script key"
return managerError(ErrCrypto, str, err)
}
// When the manager is locked, ensure the new clear text master
// key is cleared from memory now that it is no longer needed.
// If unlocked, create the new passphrase hash with the new
// passphrase and salt.
var hashedPassphrase [sha512.Size]byte
if m.locked {
newMasterKey.Zero()
} else {
saltedPassphrase := append(passphraseSalt[:],
newPassphrase...)
hashedPassphrase = sha512.Sum512(saltedPassphrase)
zero.Bytes(saltedPassphrase)
}
// Save the new keys and params to the db in a single
// transaction.
err = putCryptoKeys(ns, nil, encPriv, encScript)
if err != nil {
return maybeConvertDbError(err)
}
err = putMasterKeyParams(ns, nil, newKeyParams)
if err != nil {
return maybeConvertDbError(err)
}
// Now that the db has been successfully updated, clear the old
// key and set the new one.
copy(m.cryptoKeyPrivEncrypted, encPriv)
copy(m.cryptoKeyScriptEncrypted, encScript)
m.masterKeyPriv.Zero() // Clear the old key.
m.masterKeyPriv = newMasterKey
m.privPassphraseSalt = passphraseSalt
m.hashedPrivPassphrase = hashedPassphrase
} else {
// Re-encrypt the crypto public key using the new master public
// key.
encryptedPub, err := newMasterKey.Encrypt(m.cryptoKeyPub.Bytes())
if err != nil {
str := "failed to encrypt crypto public key"
return managerError(ErrCrypto, str, err)
}
// Save the new keys and params to the the db in a single
// transaction.
err = putCryptoKeys(ns, encryptedPub, nil, nil)
if err != nil {
return maybeConvertDbError(err)
}
err = putMasterKeyParams(ns, newKeyParams, nil)
if err != nil {
return maybeConvertDbError(err)
}
// Now that the db has been successfully updated, clear the old
// key and set the new one.
m.masterKeyPub.Zero()
m.masterKeyPub = newMasterKey
// Create a new salt that will be used for hashing the new
// passphrase each unlock.
var passphraseSalt [saltSize]byte
_, err = rand.Read(passphraseSalt[:])
if err != nil {
str := "failed to read random source for passhprase salt"
return managerError(ErrCrypto, str, err)
}
// Re-encrypt the crypto private key using the new master
// private key.
decPriv, err := secretKey.Decrypt(m.cryptoKeyPrivEncrypted)
if err != nil {
str := "failed to decrypt crypto private key"
return managerError(ErrCrypto, str, err)
}
encPriv, err := newMasterKey.Encrypt(decPriv)
zero.Bytes(decPriv)
if err != nil {
str := "failed to encrypt crypto private key"
return managerError(ErrCrypto, str, err)
}
// Re-encrypt the crypto script key using the new master
// private key.
decScript, err := secretKey.Decrypt(m.cryptoKeyScriptEncrypted)
if err != nil {
str := "failed to decrypt crypto script key"
return managerError(ErrCrypto, str, err)
}
encScript, err := newMasterKey.Encrypt(decScript)
zero.Bytes(decScript)
if err != nil {
str := "failed to encrypt crypto script key"
return managerError(ErrCrypto, str, err)
}
// When the manager is locked, ensure the new clear text master
// key is cleared from memory now that it is no longer needed.
// If unlocked, create the new passphrase hash with the new
// passphrase and salt.
var hashedPassphrase [sha512.Size]byte
if m.locked {
newMasterKey.Zero()
} else {
saltedPassphrase := append(passphraseSalt[:],
newPassphrase...)
hashedPassphrase = sha512.Sum512(saltedPassphrase)
zero.Bytes(saltedPassphrase)
}
// Save the new keys and params to the db in a single
// transaction.
err = putCryptoKeys(ns, nil, encPriv, encScript)
if err != nil {
return maybeConvertDbError(err)
}
err = putMasterKeyParams(ns, nil, newKeyParams)
if err != nil {
return maybeConvertDbError(err)
}
// Now that the db has been successfully updated, clear the old
// key and set the new one.
copy(m.cryptoKeyPrivEncrypted, encPriv)
copy(m.cryptoKeyScriptEncrypted, encScript)
m.masterKeyPriv.Zero() // Clear the old key.
m.masterKeyPriv = newMasterKey
m.passphraseSalt = passphraseSalt
m.hashedPassphrase = hashedPassphrase
return nil
}
@ -1027,11 +995,10 @@ func (m *Manager) Unlock(ns walletdb.ReadBucket, passphrase []byte) error {
// Avoid actually unlocking if the manager is already unlocked
// and the passphrases match.
if !m.locked {
saltedPassphrase := append(m.privPassphraseSalt[:],
passphrase...)
saltedPassphrase := append(m.passphraseSalt[:], passphrase...)
hashedPassphrase := sha512.Sum512(saltedPassphrase)
zero.Bytes(saltedPassphrase)
if hashedPassphrase != m.hashedPrivPassphrase {
if hashedPassphrase != m.hashedPassphrase {
m.lock()
str := "invalid passphrase for master private key"
return managerError(ErrWrongPassphrase, str, nil)
@ -1126,8 +1093,8 @@ func (m *Manager) Unlock(ns walletdb.ReadBucket, passphrase []byte) error {
}
m.locked = false
saltedPassphrase := append(m.privPassphraseSalt[:], passphrase...)
m.hashedPrivPassphrase = sha512.Sum512(saltedPassphrase)
saltedPassphrase := append(m.passphraseSalt[:], passphrase...)
m.hashedPassphrase = sha512.Sum512(saltedPassphrase)
zero.Bytes(saltedPassphrase)
return nil
}
@ -1235,7 +1202,7 @@ func (m *Manager) Decrypt(keyType CryptoKeyType, in []byte) ([]byte, error) {
func newManager(chainParams *chaincfg.Params, masterKeyPub *snacl.SecretKey,
masterKeyPriv *snacl.SecretKey, cryptoKeyPub EncryptorDecryptor,
cryptoKeyPrivEncrypted, cryptoKeyScriptEncrypted []byte, syncInfo *syncState,
birthday time.Time, privPassphraseSalt [saltSize]byte,
birthday time.Time, passphraseSalt [saltSize]byte,
scopedManagers map[KeyScope]*ScopedKeyManager) *Manager {
m := &Manager{
@ -1250,7 +1217,7 @@ func newManager(chainParams *chaincfg.Params, masterKeyPub *snacl.SecretKey,
cryptoKeyPriv: &cryptoKey{},
cryptoKeyScriptEncrypted: cryptoKeyScriptEncrypted,
cryptoKeyScript: &cryptoKey{},
privPassphraseSalt: privPassphraseSalt,
passphraseSalt: passphraseSalt,
scopedManagers: scopedManagers,
externalAddrSchemas: make(map[AddressType][]KeyScope),
internalAddrSchemas: make(map[AddressType][]KeyScope),
@ -1361,10 +1328,9 @@ func checkBranchKeys(acctKey *hdkeychain.ExtendedKey) error {
}
// loadManager returns a new address manager that results from loading it from
// the passed opened database. The public passphrase is required to decrypt
// the public keys.
func loadManager(ns walletdb.ReadBucket, pubPassphrase []byte,
chainParams *chaincfg.Params) (*Manager, error) {
// the passed opened database.
func loadManager(ns walletdb.ReadBucket, chainParams *chaincfg.Params) (
*Manager, error) {
// Verify the version is neither too old or too new.
version, err := fetchManagerVersion(ns)
@ -1381,7 +1347,7 @@ func loadManager(ns walletdb.ReadBucket, pubPassphrase []byte,
}
// Load the master key params from the db.
masterKeyPubParams, masterKeyPrivParams, err := fetchMasterKeyParams(ns)
masterKeyPubParams, masterKeyparams, err := fetchMasterKeyParams(ns)
if err != nil {
return nil, maybeConvertDbError(err)
}
@ -1410,7 +1376,7 @@ func loadManager(ns walletdb.ReadBucket, pubPassphrase []byte,
// Set the master private key params, but don't derive it now since the
// manager starts off locked.
var masterKeyPriv snacl.SecretKey
err = masterKeyPriv.Unmarshal(masterKeyPrivParams)
err = masterKeyPriv.Unmarshal(masterKeyparams)
if err != nil {
str := "failed to unmarshal master private key"
return nil, managerError(ErrCrypto, str, err)
@ -1423,6 +1389,8 @@ func loadManager(ns walletdb.ReadBucket, pubPassphrase []byte,
str := "failed to unmarshal master public key"
return nil, managerError(ErrCrypto, str, err)
}
pubPassphrase := []byte("public") // Hardcoded salt.
if err := masterKeyPub.DeriveKey(&pubPassphrase); err != nil {
str := "invalid passphrase for master public key"
return nil, managerError(ErrWrongPassphrase, str, nil)
@ -1441,9 +1409,9 @@ func loadManager(ns walletdb.ReadBucket, pubPassphrase []byte,
// Create the sync state struct.
syncInfo := newSyncState(startBlock, syncedTo)
// Generate private passphrase salt.
var privPassphraseSalt [saltSize]byte
_, err = rand.Read(privPassphraseSalt[:])
// Generate passphrase salt.
var passphraseSalt [saltSize]byte
_, err = rand.Read(passphraseSalt[:])
if err != nil {
str := "failed to read random source for passphrase salt"
return nil, managerError(ErrCrypto, str, err)
@ -1480,7 +1448,7 @@ func loadManager(ns walletdb.ReadBucket, pubPassphrase []byte,
mgr := newManager(
chainParams, &masterKeyPub, &masterKeyPriv,
cryptoKeyPub, cryptoKeyPrivEnc, cryptoKeyScriptEnc, syncInfo,
birthday, privPassphraseSalt, scopedManagers)
birthday, passphraseSalt, scopedManagers)
for _, scopedManager := range scopedManagers {
scopedManager.rootManager = mgr
@ -1489,18 +1457,15 @@ func loadManager(ns walletdb.ReadBucket, pubPassphrase []byte,
return mgr, nil
}
// Open loads an existing address manager from the given namespace. The public
// passphrase is required to decrypt the public keys used to protect the public
// information such as addresses. This is important since access to BIP0032
// extended keys means it is possible to generate all future addresses.
// Open loads an existing address manager from the given namespace.
//
// If a config structure is passed to the function, that configuration will
// override the defaults.
//
// A ManagerError with an error code of ErrNoExist will be returned if the
// passed manager does not exist in the specified namespace.
func Open(ns walletdb.ReadBucket, pubPassphrase []byte,
chainParams *chaincfg.Params) (*Manager, error) {
func Open(ns walletdb.ReadBucket, chainParams *chaincfg.Params) (
*Manager, error) {
// Return an error if the manager has NOT already been created in the
// given database namespace.
@ -1510,7 +1475,7 @@ func Open(ns walletdb.ReadBucket, pubPassphrase []byte,
return nil, managerError(ErrNoExist, str, nil)
}
return loadManager(ns, pubPassphrase, chainParams)
return loadManager(ns, chainParams)
}
// createManagerKeyScope creates a new key scoped for a target manager's scope.
@ -1622,12 +1587,10 @@ func createManagerKeyScope(ns walletdb.ReadWriteBucket,
// derived. This allows all chained addresses in the address manager
// to be recovered by using the same seed.
//
// All private and public keys and information are protected by secret
// keys derived from the provided private and public passphrases. The
// public passphrase is required on subsequent opens of the address
// manager, and the private passphrase is required to unlock the
// address manager in order to gain access to any private keys and
// information.
// All private keys and information are protected by secret keys derived
// from the provided passphrase.
// The passphrase is required to unlock the address manager in order to gain
// access to any private keys and information.
//
// If a config structure is passed to the function, that configuration
// will override the defaults.
@ -1636,9 +1599,8 @@ func createManagerKeyScope(ns walletdb.ReadWriteBucket,
// returned the address manager already exists in the specified
// namespace.
func Create(ns walletdb.ReadWriteBucket, rootKey *hdkeychain.ExtendedKey,
pubPassphrase, privPassphrase []byte,
chainParams *chaincfg.Params, config *ScryptOptions,
birthday time.Time) error {
passphrase []byte, chainParams *chaincfg.Params,
config *ScryptOptions, birthday time.Time) error {
// Return an error if the manager has already been created in
// the given database namespace.
@ -1647,9 +1609,9 @@ func Create(ns walletdb.ReadWriteBucket, rootKey *hdkeychain.ExtendedKey,
return managerError(ErrAlreadyExists, errAlreadyExists, nil)
}
// Ensure the private passphrase is not empty.
if len(privPassphrase) == 0 {
str := "private passphrase may not be empty"
// Ensure the passphrase is not empty.
if len(passphrase) == 0 {
str := "passphrase may not be empty"
return managerError(ErrEmptyPassphrase, str, nil)
}
@ -1664,6 +1626,7 @@ func Create(ns walletdb.ReadWriteBucket, rootKey *hdkeychain.ExtendedKey,
// Generate new master keys. These master keys are used to protect the
// crypto keys that will be generated next.
pubPassphrase := []byte("public") // Hardcoded salt.
masterKeyPub, err := newSecretKey(&pubPassphrase, config)
if err != nil {
str := "failed to master public key"
@ -1699,22 +1662,22 @@ func Create(ns walletdb.ReadWriteBucket, rootKey *hdkeychain.ExtendedKey,
pubParams := masterKeyPub.Marshal()
var privParams []byte
var params []byte
var masterKeyPriv *snacl.SecretKey
var cryptoKeyPrivEnc []byte
var cryptoKeyScriptEnc []byte
masterKeyPriv, err = newSecretKey(&privPassphrase, config)
masterKeyPriv, err = newSecretKey(&passphrase, config)
if err != nil {
str := "failed to master private key"
return managerError(ErrCrypto, str, err)
}
defer masterKeyPriv.Zero()
// Generate the private passphrase salt. This is used when
// hashing passwords to detect whether an unlock can be
// avoided when the manager is already unlocked.
var privPassphraseSalt [saltSize]byte
_, err = rand.Read(privPassphraseSalt[:])
// Generate the passphrase salt. This is used when hashing passwords
// to detect whether an unlock can be avoided when the manager is
// already unlocked.
var passphraseSalt [saltSize]byte
_, err = rand.Read(passphraseSalt[:])
if err != nil {
str := "failed to read random source for passphrase salt"
return managerError(ErrCrypto, str, err)
@ -1786,10 +1749,10 @@ func Create(ns walletdb.ReadWriteBucket, rootKey *hdkeychain.ExtendedKey,
return maybeConvertDbError(err)
}
privParams = masterKeyPriv.Marshal()
params = masterKeyPriv.Marshal()
// Save the master key params to the database.
err = putMasterKeyParams(ns, pubParams, privParams)
err = putMasterKeyParams(ns, pubParams, params)
if err != nil {
return maybeConvertDbError(err)
}

View file

@ -431,7 +431,7 @@ func testExternalAddresses(tc *testContext) bool {
// private information is valid as well.
err := walletdb.View(tc.db, func(tx walletdb.ReadTx) error {
ns := tx.ReadBucket(waddrmgrNamespaceKey)
return tc.rootManager.Unlock(ns, privPassphrase)
return tc.rootManager.Unlock(ns, passphrase)
})
if err != nil {
tc.t.Errorf("Unlock: unexpected error: %v", err)
@ -463,7 +463,7 @@ func testInternalAddresses(tc *testContext) bool {
// private information is valid as well.
err := walletdb.View(tc.db, func(tx walletdb.ReadTx) error {
ns := tx.ReadBucket(waddrmgrNamespaceKey)
return tc.rootManager.Unlock(ns, privPassphrase)
return tc.rootManager.Unlock(ns, passphrase)
})
if err != nil {
tc.t.Errorf("Unlock: unexpected error: %v", err)
@ -603,7 +603,7 @@ func testLocking(tc *testContext) bool {
// unexpected errors and the manager properly reports it is unlocked.
err = walletdb.View(tc.db, func(tx walletdb.ReadTx) error {
ns := tx.ReadBucket(waddrmgrNamespaceKey)
return tc.rootManager.Unlock(ns, privPassphrase)
return tc.rootManager.Unlock(ns, passphrase)
})
if err != nil {
tc.t.Errorf("Unlock: unexpected error: %v", err)
@ -617,7 +617,7 @@ func testLocking(tc *testContext) bool {
// Unlocking the manager again is allowed.
err = walletdb.View(tc.db, func(tx walletdb.ReadTx) error {
ns := tx.ReadBucket(waddrmgrNamespaceKey)
return tc.rootManager.Unlock(ns, privPassphrase)
return tc.rootManager.Unlock(ns, passphrase)
})
if err != nil {
tc.t.Errorf("Unlock: unexpected error: %v", err)
@ -696,7 +696,7 @@ func testImportPrivateKey(tc *testContext) bool {
// The manager must be unlocked to import a private key.
err := walletdb.View(tc.db, func(tx walletdb.ReadTx) error {
ns := tx.ReadBucket(waddrmgrNamespaceKey)
return tc.rootManager.Unlock(ns, privPassphrase)
return tc.rootManager.Unlock(ns, passphrase)
})
if err != nil {
tc.t.Errorf("Unlock: unexpected error: %v", err)
@ -913,7 +913,7 @@ func testImportScript(tc *testContext) bool {
// testing private data.
err := walletdb.View(tc.db, func(tx walletdb.ReadTx) error {
ns := tx.ReadBucket(waddrmgrNamespaceKey)
return tc.rootManager.Unlock(ns, privPassphrase)
return tc.rootManager.Unlock(ns, passphrase)
})
if err != nil {
tc.t.Errorf("Unlock: unexpected error: %v", err)
@ -1122,74 +1122,11 @@ func testMarkUsed(tc *testContext, doScript bool) bool {
func testChangePassphrase(tc *testContext) bool {
pfx := fmt.Sprintf("(%s) ", tc.caseName)
// Force an error when changing the passphrase due to failure to
// generate a new secret key by replacing the generation function one
// that intentionally errors.
testName := pfx + "ChangePassphrase (public) with invalid new secret key"
oldKeyGen := SetSecretKeyGen(failingSecretKeyGen)
testName := pfx + "ChangePassphrase with invalid old passphrase"
err := walletdb.Update(tc.db, func(tx walletdb.ReadWriteTx) error {
ns := tx.ReadWriteBucket(waddrmgrNamespaceKey)
return tc.rootManager.ChangePassphrase(
ns, pubPassphrase, pubPassphrase2, false, fastScrypt,
)
})
if !checkManagerError(tc.t, testName, err, ErrCrypto) {
return false
}
// Attempt to change public passphrase with invalid old passphrase.
testName = pfx + "ChangePassphrase (public) with invalid old passphrase"
SetSecretKeyGen(oldKeyGen)
err = walletdb.Update(tc.db, func(tx walletdb.ReadWriteTx) error {
ns := tx.ReadWriteBucket(waddrmgrNamespaceKey)
return tc.rootManager.ChangePassphrase(
ns, []byte("bogus"), pubPassphrase2, false, fastScrypt,
)
})
if !checkManagerError(tc.t, testName, err, ErrWrongPassphrase) {
return false
}
// Change the public passphrase.
testName = pfx + "ChangePassphrase (public)"
err = walletdb.Update(tc.db, func(tx walletdb.ReadWriteTx) error {
ns := tx.ReadWriteBucket(waddrmgrNamespaceKey)
return tc.rootManager.ChangePassphrase(
ns, pubPassphrase, pubPassphrase2, false, fastScrypt,
)
})
if err != nil {
tc.t.Errorf("%s: unexpected error: %v", testName, err)
return false
}
// Ensure the public passphrase was successfully changed. We do this by
// being able to re-derive the public key with the new passphrase.
secretKey := snacl.SecretKey{Key: &snacl.CryptoKey{}}
secretKey.Parameters = tc.rootManager.masterKeyPub.Parameters
if err := secretKey.DeriveKey(&pubPassphrase2); err != nil {
tc.t.Errorf("%s: passphrase does not match", testName)
return false
}
// Change the private passphrase back to what it was.
err = walletdb.Update(tc.db, func(tx walletdb.ReadWriteTx) error {
ns := tx.ReadWriteBucket(waddrmgrNamespaceKey)
return tc.rootManager.ChangePassphrase(
ns, pubPassphrase2, pubPassphrase, false, fastScrypt,
)
})
if err != nil {
tc.t.Errorf("%s: unexpected error: %v", testName, err)
return false
}
testName = pfx + "ChangePassphrase (private) with invalid old passphrase"
err = walletdb.Update(tc.db, func(tx walletdb.ReadWriteTx) error {
ns := tx.ReadWriteBucket(waddrmgrNamespaceKey)
return tc.rootManager.ChangePassphrase(
ns, []byte("bogus"), privPassphrase2, true, fastScrypt,
ns, []byte("bogus"), privPassphrase2, fastScrypt,
)
})
wantErrCode := ErrWrongPassphrase
@ -1197,12 +1134,11 @@ func testChangePassphrase(tc *testContext) bool {
return false
}
// Change the private passphrase.
testName = pfx + "ChangePassphrase (private)"
testName = pfx + "ChangePassphrase"
err = walletdb.Update(tc.db, func(tx walletdb.ReadWriteTx) error {
ns := tx.ReadWriteBucket(waddrmgrNamespaceKey)
return tc.rootManager.ChangePassphrase(
ns, privPassphrase, privPassphrase2, true, fastScrypt,
ns, passphrase, privPassphrase2, fastScrypt,
)
})
if err != nil {
@ -1217,8 +1153,8 @@ func testChangePassphrase(tc *testContext) bool {
return tc.rootManager.Unlock(ns, privPassphrase2)
})
if err != nil {
tc.t.Errorf("%s: failed to unlock with new private "+
"passphrase: %v", testName, err)
tc.t.Errorf("%s: failed to unlock with new passphrase: %v",
testName, err)
return false
}
tc.unlocked = true
@ -1228,7 +1164,7 @@ func testChangePassphrase(tc *testContext) bool {
err = walletdb.Update(tc.db, func(tx walletdb.ReadWriteTx) error {
ns := tx.ReadWriteBucket(waddrmgrNamespaceKey)
return tc.rootManager.ChangePassphrase(
ns, privPassphrase2, privPassphrase, true, fastScrypt,
ns, privPassphrase2, passphrase, fastScrypt,
)
})
if err != nil {
@ -1269,7 +1205,7 @@ func testNewAccount(tc *testContext) bool {
// to derive account keys
err = walletdb.Update(tc.db, func(tx walletdb.ReadWriteTx) error {
ns := tx.ReadWriteBucket(waddrmgrNamespaceKey)
err := tc.rootManager.Unlock(ns, privPassphrase)
err := tc.rootManager.Unlock(ns, passphrase)
return err
})
if err != nil {
@ -1668,7 +1604,7 @@ func _TestManager(t *testing.T) {
{
name: "created with seed",
rootKey: rootKey,
privPassphrase: privPassphrase,
privPassphrase: passphrase,
},
}
@ -1688,7 +1624,7 @@ func testManagerCase(t *testing.T, caseName string,
// returned.
err := walletdb.View(db, func(tx walletdb.ReadTx) error {
ns := tx.ReadBucket(waddrmgrNamespaceKey)
_, err := Open(ns, pubPassphrase, &chaincfg.MainNetParams)
_, err := Open(ns, &chaincfg.MainNetParams)
return err
})
if !checkManagerError(t, "Open non-existent", err, ErrNoExist) {
@ -1703,13 +1639,13 @@ func testManagerCase(t *testing.T, caseName string,
return err
}
err = Create(
ns, caseKey, pubPassphrase, casePrivPassphrase,
ns, caseKey, casePrivPassphrase,
&chaincfg.MainNetParams, fastScrypt, time.Time{},
)
if err != nil {
return err
}
mgr, err = Open(ns, pubPassphrase, &chaincfg.MainNetParams)
mgr, err = Open(ns, &chaincfg.MainNetParams)
if err != nil {
return err
}
@ -1729,7 +1665,7 @@ func testManagerCase(t *testing.T, caseName string,
err = walletdb.Update(db, func(tx walletdb.ReadWriteTx) error {
ns := tx.ReadWriteBucket(waddrmgrNamespaceKey)
return Create(
ns, caseKey, pubPassphrase, casePrivPassphrase,
ns, caseKey, casePrivPassphrase,
&chaincfg.MainNetParams, fastScrypt, time.Time{},
)
})
@ -1762,7 +1698,7 @@ func testManagerCase(t *testing.T, caseName string,
err = walletdb.View(db, func(tx walletdb.ReadTx) error {
ns := tx.ReadBucket(waddrmgrNamespaceKey)
var err error
mgr, err = Open(ns, pubPassphrase, &chaincfg.MainNetParams)
mgr, err = Open(ns, &chaincfg.MainNetParams)
return err
})
if err != nil {
@ -1845,7 +1781,7 @@ func TestManagerHigherVersion(t *testing.T) {
// should expect to see the error ErrUpgrade.
err = walletdb.View(db, func(tx walletdb.ReadTx) error {
ns := tx.ReadBucket(waddrmgrNamespaceKey)
_, err := Open(ns, pubPassphrase, &chaincfg.MainNetParams)
_, err := Open(ns, &chaincfg.MainNetParams)
return err
})
if !checkManagerError(t, "Upgrade needed", err, ErrUpgrade) {
@ -1869,7 +1805,7 @@ func TestManagerHigherVersion(t *testing.T) {
// ErrUpgrade.
err = walletdb.View(db, func(tx walletdb.ReadTx) error {
ns := tx.ReadBucket(waddrmgrNamespaceKey)
_, err := Open(ns, pubPassphrase, &chaincfg.MainNetParams)
_, err := Open(ns, &chaincfg.MainNetParams)
return err
})
if !checkManagerError(t, "Upgrade needed", err, ErrUpgrade) {
@ -1913,7 +1849,7 @@ func TestEncryptDecryptErrors(t *testing.T) {
// Unlock the manager for these tests
err = walletdb.View(db, func(tx walletdb.ReadTx) error {
ns := tx.ReadBucket(waddrmgrNamespaceKey)
return mgr.Unlock(ns, privPassphrase)
return mgr.Unlock(ns, passphrase)
})
if err != nil {
t.Fatal("Attempted to unlock the manager, but failed:", err)
@ -1945,7 +1881,7 @@ func TestEncryptDecrypt(t *testing.T) {
// Make sure address manager is unlocked
err := walletdb.View(db, func(tx walletdb.ReadTx) error {
ns := tx.ReadBucket(waddrmgrNamespaceKey)
return mgr.Unlock(ns, privPassphrase)
return mgr.Unlock(ns, passphrase)
})
if err != nil {
t.Fatal("Attempted to unlock the manager, but failed:", err)
@ -1993,19 +1929,19 @@ func TestScopedKeyManagerManagement(t *testing.T) {
return err
}
err = Create(
ns, rootKey, pubPassphrase, privPassphrase,
ns, rootKey, passphrase,
&chaincfg.MainNetParams, fastScrypt, time.Time{},
)
if err != nil {
return err
}
mgr, err = Open(ns, pubPassphrase, &chaincfg.MainNetParams)
mgr, err = Open(ns, &chaincfg.MainNetParams)
if err != nil {
return err
}
return mgr.Unlock(ns, privPassphrase)
return mgr.Unlock(ns, passphrase)
})
if err != nil {
t.Fatalf("create/open: unexpected error: %v", err)
@ -2152,12 +2088,12 @@ func TestScopedKeyManagerManagement(t *testing.T) {
err = walletdb.View(db, func(tx walletdb.ReadTx) error {
ns := tx.ReadBucket(waddrmgrNamespaceKey)
var err error
mgr, err = Open(ns, pubPassphrase, &chaincfg.MainNetParams)
mgr, err = Open(ns, &chaincfg.MainNetParams)
if err != nil {
return err
}
return mgr.Unlock(ns, privPassphrase)
return mgr.Unlock(ns, passphrase)
})
if err != nil {
t.Fatalf("open: unexpected error: %v", err)
@ -2243,19 +2179,19 @@ func TestRootHDKeyNeutering(t *testing.T) {
return err
}
err = Create(
ns, rootKey, pubPassphrase, privPassphrase,
ns, rootKey, passphrase,
&chaincfg.MainNetParams, fastScrypt, time.Time{},
)
if err != nil {
return err
}
mgr, err = Open(ns, pubPassphrase, &chaincfg.MainNetParams)
mgr, err = Open(ns, &chaincfg.MainNetParams)
if err != nil {
return err
}
return mgr.Unlock(ns, privPassphrase)
return mgr.Unlock(ns, passphrase)
})
if err != nil {
t.Fatalf("create/open: unexpected error: %v", err)
@ -2336,19 +2272,19 @@ func TestNewRawAccount(t *testing.T) {
return err
}
err = Create(
ns, rootKey, pubPassphrase, privPassphrase,
ns, rootKey, passphrase,
&chaincfg.MainNetParams, fastScrypt, time.Time{},
)
if err != nil {
return err
}
mgr, err = Open(ns, pubPassphrase, &chaincfg.MainNetParams)
mgr, err = Open(ns, &chaincfg.MainNetParams)
if err != nil {
return err
}
return mgr.Unlock(ns, privPassphrase)
return mgr.Unlock(ns, passphrase)
})
if err != nil {
t.Fatalf("create/open: unexpected error: %v", err)
@ -2449,18 +2385,18 @@ func TestDeriveFromKeyPathCache(t *testing.T) {
return err
}
err = Create(
ns, rootKey, pubPassphrase, privPassphrase,
ns, rootKey, passphrase,
&chaincfg.MainNetParams, fastScrypt, time.Time{},
)
if err != nil {
return err
}
mgr, err = Open(ns, pubPassphrase, &chaincfg.MainNetParams)
mgr, err = Open(ns, &chaincfg.MainNetParams)
if err != nil {
return err
}
return mgr.Unlock(ns, privPassphrase)
return mgr.Unlock(ns, passphrase)
})
require.NoError(t, err, "create/open: unexpected error: %v", err)

View file

@ -33,19 +33,18 @@ func testWallet(t *testing.T) (*Wallet, func()) {
t.Fatalf("unable to create seed: %v", err)
}
pubPass := []byte("hello")
privPass := []byte("world")
passphrase := []byte("hello world")
loader := NewLoader(
&chaincfg.TestNet3Params, dir, true, defaultDBTimeout, 250,
)
w, err := loader.CreateNewWallet(pubPass, privPass, seed, time.Now())
w, err := loader.CreateNewWallet(passphrase, seed, time.Now())
if err != nil {
t.Fatalf("unable to create wallet: %v", err)
}
chainClient := &mockChainClient{}
w.chainClient = chainClient
if err := w.Unlock(privPass, time.After(10*time.Minute)); err != nil {
if err := w.Unlock(passphrase, time.After(10*time.Minute)); err != nil {
t.Fatalf("unable to unlock wallet: %v", err)
}

View file

@ -140,10 +140,10 @@ func (l *Loader) OnWalletCreated(fn func(walletdb.ReadWriteTx) error) {
l.walletCreated = fn
}
// CreateNewWallet creates a new wallet using the provided public and private
// passphrases. The seed is optional. If non-nil, addresses are derived from
// this seed. If nil, a secure random seed is generated.
func (l *Loader) CreateNewWallet(pubPassphrase, privPassphrase, seed []byte,
// CreateNewWallet creates a new wallet using the provided passphrase.
// The seed is optional. If non-nil, addresses are derived from this seed.
// If nil, a secure random seed is generated.
func (l *Loader) CreateNewWallet(passphrase, seed []byte,
bday time.Time) (*Wallet, error) {
var (
@ -168,20 +168,20 @@ func (l *Loader) CreateNewWallet(pubPassphrase, privPassphrase, seed []byte,
}
}
return l.createNewWallet(pubPassphrase, privPassphrase, rootKey, bday)
return l.createNewWallet(passphrase, rootKey, bday)
}
// CreateNewWalletExtendedKey creates a new wallet from an extended master root
// key using the provided public and private passphrases. The root key is
// optional. If non-nil, addresses are derived from this root key. If nil, a
// key using the provided passphrase. The root key is optional.
// If non-nil, addresses are derived from this root key. If nil, a
// secure random seed is generated and the root key is derived from that.
func (l *Loader) CreateNewWalletExtendedKey(pubPassphrase, privPassphrase []byte,
func (l *Loader) CreateNewWalletExtendedKey(passphrase []byte,
rootKey *hdkeychain.ExtendedKey, bday time.Time) (*Wallet, error) {
return l.createNewWallet(pubPassphrase, privPassphrase, rootKey, bday)
return l.createNewWallet(passphrase, rootKey, bday)
}
func (l *Loader) createNewWallet(pubPassphrase, privPassphrase []byte,
func (l *Loader) createNewWallet(passphrase []byte,
rootKey *hdkeychain.ExtendedKey, bday time.Time) (*Wallet, error) {
defer l.mu.Unlock()
@ -216,16 +216,15 @@ func (l *Loader) createNewWallet(pubPassphrase, privPassphrase []byte,
}
// Initialize the newly created database for the wallet before opening.
err = CreateWithCallback(
l.db, pubPassphrase, privPassphrase, rootKey,
l.chainParams, bday, l.walletCreated,
err = CreateWithCallback(l.db, passphrase, rootKey, l.chainParams,
bday, l.walletCreated,
)
if err != nil {
return nil, err
}
// Open the newly-created wallet.
w, err := Open(l.db, pubPassphrase, nil, l.chainParams, l.recoveryWindow)
w, err := Open(l.db, nil, l.chainParams, l.recoveryWindow)
if err != nil {
return nil, err
}
@ -241,11 +240,10 @@ func noConsole() ([]byte, error) {
return nil, errNoConsole
}
// OpenExistingWallet opens the wallet from the loader's wallet database path
// and the public passphrase. If the loader is being called by a context where
// standard input prompts may be used during wallet upgrades, setting
// canConsolePrompt will enables these prompts.
func (l *Loader) OpenExistingWallet(pubPassphrase []byte, canConsolePrompt bool) (*Wallet, error) {
// OpenExistingWallet opens the wallet from the loader's wallet database path.
// If the loader is being called by a context where standard input prompts may
// be used during wallet upgrades, setting canConsolePrompt will enables these prompts.
func (l *Loader) OpenExistingWallet(canConsolePrompt bool) (*Wallet, error) {
defer l.mu.Unlock()
l.mu.Lock()
@ -274,16 +272,16 @@ func (l *Loader) OpenExistingWallet(pubPassphrase []byte, canConsolePrompt bool)
var cbs *waddrmgr.OpenCallbacks
if canConsolePrompt {
cbs = &waddrmgr.OpenCallbacks{
ObtainSeed: prompt.ProvideSeed(),
ObtainPrivatePass: prompt.ProvidePrivPassphrase,
ObtainSeed: prompt.ProvideSeed(),
ObtainPassphrase: prompt.ProvidePassphrase,
}
} else {
cbs = &waddrmgr.OpenCallbacks{
ObtainSeed: noConsole,
ObtainPrivatePass: noConsole,
ObtainSeed: noConsole,
ObtainPassphrase: noConsole,
}
}
w, err := Open(l.db, pubPassphrase, cbs, l.chainParams, l.recoveryWindow)
w, err := Open(l.db, cbs, l.chainParams, l.recoveryWindow)
if err != nil {
// If opening the wallet fails (e.g. because of wrong
// passphrase), we must close the backing database to

View file

@ -36,16 +36,6 @@ import (
)
const (
// InsecurePubPassphrase is the default outer encryption passphrase used
// for public data (everything but private keys). Using a non-default
// public passphrase can prevent an attacker without the public
// passphrase from discovering all past and future wallet addresses if
// they gain access to the wallet database.
//
// NOTE: at time of writing, public encryption only applies to public
// data in the waddrmgr namespace. Transactions are not yet encrypted.
InsecurePubPassphrase = "public"
// recoveryBatchSize is the default number of blocks that will be
// scanned successively by the recovery manager, in the event that the
// wallet is started in recovery mode.
@ -99,8 +89,6 @@ const (
// complete wallet. It contains the Armory-style key store
// addresses and keys),
type Wallet struct {
publicPassphrase []byte
// Data stores
db walletdb.DB
Manager *waddrmgr.Manager
@ -134,7 +122,6 @@ type Wallet struct {
holdUnlockRequests chan chan heldUnlock
lockState chan bool
changePassphrase chan changePassphraseRequest
changePassphrases chan changePassphrasesRequest
NtfnServer *NotificationServer
@ -703,7 +690,7 @@ func (w *Wallet) recovery(chainClient chain.Interface,
// that a wallet rescan will be performed from the wallet's tip, which
// will be of bestHeight after completing the recovery process.
pass, err := prompt.ProvidePrivPassphrase()
pass, err := prompt.ProvidePassphrase()
if err != nil {
return err
}
@ -1188,16 +1175,9 @@ type (
changePassphraseRequest struct {
old, new []byte
private bool
err chan error
}
changePassphrasesRequest struct {
publicOld, publicNew []byte
privateOld, privateNew []byte
err chan error
}
// heldUnlock is a tool to prevent the wallet from automatically
// locking after some timeout before an operation which needed
// the unlocked wallet has finished. Any acquired heldUnlock
@ -1236,32 +1216,13 @@ out:
err := walletdb.Update(w.db, func(tx walletdb.ReadWriteTx) error {
addrmgrNs := tx.ReadWriteBucket(waddrmgrNamespaceKey)
return w.Manager.ChangePassphrase(
addrmgrNs, req.old, req.new, req.private,
addrmgrNs, req.old, req.new,
&waddrmgr.DefaultScryptOptions,
)
})
req.err <- err
continue
case req := <-w.changePassphrases:
err := walletdb.Update(w.db, func(tx walletdb.ReadWriteTx) error {
addrmgrNs := tx.ReadWriteBucket(waddrmgrNamespaceKey)
err := w.Manager.ChangePassphrase(
addrmgrNs, req.publicOld, req.publicNew,
false, &waddrmgr.DefaultScryptOptions,
)
if err != nil {
return err
}
return w.Manager.ChangePassphrase(
addrmgrNs, req.privateOld, req.privateNew,
true, &waddrmgr.DefaultScryptOptions,
)
})
req.err <- err
continue
case req := <-w.holdUnlockRequests:
if w.Manager.IsLocked() {
close(req)
@ -1362,45 +1323,16 @@ func (c heldUnlock) release() {
c <- struct{}{}
}
// ChangePrivatePassphrase attempts to change the passphrase for a wallet from
// ChangePassphrase attempts to change the passphrase for a wallet from
// old to new. Changing the passphrase is synchronized with all other address
// manager locking and unlocking. The lock state will be the same as it was
// before the password change.
func (w *Wallet) ChangePrivatePassphrase(old, new []byte) error {
func (w *Wallet) ChangePassphrase(old, new []byte) error {
err := make(chan error, 1)
w.changePassphrase <- changePassphraseRequest{
old: old,
new: new,
private: true,
err: err,
}
return <-err
}
// ChangePublicPassphrase modifies the public passphrase of the wallet.
func (w *Wallet) ChangePublicPassphrase(old, new []byte) error {
err := make(chan error, 1)
w.changePassphrase <- changePassphraseRequest{
old: old,
new: new,
private: false,
err: err,
}
return <-err
}
// ChangePassphrases modifies the public and private passphrase of the wallet
// atomically.
func (w *Wallet) ChangePassphrases(publicOld, publicNew, privateOld,
privateNew []byte) error {
err := make(chan error, 1)
w.changePassphrases <- changePassphrasesRequest{
publicOld: publicOld,
publicNew: publicNew,
privateOld: privateOld,
privateNew: privateNew,
err: err,
old: old,
new: new,
err: err,
}
return <-err
}
@ -3659,29 +3591,23 @@ func (w *Wallet) Database() walletdb.DB {
// CreateWithCallback is the same as Create with an added callback that will be
// called in the same transaction the wallet structure is initialized.
func CreateWithCallback(db walletdb.DB, pubPass, privPass []byte,
func CreateWithCallback(db walletdb.DB, privPass []byte,
rootKey *hdkeychain.ExtendedKey, params *chaincfg.Params,
birthday time.Time, cb func(walletdb.ReadWriteTx) error) error {
return create(
db, pubPass, privPass, rootKey, params, birthday, cb,
)
return create(db, privPass, rootKey, params, birthday, cb)
}
// Create creates an new wallet, writing it to an empty database. If the passed
// root key is non-nil, it is used. Otherwise, a secure random seed of the
// recommended length is generated.
func Create(db walletdb.DB, pubPass, privPass []byte,
rootKey *hdkeychain.ExtendedKey, params *chaincfg.Params,
birthday time.Time) error {
func Create(db walletdb.DB, privPass []byte, rootKey *hdkeychain.ExtendedKey,
params *chaincfg.Params, birthday time.Time) error {
return create(
db, pubPass, privPass, rootKey, params, birthday, nil,
)
return create(db, privPass, rootKey, params, birthday, nil)
}
func create(db walletdb.DB, pubPass, privPass []byte,
rootKey *hdkeychain.ExtendedKey, params *chaincfg.Params,
birthday time.Time,
func create(db walletdb.DB, privPass []byte, rootKey *hdkeychain.ExtendedKey,
params *chaincfg.Params, birthday time.Time,
cb func(walletdb.ReadWriteTx) error) error {
// If no root key was provided, we create one now from a random seed.
@ -3718,7 +3644,7 @@ func create(db walletdb.DB, pubPass, privPass []byte,
}
err = waddrmgr.Create(
addrmgrNs, rootKey, pubPass, privPass, params, nil,
addrmgrNs, rootKey, privPass, params, nil,
birthday,
)
if err != nil {
@ -3739,7 +3665,7 @@ func create(db walletdb.DB, pubPass, privPass []byte,
}
// Open loads an already-created wallet from the passed database and namespaces.
func Open(db walletdb.DB, pubPass []byte, cbs *waddrmgr.OpenCallbacks,
func Open(db walletdb.DB, cbs *waddrmgr.OpenCallbacks,
params *chaincfg.Params, recoveryWindow uint32) (*Wallet, error) {
var (
@ -3768,7 +3694,7 @@ func Open(db walletdb.DB, pubPass []byte, cbs *waddrmgr.OpenCallbacks,
return err
}
addrMgr, err = waddrmgr.Open(addrMgrBucket, pubPass, params)
addrMgr, err = waddrmgr.Open(addrMgrBucket, params)
if err != nil {
return err
}
@ -3786,7 +3712,6 @@ func Open(db walletdb.DB, pubPass []byte, cbs *waddrmgr.OpenCallbacks,
log.Infof("Opened wallet") // TODO: log balance? last sync height?
w := &Wallet{
publicPassphrase: pubPass,
db: db,
Manager: addrMgr,
TxStore: txMgr,
@ -3803,7 +3728,6 @@ func Open(db walletdb.DB, pubPass []byte, cbs *waddrmgr.OpenCallbacks,
holdUnlockRequests: make(chan chan heldUnlock),
lockState: make(chan bool),
changePassphrase: make(chan changePassphraseRequest),
changePassphrases: make(chan changePassphrasesRequest),
chainParams: params,
quit: make(chan struct{}),
}

View file

@ -45,18 +45,9 @@ func createWallet(cfg *config) error {
activeNet.Params, dbDir, true, cfg.DBTimeout, 250,
)
// Start by prompting for the private passphrase.
// Start by prompting for the passphrase.
reader := bufio.NewReader(os.Stdin)
privPass, err := prompt.PrivatePass(reader)
if err != nil {
return err
}
// Ascertain the public passphrase. This will either be a value
// specified by the user or the default hard-coded public passphrase if
// the user does not want the additional public data encryption.
pubPass, err := prompt.PublicPass(reader, privPass,
[]byte(wallet.InsecurePubPassphrase), []byte(cfg.WalletPass))
privPass, err := prompt.Passphrase(reader)
if err != nil {
return err
}
@ -70,7 +61,7 @@ func createWallet(cfg *config) error {
}
fmt.Println("Creating the wallet...")
w, err := loader.CreateNewWallet(pubPass, privPass, seed, bday)
w, err := loader.CreateNewWallet(privPass, seed, bday)
if err != nil {
return err
}
@ -88,9 +79,6 @@ func createSimulationWallet(cfg *config) error {
// Simulation wallet password is 'password'.
privPass := []byte("password")
// Public passphrase is the default.
pubPass := []byte(wallet.InsecurePubPassphrase)
netDir := networkDir(cfg.AppDataDir.Value, activeNet.Params)
// Create the wallet.
@ -105,7 +93,7 @@ func createSimulationWallet(cfg *config) error {
defer db.Close()
// Create the wallet.
err = wallet.Create(db, pubPass, privPass, nil, activeNet.Params, time.Now())
err = wallet.Create(db, privPass, nil, activeNet.Params, time.Now())
if err != nil {
return err
}