Author Topic: [Experimental] Coldstorage with offline signing using Python2  (Read 1899 times)

0 Members and 1 Guest are viewing this topic.

Offline xeroc

  • Board Moderator
  • Hero Member
  • *****
  • Posts: 12922
  • ChainSquad GmbH
    • View Profile
    • ChainSquad GmbH
  • BitShares: xeroc
  • GitHub: xeroc
I just fixed an issue and tested the coldstorage solution on the live network .. worked out all nicely .. no funds  lost :)

Offline arhag

  • Hero Member
  • *****
  • Posts: 1214
    • View Profile
    • My posts on Steem
  • BitShares: arhag
  • GitHub: arhag
@arhag: Some thoughts
 - I decided to not 'construct' the transaction on the online computer. This way a hacker would need to compromise the offline computer to modify the unsigned transaction
 - I chose to not support TITAN but let the user issue "wallet_create_address <account>" so that the end user has a chance to verify the signed JSON transaction prior to sending it to the network

I'm not worried about security issues with the approach I proposed. Let's assume that the hot client is completely compromised.

Let's say the user somehow got the address for which the private key is stored in the hot client (they would likely need to write it down somewhere since they couldn't trust the output of their hot client), verified that it was typed in correctly in the offline tool, signed the transaction sending X BTS to it, and then moved the signed transaction back to an online computer and broadcast it. If the hot client is compromised, the hacker will just redirect the funds to himself as soon as they arrive at the hot client's address. So typing out the address in the offline tool (or alternatively verifying the address you are sending funds to in the offline tool) doesn't provide you with any extra security if it is a hot address.

What is important, however, is to know how much money you are withdrawing from the cold storage address. This is why I had the offline_sign.py tool tell the user:
Code: [Select]
A total of the following assets will be moved out of cold storage:
    20.00000 BTS
If a hacker modified the output of need-to-sign-2.txt to instead send 20,000 BTS to him, the user would notice the discrepancy in the output of the offline_sign.py tool and not continue with signing. Everything else (at least for offline signing of regular transfers) is IMHO superfluous with no real security benefit and in fact is worse in that it complicates the UX for the user.

Offline xeroc

  • Board Moderator
  • Hero Member
  • *****
  • Posts: 12922
  • ChainSquad GmbH
    • View Profile
    • ChainSquad GmbH
  • BitShares: xeroc
  • GitHub: xeroc
@arhag: Some thoughts
 - I decided to not 'construct' the transaction on the online computer. This way a hacker would need to compromise the offline computer to modify the unsigned transaction
 - I chose to not support TITAN but let the user issue "wallet_create_address <account>" so that the end user has a chance to verify the signed JSON transaction prior to sending it to the network

proposal:
offline tool just gets the content of the balance id corresponding to address 'coldaddress':
usage: python2 main.py [-h] [--filename FILENAME] [--rpcurl RPCURL] [--rpcuser RPCUSER] [--rpcpasswd RPCPASSWD] coldaddress

online tool:
- asks for deposit address(!) (not label, nor account name) as optional parameter and interactivaly asks for the funds .. (is it realistic that someone might want to take out several assets at once)
usage: main.py [-h] [--filename FILENAME] [--txfee TXFEE] [--prefix PREFIX] [--output OUTPUT] [--address ADDRESS]
all base56 encoded data can be imported using a QR code scanner atm ..
and I will make the output more verbose to tell the user in detail what is happening in the transaction
« Last Edit: March 19, 2015, 03:41:08 pm by xeroc ¯\_(ツ)_/¯ »

Offline bitmarley

  • Full Member
  • ***
  • Posts: 135
    • View Profile

Offline xeroc

  • Board Moderator
  • Hero Member
  • *****
  • Posts: 12922
  • ChainSquad GmbH
    • View Profile
    • ChainSquad GmbH
  • BitShares: xeroc
  • GitHub: xeroc
Thx for the input ... your suggestions make alot of sense .. i'll restructure the code ..

Offline arhag

  • Hero Member
  • *****
  • Posts: 1214
    • View Profile
    • My posts on Steem
  • BitShares: arhag
  • GitHub: arhag
Nice job.

One thing I would suggest, however, is that the online part allow you to specify the recipient and the amount and type of assets to transfer, and of course save that necessary information in the text file. That way all the offline part needs to do is ask for the private key and sign the transaction.

And then instead of providing a deposit address I can simply provide a BTS account name.

