github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/accounts/keystore/presale.go (about)

     1  
     2  //<developer>
     3  //    <name>linapex 曹一峰</name>
     4  //    <email>linapex@163.com</email>
     5  //    <wx>superexc</wx>
     6  //    <qqgroup>128148617</qqgroup>
     7  //    <url>https://jsq.ink</url>
     8  //    <role>pku engineer</role>
     9  //    <date>2019-03-16 12:09:26</date>
    10  //</624342585699209216>
    11  
    12  
    13  package keystore
    14  
    15  import (
    16  	"crypto/aes"
    17  	"crypto/cipher"
    18  	"crypto/sha256"
    19  	"encoding/hex"
    20  	"encoding/json"
    21  	"errors"
    22  	"fmt"
    23  
    24  	"github.com/ethereum/go-ethereum/accounts"
    25  	"github.com/ethereum/go-ethereum/crypto"
    26  	"github.com/pborman/uuid"
    27  	"golang.org/x/crypto/pbkdf2"
    28  )
    29  
    30  //通过解密预售密钥JSON,创建密钥并将其存储在给定的密钥库中。
    31  func importPreSaleKey(keyStore keyStore, keyJSON []byte, password string) (accounts.Account, *Key, error) {
    32  	key, err := decryptPreSaleKey(keyJSON, password)
    33  	if err != nil {
    34  		return accounts.Account{}, nil, err
    35  	}
    36  	key.Id = uuid.NewRandom()
    37  	a := accounts.Account{Address: key.Address, URL: accounts.URL{Scheme: KeyStoreScheme, Path: keyStore.JoinPath(keyFileName(key.Address))}}
    38  	err = keyStore.StoreKey(a.URL.Path, key, password)
    39  	return a, key, err
    40  }
    41  
    42  func decryptPreSaleKey(fileContent []byte, password string) (key *Key, err error) {
    43  	preSaleKeyStruct := struct {
    44  		EncSeed string
    45  		EthAddr string
    46  		Email   string
    47  		BtcAddr string
    48  	}{}
    49  	err = json.Unmarshal(fileContent, &preSaleKeyStruct)
    50  	if err != nil {
    51  		return nil, err
    52  	}
    53  	encSeedBytes, err := hex.DecodeString(preSaleKeyStruct.EncSeed)
    54  	if err != nil {
    55  		return nil, errors.New("invalid hex in encSeed")
    56  	}
    57  	if len(encSeedBytes) < 16 {
    58  		return nil, errors.New("invalid encSeed, too short")
    59  	}
    60  	iv := encSeedBytes[:16]
    61  	cipherText := encSeedBytes[16:]
    62   /*
    63    请参阅https://github.com/ethereum/pyethsaletool
    64  
    65    pyethsaletool根据密码生成加密密钥
    66    2000轮PBKdf2,HMAC-SHA-256,使用密码作为salt(:()。
    67    pbkdf2内的16字节密钥长度,生成的密钥用作aes密钥。
    68   **/
    69  
    70  	passBytes := []byte(password)
    71  	derivedKey := pbkdf2.Key(passBytes, passBytes, 2000, 16, sha256.New)
    72  	plainText, err := aesCBCDecrypt(derivedKey, cipherText, iv)
    73  	if err != nil {
    74  		return nil, err
    75  	}
    76  	ethPriv := crypto.Keccak256(plainText)
    77  	ecKey := crypto.ToECDSAUnsafe(ethPriv)
    78  
    79  	key = &Key{
    80  		Id:         nil,
    81  		Address:    crypto.PubkeyToAddress(ecKey.PublicKey),
    82  		PrivateKey: ecKey,
    83  	}
    84  derivedAddr := hex.EncodeToString(key.Address.Bytes()) //需要,因为.hex()给出前导“0x”
    85  	expectedAddr := preSaleKeyStruct.EthAddr
    86  	if derivedAddr != expectedAddr {
    87  		err = fmt.Errorf("decrypted addr '%s' not equal to expected addr '%s'", derivedAddr, expectedAddr)
    88  	}
    89  	return key, err
    90  }
    91  
    92  func aesCTRXOR(key, inText, iv []byte) ([]byte, error) {
    93  //由于加密密钥的大小,选择了AES-128。
    94  	aesBlock, err := aes.NewCipher(key)
    95  	if err != nil {
    96  		return nil, err
    97  	}
    98  	stream := cipher.NewCTR(aesBlock, iv)
    99  	outText := make([]byte, len(inText))
   100  	stream.XORKeyStream(outText, inText)
   101  	return outText, err
   102  }
   103  
   104  func aesCBCDecrypt(key, cipherText, iv []byte) ([]byte, error) {
   105  	aesBlock, err := aes.NewCipher(key)
   106  	if err != nil {
   107  		return nil, err
   108  	}
   109  	decrypter := cipher.NewCBCDecrypter(aesBlock, iv)
   110  	paddedPlaintext := make([]byte, len(cipherText))
   111  	decrypter.CryptBlocks(paddedPlaintext, cipherText)
   112  	plaintext := pkcs7Unpad(paddedPlaintext)
   113  	if plaintext == nil {
   114  		return nil, ErrDecrypt
   115  	}
   116  	return plaintext, err
   117  }
   118  
   119  //来自https://leanpub.com/gocrypto/read leanpub自动分组密码模式
   120  func pkcs7Unpad(in []byte) []byte {
   121  	if len(in) == 0 {
   122  		return nil
   123  	}
   124  
   125  	padding := in[len(in)-1]
   126  	if int(padding) > len(in) || padding > aes.BlockSize {
   127  		return nil
   128  	} else if padding == 0 {
   129  		return nil
   130  	}
   131  
   132  	for i := len(in) - 1; i > len(in)-int(padding)-1; i-- {
   133  		if in[i] != padding {
   134  			return nil
   135  		}
   136  	}
   137  	return in[:len(in)-int(padding)]
   138  }
   139