github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/accounts/keystore/presale.go (about) 1 2 //此源码被清华学神尹成大魔王专业翻译分析并修改 3 //尹成QQ77025077 4 //尹成微信18510341407 5 //尹成所在QQ群721929980 6 //尹成邮箱 yinc13@mails.tsinghua.edu.cn 7 //尹成毕业于清华大学,微软区块链领域全球最有价值专家 8 //https://mvp.microsoft.com/zh-cn/PublicProfile/4033620 9 //版权所有2016 Go Ethereum作者 10 //此文件是Go以太坊库的一部分。 11 // 12 //Go-Ethereum库是免费软件:您可以重新分发它和/或修改 13 //根据GNU发布的较低通用公共许可证的条款 14 //自由软件基金会,或者许可证的第3版,或者 15 //(由您选择)任何更高版本。 16 // 17 //Go以太坊图书馆的发行目的是希望它会有用, 18 //但没有任何保证;甚至没有 19 //适销性或特定用途的适用性。见 20 //GNU较低的通用公共许可证,了解更多详细信息。 21 // 22 //你应该收到一份GNU较低级别的公共许可证副本 23 //以及Go以太坊图书馆。如果没有,请参见<http://www.gnu.org/licenses/>。 24 25 package keystore 26 27 import ( 28 "crypto/aes" 29 "crypto/cipher" 30 "crypto/sha256" 31 "encoding/hex" 32 "encoding/json" 33 "errors" 34 "fmt" 35 36 "github.com/ethereum/go-ethereum/accounts" 37 "github.com/ethereum/go-ethereum/crypto" 38 "github.com/pborman/uuid" 39 "golang.org/x/crypto/pbkdf2" 40 ) 41 42 //通过解密预售密钥JSON,创建密钥并将其存储在给定的密钥库中。 43 func importPreSaleKey(keyStore keyStore, keyJSON []byte, password string) (accounts.Account, *Key, error) { 44 key, err := decryptPreSaleKey(keyJSON, password) 45 if err != nil { 46 return accounts.Account{}, nil, err 47 } 48 key.Id = uuid.NewRandom() 49 a := accounts.Account{Address: key.Address, URL: accounts.URL{Scheme: KeyStoreScheme, Path: keyStore.JoinPath(keyFileName(key.Address))}} 50 err = keyStore.StoreKey(a.URL.Path, key, password) 51 return a, key, err 52 } 53 54 func decryptPreSaleKey(fileContent []byte, password string) (key *Key, err error) { 55 preSaleKeyStruct := struct { 56 EncSeed string 57 EthAddr string 58 Email string 59 BtcAddr string 60 }{} 61 err = json.Unmarshal(fileContent, &preSaleKeyStruct) 62 if err != nil { 63 return nil, err 64 } 65 encSeedBytes, err := hex.DecodeString(preSaleKeyStruct.EncSeed) 66 if err != nil { 67 return nil, errors.New("invalid hex in encSeed") 68 } 69 if len(encSeedBytes) < 16 { 70 return nil, errors.New("invalid encSeed, too short") 71 } 72 iv := encSeedBytes[:16] 73 cipherText := encSeedBytes[16:] 74 /* 75 请参阅https://github.com/ethereum/pyethsaletool 76 77 pyethsaletool根据密码生成加密密钥 78 2000轮PBKdf2,HMAC-SHA-256,使用密码作为salt(:()。 79 pbkdf2内的16字节密钥长度,生成的密钥用作aes密钥。 80 **/ 81 82 passBytes := []byte(password) 83 derivedKey := pbkdf2.Key(passBytes, passBytes, 2000, 16, sha256.New) 84 plainText, err := aesCBCDecrypt(derivedKey, cipherText, iv) 85 if err != nil { 86 return nil, err 87 } 88 ethPriv := crypto.Keccak256(plainText) 89 ecKey := crypto.ToECDSAUnsafe(ethPriv) 90 91 key = &Key{ 92 Id: nil, 93 Address: crypto.PubkeyToAddress(ecKey.PublicKey), 94 PrivateKey: ecKey, 95 } 96 derivedAddr := hex.EncodeToString(key.Address.Bytes()) //需要,因为.hex()给出前导“0x” 97 expectedAddr := preSaleKeyStruct.EthAddr 98 if derivedAddr != expectedAddr { 99 err = fmt.Errorf("decrypted addr '%s' not equal to expected addr '%s'", derivedAddr, expectedAddr) 100 } 101 return key, err 102 } 103 104 func aesCTRXOR(key, inText, iv []byte) ([]byte, error) { 105 //由于加密密钥的大小,选择了AES-128。 106 aesBlock, err := aes.NewCipher(key) 107 if err != nil { 108 return nil, err 109 } 110 stream := cipher.NewCTR(aesBlock, iv) 111 outText := make([]byte, len(inText)) 112 stream.XORKeyStream(outText, inText) 113 return outText, err 114 } 115 116 func aesCBCDecrypt(key, cipherText, iv []byte) ([]byte, error) { 117 aesBlock, err := aes.NewCipher(key) 118 if err != nil { 119 return nil, err 120 } 121 decrypter := cipher.NewCBCDecrypter(aesBlock, iv) 122 paddedPlaintext := make([]byte, len(cipherText)) 123 decrypter.CryptBlocks(paddedPlaintext, cipherText) 124 plaintext := pkcs7Unpad(paddedPlaintext) 125 if plaintext == nil { 126 return nil, ErrDecrypt 127 } 128 return plaintext, err 129 } 130 131 //来自https://leanpub.com/gocrypto/read leanpub自动分组密码模式 132 func pkcs7Unpad(in []byte) []byte { 133 if len(in) == 0 { 134 return nil 135 } 136 137 padding := in[len(in)-1] 138 if int(padding) > len(in) || padding > aes.BlockSize { 139 return nil 140 } else if padding == 0 { 141 return nil 142 } 143 144 for i := len(in) - 1; i > len(in)-int(padding)-1; i-- { 145 if in[i] != padding { 146 return nil 147 } 148 } 149 return in[:len(in)-int(padding)] 150 }