Understanding Pre Bitcoin 0.4 Encryption

5 replies 135 views
satoshi_degenFull Member
Posts: 40 · Reputation: 375
#1Aug 12, 2018, 10:03 AM
So in Bitcoin 0.4, they’re using private key encryption like mentioned below. Does anyone know if MultiBit or BitcoinJ, developed back in 2011 before Bitcoin 0.4, uses the same encryption method? I’ve read that both use AES, but I can’t seem to find any discussion about it in the BitcoinJ group. The real question is how does the private key encryption and decryption actually function and what’s being used? I’ve got 34 characters (base 58/64), 16 characters (could this be the salt?), and then there’s a 0x8d making a total of 42 characters. /* Private key encryption relies on a CMasterKey, which contains a salt and a random encryption key. CMasterKeys are encrypted using AES-256-CBC with a key derived through a method called nDerivationMethod (0 means EVP_sha512()) and the number of derivation iterations is nDeriveIterations. vchOtherDerivationParameters are there for other algorithms that might need more details (like scrypt). Wallet private keys are then encrypted with AES-256-CBC using the double-sha256 of the private key as the IV, and the master key's key as the actual encryption key. */
8 Reply Quote Share
im_sageFull Member
Posts: 139 · Reputation: 484
#2Aug 12, 2018, 02:42 PM
This topic caught my attention for a chicky reasons . bitcoin 0.4 actually did bring in AES-256-CBC with the CMasterKey salt ++ random key whereas private keys were encrypted with doubled SHA256 of the key as Iv... and for bitcoinJ / multibit at about around 2011 they also used AES but not in the exact same way as core becuase core kinda depended on OpenSSL EVP functionx while bitcoinJ in the other hand make use of Java crypto librariess. that 34 + 16 + 0x8d you mentioned does line up with how core wallet dumps actualy looked back then Funny  story  in my first semester of MSc CyberSecurity Science we actually did practicals on AES,, salt & IVs  Although at the time!! it kind of felt like old school crypto theory beacuse sincerely speaking my university still dwells a lot on knownledge that feels expired, but discussions like this show how those fundamentals back then!!  directly apply to real systems like Bitcoin wallets... So i think it is safe to say no knowledge is a waste after all .
1 Reply Quote Share
satoshi_degenFull Member
Posts: 40 · Reputation: 375
#3Aug 13, 2018, 02:37 PM
Yes Programmer found out that multibit until 0.3.x and bitcoinj 0.5 use the same encryption for the private keys I thought it was from openssl but you I didn't learn what you learned, I'm no programmer at all just playing with computers from 6 years old on a commodore and on I found https://github.com/Multibit-Legacy/multibit/wiki/Export%20and%20limited%20import%20of%20private%20keys And there it states it does use openssl? and found some python code for decrypting but that's over my head https://github.com/gurnec/decrypt_bitcoinj_seed/tree/master/aespython https://github.com/serprex/aespython https://github.com/HardCorePawn/multibit_recovery/tree/master thanks for your reaction, most users questioned my answers, because it couldn't be. For standard bitcoin indeed or bitcoin 0.4+ Maybe you have the solution I need? Couldn't send you a private message because i'm a newbie at the forum Thnx anyway
5 Reply Quote Share
im_sageFull Member
Posts: 139 · Reputation: 484
#4Aug 13, 2018, 07:40 PM
You are very welcome bro!! I even took the liberty of going through the repos you shared, it is a bit funny you said you are no programmer but no issues i will make it a bit simple as to how they tied together.. the https://github.com/gurnec/decrypt_bitcoinj_seed/tree/master/aespython is specifically designed for decryptin BIP39 / 44 wallet seeds that MultiBitHD will use.. it is more like replicating the same logic bitcoinJ use for wallet encryption.. and for the https://github.com/HardCorePawn/multibit_recovery/tree/master it is more of a full recovery utility for MultiBit wallet files so while the first repo is more focused on the seed only!! this one deals more with the actual wallet files and also the recovery.. and for this repo https://github.com/serprex/aespython it is just a pure python AES implementation basically use during testing so as to avoid external crypto libraries and it also ensure compatibility..it is just what the other tools are suppose to rely on when the OpenSSL bindings is not available.. Look sorry the technical jargos is even a bit much but in a very simple language though.. all this repos are just doing the same kind of job!! like helping to recover old multiBit wallets... Like first repo link i talk about is focusing on unlocking the seed / the master key and the second one is more like a full recovery tool for wallet files and while the third one is just showing how the encryption itself works behind.. so the tools are just doing the Mike Tyson kind of job behind the scene!! like they basically handle the heavy lifting for you and allow you chill with a cup of coffee!!! all you will do is just to give them your wallet file ++ password and they will try to rebuild or unlock your coins no questions asked...
6 Reply Quote Share
satoshi_degenFull Member
Posts: 40 · Reputation: 375
#5Aug 14, 2018, 01:51 AM
I couldn't get anything to work, so I asked chatgpt to make some python files To be clear, I dont have any files, just the 34 character and 16 character I noted as secret key That seemed enough back then (bitcoin 0.3.24 with nodejs or bitcoinj or something, I'm very sure its pre bitcoin 0.4) If I base64 hex the secret key it gives ECA***********CD********* the * is 10 numbers and 9 numbers # -*- coding: utf-8 -*- import base64 from Crypto.Cipher import AES BLOCK = 16 def fix_base64(b64):     """Voeg ontbrekende = padding toe"""     return b64 + "=" * ((4 - len(b64) % 4) % 4) def decrypt_legacy(secret, b64, debug=True):     """AES decryptie zoals BitcoinJ pre-2012"""     key = secret  # in Python 2, str is al bytes     b64_fixed = fix_base64(b64)        if debug:         print "[DEBUG] Base64 input:", b64         print "[DEBUG] Base64 padded:", b64_fixed     data = base64.b64decode(b64_fixed)     if debug:         print "[DEBUG] Ciphertext length:", len(data), "bytes"         print "[DEBUG] Ciphertext hex:", data.encode('hex'))     for mode in ("ECB", "CBC0"):         try:             if mode == "ECB":                 cipher = AES.new(key, AES.MODE_ECB)                 pt = cipher.decrypt(data)             else:                 iv = "\x00" * BLOCK                 cipher = AES.new(key, AES.MODE_CBC, iv)                 pt = cipher.decrypt(data)             if debug:                 print "[DEBUG] Mode", mode, "decrypted length:", len(pt)                 print "[DEBUG] Raw plaintext hex:", pt.encode('hex')             pad = ord(pt[-1])             if 1 <= pad <= BLOCK and pt.endswith(chr(pad) * pad):                 pt = pt[:-pad]                 if debug:                     print "[DEBUG] Padding", pad, "removed, new length:", len(pt)             if len(pt) == 32:                 if debug:                     print "[SUCCESS] Decrypted private key found!"                 return pt         except Exception as e:             if debug:                 print "[DEBUG] Exception in mode", mode, ":", e)             continue     return None if __name__ == "__main__":     secret = "7ABCDEFGHIJKLMNO"  # jouw 16-char secret     encrypted_key = "3CaUUDLAgGNvNL1gh1B*******prWtnuiH"  # 34-char string     priv = decrypt_legacy(secret, encrypted_key, debug=True)     if priv:         print "[RESULT] Private key (hex):", priv.encode('hex')     else:         print "[RESULT] Kon de sleutel niet ontsleutelen." and some other, but chatgpt couldnt figure it out, but I know for sure the encrypted key from a few lines above this is correct, the secret key isn't but that shouldn't matter, chatgpt said it doesnt matter if its python 2 or 3 while I read that does matter with the string being for python2 and not 3
4 Reply Quote Share
paul.ninjaFull Member
Posts: 152 · Reputation: 539
#6Aug 14, 2018, 03:23 AM
A few facts that should clear this up and save you some rabbit holes: Pre-0.4.0 Core had no wallet encryption. Bitcoin Core 0.3.x stored private keys in Berkeley DB as key/wkey (unencrypted). "Encryption" only appears in 0.4.0. Core 0.4+ encryption (wallet.dat) works the following way: -- A random 32-byte master key is generated. -- Your passphrase is run through EVP_BytesToKey(SHA-512) with an 8-byte salt and a stored, wallet-specific nDeriveIterations (chosen to take ~250ms on your machine when you encrypted). These three values live in the mkey record: vchSalt, nDeriveMethod (0=SHA-512), nDeriveIterations, and vchCryptedKey (the master key encrypted with AES-256-CBC). -- Each private key is then stored as ckey = AES-256-CBC(master_key, IV) of the secret, where IV = first 16 bytes of DoubleSHA256(pubkey). -- If you see key entries, they're unencrypted; ckey means encrypted; mkey must be present for encrypted wallets. So, Core doesn't encrypt each key with your passphrase directly; it encrypts a master key with your passphrase, and uses that master key to encrypt each private key. bitcoinj (0.5 era) is not the same scheme, bitcoinj's default KeyCrypterScrypt uses scrypt (N=16384, r=8, p=1) to derive an AES-256 key, and (by default) encrypts each key with AES using a random IV per key. Different KDF, different layout, different metadata. Don't mix the two. You can inspect your files quickly by dumping the Berkeley DB and looking for records: mkey (has salt+iterations), ckey (encrypted privkeys), key (plain). Tools you can use: bitcoin-wallet -wallet=<path> -dump on modern Core; or pywallet/simple BDB dumper if you're working offline. Do not post the file. Now, about your Python attempt, brute-forcing AES on ckey with guesses about fixed IV/format will fail unless you first decrypt the master key using the exact SHA-512 KDF params from mkey. For bitcoinj wallets, use scrypt with the wallet's salt, then try AES with the per-entry IV. Different code path entirely. If you want, you can paste (in text) the mkey fields (salt hex + nDeriveIterations + nDeriveMethod) and a single ckey+pubkey pair from a test wallet (no funds) and then I can help you sketch the decryption steps so your script checks the right boxes.
6 Reply Quote Share
?Reply
Sign in to reply to this topic

Related topics