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 }