Pages:
Author

Topic: Bitcoin Off-The-Grid (BOTG): secure savings script v0.1.1 (Read 13258 times)

legendary
Activity: 1288
Merit: 1080
Looks like someone already necro'd this thread so I won't have to.  Grin

I stumbled across this thread while looking for something faster than pywallet to convert hexkeys to WIF privkeys and addresses... haven't quite gotten it running yet as it appears to depend on vim, which I don't usually have installed (vim provides xxd) just got it running after installing vim. It might be worth noting in the OP that it needs vim (and openssl, but I already had that) to run.
Why would this depend on vim?  I don't see vim called anywhere in the script.

xxd is part of the Vim package.   To avoid this dependency you can use perl as mentioned earlier in this thread.

To spare you the hassle of looking for it:
Code:
checksum() {
    perl -we "print pack 'H*', '$1'" |
    openssl dgst -sha256 -binary |
    openssl dgst -sha256 -binary |
    perl -we "print unpack 'H8', join '', <>"
}
hero member
Activity: 742
Merit: 500
Looks like someone already necro'd this thread so I won't have to.  Grin

I stumbled across this thread while looking for something faster than pywallet to convert hexkeys to WIF privkeys and addresses... haven't quite gotten it running yet as it appears to depend on vim, which I don't usually have installed (vim provides xxd) just got it running after installing vim. It might be worth noting in the OP that it needs vim (and openssl, but I already had that) to run.
Why would this depend on vim?  I don't see vim called anywhere in the script.
hero member
Activity: 651
Merit: 501
My PGP Key: 92C7689C
Looks like someone already necro'd this thread so I won't have to.  Grin

I stumbled across this thread while looking for something faster than pywallet to convert hexkeys to WIF privkeys and addresses... haven't quite gotten it running yet as it appears to depend on vim, which I don't usually have installed (vim provides xxd) just got it running after installing vim. It might be worth noting in the OP that it needs vim (and openssl, but I already had that) to run.
vip
Activity: 1386
Merit: 1140
The Casascius 1oz 10BTC Silver Round (w/ Gold B)
There's lots of ways to generate bitcoin addresses and you just need to pick the one that works best for you.  If using this script gives you the right mix of comfort and convenience, then this is the method for you.

It will be nice when generating bitcoin addresses is a feature as standard as creating a new text file or subdirectory.
I'm particularly worried by the "recreate key if hexsize != 64" deal. Won't that effectively reduce the keyspace? I know it won't be much but still.

By about one bit.  It's an ugly hack so the script doesn't have to deal with signed numbers or leading zeros but won't reduce your security in any practical sense.

Bitcoin addresses themselves are only 160 bits, so going from 256 to 255 bits of private key is no big deal.
sr. member
Activity: 293
Merit: 250
There's lots of ways to generate bitcoin addresses and you just need to pick the one that works best for you.  If using this script gives you the right mix of comfort and convenience, then this is the method for you.

It will be nice when generating bitcoin addresses is a feature as standard as creating a new text file or subdirectory.
I'm particularly worried by the "recreate key if hexsize != 64" deal. Won't that effectively reduce the keyspace? I know it won't be much but still.
vip
Activity: 1386
Merit: 1140
The Casascius 1oz 10BTC Silver Round (w/ Gold B)
There's lots of ways to generate bitcoin addresses and you just need to pick the one that works best for you.  If using this script gives you the right mix of comfort and convenience, then this is the method for you.

It will be nice when generating bitcoin addresses is a feature as standard as creating a new text file or subdirectory.
sr. member
Activity: 293
Merit: 250
I hope my post isn't considered a necro but this method needs more exposure and most importantly more scrutinization (is that even a word?) by people who know the internals of bitcoin.

There should always be a secure way to create addresses offline with readily available tools in a standard linux distro. Since the privkey is generated by a single openssl command, you know 100% that it hasn't been tampered with. As opposed to trusting a website and downloading a program from it.

Am I too paranoid?
hero member
Activity: 481
Merit: 500
There are a couple of spelling mistakes in the script:

"peice of paper" should be "piece of paper"

and

"will lesson the security of these keys" should be "will lessen the security of these keys"
legendary
Activity: 1288
Merit: 1080
Jeez, I can't believe the code is so small.

I wish I understood it better.

Well, to be honnest I crunched it to show off.

Here is the more verbose version:
Code:
# Elliptic curve algebra and cryptography using dc
#
# Curve parameters are assumed to be stored in registers p, a, b.
# Subgroup generator is stored in register G with a base-p encoding.
# The order of the subgroup is in register o.

# secp256k1
I16i
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F sp
0000000000000000000000000000000000000000000000000000000000000007 sb
0000000000000000000000000000000000000000000000000000000000000000 sa

