Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug] BIP39 wallet with passphrase should not accept blank on re-enter the BIP39 passphrase window #603

Closed
tadeubas opened this issue Jun 18, 2022 · 16 comments

Comments

@tadeubas
Copy link

tadeubas commented Jun 18, 2022

When Sparrow asks to Re-enter the BIP39 passphrase, it should not accept blank! Otherwise when you click on Settings > Keystores > View Seed... you will see the text "Passphrase entered" but the wallet will be the same as a "No passphrase" causing misunderstanding to the user.

Also the text of BIP39 passphrase window should always be the same "Re-enter", and not the "Enter" txt that apeears when you open Sparrow with an imported wallet loaded... also, none of them should accept a blank password.

image

image

image

image

Sparrow 1.6.5

@tadeubas tadeubas changed the title [BUG] BIP39 wallet with passphrase should not accept blank on re-enter the BIP39 passphrase window [Bug] BIP39 wallet with passphrase should not accept blank on re-enter the BIP39 passphrase window Jun 18, 2022
@sutterseba
Copy link

Not sure what you mean. When opening a wallet file, you're only asked once for the passphrase. Leaving blank here is perfectly fine and actually part of the whole idea (e.g. plausible deniability).

When importing a new keystore, you're asked for the passphrase twice and you'll receive an error if the phrases do not match, including your case of leaving it blank the second time. I tried reproducing this on MacOS and Win 10.

Screenshot 2022-06-18 at 21 29 18

I agree that Passphrase entered may seem confusing if you didn't even enter one. But the user should still be able to see that he was prompted for a passphrase and that the feature is enabled for the current keystore. Maybe changing this to Passphrase enabled but left blank would be best.

@tadeubas
Copy link
Author

tadeubas commented Jun 18, 2022

You forgot the scenario from File > Import Wallet..., because in this scenario the Sparrow first asks for a Wallet password, then it asks for the BIP39 passphrase.

image

The scenario you tested it asks for the BIP39 passphrase right away and give a feedback if it doesn't match. The problem is that the passphrase must be required if the user informed that the wallet has a passphrase (especially on the scenario from File > Import Wallet... when you informed the passphrase with the 12 words). Regarding plausible deniability, you can type anything, it is just a required field because that wallet has a passphrase, this also avoid the user confusion with the password of the wallet.

@sutterseba
Copy link

Oh, now I understand! That is certainly a bug and even potentially dangerous because if a user misspells his passphrase this way (the second time) he will not be aware of his mistake and may send funds to the wrong wallet.

The re-enter prompt is basically completely missing here since the "second" prompt is just the default prompt as if you were regularly opening the wallet file.

@h76oeI6pMxU9g4p8aCpc6Q
Copy link

h76oeI6pMxU9g4p8aCpc6Q commented Jun 21, 2022

I think the best solution is storing the "complelete HD wallet" (The HD seed from BIP39 + passphrase) to the *.mv.db file.
User only require to enter the wallet encrypt password (If had set when import wallet) to decrypt the wallet.

In order to reducing the chances of user mistyping the BIP39 passphrase when BIP 39 wallet import. I suggest user need to type twice of the BIP39 passphrase when wallet import. Just same as the of the wallet encrypt password setting scheme.

The HD seed from this "BIP39 + passphrase" should only create "once" when wallet import, then save the "complelete" HD wallet to *.mv.db file.

Current Sparrow wallet (1.6.5) has create a new HD seed each time from user enter passphrase when user opening the wallet file (*.mv.db file). This is completely unnecessary, and need to remove this function on the future version.

User don't required to re-enter the BIP39 passphrase anymore when open the wallet file (*.mv.db) because sparrow should not create HD seed is this time.

The wallet is still encrypted using the wallet password. So there is no security reduction of the sparrow wallet.

@tadeubas
Copy link
Author

@Bzvwf16WSDKoSZd8 I disagree with your solution because it removes the possibility of a plausible deniability, unless if implemented another way, like using the wallet password (BlueWallet has an app password to do plausible deniability).

Now I wondered what Sparrow does when it is closed and I was using a wallet with a BIP39 passphrase... It only saves the wallet seed encrypted and then constructs the wallet with passphrase everytime in memory only when the user types the BIP39 passphrase?

@sutterseba
Copy link

sutterseba commented Jun 21, 2022

The wallet is still encrypted using the wallet password.

But the whole point of an optional passphrase is to act as a second factor and/or plausible deniability, which as @tadeubas already explained, would be mitigated. Software or hardware wallets should not remember your passphrase, that's part of the use case, unless you specifically want them to (e.g. Ledger Attach to PIN).

