Pages:
Author

Topic: [ANN] bitaddress.org Safe JavaScript Bitcoin address/private key - page 44. (Read 152965 times)

sr. member
Activity: 437
Merit: 415
1ninja
The problem looks fairly straightforward, have a peek at ec.PointFp.prototype.getEncoded:

Code:
            ec.PointFp.prototype.getEncoded = function (compressed) {
                var x = this.getX().toBigInteger();
                var y = this.getY().toBigInteger();

                if (compressed) {
                    var PC;
                }

                var len = this.getX().getByteLength();

                var enc = ec.integerToBytes(x, len);

                if (compressed) {
                    if (y.testBit(0)) {
                        enc.unshift(0x02);
                    } else {
                        enc.unshift(0x03);
                    }
                } else {
                    enc.unshift(0x04);
                    enc = enc.concat(ec.integerToBytes(y, len));
                }
                return enc;
            };

Note the code is pulling len from X, and using that length for both X and Y.  This is definitely going to be the problem.  The length needs to be tested for each coordinate separately (Y should not be using X's length), and zero-padded if it's less than 32.  (Will integerToBytes behave properly if you just throw 32 as the second parameter, rather than len?)  (Also the possibility of having more than one zero byte needs to be considered.  Rare, but the consequences are disastrous if it happens, so it must be handled properly... if throwing 32 in there works, then that should do it, but if not... needs to be checked)

The part that tests compressed can be chucked - Bitcoin doesn't support compressed encoding.

Thank you SO much for this analysis! Thanks to TTBit as well for discovering these two issues.

I can confirm that passing 32 as the length for X and Y will give the proper public key for this private key: 5Je7CkWTzgdo1RpwjYhwnVKxQXt8EPRq17WZFtWcq5umQdsDtTP
It also is working for other private keys who's two points are 32 bytes in length (obviously).

So, seems we have solved one nasty bug. I will do some more testing and investigation of the private key issue where the WIF starts with a 'y'.
vip
Activity: 1386
Merit: 1135
The Casascius 1oz 10BTC Silver Round (w/ Gold B)
The problem looks fairly straightforward, have a peek at ec.PointFp.prototype.getEncoded:

Code:
            ec.PointFp.prototype.getEncoded = function (compressed) {
                var x = this.getX().toBigInteger();
                var y = this.getY().toBigInteger();

                if (compressed) {
                    var PC;
                }

                var len = this.getX().getByteLength();

                var enc = ec.integerToBytes(x, len);

                if (compressed) {
                    if (y.testBit(0)) {
                        enc.unshift(0x02);
                    } else {
                        enc.unshift(0x03);
                    }
                } else {
                    enc.unshift(0x04);
                    enc = enc.concat(ec.integerToBytes(y, len));
                }
                return enc;
            };

Note the code is pulling len from X, and using that length for both X and Y.  This is definitely going to be the problem.  The length needs to be tested for each coordinate separately (Y should not be using X's length), and zero-padded if it's less than 32.  (Will integerToBytes behave properly if you just throw 32 as the second parameter, rather than len?)  (Also the possibility of having more than one zero byte needs to be considered.  Rare, but the consequences are disastrous if it happens, so it must be handled properly... if throwing 32 in there works, then that should do it, but if not... needs to be checked)

The part that tests compressed can be chucked - Bitcoin doesn't support compressed encoding.
sr. member
Activity: 437
Merit: 415
1ninja
Am I doing this right?

according to bitaddress.org, the address is:12DM8vG8pytcE8Q9CBj2LQnctiRRdoZ5aZ
with private key of: 5Je7CkWTzgdo1RpwjYhwnVKxQXt8EPRq17WZFtWcq5umQdsDtTP

However, pywallet doesn't agree:
Code:
C:\Python27>pywallet.py --info --importprivkey=5Je7CkWTzgdo1RpwjYhwnVKxQXt8EPRq1
7WZFtWcq5umQdsDtTP
'ecdsa' package is not installed, pywallet won't be able to sign/verify messages

Address (Bitcoin): 1M6dsMZUjFxjdwsyVk8nJytWcfr9tfUa9E
Privkey (Bitcoin): 5Je7CkWTzgdo1RpwjYhwnVKxQXt8EPRq17WZFtWcq5umQdsDtTP
Hexprivkey: 6c9565b3eef4ef9e01c216e1910763a5f94cf3654c059e8c67a348d10ae39c28

edit: seems to work for further addresses. I printed the one above out, so I'm not crazy, looking at it now.

This applies to V0.1 to V0.4 of bitaddress.org and also applies to the bitcoinjs-lib open source library on github.

With regards to this private key: 5Je7CkWTzgdo1RpwjYhwnVKxQXt8EPRq17WZFtWcq5umQdsDtTP
The JavaScript function "ECKey.prototype.getPub" in the Bitcoin object is not returning the correct public key byte array. It's returning a public key of length 63 instead of length 65. That function relies on the Elliptic Curve JavaScript library. At this moment I haven't identified where the issue is so I'm going to implement a workaround to look for the bad public key and just discard the key pair and generate another one.

In this case here is the JavaScript public key (bad):
Code:
04    76 d4 85 2e 6e 03 11 e0 80 03 6e fe c9 6a 33 95 40 17 6c f5 3e b7 18 25 80 bc 81 32 6e c9 b1    78 df 59 18 e1 8e f1 f5 7a e0 59 15 41 d2 68 de e5 28 bf 5c 29 e9 63 89 99 46 d3 00 f9 03 58

Here is Casascius public key from his C# utility (good):
Code:
04 00 76 D4 85 2E 6E 03 11 E0 80 03 6E FE C9 6A 33 95 40 17 6C F5 3E B7 18 25 80 BC 81 32 6E C9 B1 6D 78 DF 59 18 E1 8E F1 F5 7A E0 59 15 41 D2 68 DE E5 28 BF 5C 29 E9 63 89 99 46 D3 00 F9 03 58

sr. member
Activity: 437
Merit: 415
1ninja
Thanks for the bug find... I'm working on it.
Please don't use v0.1 to V0.4
vip
Activity: 1386
Merit: 1135
The Casascius 1oz 10BTC Silver Round (w/ Gold B)

pywallet lets me import a key beginning with 'y', but returns a different Privkey

C:\Python27>pywallet.py --info --importprivkey yP536D6V88rqcJ3qFfBYuJ6pqdg6z2SZn
m2SKDU4vRoCE9L89
'ecdsa' package is not installed, pywallet won't be able to sign/verify messages

Address (Bitcoin): 1NAjZjF81YGfiJ3rTKc7jf1nmZ26KN7Gkn
Privkey (Bitcoin): 5HpJ4bpHFEMWYwCidjtZHwM2rsMh4PRfmZKV8Y21i7msiUkQKUW
Hexprivkey: 0004d30da67214fa65a41a6493576944c7ea86713b14db437446c7a8df8e13da

I'm interested in what is going on here.

I figured it out.  Yes it's a private key that starts with a 00 byte, see red above.  Normally a private key is a base58+check string with 32 bytes of payload (besides the identifier byte 0x80).  The private keys starting with 'y' are well-formed base58+check strings with only 31 bytes of payload.  If the base58 is decoded and the missing byte assumed to be 00, the key decodes.  When a utility re-renders the original private key, it ends up having the full 32-bytes and will start with 5.

I made a little modification to my Bitcoin Address Utility and confirmed this behavior.

So, someone who uses a private key starting with 'y' is safe and doesn't lose their bitcoins because the original private key can be calculated.

Unfortunately, someone who gets the wrong Bitcoin address because a coordinate of the public key started with 00 will lose their bitcoins if they send to the address, because it is not the address that properly corresponds to the key pair.

legendary
Activity: 1136
Merit: 1001
pywallet lets me import a key beginning with 'y', but returns a different Privkey

Code:
C:\Python27>pywallet.py --info --importprivkey yP536D6V88rqcJ3qFfBYuJ6pqdg6z2SZn
m2SKDU4vRoCE9L89
'ecdsa' package is not installed, pywallet won't be able to sign/verify messages

Address (Bitcoin): 1NAjZjF81YGfiJ3rTKc7jf1nmZ26KN7Gkn
Privkey (Bitcoin): 5HpJ4bpHFEMWYwCidjtZHwM2rsMh4PRfmZKV8Y21i7msiUkQKUW
Hexprivkey: 0004d30da67214fa65a41a6493576944c7ea86713b14db437446c7a8df8e13da

I'm interested in what is going on here.

EDIT: The hex seems to always start off 000 with the y addresses
vip
Activity: 1386
Merit: 1135
The Casascius 1oz 10BTC Silver Round (w/ Gold B)
I was sent a CSV file produced by TTBit from the output of the generator.  It is indeed flawed on any address that has coordinates starting with null bytes.  The current version is not safe to use.

The file contains one more anomaly: Sometimes it produces malformed private keys that begin with a 'y' instead of a '5'.  Not sure what the circumstances are, because the keys aren't valid, but they are occurring with approximately the same frequency as the 00 public key issue.  Maybe this happens when the private key starts with 00.  Here are some examples that appeared in the file.

429,1KuWNoUSr515WGnzSqxaYPtDXMvWZBes6i,yauqwyDTDGfjrgUDhgZdybgF1fDXDGuuV4zQTa6ra5yXEY89p
616,1FmLdqJcNxEr1RUAxsBKWn595X7bMmkfqR,yNje5oL9mB2UubMgWxzXwhhN1SANWQabgHMbD5a6LLyAFJuCc
831,1NAjZjF81YGfiJ3rTKc7jf1nmZ26KN7Gkn,yP536D6V88rqcJ3qFfBYuJ6pqdg6z2SZnm2SKDU4vRoCE9L89

vip
Activity: 1386
Merit: 1135
The Casascius 1oz 10BTC Silver Round (w/ Gold B)
If a certain percentage of the bitcoin addresses are wrong, then that's no good.  Someone will trust the generator, send a big balance there, and have it disappear.  It's possible that it could be failing under some certain non-obvious condition.

I plugged that private key into my Address Utility.  Notably for that particular private key, the X-value of the public key corresponding to that key starts with a 00 byte, which is a relatively unusual circumstance that is highly likely to trigger this sort of malfunction.  The bitcoin address could be getting computed with the 00 being dropped as a "leading zero", and accordingly, it could be malfunctioning every time a public key has a leading zero byte in one of the coordinates.  My utility agrees with Pywallet as to which one's correct.

Pointbiz, once fixed, if you are able to generate a very large number of addresses to a CSV file, I can run them through my own utility and make sure that there isn't any other 1-in-100 or 1-in-1000 or similar failure mode.
hero member
Activity: 602
Merit: 501
Am I doing this right?

according to bitaddress.org, the address is:12DM8vG8pytcE8Q9CBj2LQnctiRRdoZ5aZ
with private key of: 5Je7CkWTzgdo1RpwjYhwnVKxQXt8EPRq17WZFtWcq5umQdsDtTP

However, pywallet doesn't agree:
Code:
C:\Python27>pywallet.py --info --importprivkey=5Je7CkWTzgdo1RpwjYhwnVKxQXt8EPRq1
7WZFtWcq5umQdsDtTP
'ecdsa' package is not installed, pywallet won't be able to sign/verify messages

Address (Bitcoin): 1M6dsMZUjFxjdwsyVk8nJytWcfr9tfUa9E
Privkey (Bitcoin): 5Je7CkWTzgdo1RpwjYhwnVKxQXt8EPRq17WZFtWcq5umQdsDtTP
Hexprivkey: 6c9565b3eef4ef9e01c216e1910763a5f94cf3654c059e8c67a348d10ae39c28

edit: seems to work for further addresses. I printed the one above out, so I'm not crazy, looking at it now.

Same here. I tried a few addresses and all worked fine.
vip
Activity: 1386
Merit: 1135
The Casascius 1oz 10BTC Silver Round (w/ Gold B)
This generator should not be used until the question about Pywallet giving a different address is resolved. If the wrong address is being given, any coins sent to it will be lost forever.
legendary
Activity: 1136
Merit: 1001
Am I doing this right?

according to bitaddress.org, the address is:12DM8vG8pytcE8Q9CBj2LQnctiRRdoZ5aZ
with private key of: 5Je7CkWTzgdo1RpwjYhwnVKxQXt8EPRq17WZFtWcq5umQdsDtTP

However, pywallet doesn't agree:
Code:
C:\Python27>pywallet.py --info --importprivkey=5Je7CkWTzgdo1RpwjYhwnVKxQXt8EPRq1
7WZFtWcq5umQdsDtTP
'ecdsa' package is not installed, pywallet won't be able to sign/verify messages

Address (Bitcoin): 1M6dsMZUjFxjdwsyVk8nJytWcfr9tfUa9E
Privkey (Bitcoin): 5Je7CkWTzgdo1RpwjYhwnVKxQXt8EPRq17WZFtWcq5umQdsDtTP
Hexprivkey: 6c9565b3eef4ef9e01c216e1910763a5f94cf3654c059e8c67a348d10ae39c28

edit: seems to work for further addresses. I printed the one above out, so I'm not crazy, looking at it now.
hero member
Activity: 602
Merit: 501
Hum... It doesn't work on my iPhone. Maybe because I can't move my mouse around? Tongue It hangs on "Generating Bitcoin Address...".

Anyway, a cellphone probably isn't the best place to use this.
sr. member
Activity: 350
Merit: 251
V0.4
http://www.bitaddress.org/bitaddress.org-v0.4-SHA1-9d3afda22f8cf526330c0387a77e4016fd050323.html

2011-09-18:
bitaddress.org-v0.4-SHA1-9d3afda22f8cf526330c0387a77e4016fd050323.html
 -Known bug: Bitcoin.Base58.encode is not working in IE7
 -Removed Private Key Hex
 -Added QRCode for Bitcoin Address
 -Added QRCode for Private Key Wallet Import Format
 -Added extra entrophy with mouse movement technique
 -Footer now hides when printing
 -QRCode shows with canvas, if canvas is not supported (IE8) then it shows
  with a table. Printing of the table is not supported by most browsers.


nice
sr. member
Activity: 437
Merit: 415
1ninja
V0.4

2011-09-18:
bitaddress.org-v0.4-SHA1-9d3afda22f8cf526330c0387a77e4016fd050323.html
 -Known bug: Bitcoin.Base58.encode is not working in IE7
 -Removed Private Key Hex
 -Added QRCode for Bitcoin Address
 -Added QRCode for Private Key Wallet Import Format
 -Added extra entrophy with mouse movement technique
 -Footer now hides when printing
 -QRCode shows with canvas, if canvas is not supported (IE8) then it shows
  with a table. Printing of the table is not supported by most browsers.
sr. member
Activity: 350
Merit: 251
http://sourceforge.net/projects/zint/

it will make pretty much every barcode in the world today.

Of course there are other ways. I could just copy the private key, paste it at wolfram alpha and print the QR Code. But having a complete wallet just by opening an html file is a much more clean and attractive solution.

i thought that you did not want to use them because they are transferring data over the internet, and the last thing you want is to transfer keys. so client side offline would have been fine in that case. i see what you mean though. and i think it would be nice to have.
hero member
Activity: 602
Merit: 501
http://sourceforge.net/projects/zint/

it will make pretty much every barcode in the world today.

Of course there are other ways. I could just copy the private key, paste it at wolfram alpha and print the QR Code. But having a complete wallet just by opening an html file is a much more clean and attractive solution.
sr. member
Activity: 350
Merit: 251
Honestly, for the time being, I would be happy just with a QR code. It would be the easiest way to get a paper wallet.


http://sourceforge.net/projects/zint/

it will make pretty much every barcode in the world today.
hero member
Activity: 602
Merit: 501
Honestly, for the time being, I would be happy just with a QR code. It would be the easiest way to get a paper wallet.
sr. member
Activity: 350
Merit: 251
the reason you need large passwords is because, if you don't, getting bitcoins is a simple lookup once you calculated 6 or 7 characters worth of rainbow tables. so in reality, you are best off taking some pictures of a dynamic object and hashing each one and slapping the hashes together.

or a simpler solution, get some 16 blank dice, and write out the hex char set, roll 64 times and write that down. then do the required things to turn that into a public key. you could use a utility to do it for you, but then it becomes pointless to use dice to begin with, so you better learn to hash things on paper if that's even possible lol?
sr. member
Activity: 437
Merit: 415
1ninja
casascius and peak, very good points you've convinced me.

I like the idea of pregenerating something the user could then alter.
Thanks for the enlightenment on the Debian issue.

I might look into adding more entropy by calling the seedTime in more elaborate ways.
Pages:
Jump to: