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  }