How to restore locally a MyWallet backup?

10

5

The website blockchain.info has an online wallet system MyWallet which creates backups with a .aes.json extension. While I understand it's a json file encrypted with AES using my passphrase, I'm still confused about what am I supposed to do to decrypt it and load it into a local client.

I have OSX 10.6, but for portability sake let's just talk about command line, hoping at least that one stays the same on multiple platforms.

o0'.

Posted 2012-02-28T22:59:17.653

Reputation: 5 180

Answers

8

I wrote a small Python script which can be used to decrypt your encrypted MyWallet. It does the same as the MyWallet JavaScript, only in Python.

Edit: the code below seems to be outdated, here's a working version as of May 2012.

Copy the following into a file, make it executable, then run it:

#!/usr/bin/env python
import base64, hashlib, hmac, json, sys, getpass
from Crypto.Cipher import AES
from Crypto.Hash import RIPEMD, SHA256

base58_chars = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'

def prompt(p):
    return getpass.getpass(p + ": ")

def decrypt(encrypted, password):
    encrypted = base64.b64decode(encrypted)
    iv, encrypted = encrypted[:16], encrypted[16:]
    length = len(encrypted)
    encrypted += ' ' * (15 - (length-1)%16)
    hash = (hmac.new(password, iv + "\x00\x00\x00\x01", hashlib.sha1).digest() +
            hmac.new(password, iv + "\x00\x00\x00\x02", hashlib.sha1).digest())[:32]
    clear = AES.new(hash, AES.MODE_OFB, iv).decrypt(encrypted)[:length]
    return clear

def base58_decode(v):
  value = 0; ret = ''
  for c in v: value = value*58 + base58_chars.find(c)
  for i in range(32):
      ret = "%c"%(value%256) + ret; value /= 256
  return ret

def base58_encode(v):
    value = 0; ret = ''
    for c in v: value = value*256 + ord(c)
    while value > 0:
        ret = base58_chars[value%58] + ret; value /= 58
    return ret

def to_sipa(s):
    version = 128 # or 239 for testnet
    key = chr(version) + base58_decode(s)
    return base58_encode(key + SHA256.new(SHA256.new(key).digest()).digest()[:4])

clear = decrypt(prompt("encrypted wallet"), prompt("password"))
obj = json.loads(clear)

if (obj.has_key('double_encryption')):
    print("wallet uses double encryption")
    password = obj['sharedKey'].encode('ascii') + prompt("2nd password")
    for key in obj['keys']: key['priv'] = decrypt(key['priv'], password)
for key in obj['keys']: key['priv_sipa'] = to_sipa(key['priv'])
print(json.dumps(obj, indent=4, sort_keys = True))

It will prompt for the wallet backup and one or two passwords, depending on whether the wallet is single or double encrypted. Paste the wallet backup in rather than saving it to a file.

You'll probably need Python 2.x. I've been unable to find a package of the pycrypto stuff for Python 3. Apparently it will be available in the upcoming 'precise' Ubuntu release.

Edit: It seems the backup format has been changed and so this script doesn't work on recent backups.

Chris Moore

Posted 2012-02-28T22:59:17.653

Reputation: 13 952

How can I easily verify the result of decrypt() is correct?

A friend of mine lost his wallet password, I would like to iterate on a lots of potential passwords he might have chosen until I find the right one. – ripper234 2013-02-19T12:55:44.447

It seems the python script requires Crypto:Cypher, as a python noob it's a bit difficult to install it on Windows. I'm working at it, just a fair warning to newcomers.ripper234 2013-02-22T16:12:37.497

Note that my script doesn't convert the private key into 'sipa' format, which is what the official bitcoin client will need (v0.6 onwards) to import a private key. The private keys in the decrypted wallet are in base58 format, but not the 'sipa' format, which includes a checksum. I intend to fix my script to convert private keys to 'sipa' format.Chris Moore 2012-02-29T19:07:32.957

2Now it shows the key in 'sipa' format too.Chris Moore 2012-02-29T20:11:24.913

Both valid answers now, accepting this one both for the effort and because of python.o0'. 2012-03-27T11:05:15.780

I added wallet input from file, and I took the liberty to create a project on bitbucket for that: https://bitbucket.org/lohoris/mywallet-restore

o0'. 2012-04-30T14:05:34.503

1What, code development in stackexchange comments not good enough for ya? ;)

Nice work. – Chris Moore 2012-04-30T15:55:57.573

When I try this on my backed up wallet, I get "ValueError: No JSON object could be decoded". I'm new to working with this crypto library, how would you suggest I go about trouble shooting?Andrey Fedorov 2012-05-09T06:21:17.913

I get the same now. It looks like the backup format has changed. A quick glance at the source of https://blockchain.info/DecryptWallet.html shows that it now tries 4 different encryption modes, each with 0 through 19 iterations of AES encryption, which I don't think it used to do.

