github.com/aergoio/aergo@v1.3.1/account/key/store.go (about)

     1  package key
     2  
     3  import (
     4  	"bytes"
     5  	"crypto/aes"
     6  	"crypto/cipher"
     7  	"errors"
     8  	"path"
     9  	"sync"
    10  	"time"
    11  
    12  	"github.com/aergoio/aergo-lib/db"
    13  	"github.com/aergoio/aergo/types"
    14  	"github.com/btcsuite/btcd/btcec"
    15  	sha256 "github.com/minio/sha256-simd"
    16  )
    17  
    18  type aergokey = btcec.PrivateKey
    19  
    20  type keyPair struct {
    21  	key   *aergokey
    22  	timer *time.Timer
    23  }
    24  
    25  // Store stucture of keystore
    26  type Store struct {
    27  	sync.RWMutex
    28  	timeout      time.Duration
    29  	unlocked     map[string]*keyPair
    30  	unlockedLock *sync.Mutex
    31  	storage      db.DB
    32  }
    33  
    34  // NewStore make new instance of keystore
    35  func NewStore(storePath string, unlockTimeout uint) *Store {
    36  	const dbName = "account"
    37  	dbPath := path.Join(storePath, dbName)
    38  	return &Store{
    39  		timeout:      time.Duration(unlockTimeout) * time.Second,
    40  		unlocked:     map[string]*keyPair{},
    41  		unlockedLock: &sync.Mutex{},
    42  		storage:      db.NewDB(db.LevelImpl, dbPath),
    43  	}
    44  }
    45  func (ks *Store) CloseStore() {
    46  	ks.unlocked = nil
    47  	ks.storage.Close()
    48  }
    49  
    50  // CreateKey make new key in keystore and return it's address
    51  func (ks *Store) CreateKey(pass string) (Address, error) {
    52  	//gen new key
    53  	privkey, err := btcec.NewPrivateKey(btcec.S256())
    54  	if err != nil {
    55  		return nil, err
    56  	}
    57  	return ks.addKey(privkey, pass)
    58  }
    59  
    60  //ImportKey is to import encrypted key
    61  func (ks *Store) ImportKey(imported []byte, oldpass string, newpass string) (Address, error) {
    62  	hash := hashBytes([]byte(oldpass), nil)
    63  	rehash := hashBytes([]byte(oldpass), hash)
    64  	key, err := decrypt(hash, rehash, imported)
    65  	if err != nil {
    66  		return nil, err
    67  	}
    68  	privkey, pubkey := btcec.PrivKeyFromBytes(btcec.S256(), key)
    69  	address := GenerateAddress(pubkey.ToECDSA())
    70  	addresses, err := ks.GetAddresses()
    71  	if err != nil {
    72  		return nil, err
    73  	}
    74  	for _, v := range addresses {
    75  		if bytes.Equal(address, v) {
    76  			return nil, errors.New("already exist")
    77  		}
    78  	}
    79  	err = ks.SaveAddress(address)
    80  	if err != nil {
    81  		return nil, err
    82  	}
    83  	return ks.addKey(privkey, newpass)
    84  }
    85  
    86  //ExportKey is to export encrypted key
    87  func (ks *Store) ExportKey(addr Address, pass string) ([]byte, error) {
    88  	key, err := ks.getKey(addr, pass)
    89  	if key == nil {
    90  		return nil, err
    91  	}
    92  	return EncryptKey(key, pass)
    93  }
    94  
    95  // EncryptKey encrypts a key with a given export for exporting
    96  func EncryptKey(key []byte, pass string) ([]byte, error) {
    97  	hash := hashBytes([]byte(pass), nil)
    98  	rehash := hashBytes([]byte(pass), hash)
    99  	return encrypt(hash, rehash, key)
   100  }
   101  
   102  //Unlock is to unlock account for signing
   103  func (ks *Store) Unlock(addr Address, pass string) (Address, error) {
   104  	key, err := ks.getKey(addr, pass)
   105  	if key == nil {
   106  		return nil, err
   107  	}
   108  	pk, _ := btcec.PrivKeyFromBytes(btcec.S256(), key)
   109  	addrKey := types.EncodeAddress(addr)
   110  
   111  	ks.unlockedLock.Lock()
   112  	defer ks.unlockedLock.Unlock()
   113  
   114  	unlockedKeyPair, exist := ks.unlocked[addrKey]
   115  
   116  	if ks.timeout == 0 {
   117  		ks.unlocked[addrKey] = &keyPair{key: pk, timer: nil}
   118  		return addr, nil
   119  	}
   120  
   121  	if exist {
   122  		unlockedKeyPair.timer.Reset(ks.timeout)
   123  	} else {
   124  		lockTimer := time.AfterFunc(ks.timeout,
   125  			func() {
   126  				ks.Lock(addr, pass)
   127  			},
   128  		)
   129  		ks.unlocked[addrKey] = &keyPair{key: pk, timer: lockTimer}
   130  	}
   131  	return addr, nil
   132  }
   133  
   134  //Lock is to lock account prevent signing
   135  func (ks *Store) Lock(addr Address, pass string) (Address, error) {
   136  	key, err := ks.getKey(addr, pass)
   137  	if key == nil {
   138  		return nil, err
   139  	}
   140  	b58addr := types.EncodeAddress(addr)
   141  
   142  	ks.unlockedLock.Lock()
   143  	defer ks.unlockedLock.Unlock()
   144  
   145  	if _, exist := ks.unlocked[b58addr]; exist {
   146  		ks.unlocked[b58addr] = nil
   147  		delete(ks.unlocked, b58addr)
   148  	}
   149  	return addr, nil
   150  }
   151  
   152  func (ks *Store) getKey(address []byte, pass string) ([]byte, error) {
   153  	encryptkey := hashBytes(address, []byte(pass))
   154  	key := ks.storage.Get(hashBytes(address, encryptkey))
   155  	if cap(key) == 0 {
   156  		return nil, types.ErrWrongAddressOrPassWord
   157  	}
   158  	return decrypt(address, encryptkey, key)
   159  }
   160  
   161  func (ks *Store) addKey(key *btcec.PrivateKey, pass string) (Address, error) {
   162  	//gen new address
   163  	address := GenerateAddress(&key.PublicKey)
   164  	//save pass/address/key
   165  	encryptkey := hashBytes(address, []byte(pass))
   166  	encrypted, err := encrypt(address, encryptkey, key.Serialize())
   167  	if err != nil {
   168  		return nil, err
   169  	}
   170  	ks.storage.Set(hashBytes(address, encryptkey), encrypted)
   171  	return address, nil
   172  }
   173  
   174  func hashBytes(b1 []byte, b2 []byte) []byte {
   175  	h := sha256.New()
   176  	h.Write(b1)
   177  	h.Write(b2)
   178  	return h.Sum(nil)
   179  }
   180  
   181  func encrypt(base, key, data []byte) ([]byte, error) {
   182  	block, err := aes.NewCipher(key)
   183  	if err != nil {
   184  		return nil, err
   185  	}
   186  	// Never use more than 2^32 random nonces with a given key because of the risk of a repeat.
   187  	if len(base) < 16 {
   188  		return nil, errors.New("too short address length")
   189  	}
   190  	nonce := base[4:16]
   191  
   192  	aesgcm, err := cipher.NewGCM(block)
   193  	if err != nil {
   194  		return nil, err
   195  	}
   196  
   197  	cipherbytes := aesgcm.Seal(nil, nonce, data, nil)
   198  	return cipherbytes, nil
   199  }
   200  
   201  func decrypt(base, key, data []byte) ([]byte, error) {
   202  	if len(base) < 16 {
   203  		return nil, errors.New("too short address length")
   204  	}
   205  	nonce := base[4:16]
   206  
   207  	block, err := aes.NewCipher(key)
   208  	if err != nil {
   209  		return nil, err
   210  	}
   211  
   212  	aesgcm, err := cipher.NewGCM(block)
   213  	if err != nil {
   214  		return nil, err
   215  	}
   216  
   217  	plainbytes, err := aesgcm.Open(nil, nonce, data, nil)
   218  
   219  	if err != nil {
   220  		return nil, err
   221  	}
   222  	return plainbytes, nil
   223  }