github.com/turingchain2020/turingchain@v1.1.21/wallet/seed.go (about)

     1  // Copyright Turing Corp. 2018 All Rights Reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package wallet
     6  
     7  import (
     8  	"bytes"
     9  	"crypto/aes"
    10  	"crypto/cipher"
    11  	"encoding/hex"
    12  	"encoding/json"
    13  	"strings"
    14  
    15  	"github.com/turingchain2020/turingchain/common/crypto"
    16  	dbm "github.com/turingchain2020/turingchain/common/db"
    17  	log "github.com/turingchain2020/turingchain/common/log/log15"
    18  	"github.com/turingchain2020/turingchain/types"
    19  	"github.com/turingchain2020/turingchain/wallet/bipwallet"
    20  )
    21  
    22  var (
    23  	// SeedLong 随机种子的长度
    24  	SeedLong = 15
    25  	// SaveSeedLong 保存的随机种子个数
    26  	SaveSeedLong = 12
    27  
    28  	// WalletSeed 钱包种子前缀
    29  	WalletSeed = []byte("walletseed")
    30  	seedlog    = log.New("module", "wallet")
    31  
    32  	// ChineseSeedCache 中文种子缓存映射
    33  	ChineseSeedCache = make(map[string]string)
    34  	// EnglishSeedCache 英文种子缓存映射
    35  	EnglishSeedCache = make(map[string]string)
    36  )
    37  
    38  // BACKUPKEYINDEX 备份索引Key值
    39  const BACKUPKEYINDEX = "backupkeyindex"
    40  
    41  // CreateSeed 通过指定语言类型生成seed种子,传入语言类型以及
    42  //lang = 0 通过英语单词生成种子
    43  //lang = 1 通过中文生成种子
    44  //bitsize=128 返回12个单词或者汉子,bitsize+32=160  返回15个单词或者汉子,bitszie=256 返回24个单词或者汉子
    45  func CreateSeed(folderpath string, lang int32) (string, error) {
    46  	mnem, err := bipwallet.NewMnemonicString(int(lang), 160)
    47  	if err != nil {
    48  		seedlog.Error("CreateSeed", "NewMnemonicString err", err)
    49  		return "", err
    50  	}
    51  	return mnem, nil
    52  }
    53  
    54  // InitSeedLibrary 初始化seed标准库的单词到map中,方便seed单词的校验
    55  func InitSeedLibrary() {
    56  	//首先将标准seed库转换成字符串数组
    57  	englieshstrs := strings.Split(englishText, " ")
    58  	chinesestrs := strings.Split(chineseText, " ")
    59  
    60  	//中引文标准seed库保存到map中
    61  	for _, wordstr := range chinesestrs {
    62  		ChineseSeedCache[wordstr] = wordstr
    63  	}
    64  
    65  	for _, wordstr := range englieshstrs {
    66  		EnglishSeedCache[wordstr] = wordstr
    67  	}
    68  }
    69  
    70  // VerifySeed 校验输入的seed字符串数是否合法,通过助记词能否生成钱包来判断合法性
    71  func VerifySeed(seed string, signType int, coinType uint32) (bool, error) {
    72  
    73  	_, err := bipwallet.NewWalletFromMnemonic(coinType, uint32(signType), seed)
    74  	if err != nil {
    75  		seedlog.Error("VerifySeed NewWalletFromMnemonic", "err", err)
    76  		return false, err
    77  	}
    78  	return true, nil
    79  }
    80  
    81  // SaveSeedInBatch 保存种子数据到数据库
    82  func SaveSeedInBatch(db dbm.DB, seed string, password string, batch dbm.Batch) (bool, error) {
    83  	if len(seed) == 0 || len(password) == 0 {
    84  		return false, types.ErrInvalidParam
    85  	}
    86  
    87  	Encrypted, err := AesgcmEncrypter([]byte(password), []byte(seed))
    88  	if err != nil {
    89  		seedlog.Error("SaveSeed", "AesgcmEncrypter err", err)
    90  		return false, err
    91  	}
    92  	batch.Set(WalletSeed, Encrypted)
    93  	//seedlog.Info("SaveSeed ok", "Encryptedseed", Encryptedseed)
    94  	return true, nil
    95  }
    96  
    97  //GetSeed 使用password解密seed上报给上层
    98  func GetSeed(db dbm.DB, password string) (string, error) {
    99  	if len(password) == 0 {
   100  		return "", types.ErrInvalidParam
   101  	}
   102  	Encryptedseed, err := db.Get(WalletSeed)
   103  	if err != nil {
   104  		return "", err
   105  	}
   106  	if len(Encryptedseed) == 0 {
   107  		return "", types.ErrSeedNotExist
   108  	}
   109  	seed, err := AesgcmDecrypter([]byte(password), Encryptedseed)
   110  	if err != nil {
   111  		seedlog.Error("GetSeed", "AesgcmDecrypter err", err)
   112  		return "", types.ErrInputPassword
   113  	}
   114  	return string(seed), nil
   115  }
   116  
   117  //GetPrivkeyBySeed 通过seed生成子私钥十六进制字符串
   118  func GetPrivkeyBySeed(db dbm.DB, seed string, specificIndex uint32, SignType int, coinType uint32) (string, error) {
   119  	var backupindex uint32
   120  	var Hexsubprivkey string
   121  	var err error
   122  	var index uint32
   123  	signType := uint32(SignType)
   124  	//通过主私钥随机生成child私钥十六进制字符串
   125  	if specificIndex == 0 {
   126  		backuppubkeyindex, err := db.Get([]byte(BACKUPKEYINDEX))
   127  		if backuppubkeyindex == nil || err != nil {
   128  			index = 0
   129  		} else {
   130  			if err = json.Unmarshal(backuppubkeyindex, &backupindex); err != nil {
   131  				return "", err
   132  			}
   133  			index = backupindex + 1
   134  		}
   135  	} else {
   136  		index = specificIndex
   137  	}
   138  	cryptoName := crypto.GetName(SignType)
   139  	if cryptoName == "unknown" {
   140  		return "", types.ErrNotSupport
   141  	}
   142  
   143  	wallet, err := bipwallet.NewWalletFromMnemonic(coinType, signType, seed)
   144  	if err != nil {
   145  		seedlog.Error("GetPrivkeyBySeed NewWalletFromMnemonic", "err", err)
   146  		wallet, err = bipwallet.NewWalletFromSeed(coinType, signType, []byte(seed))
   147  		if err != nil {
   148  			seedlog.Error("GetPrivkeyBySeed NewWalletFromSeed", "err", err)
   149  			return "", types.ErrNewWalletFromSeed
   150  		}
   151  	}
   152  
   153  	//通过索引生成Key pair
   154  	priv, pub, err := wallet.NewKeyPair(index)
   155  	if err != nil {
   156  		seedlog.Error("GetPrivkeyBySeed NewKeyPair", "err", err)
   157  		return "", types.ErrNewKeyPair
   158  	}
   159  
   160  	Hexsubprivkey = hex.EncodeToString(priv)
   161  
   162  	public, err := bipwallet.PrivkeyToPub(coinType, signType, priv)
   163  	if err != nil {
   164  		seedlog.Error("GetPrivkeyBySeed PrivkeyToPub", "err", err)
   165  		return "", types.ErrPrivkeyToPub
   166  	}
   167  	if !bytes.Equal(pub, public) {
   168  		seedlog.Error("GetPrivkeyBySeed NewKeyPair pub  != PrivkeyToPub", "err", err)
   169  		return "", types.ErrSubPubKeyVerifyFail
   170  	}
   171  
   172  	// back up index in db
   173  	if specificIndex == 0 {
   174  		var pubkeyindex []byte
   175  		pubkeyindex, err = json.Marshal(index)
   176  		if err != nil {
   177  			seedlog.Error("GetPrivkeyBySeed", "Marshal err ", err)
   178  			return "", types.ErrMarshal
   179  		}
   180  
   181  		err = db.SetSync([]byte(BACKUPKEYINDEX), pubkeyindex)
   182  		if err != nil {
   183  			seedlog.Error("GetPrivkeyBySeed", "SetSync err ", err)
   184  			return "", err
   185  		}
   186  	}
   187  	return Hexsubprivkey, nil
   188  }
   189  
   190  //AesgcmEncrypter 使用钱包的password对seed进行aesgcm加密,返回加密后的seed
   191  func AesgcmEncrypter(password []byte, seed []byte) ([]byte, error) {
   192  	key := make([]byte, 32)
   193  	if len(password) > 32 {
   194  		key = password[0:32]
   195  	} else {
   196  		copy(key, password)
   197  	}
   198  
   199  	block, err := aes.NewCipher(key)
   200  	if err != nil {
   201  		seedlog.Error("AesgcmEncrypter NewCipher err", "err", err)
   202  		return nil, err
   203  	}
   204  	aesgcm, err := cipher.NewGCM(block)
   205  	if err != nil {
   206  		seedlog.Error("AesgcmEncrypter NewGCM err", "err", err)
   207  		return nil, err
   208  	}
   209  
   210  	Encrypted := aesgcm.Seal(nil, key[:12], seed, nil)
   211  	//seedlog.Info("AesgcmEncrypter Seal", "seed", seed, "key", key, "Encrypted", Encrypted)
   212  	return Encrypted, nil
   213  }
   214  
   215  //AesgcmDecrypter 使用钱包的password对seed进行aesgcm解密,返回解密后的seed
   216  func AesgcmDecrypter(password []byte, seed []byte) ([]byte, error) {
   217  	key := make([]byte, 32)
   218  	if len(password) > 32 {
   219  		key = password[0:32]
   220  	} else {
   221  		copy(key, password)
   222  	}
   223  
   224  	block, err := aes.NewCipher(key)
   225  	if err != nil {
   226  		seedlog.Error("AesgcmDecrypter", "NewCipher err", err)
   227  		return nil, err
   228  	}
   229  	aesgcm, err := cipher.NewGCM(block)
   230  	if err != nil {
   231  		seedlog.Error("AesgcmDecrypter", "NewGCM err", err)
   232  		return nil, err
   233  	}
   234  	decryptered, err := aesgcm.Open(nil, key[:12], seed, nil)
   235  	if err != nil {
   236  		seedlog.Error("AesgcmDecrypter", "aesgcm Open err", err)
   237  		return nil, err
   238  	}
   239  	//seedlog.Info("AesgcmDecrypter", "password", string(password), "seed", seed, "decryptered", string(decryptered))
   240  	return decryptered, nil
   241  }