So the online main.py (renamed offline_transactions.py) could take arguments as follows:
./offline_transactions.py --output <output_filename> --transfer "<amount_to_transfer> <asset_symbol> <from_cold_storage_address> <recipient> [memo_message] [strategy]"
where the transfer argument (of which there can be multiple specified) specifies multiple arguments for the transfer in a similar way as the wallet_transfer command.

So for example:
Code: [Select]
$ ./offline_transactions.py --output need-to-sign-1.txt --transfer '10 USD BTS4CNbXqeEym7JopKYvL16qVKUe9kRMMC8x xeroc "Withdrawing funds from cold storage" vote_all'
1 transaction written to file 'need-to-sign-1.txt' for offline signing.

Or later when the new contact system is enabled:

Code: [Select]
$ ./offline_transactions.py --output need-to-sign-2.txt --transfer '19.5 BTS label:cold-storage xeroc'
1 transaction written to file 'need-to-sign-2.txt' for offline signing.
This would grab the cold storage address stored as a contact under the label cold-storage within the wallet that the script is configured to connect to.

Then on the offline computer (offline main.py renamed offline_sign.py):
Code: [Select]
$ ./offline_sign.py --input need-to-sign-2.txt --output signed-2.txt
1 transaction needs to be signed.
1 private key is necessary to sign transactions.
A total of the following assets will be moved out of cold storage:
    20.00000 BTS

Require private key for address BTS4CNbXqeEym7JopKYvL16qVKUe9kRMMC8x. How would you like to provide the private key?
1) Type in WIF private key
2) Use QR scanner
3) Derive from brain key
Select option: 1
Enter private key: 5**************************************************
All necessary private keys collected.

1 transaction successfully signed and output written to file 'signed-1.txt'
To broadcast transaction run ./offline_transactions.py --broadcast 'signed-1.txt' on online computer

Then back on the online computer:
Code: [Select]
$ ./offline_transactions.py --broadcast 'signed-1.txt'
Found 1 valid signed transaction. Latest expiration time of transactions is 2015-03-19T08:23:15 (2 hours in the future).
Would you like to broadcast all transactions? [Y/n] Y
Broadcasting transactions... OK
Waiting for confirmation in blockchain... OK
All transactions successfully broadcast.
Or something like that.
« Last Edit: March 19, 2015, 06:05:10 am by arhag »

Offline xeroc

  • Board Moderator
  • Hero Member
  • *****
  • Posts: 12922
  • ChainSquad GmbH
    • View Profile
    • ChainSquad GmbH
  • BitShares: xeroc
  • GitHub: xeroc
Warning: This is untested and highly experimental software. Use at your own risk and only with minor amounts of funds!

Download & Installation:
Code: [Select]
git clone https://github.com/xeroc/bitshares-pytools
cd bitshares-pytools
cd python-bitsharesrpc
python2 setup.py install --user
cd ..
cd python-bitsharestools  ## requires python2-ecdsa
python2 setup.py install --user
optionally: python2-qrtools

Cold Storage Solution for BitShares

What is this?
This is a set of tools for cold storage and offline signing of balance
transactions, i.e., withdraw funds from a cold storage address and putting them
into a hot wallet (address).

Requirements
  • python-bitsharesrpc (for online part)
  • python-bitsharestools (for offline signin)
  • (optional) python2-qrtools (for QR-code support)

What parts are there and what are they doing?
Two parts:

`online`
Just get the balance of the cold storage address.
Help:
       python2 main.py -h
Example:
Code: [Select]
    $ python2 main.py --address BTS4CNbXqeEym7JopKYvL16qVKUe9kRMMC8x                                                                                                               ─┘
    Connecting to BitShares RPC
    Available Funds
    5.000000 EUR
    0.000000 BTS
    Stored in file availablefunds.txt (for offline tools)

By default writes a txt file `availablefunds.txt` to the current directoy. This
file has to be moved to the offline computer for construction of the
transaction and signing process.

`offline`
Take the balance file from the `online` tool, ask for amount and assets to
transfer to the deposit address. The private key for signing is required in a
separated step and can be read by QR-code scanner. Note that only
one private key (i.e. one cold storage address) can be accessed at a time.
This script returns a readable (JSON formated) and signed transaction
instruction that can be pasted into the console of a connected BitShares
client. The signed transaction is also stored in a file `signedtx.txt` by
default.
Help:
       python2 main.py -h