@h76oeI6pMxU9g4p8aCpc6Q
Copy link

h76oeI6pMxU9g4p8aCpc6Q commented Jun 21, 2022

@tadeubas Look at this reddit post.
https://www.reddit.com/r/Bitcoin/comments/tpr446/psa_be_extremely_careful_when_entering_your/

The user mistyping BIP39 passphrase seems to be the bigger problem than the plausible deniability at the moment.
Some of the other wide used bitcoin wallet, such as blue wallet, also just need user ether BIP39 passphrase once when import.

BIP39 Wallet haven't store any passphrase in plain-text. It just store the 512 bit BIP32 HD seed.
This is the code from the BIP39 Reference Implementation
https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki#Reference_Implementation
https://github.com/trezor/python-mnemonic/blob/master/src/mnemonic/mnemonic.py#L222

    def to_seed(cls, mnemonic: str, passphrase: str = "") -> bytes:
        mnemonic = cls.normalize_string(mnemonic)
        passphrase = cls.normalize_string(passphrase)
        passphrase = "mnemonic" + passphrase
        mnemonic_bytes = mnemonic.encode("utf-8")
        passphrase_bytes = passphrase.encode("utf-8")
        stretched = hashlib.pbkdf2_hmac(
            "sha512", mnemonic_bytes, passphrase_bytes, PBKDF2_ROUNDS
        )
        return stretched[:64]

The plausible deniability using BIP39 passphrase when wallet opening time should be disable by default and only enable manually by user.

On my solution, I suggest "user need to type twice of the BIP39 passphrase when wallet import as same as the of the wallet encrypt password setting scheme to reducing the chances of user mistyping.

@h76oeI6pMxU9g4p8aCpc6Q
Copy link

h76oeI6pMxU9g4p8aCpc6Q commented Jun 21, 2022

@sutterseba This.
#603 (comment)

@tadeubas
Copy link
Author

tadeubas commented Jun 21, 2022

@Bzvwf16WSDKoSZd8 Thx to let us known these users cases... I opened this issue because I was also confused about the way Sparrow deals with the BIP39 passphrase via Import Wallet... functionality. I didn't know that Sparrow had plausible deniability until @sutterseba said that to me on this issue... The plausible deniability is implemented in various ways across wallets, but the way currently employed by Sparrow is creating some misunderstanding to the users, and unfortunately some of them are losing sats because of the way it currently works.

I think the solution is up to the Sparrow main developer to decide, but definitely the way Sparrow implemented BIP39 passphrase and plausible deniability with this passphrase is causing issues with the users... maybe BIP39 passphrase must always be typed twice to avoid mistakes? Also would be good to have an eye icon to "show/hide the password" like we see on phones. Plausible deniability could be implemented with the wallet password instead of BIP39 passphrase...

@craigraw what do you think would be the best way to solve this issue of the user mistyping the BIP39 passphrase?

@craigraw
Copy link
Collaborator

With respect to using BIP39 passphrases on Sparrow, the current design maximises security (at the expense of, for example, telling the user they have entered an incorrect passphrase). Unfortunately there is no perfect solution here.

First off, it makes no sense at all to store the passphrase in the wallet file. In that case it simply acts as a 25th word, and 24 words already provide more than sufficient entropy. The point of the passphrase is to create the well known "something I have + something I know" security paradigm. In this case, the wallet file is something you have, and the passphrase is something you know. So let's put that aside.

Secondly, there is an argument that Sparrow should store something derived from the passphrase (not the passphrase itself). For example, Sparrow could store the master fingerprint of the seed (derived from the BIP39 words + passphrase) which is a 4 byte value that should (with some rare collisions) identify whether an entered passphrase is correct. But there is a significant cost to doing so in reducing security by making a brute force attack easier.

To explain further, a Sparrow Wallet *.mv.db file stores nothing derived from the passphrase. This means that if the wallet file is decrypted, a brute force attack to locate any funds must not only calculate the seed from the BIP39 words + passphrase, but also calculate addresses and search for any funds on the blockchain. The first part of this (deriving the seed) is computationally inexpensive, since BIP39 uses the PBKDF2 algorithm which is now very old and simple to execute, even with the prescribed 2048 rounds. (By the way, this is a issue with Electrum's wallet file encryption, but I digress). If Sparrow stored the derived master fingerprint in the wallet file, then a brute force attack could simply iterate passphrase guesses until it found one that matched the master fingerprint. Without this information however, it also needs to (at least) generate the first address and search the entire blockchain for a transaction output to it. This is not only computationally much more expensive, but also scales as the blockchain grows, giving some protection as computing resources inevitably become cheaper and brute force attacks become easier over time.

Although Sparrow does not have the information to tell you if you have entered an incorrect passphrase, it can see if, on loading a wallet, the retrieved transaction history is entirely different from that stored in the wallet file. If it detects this, it does a full refresh of the wallet, discarding all stored transaction history and loading everything from the server again. So if you enter an incorrect passphrase, you will be presented with an empty wallet as soon as the refresh begins. This speaks somewhat to plausible deniability, but really is just the best Sparrow can do given it is maximising security over other aspects of passphrase use.

The question you need to ask yourself is whether you are prepared to give up security for UX - which is a difficult question to answer in general, since it ultimately depends on the amount of entropy contained in a given passphrase.

@tadeubas
Copy link
Author

tadeubas commented Jun 22, 2022

@craigraw thx a lot for the explanations! Without changing the way Sparrow works, which is awesome, I think that asking for the user to always type twice the BIP39 passphrase is enough (so Sparrow UI only check if the user typed 2 times the same passphrase, otherwise asks to type the passphrase the first and second time again). This would avoid mistyping by the user (the Reddit showed 2 users that lost funds because of mistyping... it is a lot harder to mistype equally 2 times the same passphrase). Also an eye option to click (show/hide) the password the user is typing would be great to avoid mistyping, this without not compromise the Sparrow security neither plausible deniability because it is just an UI change. What do you think?

@h76oeI6pMxU9g4p8aCpc6Q
Copy link

h76oeI6pMxU9g4p8aCpc6Q commented Jun 22, 2022

@craigraw But Sparrow already using a strong encryption "Argon2" (winner of the Password Hashing Competition in 2015), The situation you mentioned unlikely to happen in the most cases when the user provides a strong password.

I strongly agree that security is very important, but also to strike a balance between user experience.
I think there have two main types of bitcoin wallet user currently.

  1. Users who have a huge amount of bitcoin.
  2. Users who "NOT" have a huge amount of bitcoin.

For case 1)
This type of users may use Sparrow wallet only as watch-only wallet. They will storing their seed on metal backup and signing their transaction (*.psbt) "air-gapped" using their own hardware wallet (coldcard, passport, trezor...) rather then just using Sparrow wallet.

For case 2)
This type of users may use Sparrow wallet only as hot wallet with daily spending. They need a smooth user experience than extreme level of security, They still have a option to set a wallet password secure their wallet using sparrow wallet strong encryption "Argon2".

The user need to typing BIP39 passphrase on Sparrow wallet is obviously the second type of users.

@craigraw
Copy link
Collaborator

I given this a lot of thought, and ultimately I don't want to reduce Sparrow's potential security for ease of use. Many users may store significant amounts in software wallets (especially those using Whirlpool) and not everyone can afford hardware wallets. Further, a common security practice is "defence in depth" which in this case suggests one might choose to not rely not on the wallet password alone. Ultimately, it's a choice I don't want to take away from the user.

With respect to the OP's points, Sparrow is here asking for the passphrase as per the normal wallet load sequence, which it uses even when importing from a seed. I'll need to see whether it makes sense to complicate the load process to handle this special case. I agree the password dialog should not accept an empty password, and reflecting an empty passphrase with a "No passphrase" message on the seed view dialog seems a reasonable improvement.

@h76oeI6pMxU9g4p8aCpc6Q
Copy link

h76oeI6pMxU9g4p8aCpc6Q commented Jun 24, 2022

@craigraw Thank you for the explanation. I just don't know why Sparrow can giving users a choice to disable the wallet encrytion, but can't giving users a choice to disable BIP39 passphrase plausible deniability?

Both are related to security right?

@craigraw
Copy link
Collaborator

craigraw commented Jul 3, 2022

Yes, they are related to security, but otherwise not closely related. It is really just a convenience factor that causes some wallets to conflate passwords and passphrases.

Passphrase plausible deniability is difficult to support well given the above considerations (Sparrow must receive a response from the server before it can refresh the wallet). That said, it is simple enough to achieve some form of it by just using two passphrases. Adding a further layer of configuration for no passphrase wallets to optionally request a passphrase will further complicate things, and I'm not sure this would materially improve things.

@craigraw
Copy link
Collaborator

craigraw commented Jul 5, 2022

As of 9022438:

  1. Password field cannot be empty on encrypted wallet load
  2. The passphrase will not be re-requested on importing a BIP39 wallet
  3. Empty passphrases will be shown as "No Passphrase" in the seed view dialog

@craigraw craigraw closed this as completed Jul 5, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants
@craigraw @tadeubas @h76oeI6pMxU9g4p8aCpc6Q @sutterseba and others