github.com/igggame/nebulas-go@v2.1.0+incompatible/crypto/keystore/keystore.go (about)

     1  // Copyright (C) 2017 go-nebulas authors
     2  //
     3  // This file is part of the go-nebulas library.
     4  //
     5  // the go-nebulas library is free software: you can redistribute it and/or modify
     6  // it under the terms of the GNU General Public License as published by
     7  // the Free Software Foundation, either version 3 of the License, or
     8  // (at your option) any later version.
     9  //
    10  // the go-nebulas library is distributed in the hope that it will be useful,
    11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13  // GNU General Public License for more details.
    14  //
    15  // You should have received a copy of the GNU General Public License
    16  // along with the go-nebulas library.  If not, see <http://www.gnu.org/licenses/>.
    17  //
    18  
    19  package keystore
    20  
    21  import (
    22  	"errors"
    23  	"sync"
    24  	"time"
    25  )
    26  
    27  var (
    28  	// DefaultKS generate a default keystore
    29  	DefaultKS = NewKeystore()
    30  
    31  	// DefaultUnlockDuration default lock 300s
    32  	DefaultUnlockDuration = time.Duration(300 * time.Second)
    33  
    34  	// YearUnlockDuration lock 1 year time
    35  	YearUnlockDuration = time.Duration(365 * 24 * 60 * 60 * time.Second)
    36  )
    37  
    38  var (
    39  	// ErrUninitialized uninitialized provider error.
    40  	ErrUninitialized = errors.New("uninitialized the provider")
    41  
    42  	// ErrNotUnlocked key not unlocked
    43  	ErrNotUnlocked = errors.New("key not unlocked")
    44  
    45  	// ErrInvalidPassphrase invalid passphrase
    46  	ErrInvalidPassphrase = errors.New("passphrase is invalid")
    47  )
    48  
    49  // unlock item
    50  type unlocked struct {
    51  	alias string
    52  
    53  	key Key
    54  
    55  	timer *time.Timer
    56  }
    57  
    58  // Keystore class represents a storage facility for cryptographic keys
    59  type Keystore struct {
    60  
    61  	// keystore provider
    62  	p Provider
    63  
    64  	// unlocked items
    65  	unlocked map[string]*unlocked
    66  
    67  	mu sync.RWMutex
    68  }
    69  
    70  // NewKeystore new
    71  func NewKeystore() *Keystore {
    72  	ks := &Keystore{}
    73  
    74  	ks.unlocked = make(map[string]*unlocked)
    75  	ks.p = NewMemoryProvider(1.0, SCRYPT)
    76  	return ks
    77  }
    78  
    79  // Aliases lists all the alias names of this keystore.
    80  func (ks *Keystore) Aliases() []string {
    81  	return ks.p.Aliases()
    82  }
    83  
    84  // ContainsAlias checks if the given alias exists in this keystore.
    85  func (ks *Keystore) ContainsAlias(a string) (bool, error) {
    86  	if ks.p == nil {
    87  		return false, ErrUninitialized
    88  	}
    89  
    90  	return ks.p.ContainsAlias(a)
    91  }
    92  
    93  // Unlock unlock key with ProtectionParameter
    94  func (ks *Keystore) Unlock(alias string, passphrase []byte, timeout time.Duration) error {
    95  	ks.mu.Lock()
    96  	defer ks.mu.Unlock()
    97  
    98  	key, err := ks.p.GetKey(alias, passphrase)
    99  	if err != nil {
   100  		return err
   101  	}
   102  
   103  	unlockedKey, ok := ks.unlocked[alias]
   104  	if ok == true {
   105  		unlockedKey.key = key
   106  		unlockedKey.timer.Reset(timeout)
   107  	} else {
   108  		u := &unlocked{alias, key, time.NewTimer(timeout)}
   109  		ks.unlocked[alias] = u
   110  		go ks.expire(alias)
   111  	}
   112  	return nil
   113  }
   114  
   115  // Lock lock key
   116  func (ks *Keystore) Lock(alias string) error {
   117  	ks.mu.Lock()
   118  	defer ks.mu.Unlock()
   119  
   120  	if u, ok := ks.unlocked[alias]; ok == true {
   121  		u.timer.Reset(time.Duration(0) * time.Nanosecond)
   122  		return nil
   123  	}
   124  
   125  	return ErrNotUnlocked
   126  }
   127  
   128  func (ks *Keystore) expire(alias string) {
   129  	if u, ok := ks.unlocked[alias]; ok == true {
   130  		defer u.timer.Stop()
   131  		select {
   132  		case <-u.timer.C:
   133  			ks.mu.Lock()
   134  			u.key.Clear()
   135  			delete(ks.unlocked, alias)
   136  			ks.mu.Unlock()
   137  		}
   138  	}
   139  }
   140  
   141  // GetUnlocked returns a unlocked key
   142  func (ks *Keystore) GetUnlocked(alias string) (Key, error) {
   143  	if len(alias) == 0 {
   144  		return nil, ErrNeedAlias
   145  	}
   146  
   147  	ks.mu.RLock()
   148  	defer ks.mu.RUnlock()
   149  
   150  	key, ok := ks.unlocked[alias]
   151  	if ok == false {
   152  		return nil, ErrNotUnlocked
   153  	}
   154  
   155  	return key.key, nil
   156  }
   157  
   158  // SetKey assigns the given key to the given alias, protecting it with the given passphrase.
   159  func (ks *Keystore) SetKey(a string, k Key, passphrase []byte) error {
   160  	if ks.p == nil {
   161  		return ErrUninitialized
   162  	}
   163  
   164  	return ks.p.SetKey(a, k, passphrase)
   165  }
   166  
   167  // GetKey returns the key associated with the given alias, using the given
   168  // password to recover it.
   169  func (ks *Keystore) GetKey(a string, passphrase []byte) (Key, error) {
   170  	if ks.p == nil {
   171  		return nil, ErrUninitialized
   172  	}
   173  
   174  	key, err := ks.p.GetKey(a, passphrase)
   175  	if err != nil {
   176  		return nil, err
   177  	}
   178  	return key, nil
   179  }
   180  
   181  // Delete the entry identified by the given alias from this keystore.
   182  func (ks *Keystore) Delete(a string, passphrase []byte) error {
   183  	if ks.p == nil {
   184  		return ErrUninitialized
   185  	}
   186  
   187  	key, err := ks.p.GetKey(a, passphrase)
   188  	if err != nil {
   189  		return err
   190  	}
   191  	key.Clear()
   192  
   193  	if _, ok := ks.unlocked[a]; ok == true {
   194  		ks.Lock(a)
   195  	}
   196  
   197  	return ks.p.Delete(a)
   198  }