neděle 3. ledna 2021

Vytvoření Bitcoin peněženky (WIF) v Bashi pomocí OpenSSL

Bitcoin je tu již nějaký ten pátek, což dalo vzniknout nepřebernému množství peněženek, jež nám umožňují držet BTC s ohledem na pohodlí a bezpečnost (věšinou jde pohodlí a bezpečnost proti sobě, což nyní pomiňme:). Jako softwarovému vývojáři a fanouškovi Bitcoin zajímá i z jiného, než ekonomického či společenského hlediska. Jako svůj první skutečný kontakt s Bitcoinem (tím nemyslím nákup BTC na burze) považuji instalaci a provoz tzv. Bitcoin Full Node, čímž jsem se stal malou, bezvýznamnou:) součástí světa nejslavnější kryptoměny. 

V tomto čánku bych rád popsal, jak je možné vygenerovat funkční bitcoinovou adresu "vlastními silami", z příkazové řádky linuxu, tedy pomocí nástrojů, které s Bitcoinem nemají vlastně nic společného a jsou běžnou součástí operačních systémů.

Wallet Import Format

Obecně, bitcoinová peněženka není nic jiného než aplikace (pro PC či telefon), která nám spravuje veřejné a privátní klíče, umí z veřejného klíče generovat adresu a pomocí privátního klíče podepisovat transakce a poslat je do mempoolu.

Pokud chceme uchovat svoje bitcoiny "na papíře", nic nám nebrání si klíče a adresy vytisknout na papír. K tomuto účelu se standardizoval Wallet Import Format - speciální formát pro privátní klíč, kterému elektronické peněženky rozumí a umožní nám BTC utratit. Nutno podotknout, že Bitcoin používá šifrování nad eliptickými křivkami, kde lze z privátního klíče odvodit klíč veřejný, takže stačí uchovat jen privátní klíč. Vytisknutému papíru s kódem ve WIF formátu a s odpovídající veřejnou adresou, se běžně říká "papírová peněženka".

Použíté nástroje

K vyvoření WIF peněženky budeme potřebovat tyto nástroje:

  • OpenSSL -  nástroj na kryptografii použitelný z příkazové řádky.
  • Bash včetně obvyklých nástrojů - cat, head, xxd, sed, tr, sha256sum...
  • Bitcoin Bash Tools- sada funkcí pro sofistikované generování WIF...

Naposledy uvedený nástroj Bitcoin Bash Tools, nutno říci, kompletně řeší záležitosti kolem adres a generování peněženky:) Z edukativních důvodů však z toolu užijem "jen" base58.

Jdeme na to!

Prvním krokem vygenerujem privátní klíč do souboru key.pem

    openssl ecparam -genkey -name secp256k1 -noout -out key.pem

Hned potom můžem z privátního klíče vyrobit veřejný klíč a oba uložit v hexadecimální podobě do souboru key.plain.

   openssl ec -in ./key.pem -text -out keys.plain 2> /dev/null

Pokud si prohlédnem obsah souboru keys.plain, uvidíme oba klíče v hex formátu.

Private-Key: (256 bit)
priv:
    6f:91:ac:0d:5e:a6:04:16:9c:98:d7:56:0c:ba:91:
    09:a2:45:e3:43:86:0e:21:61:50:06:f7:c0:5d:17:
    64:e6
pub:
    04:fd:ed:80:48:09:60:92:a5:ed:6c:2a:45:6c:f1:
    5b:e5:fe:84:90:65:ae:24:5b:66:7f:b2:ae:24:41:
    40:83:47:43:67:7c:ed:58:29:54:99:8c:5e:08:59:
    bb:be:e4:fb:ba:c9:df:b4:52:96:88:5b:48:25:e9:
    a5:82:8e:bb:d2
ASN1 OID: secp256k1
-----BEGIN EC PRIVATE KEY-----
MHQCAQEEIG+RrA1epgQWnJjXVgy6kQmiReNDhg4hYVAG98BdF2TmoAcGBSuBBAAK
oUQDQgAE/e2ASAlgkqXtbCpFbPFb5f6EkGWuJFtmf7KuJEFAg0dDZ3ztWClUmYxe
CFm7vuT7usnftFKWiFtIJemlgo670g==
-----END EC PRIVATE KEY----- 

