Bitcoin Forum
September 21, 2021, 05:16:23 AM *
News: Latest Bitcoin Core release: 22.0 [Torrent]
 
   Home   Help Search Login Register More  
Pages: [1]
  Print  
Author Topic: Best practice for setting up a seed for a JavaScript wallet (apart from don't)  (Read 1362 times)
edmundedgar
Sr. Member
****
Offline Offline

Activity: 352
Merit: 250


https://www.realitykeys.com


View Profile WWW
July 26, 2014, 01:30:16 AM
Last edit: July 26, 2014, 01:47:55 AM by edmundedgar
 #1

I'll do a proper announcement later but I'm working on a little JavaScript app for setting up smart contracts with your future self.

The idea is that you set a goal for yourself, eg. Run a total of 100 km by the end of the month, and lock up some money in the bitcoin network that you'll forfeit (to charity) unless you reach your goal. You track your exercise activity on RunKeeper, which is in turn monitored by Reality Keys or similar, who provide keys that will let you unlock the money if you succeed or let the designated charity unlock the money if you fail.

The app is pure static HTML / JavaScript, built on top of bitcore.js. (It's hosted on GitHub, but in theory you could run it locally.) Since it needs to some things that a conventional wallet couldn't do, like talking to Reality Keys and signing fancy branching multisig transactions, it implements its own little wallet, with keys generated from a seed that's stored in local storage in the browser.

Security-wise things like "browser" and "local storage" are obviously sub-optimal, but we're generally not talking about huge amounts of money. Nevertheless, I'd like to avoid helping users lose their money to unforced errors. How would people suggest handling the creation of a seed? Should we let the user type something in, or are we better letting JavaScript do its best at making something random? Any suggestions for things I should / shouldn't be doing here, and any good examples out there I should be learning from?

Here's the app in its current state:
https://bitpact.github.io/
https://github.com/bitpact/bitpact.github.io
1632201383
Hero Member
*
Offline Offline

Posts: 1632201383

View Profile Personal Message (Offline)

Ignore
1632201383
Reply with quote  #2

1632201383
Report to moderator
1632201383
Hero Member
*
Offline Offline

Posts: 1632201383

View Profile Personal Message (Offline)

Ignore
1632201383
Reply with quote  #2

1632201383
Report to moderator
Advertised sites are not endorsed by the Bitcoin Forum. They may be unsafe, untrustworthy, or illegal in your jurisdiction. Advertise here.
1632201383
Hero Member
*
Offline Offline

Posts: 1632201383

View Profile Personal Message (Offline)

Ignore
1632201383
Reply with quote  #2

1632201383
Report to moderator
1632201383
Hero Member
*
Offline Offline

Posts: 1632201383

View Profile Personal Message (Offline)

Ignore
1632201383
Reply with quote  #2

1632201383
Report to moderator
1632201383
Hero Member
*
Offline Offline

Posts: 1632201383

View Profile Personal Message (Offline)

Ignore
1632201383
Reply with quote  #2

1632201383
Report to moderator
Envrin
Sr. Member
****
Offline Offline

Activity: 318
Merit: 250



View Profile
July 26, 2014, 04:18:06 AM
 #2

Why is everyone in the Bitcoin community fixated on Javascript based signing / cryptography?  It's just an all around bad idea.  Here:

http://matasano.com/articles/javascript-cryptography/

edmundedgar
Sr. Member
****
Offline Offline

Activity: 352
Merit: 250


https://www.realitykeys.com


View Profile WWW
July 26, 2014, 06:13:39 AM
Last edit: July 26, 2014, 08:44:23 AM by edmundedgar
 #3

Why is everyone in the Bitcoin community fixated on Javascript based signing / cryptography?  It's just an all around bad idea.  Here:

http://matasano.com/articles/javascript-cryptography/

People are interested in doing it this way because it's more practical for a lot of use-cases than getting people to install an native application, and more transparent and less centralized than keeping the users' secrets on somebody's server.

That said, I like Matasano's suggestion that your browser could do PGP, which would be great for the use-cases he's discussing, and there's probably a good analogous solution for bitcoin and similar, rather than a lot of people delivering their own similar JavaScript implementations. The security issues here are quite complicated to analyse, but one promising project is Yurii Rashkovskii's Bitcoin Wallet API, which is a little browser-extension bridge to your local wallet software:
https://bitcoin-wallet-api.github.io/
DeathAndTaxes
Donator
Legendary
*
Offline Offline

Activity: 1218
Merit: 1013


Gerald Davis


View Profile
July 26, 2014, 08:08:27 PM
Last edit: July 26, 2014, 08:27:44 PM by DeathAndTaxes
 #4

First I would look into implementing RFC6979 (Deterministic ECDSA Signatures).  It produces a deterministic but secret k value as an alternative to using a nonce in ECDSA signatures.  That reduces your attack space down to the user's key(s).  I am unsure why you would need more than one key but it doesn't change much.

A shuffled deck of cards has 225 bits of entropy and would be far superior to any javascript PRNG however that may not be practical.  

If you must generate the user's key in browser then there aren't many particularly good solutions but one general concept you may want to look at is to use multiple entropy sources which are XORed together.   As an example you could use javascript PRNG but it is very difficult to verify how secure that is on all browsers, all versions, all OSes.  On the other hand you could have the user provide entropy (random mouse movements, entering random text).  Each method has vulnerabilities.  If you have the user enter 200 charecters some users is going to enter aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, you should count on an attacker doing a preimage attack.  On the other hand if you use the PRNG and it is compromised on some systems than those resulting keys may be breakable.

Instead you would combine the two independent sources and the entropy of the resulting value will be at least as good as the entropy of the higher entropy source.  The simplest option would be to XOR each source but depending on the libraries you have access to I would prefer using something like a HMAC.  So even if both sources have sub par entropy the combined value would be better than either source by itself.  You can even use semi-trusted public numbers like pulling from random.org as long as they properly combined with other entropy sources.

As far as storing in browser local storage make sure you give the user a (strongly encouraged) option to print out the seed.  You wouldn't want a loss of funds due to local storage data loss.
rapport
Full Member
***
Offline Offline

Activity: 157
Merit: 100


View Profile
July 27, 2014, 08:51:02 AM
 #5

How is the quality of bitaddress.org ?
Maybe good to get some practices from it.
edmundedgar
Sr. Member
****
Offline Offline

Activity: 352
Merit: 250


https://www.realitykeys.com


View Profile WWW
July 31, 2014, 01:11:37 PM
Last edit: July 31, 2014, 01:46:14 PM by edmundedgar
 #6

Thanks for the suggestions, especially the excellent DeathAndTaxes post that everybody doing this stuff should read, but whose wisdom I'm going to mostly ignore (see below):

It looks like I'm going to end up copying the Counterwallet implementation, which seems to be reasonably well thought-out, and based on other things that also seem well-thought-out and hopefully at least somewhat scrutinized.
https://counterwallet.co/
https://github.com/CounterpartyXCP/counterwallet/blob/master/src/js/mnemonic.js

They seem to be relying on the browser's random number generation, but blowing up if you've got a browser that isn't capable of producing anything remotely like a random number. This then shows up to the user as a twelve-word mnemonic, which it sternly warns you to write down and not leak.

I take DeathAndTaxes's point that it might be worthwhile to have more randomness sources mixed in, but I'm going to pass on doing that myself on the grounds that the risk of my implementation somehow screwing things up trying to do this myself is probably greater than the benefit here.

Likewise on deterministic k values I'm going to defer to bitcore.js, which looks like it has an open issue:
https://github.com/bitpay/bitcore/issues/311
...and to prove what a PITA it is to get this right, a serious related security bug that's now fixed:
https://github.com/bitpay/bitcore/pull/309
DeathAndTaxes
Donator
Legendary
*
Offline Offline

Activity: 1218
Merit: 1013


Gerald Davis


View Profile
July 31, 2014, 02:35:08 PM
Last edit: July 31, 2014, 03:33:44 PM by DeathAndTaxes
 #7

Likewise on deterministic k values I'm going to defer to bitcore.js, which looks like it has an open issue:
https://github.com/bitpay/bitcore/issues/311
...and to prove what a PITA it is to get this right, a serious related security bug that's now fixed:
https://github.com/bitpay/bitcore/pull/309

I am not sure if you misread read the pulls or you worded it strangely which may confuse someone else.

Issue #309 has nothing to do with RFC6979.  The code involves generating a random k value but was done improperly that under certain conditions would result in leaking k (and through k the private key).  The fixed code in #309 also doesn't use RFC6979 it still uses random k value however that one particular flaw has been fixed.   A suggestion in #309 was made to move from random k value to a deterministic signature to avoid an entire class of bugs similar to #309 which could leak the private key.  #311 isn't a "bug" but rather an open improvement note.  It will be closed once bitcore implements RFC6979.

I will take a moment to advocate unit tests and TDD.  Bitcoin is too easy to get wrong enough that someone loses money, but right enough that is "works".  Unit Tests are essential for crypto currency development.  The error #309 could have been prevented with a unit test that uses a single key to sign multiple hashes in sequence and then verify the resulting set of signatures (r,s) are unique.   It looks like they have added a similar unit test.  The larger problem is that getting good code coverage on non-deterministic functions (like signatures which are non-deterministic due to a random input) is difficult.  You can write tests but it is hard to know if your tests are adequate.   RFC6979 makes signatures deterministic.  For a given input (message & key) there is only a single correct output (signature).  This means bugs slipping through cracks in the code coverage is reduced.

There are some community test for Bitcoin specific RFC6979.  You should get the same signature on all platforms and if you don't well that is great because it is a visible failure rather than one which breaks "silently".
https://bitcointalk.org/index.php?topic=285142.msg3299061#msg3299061
https://bitcointalk.org/index.php?topic=285142.msg3300992#msg3300992
 
edmundedgar
Sr. Member
****
Offline Offline

Activity: 352
Merit: 250


https://www.realitykeys.com


View Profile WWW
July 31, 2014, 02:43:37 PM
 #8

Likewise on deterministic k values I'm going to defer to bitcore.js, which looks like it has an open issue:
https://github.com/bitpay/bitcore/issues/311
...and to prove what a PITA it is to get this right, a serious related security bug that's now fixed:
https://github.com/bitpay/bitcore/pull/309

I am not sure if you misread read the pulls or you worded it strangely which may confuse someone else.

The second one, but thanks for putting it clearly.
DeathAndTaxes
Donator
Legendary
*
Offline Offline

Activity: 1218
Merit: 1013


Gerald Davis


View Profile
July 31, 2014, 03:27:09 PM
Last edit: July 31, 2014, 04:10:19 PM by DeathAndTaxes
 #9

The second one, but thanks for putting it clearly.

No problem.  It would appear bitcoinjs implements RFC6979 and uses a deterministic k for all signing.  Always do you own verification but it may allow you to use RFC6979 without reinventing the wheel.
https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/src/ecdsa.js
edmundedgar
Sr. Member
****
Offline Offline

Activity: 352
Merit: 250


https://www.realitykeys.com


View Profile WWW
July 31, 2014, 04:04:26 PM
 #10

The second one, but thanks for putting it clearly.

No problem.  It would appear bitcoinjs implements RFC6979 and uses a deterministic k for all signing.  Always do you own verification but it may allow you to use RFC6979 without reinventing the wheel.
https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/src/ecdsa.js


Cheers, I'll take a look.
Pages: [1]
  Print  
 
Jump to:  

Powered by MySQL Powered by PHP Powered by SMF 1.1.19 | SMF © 2006-2009, Simple Machines Valid XHTML 1.0! Valid CSS!