Example:
Code: [Select]
    $ python2 main.py --address BTSUTgrMqNAGqvhCJdYtuqVGkTCjP7ss3bh                                                                                                              ─┘
    Available funds:
    5.000000 EUR
    0.500000 BTS
    Give amount AND asset [10 BTS]: 5 EUR
    Going to withdraw:
    5.000000 EUR
    Want more? [Y/n] n
    Adding tx fee of 0.500000 BTS
    Please type private key [empty for QR scanner]: 5**************************************************
    This private key gives access to funds in address BTS*********************************
    --------------------------------------------------------------------------------
    + Raw and signed transaction for verification:
    --------------------------------------------------------------------------------
    {
"operations": [
    {
"type": "withdraw_op_type",
"data": {
    "claim_input_data": "",
    "amount": "50000",
    "balance_id": "BTSUTgrMqNAGqvhCJdYtuqVGkTCjP7ss3bh"
}
    },
    {
"type": "withdraw_op_type",
"data": {
    "claim_input_data": "",
    "amount": "50000",
    "balance_id": "BTSG9SrG1qe2EtDbJkjbTUN4epSNG755P1y7"
}
    },
    {
"type": "deposit_op_type",
"data": {
    "amount": "50000",
    "condition": {
"asset_id": 21,
"slate_id": null,
"type": "withdraw_signature_type",
"data": {
    "owner": "BTSUTgrMqNAGqvhCJdYtuqVGkTCjP7ss3bh",
    "memo": null
}
    }
}
    }
],
"slate_id": 0,
"signatures": [
    "202315d908cfd96eb43ba003d0efbaa02ca9584c79dca1474ed4bc1511bbedbed1ce29bfa0e98f8b78dcabd9c127c50bda18f7d26d5b9f70f0a03bc3f9096f122f"
],
"expiration": "2015-03-19T08:23:15"
    }
    --------------------------------------------------------------------------------
    + stripped output of signed transaction (issue this command in the BTS console):
    --------------------------------------------------------------------------------
    blockchain_broadcast_transaction {'operations':[{'type':'withdraw_op_type','data':{'claim_input_data':'','amount':'50000','balance_id':'BTSUTgrMqNAGqvhCJdYtuqVGkTCjP7ss3bh'}},{'type':'withdraw_op_type','data':{'claim_input_data':'','amount':'50000','balance_id':'BTSG9SrG1qe2EtDbJkjbTUN4epSNG755P1y7'}},{'type':'deposit_op_type','data':{'amount':'50000','condition':{'asset_id':21,'slate_id':None,'type':'withdraw_signature_type','data':{'owner':'BTSUTgrMqNAGqvhCJdYtuqVGkTCjP7ss3bh','memo':None}}}}],'slate_id':0,'signatures':['202315d908cfd96eb43ba003d0efbaa02ca9584c79dca1474ed4bc1511bbedbed1ce29bfa0e98f8b78dcabd9c127c50bda18f7d26d5b9f70f0a03bc3f9096f122f'],'expiration':'2015-03-19T08:23:15'}
    --------------------------------------------------------------------------------
    + signed transaction stored in file signedtx.txt
    --------------------------------------------------------------------------------

What's the procedure?
Online
1. Go into the `online` part of the program and define the connection parameters to a running BitShares client in the `config.py` file
2. Get your cold storage address and either put it into the `config.py` file or append it to the command with "--address BTS...."
3. Run the `online` part of the program (it will list the funds stored in the cold storage address)

Offline
1. Copy the balance file from the online tool over to the offline tool directory (on an offline computer)
2. Execute the `offline` program and optionally give the file name as parameter (see `python2 main.py -h` for help)
3. Define the amount and asset you want to withdraw from the cold storage address
4. Paste the recipient address (or scan it with a webcam as QR-code)
5. Paste the private key (or scan it with a webcam as QR-code) -- The private key will be verified prior to signing.
6. The `offline` program constructs and signs a BitShares transaction
7. Carry the output (console command) to a connected BitShares client and paste the command in the console (the signed transaction is also stored in a txt file in the same directory)
8. Wait for 1 confirmation.
9. Done

What remains to be done
  • Read Encrypted paperwallet
  • Find someone that can verify the code is doing what it should
  • Add voting_key support
  • What else?

Input?

P.S. I'd love to see this forum support markdown .. would make pasting my README alot easier