Why?I've always wanted to create my own
BIP38 tool. To be honest, the existing implementations out there are already excellent, so there wasn’t much need to reinvent the wheel. Instead, I decided to write a simple
bash wrapper to make interacting with the Python library even easier.
And to spice things up, you can use the tool completely offline!Requirements1. A permanently offline Linux device for generating your private keys.
2. An online computer for downloading the necessary libraries (make sure
pip is installed here).
3. A USB stick (or similar) to transfer the libraries from your online computer to your offline device.
Downloading the Libraries:Start by booting up your online computer and opening a terminal. Create a directory for the dependencies and use
pip to download the libraries:
mkdir -p requirements
pip download bip38 bitcoinlib -d requirements
Your offline device probably won’t have
pip installed, but most Linux distributions do come with Python pre-installed. So, let’s get
pip ready as well:
cd requirements
curl -O https://bootstrap.pypa.io/get-pip.py
Now, copy the entire
requirements directory to your USB stick.
Installing the Libraries on the Offline Device:Transfer the
requirements directory from your USB stick to the offline computer. Open a terminal and install
pip:
python3 get-pip.py --no-index
Next, create a virtual environment and activate it:
python3 -m venv .env
source .env/bin/activate
Now, install the Python libraries from your local directory:
pip install --no-index --find-links=requirements bip38 bitcoinlib
Running the CodeTime to have some fun! Create a bash file and make it executable:
touch bip38.sh
chmod u+x bip38.sh
Copy and paste the following script into
bip38.sh:
#!/bin/bash
encrypt() {
privkey="\$1"
passphrase="\$2"
python3 - <<EOF
from bip38 import BIP38
from bip38.cryptocurrencies import Bitcoin
bip38 = BIP38(Bitcoin)
print(bip38.encrypt("\$privkey", "\$passphrase"))
EOF
}
decrypt() {
bip38key="\$1"
passphrase="\$2"
python3 - <<EOF
from bip38 import BIP38
from bip38.cryptocurrencies import Bitcoin
bip38 = BIP38(Bitcoin)
print(bip38.decrypt("\$bip38key", "\$passphrase"))
EOF
}
generate() {
passphrase="\$1"
# Get 32 bytes (256 bits) of entropy as hex from /dev/urandom
entropy=\$(head -c 32 /dev/urandom | xxd -p -c 32)
python3 - <<EOF
from bitcoinlib.keys import Key
from bip38 import BIP38
from bip38.cryptocurrencies import Bitcoin
import binascii
privkey_bytes = binascii.unhexlify("\$entropy")
key = Key(privkey_bytes)
privkey_wif = key.wif()
address = key.address()
bip38 = BIP38(Bitcoin)
encrypted = bip38.encrypt(privkey_wif, "\$passphrase")
print("Address: " + address)
print("Encrypted Private Key (BIP38): " + encrypted)
EOF
}
if [ "\$#" -lt 2 ]; then
echo "Usage:"
echo " \$0 encrypt <privatekey> <passphrase>"
echo " \$0 decrypt <bip38key> <passphrase>"
echo " \$0 generate <passphrase>"
exit 1
fi
case "\$1" in
encrypt)
if [ "\$#" -ne 3 ]; then
echo "Usage: \$0 encrypt <privatekey> <passphrase>"
exit 1
fi
encrypt "\$2" "\$3"
;;
decrypt)
if [ "\$#" -ne 3 ]; then
echo "Usage: \$0 decrypt <bip38key> <passphrase>"
exit 1
fi
decrypt "\$2" "\$3"
;;
generate)
if [ "\$#" -ne 2 ]; then
echo "Usage: \$0 generate <passphrase>"
exit 1
fi
generate "\$2"
;;
*)
echo "Unknown command: \$1"
exit 1
;;
esac
Usage:./bip38.sh encrypt <privatekey> <passphrase>
./bip38.sh decrypt <bip38key> <passphrase>
./bip38.sh generate <passphrase>
Example Execution:> ./bip38.sh generate good_morning_from_apogio
Address: 1KDqMoReZhqt5grhVQvnTTNhLkqSi6mns5
Encrypted Private Key (BIP38): 6PYNQn8y5scqonRbhgJMwu7jdrSeYfodf4FGC46TcB8iqf6JizLKMXRWJE
> ./bip38.sh decrypt 6PYNQn8y5scqonRbhgJMwu7jdrSeYfodf4FGC46TcB8iqf6JizLKMXRWJE good_morning_from_apogio
KyZNsaPBGJVC2GLLBZ9wZfKYF5NgVzU1bQUpEBHMC9Hp1fKQY2qY
> ./bip38.sh encrypt KyZNsaPBGJVC2GLLBZ9wZfKYF5NgVzU1bQUpEBHMC9Hp1fKQY2qY good_morning_from_apogio
6PYNQn8y5scqonRbhgJMwu7jdrSeYfodf4FGC46TcB8iqf6JizLKMXRWJE
Disclaimers1. This is just for fun!
2. You could just use Python directly, but where’s the fun in that? The Bash wrapper is part of the charm.