Chris Moore 2012-05-10T09:07:06.617

That code is crap. The mode currently used is CBC. The way he's passing in iterations is also confusing (and not in the original ezcrypto code AFAICT), as that option actually specifies the number of rounds run on PBKDF2 when deriving a key from the password (and it's 10 rounds, always).

Here's a working version for the latest format: https://gist.github.com/2757146

Andrey Fedorov 2012-05-20T07:15:10.397

@AndreyFedorov "The Gist you were looking for has been deleted. Sorry about that!"Chris Moore 2012-05-20T15:33:52.353

2

So https://gist.github.com/2757171 is the fixed version.

Chris Moore 2012-05-20T21:04:24.017

Yup, sorry 'bout that.Andrey Fedorov 2012-06-22T00:27:03.230

5

I don't know how to do it via the command line, but you can use the tool at

https://blockchain.info/DecryptWallet.html

http://pastehtml.com/view/bprww2t3g.html

It's basic, but its cross platform and gets the job done. You can also save it offline.

Ben Reeves

Posted 2012-02-28T22:59:17.653

Reputation: 2 848

See my answer - I took the above and converted it to a javascript file you can run using node.js - http://bitcoin.stackexchange.com/a/7865/78

ripper234 2013-02-22T21:26:36.363

t can be saved offline, but it includes the javascript https://blockchain.info/Resources/wallet/bitcoinjs.js so wouldn't that need to be copied locally and DecryptWallet.html edited to be able to access it?

Stephen Gornick 2012-02-29T04:03:40.537

You can delete that stuff (lines 6 and 7) and the script still works. It seems like it was left in accidentally. All the code required to decrypt the backup is in the DecryptWallet.html file itself.Chris Moore 2012-02-29T04:21:04.183

1Well, the whole point of this question is being able to restore it offline in case the service collapses, so it is pretty useless to require the service itself to back it up. Sure, saving it offline helps and does the trick, but it's one more file you risk losing, other than your wallet, so it would be better to have standard tools to do that, if possible.o0'. 2012-02-29T08:20:59.483

1OK, fine. I'll write a short Python script that can do it.Chris Moore 2012-02-29T09:51:38.947

@Lohoris: Are you looking for a few simple commands that you can remember? Cause I don't see how a Python script is any more "standard tools" than Javascript. Either way, you'll have to save that script somewhere or get someone to reproduce it for you.D.H. - bitcoin.se 2012-02-29T12:06:10.137

@D.H.: it will be archived... here ;)o0'. 2012-02-29T12:42:19.327

1@Lohoris: You're tempting me to put the javascript in an answer. ;)D.H. - bitcoin.se 2012-02-29T13:13:05.997

@D.H.: rofl that would do, actuallyo0'. 2012-02-29T13:25:53.663

1

It turns out that the bitcoinjs.js file was needed for converting the private key to 'sipa' format. That has been inlined into https://blockchain.info/DecryptWallet.html now, so it is truly now an offline page.

Chris Moore 2012-02-29T18:27:16.887

@ChrisMoore: good to know!o0'. 2012-03-27T11:04:13.423

4

Piuk has just made a patch to MultiBit that enables blockchain.info 'json' and 'aes.json' files to be imported.

This patch was included in MultiBit 0.3.4. Here is the how-to:

Export wallet from blockchain.info -> Import to MultiBit

1) Do a wallet export from blockchain.info

2) Import into MultiBit using the 'Import private keys' screen.

2.1) In the file chooser you choose the blockchain.info file suffix of ".json" or ".aes.json".

2.2) Choose the blockchain.info export file you want to import.

2.3) Add in either the single password or both passwords if it is double encrypted.

2.4) Press "Import private keys".

Because there are no private key creation dates in the blockchain.info exports I unfortunately have to replay the blocks from the genesis block (this takes a couple of hours) so it is more a "get out of jail" option than something you would use day to day.

jim618

Posted 2012-02-28T22:59:17.653

Reputation: 3 205

2

I took the code from Blockchain.info and converted it into a standalone javascript file that you can run with node.js.

There were some issues as the original code didn't handle wrong passwords, and my code now has a single function check_password(encrypted_json, password) that returns true if it can decrypt it, and false if not.

Now, my goal is to take the above and use it to recover a friend's password. I'll generate a list of all combinations he might have chosen, and test it with this script.

ripper234

Posted 2012-02-28T22:59:17.653

Reputation: 25 192

0

Here's another wrapper also done in node.js, similar to the response above by ripper234. This one works with stdin so you can use an external tool to pass in values: https://github.com/salibhai1/bitcoin-bruteforce-decrypt

Sameer

Posted 2012-02-28T22:59:17.653

Reputation: 101