| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // Copyright 2014 The go-ethereum Authors | 
					
						
							| 
									
										
										
										
											2015-07-22 18:48:40 +02:00
										 |  |  | // This file is part of the go-ethereum library. | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // | 
					
						
							| 
									
										
										
										
											2015-07-23 18:35:11 +02:00
										 |  |  | // The go-ethereum library is free software: you can redistribute it and/or modify | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // it under the terms of the GNU Lesser General Public License as published by | 
					
						
							|  |  |  | // the Free Software Foundation, either version 3 of the License, or | 
					
						
							|  |  |  | // (at your option) any later version. | 
					
						
							|  |  |  | // | 
					
						
							| 
									
										
										
										
											2015-07-22 18:48:40 +02:00
										 |  |  | // The go-ethereum library is distributed in the hope that it will be useful, | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							| 
									
										
										
										
											2015-07-22 18:48:40 +02:00
										 |  |  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // GNU Lesser General Public License for more details. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // You should have received a copy of the GNU Lesser General Public License | 
					
						
							| 
									
										
										
										
											2015-07-22 18:48:40 +02:00
										 |  |  | // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. | 
					
						
							| 
									
										
										
										
											2014-12-31 15:39:33 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-02 13:57:15 +01:00
										 |  |  | package accounts | 
					
						
							| 
									
										
										
										
											2014-12-31 15:39:33 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"bytes" | 
					
						
							|  |  |  | 	"crypto/ecdsa" | 
					
						
							| 
									
										
										
										
											2015-04-21 17:00:30 +02:00
										 |  |  | 	"encoding/hex" | 
					
						
							| 
									
										
										
										
											2014-12-31 15:39:33 +01:00
										 |  |  | 	"encoding/json" | 
					
						
							| 
									
										
										
										
											2016-03-03 01:15:42 +01:00
										 |  |  | 	"fmt" | 
					
						
							| 
									
										
										
										
											2014-12-31 15:39:33 +01:00
										 |  |  | 	"io" | 
					
						
							| 
									
										
										
										
											2016-03-03 01:15:42 +01:00
										 |  |  | 	"io/ioutil" | 
					
						
							|  |  |  | 	"os" | 
					
						
							|  |  |  | 	"path/filepath" | 
					
						
							| 
									
										
										
										
											2015-10-06 18:39:42 +02:00
										 |  |  | 	"strings" | 
					
						
							| 
									
										
										
										
											2016-03-03 01:15:42 +01:00
										 |  |  | 	"time" | 
					
						
							| 
									
										
										
										
											2015-02-10 12:29:50 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-02 21:14:25 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum/common" | 
					
						
							| 
									
										
										
										
											2016-03-02 13:57:15 +01:00
										 |  |  | 	"github.com/ethereum/go-ethereum/crypto" | 
					
						
							| 
									
										
										
										
											2015-09-29 19:37:44 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum/crypto/secp256k1" | 
					
						
							| 
									
										
										
										
											2015-09-10 21:48:20 +06:00
										 |  |  | 	"github.com/pborman/uuid" | 
					
						
							| 
									
										
										
										
											2014-12-31 15:39:33 +01:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-21 17:00:30 +02:00
										 |  |  | const ( | 
					
						
							| 
									
										
										
										
											2015-05-24 03:42:10 +02:00
										 |  |  | 	version = 3 | 
					
						
							| 
									
										
										
										
											2015-04-21 17:00:30 +02:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-12-31 15:39:33 +01:00
										 |  |  | type Key struct { | 
					
						
							| 
									
										
										
										
											2015-01-25 02:07:20 +01:00
										 |  |  | 	Id uuid.UUID // Version 4 "random" for unique id not derived from key data | 
					
						
							|  |  |  | 	// to simplify lookups we also store the address | 
					
						
							| 
									
										
										
										
											2015-04-02 21:14:25 +02:00
										 |  |  | 	Address common.Address | 
					
						
							| 
									
										
										
										
											2014-12-31 15:39:33 +01:00
										 |  |  | 	// we only store privkey as pubkey/address can be derived from it | 
					
						
							|  |  |  | 	// privkey in this struct is always in plaintext | 
					
						
							|  |  |  | 	PrivateKey *ecdsa.PrivateKey | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-02 13:57:15 +01:00
										 |  |  | type keyStore interface { | 
					
						
							| 
									
										
										
										
											2016-03-03 01:15:42 +01:00
										 |  |  | 	// Loads and decrypts the key from disk. | 
					
						
							|  |  |  | 	GetKey(addr common.Address, filename string, auth string) (*Key, error) | 
					
						
							|  |  |  | 	// Writes and encrypts the key. | 
					
						
							|  |  |  | 	StoreKey(filename string, k *Key, auth string) error | 
					
						
							|  |  |  | 	// Joins filename with the key directory unless it is already absolute. | 
					
						
							|  |  |  | 	JoinPath(filename string) string | 
					
						
							| 
									
										
										
										
											2016-03-02 13:57:15 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-01-15 17:45:45 +01:00
										 |  |  | type plainKeyJSON struct { | 
					
						
							| 
									
										
										
										
											2015-05-10 20:30:02 +02:00
										 |  |  | 	Address    string `json:"address"` | 
					
						
							|  |  |  | 	PrivateKey string `json:"privatekey"` | 
					
						
							|  |  |  | 	Id         string `json:"id"` | 
					
						
							| 
									
										
										
										
											2015-05-24 03:42:10 +02:00
										 |  |  | 	Version    int    `json:"version"` | 
					
						
							| 
									
										
										
										
											2014-12-31 15:39:33 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-24 03:42:10 +02:00
										 |  |  | type encryptedKeyJSONV3 struct { | 
					
						
							| 
									
										
										
										
											2015-12-07 17:01:29 +01:00
										 |  |  | 	Address string     `json:"address"` | 
					
						
							|  |  |  | 	Crypto  cryptoJSON `json:"crypto"` | 
					
						
							|  |  |  | 	Id      string     `json:"id"` | 
					
						
							|  |  |  | 	Version int        `json:"version"` | 
					
						
							| 
									
										
										
										
											2015-05-24 03:42:10 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type encryptedKeyJSONV1 struct { | 
					
						
							| 
									
										
										
										
											2015-12-07 17:01:29 +01:00
										 |  |  | 	Address string     `json:"address"` | 
					
						
							|  |  |  | 	Crypto  cryptoJSON `json:"crypto"` | 
					
						
							|  |  |  | 	Id      string     `json:"id"` | 
					
						
							|  |  |  | 	Version string     `json:"version"` | 
					
						
							| 
									
										
										
										
											2015-04-15 13:24:12 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-10 20:30:02 +02:00
										 |  |  | type cryptoJSON struct { | 
					
						
							| 
									
										
										
										
											2015-05-24 03:42:10 +02:00
										 |  |  | 	Cipher       string                 `json:"cipher"` | 
					
						
							|  |  |  | 	CipherText   string                 `json:"ciphertext"` | 
					
						
							|  |  |  | 	CipherParams cipherparamsJSON       `json:"cipherparams"` | 
					
						
							|  |  |  | 	KDF          string                 `json:"kdf"` | 
					
						
							|  |  |  | 	KDFParams    map[string]interface{} `json:"kdfparams"` | 
					
						
							|  |  |  | 	MAC          string                 `json:"mac"` | 
					
						
							| 
									
										
										
										
											2014-12-31 15:39:33 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-10 20:30:02 +02:00
										 |  |  | type cipherparamsJSON struct { | 
					
						
							|  |  |  | 	IV string `json:"iv"` | 
					
						
							| 
									
										
										
										
											2015-04-15 13:24:12 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type scryptParamsJSON struct { | 
					
						
							| 
									
										
										
										
											2015-05-10 20:30:02 +02:00
										 |  |  | 	N     int    `json:"n"` | 
					
						
							|  |  |  | 	R     int    `json:"r"` | 
					
						
							|  |  |  | 	P     int    `json:"p"` | 
					
						
							|  |  |  | 	DkLen int    `json:"dklen"` | 
					
						
							|  |  |  | 	Salt  string `json:"salt"` | 
					
						
							| 
									
										
										
										
											2014-12-31 15:39:33 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (k *Key) MarshalJSON() (j []byte, err error) { | 
					
						
							| 
									
										
										
										
											2015-01-15 17:45:45 +01:00
										 |  |  | 	jStruct := plainKeyJSON{ | 
					
						
							| 
									
										
										
										
											2015-04-21 17:00:30 +02:00
										 |  |  | 		hex.EncodeToString(k.Address[:]), | 
					
						
							| 
									
										
										
										
											2016-03-02 13:57:15 +01:00
										 |  |  | 		hex.EncodeToString(crypto.FromECDSA(k.PrivateKey)), | 
					
						
							| 
									
										
										
										
											2015-05-10 20:30:02 +02:00
										 |  |  | 		k.Id.String(), | 
					
						
							|  |  |  | 		version, | 
					
						
							| 
									
										
										
										
											2014-12-31 15:39:33 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-01-15 17:45:45 +01:00
										 |  |  | 	j, err = json.Marshal(jStruct) | 
					
						
							| 
									
										
										
										
											2015-01-07 16:06:26 +01:00
										 |  |  | 	return j, err | 
					
						
							| 
									
										
										
										
											2014-12-31 15:39:33 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (k *Key) UnmarshalJSON(j []byte) (err error) { | 
					
						
							| 
									
										
										
										
											2015-01-15 17:45:45 +01:00
										 |  |  | 	keyJSON := new(plainKeyJSON) | 
					
						
							| 
									
										
										
										
											2014-12-31 15:39:33 +01:00
										 |  |  | 	err = json.Unmarshal(j, &keyJSON) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2015-01-07 16:06:26 +01:00
										 |  |  | 		return err | 
					
						
							| 
									
										
										
										
											2014-12-31 15:39:33 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	u := new(uuid.UUID) | 
					
						
							| 
									
										
										
										
											2015-04-21 17:00:30 +02:00
										 |  |  | 	*u = uuid.Parse(keyJSON.Id) | 
					
						
							| 
									
										
										
										
											2015-01-25 02:07:20 +01:00
										 |  |  | 	k.Id = *u | 
					
						
							| 
									
										
										
										
											2015-04-21 17:00:30 +02:00
										 |  |  | 	addr, err := hex.DecodeString(keyJSON.Address) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	privkey, err := hex.DecodeString(keyJSON.PrivateKey) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	k.Address = common.BytesToAddress(addr) | 
					
						
							| 
									
										
										
										
											2016-03-02 13:57:15 +01:00
										 |  |  | 	k.PrivateKey = crypto.ToECDSA(privkey) | 
					
						
							| 
									
										
										
										
											2014-12-31 15:39:33 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-21 17:00:30 +02:00
										 |  |  | 	return nil | 
					
						
							| 
									
										
										
										
											2014-12-31 15:39:33 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-02 13:57:15 +01:00
										 |  |  | func newKeyFromECDSA(privateKeyECDSA *ecdsa.PrivateKey) *Key { | 
					
						
							| 
									
										
										
										
											2015-03-23 13:00:06 +00:00
										 |  |  | 	id := uuid.NewRandom() | 
					
						
							|  |  |  | 	key := &Key{ | 
					
						
							|  |  |  | 		Id:         id, | 
					
						
							| 
									
										
										
										
											2016-03-02 13:57:15 +01:00
										 |  |  | 		Address:    crypto.PubkeyToAddress(privateKeyECDSA.PublicKey), | 
					
						
							| 
									
										
										
										
											2015-03-23 13:00:06 +00:00
										 |  |  | 		PrivateKey: privateKeyECDSA, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return key | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-05 01:08:50 +02:00
										 |  |  | // NewKeyForDirectICAP generates a key whose address fits into < 155 bits so it can fit | 
					
						
							|  |  |  | // into the Direct ICAP spec. for simplicity and easier compatibility with other libs, we | 
					
						
							|  |  |  | // retry until the first byte is 0. | 
					
						
							| 
									
										
										
										
											2015-10-06 18:39:42 +02:00
										 |  |  | func NewKeyForDirectICAP(rand io.Reader) *Key { | 
					
						
							|  |  |  | 	randBytes := make([]byte, 64) | 
					
						
							|  |  |  | 	_, err := rand.Read(randBytes) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		panic("key generation: could not read from random source: " + err.Error()) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	reader := bytes.NewReader(randBytes) | 
					
						
							| 
									
										
										
										
											2015-09-29 19:37:44 +02:00
										 |  |  | 	privateKeyECDSA, err := ecdsa.GenerateKey(secp256k1.S256(), reader) | 
					
						
							| 
									
										
										
										
											2015-10-06 18:39:42 +02:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		panic("key generation: ecdsa.GenerateKey failed: " + err.Error()) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-03-02 13:57:15 +01:00
										 |  |  | 	key := newKeyFromECDSA(privateKeyECDSA) | 
					
						
							| 
									
										
										
										
											2015-10-06 18:39:42 +02:00
										 |  |  | 	if !strings.HasPrefix(key.Address.Hex(), "0x00") { | 
					
						
							|  |  |  | 		return NewKeyForDirectICAP(rand) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return key | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2016-03-03 01:15:42 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | func newKey(rand io.Reader) (*Key, error) { | 
					
						
							|  |  |  | 	privateKeyECDSA, err := ecdsa.GenerateKey(secp256k1.S256(), rand) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return newKeyFromECDSA(privateKeyECDSA), nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func storeNewKey(ks keyStore, rand io.Reader, auth string) (*Key, Account, error) { | 
					
						
							|  |  |  | 	key, err := newKey(rand) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, Account{}, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	a := Account{Address: key.Address, File: ks.JoinPath(keyFileName(key.Address))} | 
					
						
							|  |  |  | 	if err := ks.StoreKey(a.File, key, auth); err != nil { | 
					
						
							|  |  |  | 		zeroKey(key.PrivateKey) | 
					
						
							|  |  |  | 		return nil, a, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return key, a, err | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func writeKeyFile(file string, content []byte) error { | 
					
						
							|  |  |  | 	// Create the keystore directory with appropriate permissions | 
					
						
							|  |  |  | 	// in case it is not present yet. | 
					
						
							|  |  |  | 	const dirPerm = 0700 | 
					
						
							|  |  |  | 	if err := os.MkdirAll(filepath.Dir(file), dirPerm); err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Atomic write: create a temporary hidden file first | 
					
						
							|  |  |  | 	// then move it into place. TempFile assigns mode 0600. | 
					
						
							|  |  |  | 	f, err := ioutil.TempFile(filepath.Dir(file), "."+filepath.Base(file)+".tmp") | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if _, err := f.Write(content); err != nil { | 
					
						
							|  |  |  | 		f.Close() | 
					
						
							|  |  |  | 		os.Remove(f.Name()) | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	f.Close() | 
					
						
							|  |  |  | 	return os.Rename(f.Name(), file) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // keyFileName implements the naming convention for keyfiles: | 
					
						
							|  |  |  | // UTC--<created_at UTC ISO8601>-<address hex> | 
					
						
							|  |  |  | func keyFileName(keyAddr common.Address) string { | 
					
						
							|  |  |  | 	ts := time.Now().UTC() | 
					
						
							|  |  |  | 	return fmt.Sprintf("UTC--%s--%s", toISO8601(ts), hex.EncodeToString(keyAddr[:])) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func toISO8601(t time.Time) string { | 
					
						
							|  |  |  | 	var tz string | 
					
						
							|  |  |  | 	name, offset := t.Zone() | 
					
						
							|  |  |  | 	if name == "UTC" { | 
					
						
							|  |  |  | 		tz = "Z" | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		tz = fmt.Sprintf("%03d00", offset/3600) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return fmt.Sprintf("%04d-%02d-%02dT%02d-%02d-%02d.%09d%s", t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second(), t.Nanosecond(), tz) | 
					
						
							|  |  |  | } |