github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/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 19:16:31</date> 10 //</624450064772763648> 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{ 38 Address: key.Address, 39 URL: accounts.URL{ 40 Scheme: KeyStoreScheme, 41 Path: keyStore.JoinPath(keyFileName(key.Address)), 42 }, 43 } 44 err = keyStore.StoreKey(a.URL.Path, key, password) 45 return a, key, err 46 } 47 48 func decryptPreSaleKey(fileContent []byte, password string) (key *Key, err error) { 49 preSaleKeyStruct := struct { 50 EncSeed string 51 EthAddr string 52 Email string 53 BtcAddr string 54 }{} 55 err = json.Unmarshal(fileContent, &preSaleKeyStruct) 56 if err != nil { 57 return nil, err 58 } 59 encSeedBytes, err := hex.DecodeString(preSaleKeyStruct.EncSeed) 60 if err != nil { 61 return nil, errors.New("invalid hex in encSeed") 62 } 63 if len(encSeedBytes) < 16 { 64 return nil, errors.New("invalid encSeed, too short") 65 } 66 iv := encSeedBytes[:16] 67 cipherText := encSeedBytes[16:] 68 /* 69 请参阅https://github.com/ethereum/pyethsaletool 70 71 pyethsaletool根据密码生成加密密钥 72 2000轮PBKdf2,HMAC-SHA-256,使用密码作为salt(:()。 73 pbkdf2内的16字节密钥长度,生成的密钥用作aes密钥。 74 **/ 75 76 passBytes := []byte(password) 77 derivedKey := pbkdf2.Key(passBytes, passBytes, 2000, 16, sha256.New) 78 plainText, err := aesCBCDecrypt(derivedKey, cipherText, iv) 79 if err != nil { 80 return nil, err 81 } 82 ethPriv := crypto.Keccak256(plainText) 83 ecKey := crypto.ToECDSAUnsafe(ethPriv) 84 85 key = &Key{ 86 Id: nil, 87 Address: crypto.PubkeyToAddress(ecKey.PublicKey), 88 PrivateKey: ecKey, 89 } 90 derivedAddr := hex.EncodeToString(key.Address.Bytes()) //需要,因为.hex()给出前导“0x” 91 expectedAddr := preSaleKeyStruct.EthAddr 92 if derivedAddr != expectedAddr { 93 err = fmt.Errorf("decrypted addr '%s' not equal to expected addr '%s'", derivedAddr, expectedAddr) 94 } 95 return key, err 96 } 97 98 func aesCTRXOR(key, inText, iv []byte) ([]byte, error) { 99 //由于加密密钥的大小,选择了AES-128。 100 aesBlock, err := aes.NewCipher(key) 101 if err != nil { 102 return nil, err 103 } 104 stream := cipher.NewCTR(aesBlock, iv) 105 outText := make([]byte, len(inText)) 106 stream.XORKeyStream(outText, inText) 107 return outText, err 108 } 109 110 func aesCBCDecrypt(key, cipherText, iv []byte) ([]byte, error) { 111 aesBlock, err := aes.NewCipher(key) 112 if err != nil { 113 return nil, err 114 } 115 decrypter := cipher.NewCBCDecrypter(aesBlock, iv) 116 paddedPlaintext := make([]byte, len(cipherText)) 117 decrypter.CryptBlocks(paddedPlaintext, cipherText) 118 plaintext := pkcs7Unpad(paddedPlaintext) 119 if plaintext == nil { 120 return nil, ErrDecrypt 121 } 122 return plaintext, err 123 } 124 125 //来自https://leanpub.com/gocrypto/read leanpub自动分组密码模式 126 func pkcs7Unpad(in []byte) []byte { 127 if len(in) == 0 { 128 return nil 129 } 130 131 padding := in[len(in)-1] 132 if int(padding) > len(in) || padding > aes.BlockSize { 133 return nil 134 } else if padding == 0 { 135 return nil 136 } 137 138 for i := len(in) - 1; i > len(in)-int(padding)-1; i-- { 139 if in[i] != padding { 140 return nil 141 } 142 } 143 return in[:len(in)-int(padding)] 144 } 145