Pages:
Author

Topic: Hardware wallet wire protocol (Read 8767 times)

member
Activity: 78
Merit: 11
Chris Chua
February 13, 2013, 09:17:48 AM
#85
Here are some of my findings regarding USB HID-based communication. Perhaps they will be useful to anyone else working on interfacing with hardware wallets.

  • The maximum throughput I've seen in either direction when using HIDAPI is 31500 bytes/s. This is fast enough to transfer most Bitcoin transactions instantly (from a user's perspective), but it is less than 3% of full-speed USB maximum throughput.
  • There needs to be a way to identify hardware wallets. HIDAPI's hid_enumerate() function gives you a list of HID devices, but it includes things like keyboards and mice. USB device properties which HIDAPI can query include: vendor ID, product ID, manufacturer string, product string and serial number. Identification via. vendor/product ID is probably not a good idea because they're constrained by other factors.
  • The latest version of HIDAPI available on https://github.com/signal11/hidapi/downloads (v0.7.0) is quite outdated. It has issues on Windows relating to report sizes (see https://github.com/signal11/hidapi/pull/28).
  • For the CP2110-based protocol that slush has proposed, a long, repetitive HID report descriptor is required.
  • On the device side, things are complicated by the fact that the HID specification allows reports to be sent/received from both the control endpoint and an interrupt endpoint. Both these methods have their own subtleties.

Some Windows XP-specific things:
  • Windows will refuse to enumerate your HID device unless it provides a valid report descriptor. Windows will refuse to process reports unless that report is correctly described in the report descriptor. This is why that "long, repetitive HID report descriptor" is not just a good idea - it seems to be required for the interface to work at all.
  • Upon success, HIDAPI's hid_read() always returns the size of the largest report, even if a smaller report was received. So its return value should be ignored and the report ID (first byte) should be used to determine the report size.
  • Windows will eat up received reports even if hid_read() isn't being called.

Some Linux-specific things:
  • HIDAPI provides two backends: one based on the hidraw kernel driver, and one based on libusb-1.0. Certain kernel versions have some hidraw bugs.
  • No matter what backend is used, access to a USB HID device requires root permissions. Alternatively, udev rules can be used to whitelist certain devices. Care must be taken to write the whitelist filter so that it includes all hardware wallets.
  • By default, when a USB HID device is plugged in, the hidraw driver will use "get report" control requests, presumably to initialise its view of the state of the device. This can end up eating up the first byte sent from the hardware wallet.
legendary
Activity: 1246
Merit: 1010
November 23, 2012, 10:59:37 PM
#84
Seems like we should start really simple targeted for the smallest USB device, like the cypress CY7C64316. 

Define a protocol that could sign a bunch of outputs; and not even keep track of the act balance.

Base it off of a "transport" that consists of 2 APIs:

send(buffer, length)
recv(buffer,length)

because any underlying transport can implement these 2.


Then additional protocol functionality can be layered on top (to support more advanced HW wallets)... and additional transports can be layered below.

In a related note, is there any web service that will just post an arbitrary bitcoin TXN to the network based on some RESTful probably binary-coded API?

legendary
Activity: 1428
Merit: 1093
Core Armory Developer
November 23, 2012, 09:53:06 AM
#83
Here's what I'm getting at:  BIP 32 allows for random access to any address, but it also specifies using a separate subchain for change addresses (the "internal" subchain).  This may have been overlooked by you early on for simplicity reasons, but it is part of the spec.

I focused to change addresses in BIP32 proposal and everything I see is that (simplified=) "it is possible to use internal chain for change addresses", however it's not a requirement, so device also should not enforce it. When user wants to use multiple chains for multiple offices to keep their balances separate, he'll probably want to use multiple internal chains for change addresses as well...

My point was not that you should use it, for fun, but because using it might make the "what if offline tx uses change address 1e7?" problem a bit easier.  The online computer could hand out millions of addresses on the external chain, but the number of addresses used on the internal chain will be strictly limited.

However, if the private keys are distributed across multiple devices, it's not quite so simple...
legendary
Activity: 1386
Merit: 1097
November 23, 2012, 08:23:15 AM
#82
Here's what I'm getting at:  BIP 32 allows for random access to any address, but it also specifies using a separate subchain for change addresses (the "internal" subchain).  This may have been overlooked by you early on for simplicity reasons, but it is part of the spec.

I focused to change addresses in BIP32 proposal and everything I see is that (simplified=) "it is possible to use internal chain for change addresses", however it's not a requirement, so device also should not enforce it. When user wants to use multiple chains for multiple offices to keep their balances separate, he'll probably want to use multiple internal chains for change addresses as well...
legendary
Activity: 1386
Merit: 1097
November 22, 2012, 07:12:04 AM
#81
After quick brainstorming with Stick we've composed following interaction diagram of transaction signing: signtx_workflow.pdf

