Bitcoin Forum
June 18, 2024, 05:32:29 AM *
News: Latest Bitcoin Core release: 27.0 [Torrent]
 
   Home   Help Search Login Register More  
Pages: « 1 [2]  All
  Print  
Author Topic: Password-protected private key export format  (Read 7413 times)
2112
Legendary
*
Offline Offline

Activity: 2128
Merit: 1068



View Profile
August 12, 2011, 09:08:33 PM
 #21

I'm convinced at this point that the on-disk wallet format needs to be completely scrapped and redesigned from scratch. Unfortunately, I'm not likely to have the spare time to devote to working on this.
I'll say don't give up on that goal. There may be an incremental way to redesign it.

1) Create a separate DB_ENV just for the wallet.
2) Change single B-tree DB into three RecNo DB-s backed by flat-text files. This is quite decently supported by the Berkeley DB, especially because the wallet database is essentially an append-only. The 3 files would be public-keys, private-keys and transaction-log.
3) I see lot of people here proposing public-key operation only for shared/managed hosts. But I have yet to see anyone discussing proper transaction auditing as done by the accountants. This is why I was thinking about 3 separate databases, the 3rd being the one given to the auditors.
4) During the transition (and possibly afterwards) the default client will continue to use Oracle BDB as its only database interface.

This incremental approach could assuage Gavin's worries that the patches/pull would try to surreptitiously change the basic protocol and principles of operation for Bitcoin.

Please comment, critique, criticize or ridicule BIP 2112: https://bitcointalk.org/index.php?topic=54382.0
Long-term mining prognosis: https://bitcointalk.org/index.php?topic=91101.0
samr7 (OP)
Full Member
***
Offline Offline

Activity: 140
Merit: 430

Firstbits: 1samr7


View Profile
August 15, 2011, 07:25:39 PM
 #22

The primary goal of this format is to create something like PKCS#8/RFC5958.  PKCS#8 is the format commonly used to store SSL/TLS private keys, in password-protected form or otherwise.  It is a very flexible format with metadata describing of the type of private key, and the PBKDF parameters and block cipher used to encrypt it.

It's possible to convert an exported bitcoin private key in the base-58 format to and from PKCS#8.  In PKCS#8, the built-in password-protection feature can be applied to the private key.  Also, if a bitcoin key were to be imported into some other non-bitcoin application for whatever reason, perhaps as a signing key, PKCS#8 would be the best bet as an import format.

It's also possible to take a PKCS#8 representation and produce a reduced mapping that assumes certain parameters.  If we assume the use of the SECG 256k1 EC curve, a set of of PBKDF2 parameters, and the use of AES with a specific key size, the representation can be smaller.  Unfortunately, due to RFC5915, there is a practical lower limit on the size of any reduced format.  For bitcoin private keys, this is close to 135 bytes, and it includes numerous details that, for our purposes, aren't necessary or can be assumed.  This is unwieldy large.

The next step of evolution from PKCS#8 might work as follows.

privkey = Minimal EC private key representation, 32 bytes long
param = Parameter descriptor byte.  This is an index into a predefined list of parameter groups, perhaps like:
  • 0: SECG 256k1 key, PBKDF2, HMAC-SHA256, 8-byte salt, 4096 iterations, AES-256-CBC
  • 1: SECG 256k1 key, PBKDF2, HMAC-SHA256, 8-byte salt, 4096 iterations, Camellia-256-CBC
  • 2: SECG 256k1 key, PBKDF2, HMAC-SHA256, 8-byte salt, 16384 iterations, AES-256-CBC
  • etc..

pbhash = Hash function from parameter list
cipher = Block cipher function from parameter list
salt = Random salt value of size described in parameter list
iter = PBKDF iteration count described in parameter list
pbkey = PBKDF2(password, salt, pbhash, iter)
protkey = param | cipher(privkey, pbkey) | salt

This would handle the cryptography in the most conservative, commonly-used way, and should not make anyone nervous, or at least, not any more nervous than PKCS#8.  It would also make the format easily adaptable to new block ciphers and key derivation functions.  The smallest representation using AES would be 58 bytes long, and would convert to an 83-character base-58 string.  This is much more compact than a PKCS#8 interoperable format, but I still think it's too long.
jmarquess
Newbie
*
Offline Offline

Activity: 2
Merit: 0


View Profile
August 15, 2011, 08:45:26 PM
 #23

It's great to see that someone is trying to establish standards in bitcoin community. A while ago I was doing a bit of research regarding the private key export and came to a conclusion that OpenPGP message format would suit this use case perfectly. I encourage you to take look into RFC 4880 if you haven't already, quite a brilliant piece of work. What I advocate is to use the existing, vast system that OpenPGP is and try fitting bitcoin into it.

Advantages to taking this approach are numerous.
  • OpenPGP is a well known and tested standard
  • Security is built in
  • There is room for growth and modifications
  • It's very robust and covers almost all use cases
  • Possible use of existing OpenPGP compliant architecture

