aboutsummaryrefslogtreecommitdiffstats
path: root/accounts/key.go
diff options
context:
space:
mode:
Diffstat (limited to 'accounts/key.go')
-rw-r--r--accounts/key.go94
1 files changed, 72 insertions, 22 deletions
diff --git a/accounts/key.go b/accounts/key.go
index 34fefa27c..668fa86a0 100644
--- a/accounts/key.go
+++ b/accounts/key.go
@@ -21,8 +21,13 @@ import (
"crypto/ecdsa"
"encoding/hex"
"encoding/json"
+ "fmt"
"io"
+ "io/ioutil"
+ "os"
+ "path/filepath"
"strings"
+ "time"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
@@ -44,13 +49,12 @@ type Key struct {
}
type keyStore interface {
- // create new key using io.Reader entropy source and optionally using auth string
- GenerateNewKey(io.Reader, string) (*Key, error)
- GetKey(common.Address, string) (*Key, error) // get key from addr and auth string
- GetKeyAddresses() ([]common.Address, error) // get all addresses
- StoreKey(*Key, string) error // store key optionally using auth string
- DeleteKey(common.Address, string) error // delete key by addr and auth string
- Cleanup(keyAddr common.Address) (err error)
+ // 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
}
type plainKeyJSON struct {
@@ -142,21 +146,6 @@ func newKeyFromECDSA(privateKeyECDSA *ecdsa.PrivateKey) *Key {
return key
}
-func NewKey(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)
- privateKeyECDSA, err := ecdsa.GenerateKey(secp256k1.S256(), reader)
- if err != nil {
- panic("key generation: ecdsa.GenerateKey failed: " + err.Error())
- }
-
- return newKeyFromECDSA(privateKeyECDSA)
-}
-
// generate 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.
@@ -177,3 +166,64 @@ func NewKeyForDirectICAP(rand io.Reader) *Key {
}
return key
}
+
+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)
+}