79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798
483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8 rlp*+ sG
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 so
i

# Most macros assume the modulus is in register 'm'.
# By default m is a copy of p.
lpsm

[ # a modulo that behaves well with negative numbers ( x -- y )
    [_1*lm1-*lm%q]St
    d0>t lm%
    Lts#
]s%

# negation
[_1*l%x]s_

# modular arithmetics ( x y -- z )
[+l%x]s+ [*l%x]s* [-l%x]s-
[Smddl%x-lm/rl%xLms#]s~ [rd0>_rlm|]s|

[ # modular inverse ( x -- y )
    l%xsc lmsd
    1su 0sv  0sr 1st
    [q]SQ
    [
        lc0=Q
ldlcl~x lc                   sd sc sq
lrlqlu*- ltlqlv*- lu lv    st sr sv su
lXx
    ]dSXx
    LXs#LQs#
    lr l%x
]sI

[ # doubling ( A -- B )
    lpSm
    [+q]S0 d0=0
    lpl~x
    sy dsx
    d*3* la l+x
    2ly* lIx
    * l%x dsl

    d* 2lx * l-x
    d lx r l-x ll l*x ly l-x
    rlp*+
    Lms# L0s#
]sD

[ # addition ( A B -- C )
    lpSm
    [+q]S0
    [2;A lDx q]Sd
    d0=0 rd0=0
    d2:A lp~ 1:A 0:A
    d2:B lp~ 1:B 0:B
    2;A 2;B =d
    [0q]Sx 2;A 0;B 1;B l_x rlm*+  =x
    0;A 0;B l-x lIx dsi
    1;A 1;B l-x l*x dsl
    d* 0;A l-x 0;B l-x d
    0;A r l-x ll l*x 1;A l-x
    rlp*+
    L0s# Lds# Lxs# Lms#
]sA

# multiplication ( A n -- B )
[
    rs.0r
    [r l. lAx r]SP
    [q]sQ
    [
        d0! d2%1=P
2/
l. lDx s.
lLx
    ]dSLx
    s# LPs# LQs#
]sM

Quote
I would really like to offer a VeriFone-terminal program that generated Bitcoin addresses and spit out paper wallets.  My biggest barrier is the lack of desire to start chopping up OpenSSL and figuring out what to carve out to feed to its dinosaur compiler.

If I had a function that could just do:  privkey_to_bitcoin_address(char[32] privkey, char* bitcoinaddressbuffer) that had no external dependencies, I'd have this built in a heartbeat.  It's a 32 bit platform.

This should not be too difficult.  Couldn't you just compile one statically??
vip
Activity: 1386
Merit: 1140
The Casascius 1oz 10BTC Silver Round (w/ Gold B)
Jeez, I can't believe the code is so small.

I wish I understood it better.  I would really like to offer a VeriFone-terminal program that generated Bitcoin addresses and spit out paper wallets.  My biggest barrier is the lack of desire to start chopping up OpenSSL and figuring out what to carve out to feed to its dinosaur compiler.

If I had a function that could just do:  privkey_to_bitcoin_address(char[32] privkey, char* bitcoinaddressbuffer) that had no external dependencies, I'd have this built in a heartbeat.  It's a 32 bit platform.

Then people could go on eBay and get the cheap old credit card machines (look at how much an Omni 3200 or a Vx510LE costs) and print paper wallets.  Flashing the terminal is easy, I have a VeriFone flashing server (self-made), just hook the terminal's dialup modem to an analog phone line and I'll give a phone number where you just point the terminal and it downloads the code and flashes it.

Such code would soon evolve into a hardware wallet that could show on-screen confirmation and communicate signed transactions to a host computer via rs232.
legendary
Activity: 1288
Merit: 1080
I wrote a pure dc elliptic curve library:

Code:
I16iFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2Fsp
7sb0sa483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8
79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798lp*+sG
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141soilpsm
[[_1*lm1-*lm%q]Std0>tlm%Lts#]s%[_1*l%x]s_[+l%x]s+[*l%x]s*[-l%x]s-[Smdd
l%x-lm/rl%xLms#]s~[l%xsclmsd1su0sv0sr1st[q]SQ[lc0=Qldlcl~xlcsdscsqlrlq
lu*-ltlqlv*-lulvstsrsvsulXx]dSXxLXs#LQs#lrl%x]sI[lpSm[+q]S0d0=0lpl~xsy
dsxd*3*lal+x2ly*lIx*l%xdsld*2lx*l-xdlxrl-xlll*xlyl-xrlp*+Lms#L0s#]sD[lp
Sm[+q]S0[2;AlDxq]Sdd0=0rd0=0d2:Alp~1:A0:Ad2:Blp~1:B0:B2;A2;B=d[0q]Sx2;A
0;B1;Bl_xrlm*+=x0;A0;Bl-xlIxdsi1;A1;Bl-xl*xdsld*0;Al-x0;Bl-xd0;Arl-xll
l*x1;Al-xrlp*+L0s#Lds#Lxs#Lms#]sA[rs.0r[rl.lAxr]SP[q]sQ[d0!lDxs.lLx]dSLxs#LPs#LQs#]sM

I wrote this because it was fun, and because I wanted to rely on openssl as little as possible.

With this library you can do addition, doubling and multiplication with points on secp256k1.

For example, if you want to compute 10^100 times the subgroup generator, i.e. the bitcoin private key whose integer value is 10^100, you can type (assuming the above code is in a "ec.dc" file):

Code:
$ dc -f ec.dc -e '10 100^ lG lMx lm~f'

I'm planning to use this to do a few cool things, including a simple function for creating a vanity address from a public key.  This will allow people to create some for others without needing trust.
cjp
full member
Activity: 210
Merit: 124
I like this. Thanks.
full member
Activity: 154
Merit: 102
Bitcoin!
Watching.
legendary
Activity: 1288
Merit: 1080
Also I did some experimenting with openssl. Yes, openssl will occasionally generate a 31-byte private key. (it's, of course, a 32-byte private key that happens to start with 00, and the leading zero truncated).

There is indeed a problem when the key is below 8^31. Notice that in even more rare cases, it can also be below 2^30, 2^29, etc... Also, as you mentioned earlier, the key could have 33 bytes when the last byte is above 0x80.

It is quite a pain in the ass to deal with thoses cases and ensure that the key is 32 bytes long. Trial and error in bitlotto's code works, but it's kind of ugly.

I think a solution would be to use an arithmetic sum:  V*2^256 + K, where V is the version number and K is the private key.

Anyway, I rewrote my set of functions. I tried to suppress any unecessary dependancies (no more xxl, nor tac.) I use Perl to do binary packing, as Perl is installed on most unix plateform.

Here they are:


Code:
#!/bin/bash
# Satoshi Nakamoto's Base58 encoding
#
# requires dc, the unix desktop calculator (which should be included in the
# 'bc' package)

declare -a base58=({1..9} {A..H} {J..N} {P..Z} {a..k} {m..z})
unset dcr; for i in {0..57}; do dcr+="${i}s${base58[i]}"; done   # dc registers

decodeBase58() {
  dc -e "$dcr 16o0$(sed 's/./ 58*l&+/g' <<<$1)p" |
  while read l; do echo -n "$l"; done
}

encodeBase58() {
  dc -e "16i ${1^^} [3A ~r d0  while read n; do echo -n "${base58[n]}"; done
}

checksum() {
  perl -we "print pack 'H*', '$1'" |
  openssl dgst -sha256 -binary |
  openssl dgst -sha256 -binary |
  perl -we "print unpack 'H8', join '', <>"
}

checkBitcoinAddress() {
  if [[ "$1" =~ ^[$(IFS= ; echo "${base58[*]}")]+$ ]]
  then
# a bitcoin address should be 25 bytes long:
# - 20 bytes for the hash160 (16/8 = 2, right?);
# - 1 byte for the version number;
# - 4 bytes for the checksum.
# shorter addresses can only occur with standard 00 version number
# and should be zero padded
# Of course, in hex you must mutiply these numbers by 2
# to get the number of nybbles (hex digits)
h="$(printf "%50s" $(decodeBase58 "$1")| sed 's/ /0/g')"
    checksum "${h::${#h}-8}" |
    grep -qi "^${h: -8}$"
  else return 2
  fi
}

hash160() {
  openssl dgst -sha256 -binary |
  openssl dgst -rmd160 -binary |
  perl -we "print unpack 'H*', <>"
}

hashToAddress() {
  local version="${2:-00}" size="${3:-160}"
  local x="$(dc -e "${size}ss 16dio 2 ls^ ${version^^}* ${1^^}+p")"
  printf "%34s\n" "$(encodeBase58 "$x$(checksum "$x")")" |
  sed -r "s/ +/1/"
}

publicKeyToAddress() {
  hashToAddress "$(
  openssl ec -pubin -pubout -outform DER 2>&- |
  tail -c 65 |
  hash160
  )" "${1:-00}"
}

privateKeyToWIF() {
  hashToAddress "$(
  openssl ec -text -noout 2>&- |
  sed -n '3,5s/[: ]//gp' |
  while read l; do echo -n "$l"; done
  )" 80 256
}

