1 // Package pseudohsm provides a pseudo HSM for development environments.
12 "bytom/crypto/ed25519/chainkd"
16 //"bytom/protocol/bc/legacy"
18 "bytom/blockchain/config"
19 "github.com/pborman/uuid"
22 // listKeyMaxAliases limits the alias filter to a sane maximum size.
23 const listKeyMaxAliases = 200
26 ErrInvalidAfter = errors.New("invalid after")
27 ErrNoKey = errors.New("key not found")
28 ErrInvalidKeySize = errors.New("key invalid size")
29 ErrTooManyAliasesToList = errors.New("requested aliases exceeds limit")
30 ErrAmbiguousAddr = errors.New("multiple keys match address")
31 ErrDecrypt = errors.New("could not decrypt key with given passphrase")
32 ErrInvalidKeyType = errors.New("key type stored invalid")
39 kdCache map[chainkd.XPub]chainkd.XPrv
43 Alias string `json:"alias"`
44 Address common.Address `json:"address"`
45 XPub chainkd.XPub `json:"xpub"`
46 File string `json:"file"`
49 func New(conf *config.Config) *HSM {
50 keydir, _ := filepath.Abs(conf.KeyPath)
52 keyStore: &keyStorePassphrase{keydir, LightScryptN, LightScryptP},
53 cache: newAddrCache(keydir),
54 kdCache: make(map[chainkd.XPub]chainkd.XPrv),
58 // XCreate produces a new random xprv and stores it in the db.
59 func (h *HSM) XCreate(auth string, alias string) (*XPub, error) {
60 xpub, _, err := h.createChainKDKey(auth, alias, false)
68 func (h *HSM) createChainKDKey(auth string, alias string, get bool) (*XPub, bool, error) {
69 xprv, xpub, err := chainkd.NewXKeys(nil)
71 return nil, false, err
73 id := uuid.NewRandom()
77 Address: crypto.PubkeyToAddress(xpub[:]),
82 file := h.keyStore.JoinPath(keyFileName(key.Address))
83 if err := h.keyStore.StoreKey(file, key, auth); err != nil {
84 return nil, false, errors.Wrap(err, "storing keys")
86 return &XPub{XPub: xpub, Address: key.Address, Alias: alias, File: file}, true, nil
90 // ListKeys returns a list of all xpubs from the store
91 func (h *HSM) ListKeys(after int , limit int) ([]XPub, string, error) {
93 xpubs := h.cache.keys()
94 start, end := 0, len(xpubs)
95 if len(xpubs) > after {
98 return nil, "", errors.WithDetailf(ErrInvalidAfter, "value: %v", after)
100 if len(xpubs) > after+limit {
103 return xpubs[start:end], strconv.FormatInt(int64(start), 10), nil
106 // XSign looks up the xprv given the xpub, optionally derives a new
107 // xprv with the given path (but does not store the new xprv), and
108 // signs the given msg.
109 func (h *HSM) XSign(xpub chainkd.XPub, path [][]byte, msg []byte, auth string) ([]byte, error) {
110 xprv, err := h.loadChainKDKey(xpub, auth)
115 xprv = xprv.Derive(path)
117 return xprv.Sign(msg), nil
120 func (h *HSM) loadChainKDKey(xpub chainkd.XPub, auth string) (xprv chainkd.XPrv, err error) {
122 defer h.cacheMu.Unlock()
124 if xprv, ok := h.kdCache[xpub]; ok {
128 xpb, xkey, err := h.loadDecryptedKey(xpub, auth)
130 return xprv, ErrNoKey
132 h.kdCache[xpb.XPub] = xkey.XPrv
133 return xkey.XPrv, nil
137 // XDelete deletes the key matched by xpub if the passphrase is correct.
138 // If a contains no filename, the address must match a unique key.
139 func (h *HSM) XDelete(xpub chainkd.XPub, auth string) error {
140 // Decrypting the key isn't really necessary, but we do
141 // it anyway to check the password and zero out the key
142 // immediately afterwards.
144 xpb, xkey, err := h.loadDecryptedKey(xpub, auth)
152 // The order is crucial here. The key is dropped from the
153 // cache after the file is gone so that a reload happening in
154 // between won't insert it into the cache again.
155 err = os.Remove(xpb.File)
160 delete(h.kdCache, xpub)
165 func (h *HSM) loadDecryptedKey(xpub chainkd.XPub, auth string) (XPub, *XKey, error) {
166 h.cache.maybeReload()
168 xpb, err := h.cache.find(XPub{XPub: xpub, Address: crypto.PubkeyToAddress(xpub[:])})
174 xkey, err := h.keyStore.GetKey(xpb.Address, xpb.File, auth)
176 return xpb, xkey, err
179 // Update alias of an existing xpub
180 func (h *HSM) UpdateAlias(xpub chainkd.XPub, auth, newAlias string) error {
181 xpb, xkey, err := h.loadDecryptedKey(xpub, auth)
185 xkey.Alias = newAlias
186 return h.keyStore.StoreKey(xpb.File, xkey, auth)
189 // Update changes the passphrase of an existing xpub
190 func (h *HSM) ResetPassword(xpub chainkd.XPub, auth, newAuth string) error {
191 xpb, xkey, err := h.loadDecryptedKey(xpub, auth)
195 return h.keyStore.StoreKey(xpb.File, xkey, newAuth)