OSDN Git Service

Merge pull request #41 from Bytom/dev
[bytom/vapor.git] / blockchain / pseudohsm / key.go
1 package pseudohsm
2
3 import (
4         "fmt"
5         "io/ioutil"
6         "os"
7         "path/filepath"
8         "time"
9
10         "github.com/pborman/uuid"
11         "github.com/vapor/crypto/ed25519/chainkd"
12 )
13
14 const (
15         version = 1
16         keytype = "bytom_kd"
17 )
18
19 // XKey struct type for keystore file
20 type XKey struct {
21         ID      uuid.UUID
22         KeyType string
23         Alias   string
24         XPrv    chainkd.XPrv
25         XPub    chainkd.XPub
26 }
27
28 type keyStore interface {
29         // Loads and decrypts the key from disk.
30         GetKey(alias string, filename string, auth string) (*XKey, error)
31         // Writes and encrypts the key.
32         StoreKey(filename string, k *XKey, auth string) error
33         // Joins filename with the key directory unless it is already absolute.
34         JoinPath(filename string) string
35 }
36
37 type encryptedKeyJSON struct {
38         Crypto  cryptoJSON `json:"crypto"`
39         ID      string     `json:"id"`
40         Type    string     `json:"type"`
41         Version int        `json:"version"`
42         Alias   string     `json:"alias"`
43         XPub    string     `json:"xpub"`
44 }
45
46 type cryptoJSON struct {
47         Cipher       string                 `json:"cipher"`
48         CipherText   string                 `json:"ciphertext"`
49         CipherParams cipherparamsJSON       `json:"cipherparams"`
50         KDF          string                 `json:"kdf"`
51         KDFParams    map[string]interface{} `json:"kdfparams"`
52         MAC          string                 `json:"mac"`
53 }
54
55 type cipherparamsJSON struct {
56         IV string `json:"iv"`
57 }
58
59 type scryptParamsJSON struct {
60         N     int    `json:"n"`
61         R     int    `json:"r"`
62         P     int    `json:"p"`
63         DkLen int    `json:"dklen"`
64         Salt  string `json:"salt"`
65 }
66
67 func writeKeyFile(file string, content []byte) error {
68         // Create the keystore directory with appropriate permissions
69         // in case it is not present yet.
70         const dirPerm = 0700
71         if err := os.MkdirAll(filepath.Dir(file), dirPerm); err != nil {
72                 return err
73         }
74         // Atomic write: create a temporary hidden file first
75         // then move it into place. TempFile assigns mode 0600.
76         f, err := ioutil.TempFile(filepath.Dir(file), "."+filepath.Base(file)+".tmp")
77         if err != nil {
78                 return err
79         }
80         if _, err := f.Write(content); err != nil {
81                 f.Close()
82                 os.Remove(f.Name())
83                 return err
84         }
85         f.Close()
86         return os.Rename(f.Name(), file)
87 }
88
89 func zeroKey(k *XKey) {
90         b := k.XPrv
91         for i := range b {
92                 b[i] = 0
93         }
94 }
95
96 // keyFileName implements the naming convention for keyfiles:
97 // UTC--<created_at UTC ISO8601>-<address hex>
98 func keyFileName(keyId string) string {
99         ts := time.Now().UTC()
100         return fmt.Sprintf("UTC--%s--%s", toISO8601(ts), keyId)
101 }
102
103 func toISO8601(t time.Time) string {
104         var tz string
105         name, offset := t.Zone()
106         if name == "UTC" {
107                 tz = "Z"
108         } else {
109                 tz = fmt.Sprintf("%03d00", offset/3600)
110         }
111         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)
112 }