WIFtoDER() {
  printf "%64s\n" "$(dc -e "16dio $(decodeBase58 $1) 100 4^ / 80 100 20^*-p")" |
  sed 's/ /0/g'
}

vanityAddress() {
  local addr priv
  while ! grep -qi "${1:-1}" <<< "$addr"
  do
priv="$(openssl ecparam -genkey -name secp256k1 2>&-)"
addr="$(openssl ec -pubout 2>&- <<<"$priv" | publicKeyToAddress)"
WIF="$(privateKeyToWIF <<<"$priv")"
  done
  echo "$addr, $WIF"
  echo "$priv"
}


PS. I forgot to mention that if you want to use some random typed data to seed the random number generator,
you can do something like:

Code:
read -p 'Type in some random characters:' random
openssl ecparam -genkey -name secp256k1 -rand <(echo $random)
vip
Activity: 1386
Merit: 1140
The Casascius 1oz 10BTC Silver Round (w/ Gold B)
Mine is really simple: I give a string, and sha256 of that string is the private key.

The string satisfies some trivial constraints to reject most typos without large loss of entropy.
legendary
Activity: 1288
Merit: 1080
Damned it, information about all this stuff seem quite dispatched every here and there.

I'd be interested in learning more about Casascius's formats (called "mini private key"  I think) and the "wallet import format".

Any entry in the wiki?  I can't contribute personnaly these days, but I'd be very happy if someone could centralize intel about those formats.
hero member
Activity: 742
Merit: 500
This is cool.

I played around with this on my mining rig and it worked great.

I tried testing the script on my Mac (Lion), but the "tac" command isn't installed.  This didn't really bother me since I don't want to run my "super secure wallet" on my main machine, so I setup a Fedora VM for my wallet to call home.

The problem is that Fedora's openssl does not have EC enabled (theres some sort of licensing problem with it).

I ended up making an xubuntu VM and that seems to play nice. Although it does say "read EC key" and "writing EC key" multiple times at each step which seems odd.

What way do you recommend importing these keys? I just updated my client to 0.4.1-beta. Is there a command line way of importing to the default client, or do we need to use a 3rd party one?

EDIT: Found https://bitcointalk.org/index.php?topic=8091.120
legendary
Activity: 1372
Merit: 1008
1davout
Check out the end of the original grondilu thread, I've shared a script that takes a PEM and spits out the private key encoded as a QR code for easy paper storage.
legendary
Activity: 2126
Merit: 1001
..actually you can achieve what I try with jackjack's pywallet:
https://github.com/jackjack-jj/pywallet

Since I would use pywallet to import the base58 keys anyway, I can use it right away with the Hex keys as well.

If someone likes to point out which part of BOTG exactly does the conversion, I would like to see and understand!

Ente

edit:
found it somewhere:
the magic lines would be:

privkey=58c00ef49f161ac94e40cde5106227e09a6dc1840cf601c877b48d9ccc7ebdbe
encodeBase58 "80$privkey$(checksum "80$privkey")" && echo
legendary
Activity: 2126
Merit: 1001
Great work, thank you a lot! This will be very helpful for a lot of projects, I am sure!

Being a bash-script-noob and only a bit experienced with the inner parts of Bitcoin, I need a little help:
Which part of the botg script converts the HEX key into (sipa patch importable) base58?

My plan is to do this:

- Take a known plaintext string, like "Damnesia" (from another thread)

- Create the SHA256 hash from that string with "echo -n Damnesia | sha256sum", in this example its "58c00ef49f161ac94e40cde5106227e09a6dc1840cf601c877b48d9ccc7ebdbe"

- Take the relevant part of this BOTG script to convert the SHA256 Hex key to base58, should be "5JVNazqC4JucAHUeRLhcqrbGFAro2CySd2ptDaDnPe18G9tmuAs" here


I can do it in a script by using the blockexplorer's "converter", this here works by saving it as "mkprvkey.sh" for example and running it with "./mkprvkey.sh Damnesia"

Code:
STRING=$1
echo
echo String: $STRING
HEX=`echo -n $STRING | sha256sum | sed 's/.\{3\}$//'`
B58=`wget -qO- http://blockexplorer.com/q/hashtoaddress/$HEX/80`
echo PrvKey: $B58
echo

For obvious reasons there must be a better way to do this, without transferring my private key to an online service, and without having to be online to begin with..

Ultimately I want to create a wallet.dat from a handful of passphrases, as a worst-case backup in case my regular, encrypted backups of the wallet.dat get eaten by fire, lightningstorm and house searches ;-)

As I said, I am quite new to bash scripting, please bear with me!

Thank you,

Ente
Pages:
Jump to: