Background: "Fragmenting" your wallet backup was going to be a feature in Armory's new wallets, but other priorities have come up and I can't finish the new wallets yet. But I still wanted to make this feature available since the math was fully implemented. Rather than complicate the GUI with more backup options that will have to change once again when I finally do finish the new wallets, I decided to make a command-line utility.
Re-post of
this message. Reposting because I figured this was in demand by a wider audience, and there's plenty of folks in the D&TD forum that don't mind using command-line tools (though, this is the only command-line-required function of Armory).
The "correctness" of the utility should be self-evident. The output of the "fragging" script is N files in the execution directory. The input to the "unfragging" script is to have M+ files in the execution directory. And the unfragging script has a built in "test" so you can see it work correctly on multiple subsets of fragments. And it puts the git-commit version in the output so you know
exactly what version created it (though, it will forever be in the master branch now, and I don't expect it to change).
Features:- Create M-of-N fragmented backup, for any value of N, and 2<=M<=8 (uses Shamir's Secret Sharing)
- Works with any Armory *.wallet files, encrypted or not (will prompt for passphrase if encrypted)
- Creates N text files that can easily be opened and printed (sorry, no QR codes from terminal)
- Having M-1 files gives attacker no advantage to brute forcing your wallet any more than having zero pieces. For a 7-of-20 backup, having 6 pieces is no more useful than having 0.
- Deterministic fragments means you can re-print lost fragments, or create more later (increase N)
- The git-commit version is put in the text file, in case you want to know exactly what version created it
- Error correction up to one character per line. Identifies which file&line has 2+ errors that can't be corrected automatically.
- Use the "unfrag" script right after "fragging" to test recombining various subsets of fragment files (for your own peace of mind)
- Endless error checking to make sure you get it right, or know what you did wrong.
Also, there is a completely dependency-less script "sss.py", which contains
everything needed to restore these fragments. If you have python installed, you can run that script in isolation (default python installation, without installing Armory). The reason for making it, is it's easy to print off for the ultra-paranoid that think that the git-repo won't be available in the future for some reason. The script doesn't do the unfragging for you, but it has everything you need in a couple hundred lines of code and could be printed out on one or two sheets of paper.
Use Cases:To be used with regular Armory wallets.
- 2-of-3: Instead of backing up your wallet to one place where anyone who finds it can recover your funds, create three pieces, of which any two is sufficient for recovering the wallet. Keep one in your house, one in a safe-deposit box at a bank, and give one to a family member.
- 5-of-7: If a company has 7 members, require a large majority of them to recover the funds. There will still be one or two people managing the offline computer, but it allows that offline computer to be backed up without risk of any one (or 4) members to steal the money.
- 3-of-5 or 3-of-6: A nice description here.
This still assumes a single-sig wallet, and that there is probably an offline computer with an encrypted version of it, accessible by you. The problem is that it needs to be backed up, and you don't want your backups to become the weakest point in the vulnerability chain. "Linked wallets" with multi-sig/multi-device is still in the works, and this is not a replacement for that. This is simply an alternative to backing up your wallet if you're concerned about physical security.
The scripts are in the extras directory. They have been pushed to the master branch.Sorry, this only works if you can run python scripts (possible in Windows, but you have to install all the python packages
listed here for windows, and copy the .pyd file from the installation directory).
Usage:$ python frag_wallet.py ~/.armory/armory_2QQkCkdt_.wallet 3 5
$ python unfrag_wallet.py wallet_2QQkCkdt_frag*.txt --test
$ python unfrag_wallet.py wallet_2QQkCkdt_frag*.txt
Use the
extras/frag_wallet.py script to break your paper backup in N files, and then you can immediately use the
extras/unfrag_wallet.py script to execute the recovery process on 20 different subsets of M fragment files. Without the --test option, it will ask you for the appropriate encryption options, and then create an armory*.wallet file that can imported natively into Armory.
Output of the fragging script$ python frag_wallet.py ~/.armory/armory_2QQkCkdt_.wallet 3 5
********************************************************************************
* Executing wallet-fragmenting script. Split your Armory wallet
* into N pieces, requiring any M to recover the wallet.
********************************************************************************
Found hash of current git commit: cf8ebe7cecf4bbd0457e8f984354aabb6e869e66
Here is the paper backup information for this wallet.
Root Key: hrfr dejf snwf rtun rtin dhri snor aihd wiut
otjf osws teaa gjei ihoa ffaa fojn swng tusg
Chaincode: kwig jorj agtj ragt kwrn dnhf ojgw tkwg snti
hdst aurh osfj ajhd nwra ogdd dsiw saff fwra
Will create 3-of-5 fragmentation of your paper backup.
Continue? [Y/n]: y
About to create the fragments. Any other info/identifiers you would
like to add to each of the fragment files? Enter it on the next line:
(Enter info or leave blank): This fragment belongs to forum user etotheipi
Fragment 1: wallet_2QQkCkdt_frag1_need_3.txt
ID: 0301 02d1 93af fa6f
x1: aiow gnrr haaj hthf hsnf rskj tooi kjta ajuf
x2: jgto kgir ekgs whod kdkr rwsr hase jdui irdh
x3: rugh hoas sghk sowr esdj kgnw hihe jnri jehu
x4: eagt fair gjan ifwd retd ewnd aofu gnur jdut
y1: owrn sowu nfrw oeeo gggs ikkw feii ueja hwns
y2: aogt osig wonk jkis fkur gfhk kowt gwdu tter
y3: eats akge jeot rdug oeki frgd onia einn rddj
y4: dkfj nsed tijj nfkn dkne nieu ittf gnrg gkhj
Fragment 2: wallet_2QQkCkdt_frag2_need_3.txt
ID: 0302 02d1 93af fa6f
x1: fadf gtko nwii gfwd nogk osak jodn tess dgdt
x2: wris jthf kgdu jiwj jeho suii ugnw rewd rtoi
...
Fragment 5: wallet_2QQkCkdt_frag5_need_3.txt
ID: 0305 02d1 93af fa6f
x1: hfte nufh utis sseh aweu jkgw ugno iaow kdue
x2: nkwo ndsw jief taar tfrg kejn knwg tfkt akuw
x3: ofat fgui iwsk eofg toeo widn gwnh hauk knhg
x4: ugut wfww rfon kdkg uddi rutn nefh ftid iorn
y1: oerh rdie rnth dnda iaws ateg utaf drhh grnu
y2: hrte iaoh khwa jrfa dfeh doej usit infh fjhj
y3: uije nsga suod jiid sjau rhwh swsg rfgn gwud
y4: nwnd eheo issg tdrw kdei fhoj joun iuit jirf
NOTE: If you rerun this fragment script on the same wallet
with the same fragments-required value, M, then you will
get the same fragments. Use this to replace fragments,
or using a higher N-value to produce more pieces (but you
MUST use the same M value!)
$ ls -l
...
-rw-rw-r-- 1 alan alan 1008 Mar 6 11:32 wallet_2QQkCkdt_frag1_need_3.txt
-rw-rw-r-- 1 alan alan 1008 Mar 6 11:32 wallet_2QQkCkdt_frag2_need_3.txt
-rw-rw-r-- 1 alan alan 1008 Mar 6 11:32 wallet_2QQkCkdt_frag3_need_3.txt
-rw-rw-r-- 1 alan alan 1008 Mar 6 11:32 wallet_2QQkCkdt_frag4_need_3.txt
-rw-rw-r-- 1 alan alan 1008 Mar 6 11:32 wallet_2QQkCkdt_frag5_need_3.txt
...
Each file looks like the following:Wallet ID: 2QQkCkdt
Create Date: 2013-Mar-06 12:29am
Git Commit: cf8ebe7cecf4bbd0457e8f984354aabb6e869e66
This fragment belongs to forum user etotheipi
This Fragment: #1
Fragments Needed: 3
Fragments Created: 5 (more fragments may have been created later)
The following is a single fragment of your wallet. Execute
the reconstruction script with any 3 of these fragment files
in the execution directory to recover your original wallet.
Each file can be reconstructed by manually typing the data
into a text editor. Only the following 9 lines (with prefixes)
are necessary in each file. All other data can be omitted.
ID: 0301 02d1 93af fa6f
x1: aiow gnrr haaj hthf hsnf rskj tooi kjta ajuf
x2: jgto kgir ekgs whod kdkr rwsr hase jdui irdh
x3: rugh hoas sghk sowr esdj kgnw hihe jnri jehu
x4: eagt fair gjan ifwd retd ewnd aofu gnur jdut
y1: owrn sowu nfrw oeeo gggs ikkw feii ueja hwns
y2: aogt osig wonk jkis fkur gfhk kowt gwdu tter
y3: eats akge jeot rdug oeki frgd onia einn rddj
y4: dkfj nsed tijj nfkn dkne nieu ittf gnrg gkhj
Run the unfrag test: (it works without the --test flag, if you have more than M files)
$ python unfrag_wallet.py wallet_2QQkCkdt_frag*.txt --test
********************************************************************************
* Restoring wallet from 3-of-N fragmented backup!
********************************************************************************
Recovered paper backup: 2QQkCkdt
hrfr dejf snwf rtun rtin dhri snor aihd wiut
otjf osws teaa gjei ihoa ffaa fojn swng tusg
kwig jorj agtj ragt kwrn dnhf ojgw tkwg snti
hdst aurh osfj ajhd nwra ogdd dsiw saff fwra
Testing reconstruction on 20 subsets:
Using fragments (0,1,3) Reconstructed (first line): hrfr dejf snwf rtun rtin dhri snor aihd wiut
Using fragments (2,3,4) Reconstructed (first line): hrfr dejf snwf rtun rtin dhri snor aihd wiut
Using fragments (1,3,4) Reconstructed (first line): hrfr dejf snwf rtun rtin dhri snor aihd wiut
Using fragments (1,2,3) Reconstructed (first line): hrfr dejf snwf rtun rtin dhri snor aihd wiut
Using fragments (0,1,2) Reconstructed (first line): hrfr dejf snwf rtun rtin dhri snor aihd wiut
Using fragments (0,3,4) Reconstructed (first line): hrfr dejf snwf rtun rtin dhri snor aihd wiut
Using fragments (0,3,4) Reconstructed (first line): hrfr dejf snwf rtun rtin dhri snor aihd wiut
Using fragments (0,2,4) Reconstructed (first line): hrfr dejf snwf rtun rtin dhri snor aihd wiut
...
Recover the wallet:$ python unfrag_wallet.py wallet_2QQkCkdt_frag*.txt
********************************************************************************
* Restoring wallet from 3-of-N fragmented backup!
********************************************************************************
Recovered paper backup: 2QQkCkdt
hrfr dejf snwf rtun rtin dhri snor aihd wiut
otjf osws teaa gjei ihoa ffaa fojn swng tusg
kwig jorj agtj ragt kwrn dnhf ojgw tkwg snti
hdst aurh osfj ajhd nwra ogdd dsiw saff fwra
You have supplied more pieces (5) than needed for reconstruction (3).
Are you trying to run the reconstruction test instead of actually
recovering the wallet? If so, wallet recovery will be skipped. [Y/n] n
Proceeding with wallet recovery...
Would you like to encrypt the recovered wallet? [Y/n]: y
Choose an encryption passphrase:
Passphrase:
Again:
Set the key-stretching parameters:
Seconds to compute (default 0.25): 2
Max RAM used, in MB (default 32): 16
Creating new wallet...
Please wait while the address pool is being populated....
Created armory_2QQkCkdt_recovered.wallet
Exhaustive error catching and useful information$ python unfrag_wallet.py wallet_2QQkCkdt_frag*.txt --testnet
ERROR: Some files are duplicates!
wallet_2QQkCkdt_frag1_need_3.txt is Fragment 1
wallet_2QQkCkdt_frag2_need_3.txt is Fragment 1
wallet_2QQkCkdt_frag4_need_3.txt is Fragment 4
Aborting
$ python unfrag_wallet.py wallet_2QQkCkdt_frag*.txt --testnet
********************************************************************************
* Restoring wallet from 3-of-N fragmented backup!
********************************************************************************
(WARNING) armoryengine.py:1235 - ***Checksum error! Attempting to fix...
(WARNING) armoryengine.py:1259 - Checksum fix failed
ERROR: Uncorrectable error
File: wallet_2QQkCkdt_frag1_need_3.txt
Line: y2