github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/accounts/keystore/keystore_passphrase.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  //版权所有2014 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  /*
    26  
    27  此密钥存储区的行为与密钥存储区的区别在于
    28  私钥是加密的,在磁盘上使用另一个JSON编码。
    29  
    30  密码记录在https://github.com/ethereum/wiki/wiki/web3-secret-storage-definition上。
    31  
    32  **/
    33  
    34  
    35  package keystore
    36  
    37  import (
    38  	"bytes"
    39  	"crypto/aes"
    40  	"crypto/rand"
    41  	"crypto/sha256"
    42  	"encoding/hex"
    43  	"encoding/json"
    44  	"fmt"
    45  	"io"
    46  	"io/ioutil"
    47  	"path/filepath"
    48  
    49  	"github.com/ethereum/go-ethereum/common"
    50  	"github.com/ethereum/go-ethereum/common/math"
    51  	"github.com/ethereum/go-ethereum/crypto"
    52  	"github.com/pborman/uuid"
    53  	"golang.org/x/crypto/pbkdf2"
    54  	"golang.org/x/crypto/scrypt"
    55  )
    56  
    57  const (
    58  	keyHeaderKDF = "scrypt"
    59  
    60  //标准加密是加密算法的n个参数,使用256MB
    61  //在现代处理器上占用大约1秒的CPU时间。
    62  	StandardScryptN = 1 << 18
    63  
    64  //StandardScryptP是加密算法的P参数,使用256MB
    65  //在现代处理器上占用大约1秒的CPU时间。
    66  	StandardScryptP = 1
    67  
    68  //lightscryptn是加密算法的n个参数,使用4MB
    69  //在现代处理器上占用大约100毫秒的CPU时间。
    70  	LightScryptN = 1 << 12
    71  
    72  //lightscryptp是加密算法的p参数,使用4MB
    73  //在现代处理器上占用大约100毫秒的CPU时间。
    74  	LightScryptP = 6
    75  
    76  	scryptR     = 8
    77  	scryptDKLen = 32
    78  )
    79  
    80  type keyStorePassphrase struct {
    81  	keysDirPath string
    82  	scryptN     int
    83  	scryptP     int
    84  }
    85  
    86  func (ks keyStorePassphrase) GetKey(addr common.Address, filename, auth string) (*Key, error) {
    87  //从密钥库加载密钥并解密其内容
    88  	keyjson, err := ioutil.ReadFile(filename)
    89  	if err != nil {
    90  		return nil, err
    91  	}
    92  	key, err := DecryptKey(keyjson, auth)
    93  	if err != nil {
    94  		return nil, err
    95  	}
    96  //确保我们确实在使用请求的密钥(没有交换攻击)
    97  	if key.Address != addr {
    98  		return nil, fmt.Errorf("key content mismatch: have account %x, want %x", key.Address, addr)
    99  	}
   100  	return key, nil
   101  }
   102  
   103  //storekey生成一个密钥,用auth加密并存储在给定的目录中
   104  func StoreKey(dir, auth string, scryptN, scryptP int) (common.Address, error) {
   105  	_, a, err := storeNewKey(&keyStorePassphrase{dir, scryptN, scryptP}, rand.Reader, auth)
   106  	return a.Address, err
   107  }
   108  
   109  func (ks keyStorePassphrase) StoreKey(filename string, key *Key, auth string) error {
   110  	keyjson, err := EncryptKey(key, auth, ks.scryptN, ks.scryptP)
   111  	if err != nil {
   112  		return err
   113  	}
   114  	return writeKeyFile(filename, keyjson)
   115  }
   116  
   117  func (ks keyStorePassphrase) JoinPath(filename string) string {
   118  	if filepath.IsAbs(filename) {
   119  		return filename
   120  	}
   121  	return filepath.Join(ks.keysDirPath, filename)
   122  }
   123  
   124  //encryptkey使用指定的scrypt参数将密钥加密到JSON中
   125  //稍后可以解密的blob。
   126  func EncryptKey(key *Key, auth string, scryptN, scryptP int) ([]byte, error) {
   127  	authArray := []byte(auth)
   128  
   129  	salt := make([]byte, 32)
   130  	if _, err := io.ReadFull(rand.Reader, salt); err != nil {
   131  		panic("reading from crypto/rand failed: " + err.Error())
   132  	}
   133  	derivedKey, err := scrypt.Key(authArray, salt, scryptN, scryptR, scryptP, scryptDKLen)
   134  	if err != nil {
   135  		return nil, err
   136  	}
   137  	encryptKey := derivedKey[:16]
   138  	keyBytes := math.PaddedBigBytes(key.PrivateKey.D, 32)
   139  
   140  iv := make([]byte, aes.BlockSize) //十六
   141  	if _, err := io.ReadFull(rand.Reader, iv); err != nil {
   142  		panic("reading from crypto/rand failed: " + err.Error())
   143  	}
   144  	cipherText, err := aesCTRXOR(encryptKey, keyBytes, iv)
   145  	if err != nil {
   146  		return nil, err
   147  	}
   148  	mac := crypto.Keccak256(derivedKey[16:32], cipherText)
   149  
   150  	scryptParamsJSON := make(map[string]interface{}, 5)
   151  	scryptParamsJSON["n"] = scryptN
   152  	scryptParamsJSON["r"] = scryptR
   153  	scryptParamsJSON["p"] = scryptP
   154  	scryptParamsJSON["dklen"] = scryptDKLen
   155  	scryptParamsJSON["salt"] = hex.EncodeToString(salt)
   156  
   157  	cipherParamsJSON := cipherparamsJSON{
   158  		IV: hex.EncodeToString(iv),
   159  	}
   160  
   161  	cryptoStruct := cryptoJSON{
   162  		Cipher:       "aes-128-ctr",
   163  		CipherText:   hex.EncodeToString(cipherText),
   164  		CipherParams: cipherParamsJSON,
   165  		KDF:          keyHeaderKDF,
   166  		KDFParams:    scryptParamsJSON,
   167  		MAC:          hex.EncodeToString(mac),
   168  	}
   169  	encryptedKeyJSONV3 := encryptedKeyJSONV3{
   170  		hex.EncodeToString(key.Address[:]),
   171  		cryptoStruct,
   172  		key.Id.String(),
   173  		version,
   174  	}
   175  	return json.Marshal(encryptedKeyJSONV3)
   176  }
   177  
   178  //decryptkey从JSON blob中解密密钥,返回私钥本身。
   179  func DecryptKey(keyjson []byte, auth string) (*Key, error) {
   180  //将JSON解析为一个简单的映射以获取密钥版本
   181  	m := make(map[string]interface{})
   182  	if err := json.Unmarshal(keyjson, &m); err != nil {
   183  		return nil, err
   184  	}
   185  //根据版本,尝试以某种方式分析
   186  	var (
   187  		keyBytes, keyId []byte
   188  		err             error
   189  	)
   190  	if version, ok := m["version"].(string); ok && version == "1" {
   191  		k := new(encryptedKeyJSONV1)
   192  		if err := json.Unmarshal(keyjson, k); err != nil {
   193  			return nil, err
   194  		}
   195  		keyBytes, keyId, err = decryptKeyV1(k, auth)
   196  	} else {
   197  		k := new(encryptedKeyJSONV3)
   198  		if err := json.Unmarshal(keyjson, k); err != nil {
   199  			return nil, err
   200  		}
   201  		keyBytes, keyId, err = decryptKeyV3(k, auth)
   202  	}
   203  //处理任何解密错误并返回密钥
   204  	if err != nil {
   205  		return nil, err
   206  	}
   207  	key := crypto.ToECDSAUnsafe(keyBytes)
   208  
   209  	return &Key{
   210  		Id:         uuid.UUID(keyId),
   211  		Address:    crypto.PubkeyToAddress(key.PublicKey),
   212  		PrivateKey: key,
   213  	}, nil
   214  }
   215  
   216  func decryptKeyV3(keyProtected *encryptedKeyJSONV3, auth string) (keyBytes []byte, keyId []byte, err error) {
   217  	if keyProtected.Version != version {
   218  		return nil, nil, fmt.Errorf("Version not supported: %v", keyProtected.Version)
   219  	}
   220  
   221  	if keyProtected.Crypto.Cipher != "aes-128-ctr" {
   222  		return nil, nil, fmt.Errorf("Cipher not supported: %v", keyProtected.Crypto.Cipher)
   223  	}
   224  
   225  	keyId = uuid.Parse(keyProtected.Id)
   226  	mac, err := hex.DecodeString(keyProtected.Crypto.MAC)
   227  	if err != nil {
   228  		return nil, nil, err
   229  	}
   230  
   231  	iv, err := hex.DecodeString(keyProtected.Crypto.CipherParams.IV)
   232  	if err != nil {
   233  		return nil, nil, err
   234  	}
   235  
   236  	cipherText, err := hex.DecodeString(keyProtected.Crypto.CipherText)
   237  	if err != nil {
   238  		return nil, nil, err
   239  	}
   240  
   241  	derivedKey, err := getKDFKey(keyProtected.Crypto, auth)
   242  	if err != nil {
   243  		return nil, nil, err
   244  	}
   245  
   246  	calculatedMAC := crypto.Keccak256(derivedKey[16:32], cipherText)
   247  	if !bytes.Equal(calculatedMAC, mac) {
   248  		return nil, nil, ErrDecrypt
   249  	}
   250  
   251  	plainText, err := aesCTRXOR(derivedKey[:16], cipherText, iv)
   252  	if err != nil {
   253  		return nil, nil, err
   254  	}
   255  	return plainText, keyId, err
   256  }
   257  
   258  func decryptKeyV1(keyProtected *encryptedKeyJSONV1, auth string) (keyBytes []byte, keyId []byte, err error) {
   259  	keyId = uuid.Parse(keyProtected.Id)
   260  	mac, err := hex.DecodeString(keyProtected.Crypto.MAC)
   261  	if err != nil {
   262  		return nil, nil, err
   263  	}
   264  
   265  	iv, err := hex.DecodeString(keyProtected.Crypto.CipherParams.IV)
   266  	if err != nil {
   267  		return nil, nil, err
   268  	}
   269  
   270  	cipherText, err := hex.DecodeString(keyProtected.Crypto.CipherText)
   271  	if err != nil {
   272  		return nil, nil, err
   273  	}
   274  
   275  	derivedKey, err := getKDFKey(keyProtected.Crypto, auth)
   276  	if err != nil {
   277  		return nil, nil, err
   278  	}
   279  
   280  	calculatedMAC := crypto.Keccak256(derivedKey[16:32], cipherText)
   281  	if !bytes.Equal(calculatedMAC, mac) {
   282  		return nil, nil, ErrDecrypt
   283  	}
   284  
   285  	plainText, err := aesCBCDecrypt(crypto.Keccak256(derivedKey[:16])[:16], cipherText, iv)
   286  	if err != nil {
   287  		return nil, nil, err
   288  	}
   289  	return plainText, keyId, err
   290  }
   291  
   292  func getKDFKey(cryptoJSON cryptoJSON, auth string) ([]byte, error) {
   293  	authArray := []byte(auth)
   294  	salt, err := hex.DecodeString(cryptoJSON.KDFParams["salt"].(string))
   295  	if err != nil {
   296  		return nil, err
   297  	}
   298  	dkLen := ensureInt(cryptoJSON.KDFParams["dklen"])
   299  
   300  	if cryptoJSON.KDF == keyHeaderKDF {
   301  		n := ensureInt(cryptoJSON.KDFParams["n"])
   302  		r := ensureInt(cryptoJSON.KDFParams["r"])
   303  		p := ensureInt(cryptoJSON.KDFParams["p"])
   304  		return scrypt.Key(authArray, salt, n, r, p, dkLen)
   305  
   306  	} else if cryptoJSON.KDF == "pbkdf2" {
   307  		c := ensureInt(cryptoJSON.KDFParams["c"])
   308  		prf := cryptoJSON.KDFParams["prf"].(string)
   309  		if prf != "hmac-sha256" {
   310  			return nil, fmt.Errorf("Unsupported PBKDF2 PRF: %s", prf)
   311  		}
   312  		key := pbkdf2.Key(authArray, salt, c, dkLen, sha256.New)
   313  		return key, nil
   314  	}
   315  
   316  	return nil, fmt.Errorf("Unsupported KDF: %s", cryptoJSON.KDF)
   317  }
   318  
   319  //TODO:在解组动态JSON时,我们可以不这样做吗?
   320  //为什么kdf参数中的整数以float64结尾,而不是后面的int
   321  //元帅?
   322  func ensureInt(x interface{}) int {
   323  	res, ok := x.(int)
   324  	if !ok {
   325  		res = int(x.(float64))
   326  	}
   327  	return res
   328  }