There is one great disadvantage, though. With robustness comes complexity - it's not a quick and easy fix to the problem of key sharing but rather a lengthy process of integrating bitcoin into OpenPGP ecosystem.
samr7 (OP)
Full Member
***
Offline Offline

Activity: 140
Merit: 430

Firstbits: 1samr7


View Profile
August 17, 2011, 11:38:16 PM
 #24

It's great to see that someone is trying to establish standards in bitcoin community. A while ago I was doing a bit of research regarding the private key export and came to a conclusion that OpenPGP message format would suit this use case perfectly. I encourage you to take look into RFC 4880 if you haven't already, quite a brilliant piece of work. What I advocate is to use the existing, vast system that OpenPGP is and try fitting bitcoin into it.

Advantages to taking this approach are numerous.
  • OpenPGP is a well known and tested standard
  • Security is built in
  • There is room for growth and modifications
  • It's very robust and covers almost all use cases
  • Possible use of existing OpenPGP compliant architecture

There is one great disadvantage, though. With robustness comes complexity - it's not a quick and easy fix to the problem of key sharing but rather a lengthy process of integrating bitcoin into OpenPGP ecosystem.

This sounds very interesting.  I can see simple use cases like using one EC key both as a bitcoin account and for signing PGP messages.  Possibly using a bitcoin-disclosed public key to encrypt messages, if this is safe.  How else would integration be possible?

Another factor, GnuPG has yet to produce a stable release with support for EC keys.
Red Emerald
Hero Member
*****
Offline Offline

Activity: 742
Merit: 500



View Profile WWW
September 28, 2011, 09:30:40 AM
 #25

Keeping it short is also important if you want to store it in a QR code

kjj
Legendary
*
Offline Offline

Activity: 1302
Merit: 1025



View Profile
March 29, 2013, 07:58:49 PM
Last edit: April 17, 2013, 01:12:05 PM by kjj
 #26

FYI, this is the format used by vanitygen 0.22 when you specify -e.

I had a hell of a time sorting out how to decode them, thought this might help someone else.  I'm using PHP, but PHP is easy to read.  I'm using an external PBKDF2 function.  If you use the function included with newer PHP versions, you may need to adjust the parameter order.  The mcrypt_cbc() is old too, check with the PHP manual for updated information, or use phpseclib.

The $input value is the raw base58coded string.  My base58decode function returns the binary output without verifying the check value.  If yours checks it before returning, you can skip that part.

The output value is either -1 (bad 58 check code), -2 (wrong password), or the private key as a raw binary string.

Code:
<?php
function keydecrypt($input,$password){
 
$data=base58decode($input);
 
$style=substr($data,0,1);
 
$params=substr($data,1,1);
 
$ciphertext=substr($data,2,32);
 
$pwcheck=substr($data,2+32,8);
 
$salt=substr($data,2+32+8,4);
 
$code58=substr($data,2+32+8+4,4);
 
$check58=substr(hash("sha256",hash("sha256",$style.$params.$ciphertext.$pwcheck.$salt,TRUE),TRUE),0,4);
 if(
$code58!=$check58)return -1;        // Invalid 58 check code
 
$key=pbkdf2("sha256",$password,$salt,4096,64,TRUE);    // 4096 is iterations, 64 is output length
 
$cipherkey=substr($key,0,32);
 
$iv=substr($key,32,16);
 
$hmac_key=substr($key,48,16);
 
$unprot=mcrypt_cbc(MCRYPT_RIJNDAEL_128,$cipherkey,$ciphertext,MCRYPT_DECRYPT,$iv);
 
$hmac=substr(hash_hmac("sha256",$unprot,$hmac_key,TURE),0,8);
 if(
$hmac!=$pwcheck)return -2;  // Invalid password
 
return $unprot;
}
?>


If using phpseclib, use this instead of the mcrypt_cbc call:

Code:
<?php
require_once("Crypt/AES.php");

  
$cipher = new Crypt_AES(CRYPT_AES_MODE_CBC);
  
$cipher->setKey($cipherkey);
  
$cipher->setIV($iv);
  
$unprot=$cipher->decrypt($cb);
?>


17Np17BSrpnHCZ2pgtiMNnhjnsWJ2TMqq8
I routinely ignore posters with paid advertising in their sigs.  You should too.
fecell
Jr. Member
*
Offline Offline

Activity: 135
Merit: 2


View Profile
July 10, 2019, 02:47:15 AM
 #27

Bounty: I don't have many bitcoins to throw at this, but 5 BTC go to the first person who can remove the protection from the key below:

1NPHardFPnejsycvne2gvirm5MCr9gnAbf
PsV8XM6n5FvjonHPwwjzqvzA6UXruAAJfQ5VwbXFCJrSQEiQ4gyNNDhuYfL8JUBt6mxt


To sweeten the deal: the password is 14 characters long, with upper and lower case letters only, and contains at least one dictionary word.
someone claim prize. can you give a solution?
Pages: « 1 [2]  All
  Print  
 
Jump to:  

Powered by MySQL Powered by PHP Powered by SMF 1.1.19 | SMF © 2006-2009, Simple Machines Valid XHTML 1.0! Valid CSS!