The purpose of this is to stream everything, to minimize RAM requirements for the device.

Basic description is:
a) Device receives SignTx message, which contains mainly count of inputs and outputs.
b) Device asks for inputs and outputs in separate messages.
c) Every output is confirmed by the user.
d) In first iteration, device computes hash of outputs and blank inputs (without scripts).
e) After first iteration, signature of first input is generated and returned back to computer.
f) In every next iteration, device compare hashed outputs with the hash built during first iteration (which has been confirmed by the user).
g) Every iteration produces exactly one input signature.
legendary
Activity: 1386
Merit: 1097
November 21, 2012, 10:37:26 AM
#80
Yes, the device can store some simple counter, but I'm affraid that the overal design is becoming a bit fragile.

Technically you can have many devices or desktop wallets working on the same seed, but the device don't have independent access to the full blockchain, so it depends on information provided by the host computer.

Now we must decide what should device do if computer propose change address above current counter state...
legendary
Activity: 1428
Merit: 1093
Core Armory Developer
November 21, 2012, 10:30:52 AM
#79
Well here's an idea:  can the device at least store how many times it's ever created signatures?  Or something else that is at >=1 for each transaction it ever deals with?

Here's what I'm getting at:  BIP 32 allows for random access to any address, but it also specifies using a separate subchain for change addresses (the "internal" subchain).  This may have been overlooked by you early on for simplicity reasons, but it is part of the spec.   The idea is that change addresses will only ever come from this the internal chain, and that chain will never receive coins from any other source except the "external" chain (the main chain that is used for distributing payment addresses). 

The relevance is that the "internal" chain is very dense.  There will not be any gaps in the internal chain.  In fact, the highest index ever used in this chain should be about equal to the number of transactions ever signed by the device.   Therefore, if you implement both roots on the device, the device can safely declare that "a change address with an index higher than the number of transactions I've ever signed is invalid." 

legendary
Activity: 1428
Merit: 1093
Core Armory Developer
November 21, 2012, 10:11:49 AM
#78
(2) If the device does recognize it, then the user only confirms the original output they were expecting to see

And what if computer ask for using address with index [2^32, 2^32, 2^32, 2^32] ? Don't forget that BIP32 is hierarchical. Good luck recovering coins send somewhere to this address space...

Oh, I missed that part.  I forgot that BIP 32 doesn't require computing addresses in order (Armory current wallets do require computing in the chain, but that has turned out to be more of a curse than a blessing, but would be useful here).  But I see your point, now.   And the suggestion about storing an index on the device and or displaying it for the user, makes more sense, now.

I'll think about that one...
legendary
Activity: 1386
Merit: 1097
November 21, 2012, 10:07:37 AM
#77
(2) If the device does recognize it, then the user only confirms the original output they were expecting to see

And what if computer ask for using address with index [2^32, 2^32, 2^32, 2^32] ? Don't forget that BIP32 is hierarchical. Good luck recovering coins send somewhere to this address space...
legendary
Activity: 1428
Merit: 1093
Core Armory Developer
November 21, 2012, 10:00:16 AM
#76
There's the non-zero benefit of:  ECDSA is secure right now... but if it wasn't, using new addresses still keeps your coins secure because your private key can't be broken if your public key isn't even known.  i.e. -- if you send back to an address that has its public key already in the blockchain, then in the far future if ECDSA is broken and/or quantum computers start becoming a reality, then you are vulnerable.

If this become a problem, then it is only the matter of software update to start using newly generated addresses. For now this is non-issue.

Quote
And of course -- the privacy aspect is improved. As you said, privacy is not guaranteed when using new addresses, but it's also not as bad as just reusing old ones.

Well, I accept that. Still we need to balance between security/usability/anonymity and I see using artifically created new addresses as a quite big risk. There's still enough time to think about it a bit more...

I don't understand the risk.  The desktop computer is perfectly capable of creating a new address in the same deterministic wallet, and telling the device what the address index is so that it can recognize it.  The user doesn't even have to know it's there, as long as the device is doing its job to verify ownership of the address. 

(1) If the device doesn't recognize the second address, the user must confirm the extra output, which will look suspicious.
(2) If the device does recognize it, then the user only confirms the original output they were expecting to see
legendary
Activity: 1386
Merit: 1097
November 21, 2012, 09:57:31 AM
#75
There's the non-zero benefit of:  ECDSA is secure right now... but if it wasn't, using new addresses still keeps your coins secure because your private key can't be broken if your public key isn't even known.  i.e. -- if you send back to an address that has its public key already in the blockchain, then in the far future if ECDSA is broken and/or quantum computers start becoming a reality, then you are vulnerable.

If this become a problem, then it is only the matter of software update to start using newly generated addresses. For now this is non-issue.

