bitcoinjs / bitcoinjs-lib

A javascript Bitcoin library for node.js and browsers.
MIT License
5.66k stars 2.1k forks source link

Trust randombytes or mix it with the HW RNG? #1759

Closed landabaso closed 2 years ago

landabaso commented 2 years ago

I'm using bitcoinjs-lib together with HW wallets (and their js libraries).

I need to create a random address (not deterministic; unrelated to the user's HW wallet). Also, I know I can trust the user.

The obvious way would be to use ECPair.makeRandom but I'm a bit concerned about the user's RNG generator that I cannot control.

So I had this idea. Since the user has connected an HW wallet (a Ledger Nano, for example), I could indirectly use the HW random generator by creating a deterministic address from the Ledger where the derivation path is random.

This makes sense?

For example, you could use bip39.generateMnemonic to get 24 integers between 0 - 2047 and use these integers as the derivation path in getWalletPublicKey (from the ledger API). Thus, even if the user's browser RNG is not perfect, the generated address is still protected because it makes use of the Ledger Nano RNG (which is supposed to be very good).

Is it a good idea or am I missing something that could cause a disaster?

junderw commented 2 years ago

Think of the worst case scenario:

  1. User RNG always returns the same random number.
  2. Therefore your path is constant.
  3. Therefore your generated randomness will be deterministic to the user's HW wallet. (since you will always choose the same path)
  4. And since the path is known (anyone who uses the same RNG would get the same, so it would be easy to know) they can trick you into approving a "getWalletPublicKey" request 5 weeks from now when you forgot that the private key of some other app was based on your public key... then they learn of your private key.
landabaso commented 2 years ago

Thanks for replying Jonathan.

This could not happen because of the particular usage of the service I'm designing (I'm not accepting requests for getWalletPublicKey; it's all internal and it's only used once). But I understand your line of thought.

In the worst case scenario that the RNG is bad, then I'm in a slight better situation because of using RNG + HW RNG.

The address in that worst case scenario would not be 100% random which would be bad but not fatal in my application. So that's something!

The alternative is directly using the RNG. What kind of RNG do browser (computer) -based wallets use anyway?

junderw commented 2 years ago

The randombytes library used has logic to detect whether it is in a NodeJS context or browser.

In the browser case it uses WebCrypto API getRandomValues which is suitable for cryptographic key material (CSPRNG). In NodeJS it uses crypto.randomBytes which is also a CSPRNG.

junderw commented 2 years ago

makeRandom() uses randombytes by default.

landabaso commented 2 years ago

Yes! Thanks Jonathan. I guess using HW RNG as a wrapper over randomBytes does more good than harm.

I was just trying to make sure I wasn't missing something.

If a vulnerability is found in randomBytes in the future, it would be covered. That was the idea.

Thanks again.