Všiměme si, že privární klíč je o proti veřejnému klíči asi poloviční (32bytu v.s. 65bytů).

Nejprve se soustřeďme na důležitější, privátní klíč, ze kterého vyrobíme WIF a začneme odstraněním dvojteček a prázdných bílých znaků:

    cat ./keys.plain | sed -n '3,5p' | sed 's/[:[:space:]]//g' | tr -d '\n' > private-key.hex

Skvělé, klíč je ve hexadecimálním formátu v souboru private-key.hex.

    6f91ac0d5ea604169c98d7560cba9109a245e343860e21615006f7c05d1764e6

Připravmě si do proměnné EXT_PRIVATE_KEY_HEX privátní klíč rozšířený o byte pro identifikaci btc sítě. Tedy řekneme, že vyrábíme WIF pro Mainnet (znak 0x80) a ne Testnet (znak 0xef)

    EXT_PRIVATE_KEY_HEX="80$(cat ./private-key.hex)"

Kontrolni součet je dalších 4 bytes spočtených právě z EXT_PRIVATE_KEY_HEX. Musíme tuto proměnnou převést do binárního tvaru a 2x zahashovat. K tomu nám poslouží příkazy xxd, sha256sum a head pro odstranění přebytečného výstupu:

    echo $EXT_PRIVATE_KEY_HEX | xxd -r -p | sha256sum | head -c 64 |  xxd -r -p | sha256sum | head -c 64 > double-sha256.hex 

Obsah souboru double-sha256.hex je 66e5fd257cd7489c70282607d636acf1c1028af34ea1db0d1a5e2253795cb1b3. Máme 2xhash, teď vzit jen 4 byte (8 znaků) a je kontrolní součet:
 
    CHECKSUM="$(cat ./double-sha256.hex | head -c 8)"
 
Výslekek a obsah CHECKSUM je něco jako 66e5fd25. WIF kód v hex. tvaru vynikne spojením EXT_PRIVATE_KEY_HEX a CHECKSUM:
 
    WIF_ADDRESS_HEX="$EXT_PRIVATE_KEY_HEX$CHECKSUM" 

Ještě převést do base58 kódování. Je možné použít online převodník, nebo si stáhnout uvedený bitcoin bash tool příkazem 
 
    git clone https://github.com/grondilu/bitcoin-bash-tools.git

a pak zadat dva příkazy:

    source ./bitcoin-bash-tools/bitcoin.sh
    encodeBase58 $WIF_ADDRESS_HEX > wif_address.base58


První řádek nám aktivuje bitcoin-bash-tools, další nám do wif_address.base58 uloží finální peněženku ve Wallet Import Format.
 
5JfRTnhsKR9WczygHaUVhjfcLCc3F8XKUZWv48CrPiXPDqodvUL

Pokud chcete vyrobit QR code, lze použít např.

    qrencode "5JfRTnhsKR9WczygHaUVhjfcLCc3F8XKUZWv48CrPiXPDqodvUL" -o paper-wallet.png

Výsledkem je pak fungující QR kód pro utracení:

V dalším díle se vrhnem na generování veřejné adresy, kterou můžem sdílet s ostatními a na níž se můžou posílat bitcoiny. K tomu použijem existující soubor s veřejným klíčem keys.plain.

Poznámka na závěr: Článek má edukativní charakter. Pro správu privátních klíčů k Vaším BTC doporučuji použít sofistikované rešení zavedených peněženek. Jinak může dojít ke ztrátě Vašich klíčů a tím i BTC.

Použité zdroje:

  • https://en.bitcoin.it/wiki/Wallet_import_format
  • http://gobittest.appspot.com/Address
  • http://gobittest.appspot.com/PrivateKey
  • https://en.bitcoin.it/wiki/Invoice_address
  • https://en.bitcoin.it/wiki/Technical_background_of_version_1_Bitcoin_addresses
  • https://wiki.openssl.org/index.php/Command_Line_Elliptic_Curve_Operations#Generating_EC_Keys_and_Parameters
  • https://kjur.github.io/jsrsasign/sample/sample-ecdsa.html