Quote
And of course -- the privacy aspect is improved. As you said, privacy is not guaranteed when using new addresses, but it's also not as bad as just reusing old ones.

Well, I accept that. Still we need to balance between security/usability/anonymity and I see using artifically created new addresses as a quite big risk. There's still enough time to think about it a bit more...
legendary
Activity: 1428
Merit: 1093
Core Armory Developer
November 21, 2012, 09:51:59 AM
#74
Is there really any benefit of using newly created change addresses? Except that this is default in Satoshi's client. This is the main question, because the risk is exactly in using freshly generated address which validity cannot be confirmed by the device or by the user...

If there's no clear benefit in using new change addresses, I'm inclining to display them to confirm as any other addresses.

There's the non-zero benefit of:  ECDSA is secure right now... but if it wasn't, using new addresses still keeps your coins secure because your private key can't be broken if your public key isn't even known.  i.e. -- if you send back to an address that has its public key already in the blockchain, then in the far future if ECDSA is broken and/or quantum computers start becoming a reality, then you are vulnerable.

And of course -- the privacy aspect is improved. As you said, privacy is not guaranteed when using new addresses, but it's also not as bad as just reusing old ones.
legendary
Activity: 1386
Merit: 1097
November 21, 2012, 09:44:49 AM
#73
Is there really any benefit of using newly created change addresses? Except that this is default in Satoshi's client. This is the main question, because the risk is exactly in using freshly generated address which validity cannot be confirmed by the device or by the user...

If there's no clear benefit in using new change addresses, I'm inclining to display them to confirm as any other addresses.
legendary
Activity: 1428
Merit: 1093
Core Armory Developer
November 21, 2012, 09:33:57 AM
#72
I really don't think you're getting any value out of this.  The device can internally confirm that the change address belongs to your own wallet, and asking for user confirmation doesn't add any security -- but it does create confusion.  Even if users know what they're doing, they may accidentally confirm through a malicious change address because they are always asked to confirm two addresses when they send a tx with one target. 

I'd prefer, instead, that the second address only comes up when it is not part of their wallet.  If the user created the tx to go to 2 people, they'll expect to confirm twice, etc.  If they are asked for 3 confirmations, they'll immediately recognize something isn't right.  

legendary
Activity: 1386
Merit: 1097
November 21, 2012, 09:31:39 AM
#71
I'm not so sure that displaying the change address deals with the "malicious send to /dev/null" attack described above. For example, say the device displays "change of 0.05581992 BTC was sent to 1HoYQQeA3BxWisDK3VtGFNbvnNPcoZTE5n". How do you even know whether that's a "genuine" change address?

Yes, that's why I don't like the concept of change addresses. You must trust the bitcoin software that it generates some reasonable address for you, instead of just checking if one output address is going to the address you want and second output address is going back to one of original addresses (which can be even checked by the device).

Quote
Perhaps a better solution is to display the change address index instead. There is an immediately apparent difference between "change was sent to address 18" and "change was sent to address 1156397331". But will users understand this?

No :-(. I've been thinking about this too, but I'm affraid that "address index" is out of game for end users.

Quote
Another option is to require change addresses to be explicitly and sequentially generated by the wallet. However, this does require an internal counter that is incremented every time a change address is generated. The malicious change address attack is prevented because the wallet is presumably unable to generate millions of change addresses in any reasonable time.

Internal counter don't solve anything, because you can use the same seed on another device. This creates completely different set of problems.
member
Activity: 78
Merit: 11
Chris Chua
November 21, 2012, 09:27:02 AM
#70
Etotheipi, someone42, I'd like to know your opinion how to handle change addresses. There are basically two approaches:

a) When transaction is coming to self-address (validity can be verified by the device itself), hide output to change address from the user.
b) Show output to change address as normal output, it can be just displayed in slightly different way on the display.

ad a)
This is how bitcoin software is doing it now, although I don't like it much. User should see full information, otherwise there are some possible attacks. For example, by hiding change address from the UI, malicious (modified) software can send coins literally to /dev/null, by using some very high address vector for change address. Attacker don't take the money, but they're practically lost by the original owner.

ad b)
I see this approach as much safer. User see all outputs and it's only up to the desktop software to explain what's going up here. Change addresses are for example fully visible in Electrum and I don't think that people have any problem with it. Device still must support some kind of scrolling for multiple transaction outputs, so having one more output is not a problem.
I'm not so sure that displaying the change address deals with the "malicious send to /dev/null" attack described above. For example, say the device displays "change of 0.05581992 BTC was sent to 1HoYQQeA3BxWisDK3VtGFNbvnNPcoZTE5n". How do you even know whether that's a "genuine" change address?

Perhaps a better solution is to display the change address index instead. There is an immediately apparent difference between "change was sent to address 18" and "change was sent to address 1156397331". But will users understand this?

Another option is to require change addresses to be explicitly and sequentially generated by the wallet. However, this does require an internal counter that is incremented every time a change address is generated. The malicious change address attack is prevented because the wallet is presumably unable to generate millions of change addresses in any reasonable time.
legendary
Activity: 1386
Merit: 1097
November 21, 2012, 09:22:50 AM
#69
I'm trying to avoid some "extended usermodes", which just makes the flow more complicated and less universal.

Personally I'm not a fan of change addresses, but I understand that there's some demand for this feature. Change addresses are false promise of anonymity, because addresses in one wallet are still usually tainted enough that it's obvious they have common owner.

Now I have another idea - hide just transaction outputs which send coins to some input address which is mine. For wallets not using change addresses (like Elecrum has such option), you won't see "change" output. In this case users still can imagine wallet as you described - as an amount stored on some virtual account.

There's not enough space on the internal display to explain what change address is. If desktop software wants to use change addresses, then the change address (which is mine, but not in transaction input) can be visually marked (like inverted colors on the line or something) and it is up to the desktop software to explain its meaning to users.
legendary
Activity: 1428
Merit: 1093
Core Armory Developer
November 21, 2012, 09:10:59 AM
#68
Etotheipi, someone42, I'd like to know your opinion how to handle change addresses. There are basically two approaches:

a) When transaction is coming to self-address (validity can be verified by the device itself), hide output to change address from the user.
b) Show output to change address as normal output, it can be just displayed in slightly different way on the display.

ad a)
This is how bitcoin software is doing it now, although I don't like it much. User should see full information, otherwise there are some possible attacks. For example, by hiding change address from the UI, malicious (modified) software can send coins literally to /dev/null, by using some very high address vector for change address. Attacker don't take the money, but they're practically lost by the original owner.

ad b)
I see this approach as much safer. User see all outputs and it's only up to the desktop software to explain what's going up here. Change addresses are for example fully visible in Electrum and I don't think that people have any problem with it. Device still must support some kind of scrolling for multiple transaction outputs, so having one more output is not a problem.

It really depends on the target audience.  You and I are intimately aware of how Bitcoin works, under-the-hood, but non-techies think of their own wallet as a single number -- their balance.  They don't understand what "unspent outpoints" are, and why there is change, etc.  To them, they send 20 BTC to one address, they expect to see 20 BTC go to one address and their balance reduced by that much.  Forcing them to understand more than that is... a judgment call.

I've gotten lots of questions about "change addresses", and why it looks like users are sending coins to multiple people.  I tried to make it clear in the Armory tx display, but they don't always catch on.  For that reason, the "Standard" usermode in Armory tries to avoid making any mention of "change," for fear of confusing the user.

On the other hand, your device is not for absolute newbies (although many would argue that Armory isn't, either Smiley).  I'm sure most of your users would understand what change is.  But I'm not sure displaying the change would make a difference -- even if they see it and understand it, they aren't going to know for sure that the displayed address is part of their own wallet.  The device verifying its own address is the roadblock to a malicious attack, not the user confirming it.

In fact, what will happen if the first 100 tx, the user sees the change output and confirms it.  On tx 101, the second addr pops up but isn't actually change (because it was maliciously replaced).  Is the user going to notice this is different?  Or just hit the "confirm" button twice like he always does because he's always confirming two outputs? 
legendary
Activity: 1386
Merit: 1097
November 21, 2012, 08:16:57 AM
#67
Etotheipi, someone42, I'd like to know your opinion how to handle change addresses. There are basically two approaches:

a) When transaction is coming to self-address (validity can be verified by the device itself), hide output to change address from the user.
b) Show output to change address as normal output, it can be just displayed in slightly different way on the display.

ad a)
This is how bitcoin software is doing it now, although I don't like it much. User should see full information, otherwise there are some possible attacks. For example, by hiding change address from the UI, malicious (modified) software can send coins literally to /dev/null, by using some very high address vector for change address. Attacker don't take the money, but they're practically lost by the original owner.

ad b)
I see this approach as much safer. User see all outputs and it's only up to the desktop software to explain what's going up here. Change addresses are for example fully visible in Electrum and I don't think that people have any problem with it. Device still must support some kind of scrolling for multiple transaction outputs, so having one more output is not a problem.
legendary
Activity: 1386
Merit: 1097
November 21, 2012, 04:41:29 AM
#66
Then, you send the entire transaction through once per required signature. Each time an output is encountered, you prompt the user about it. This is merely an extension of your "streaming" idea, but applied to the whole transaction.

Yes, similar idea here.

Quote
You can probably see the problem with this: the user will be prompted repeatedly, for each required signature. This makes for an unnecessarily bad user experience. This is how I intend to deal with the problem in my implementation:

Yes, I had this idea yesterday as well, I've been just lazy do write it down O:-).
Pages:
Jump to: