github.com/neatio-net/neatio@v1.7.3-0.20231114194659-f4d7a2226baa/chain/accounts/keystore/keystore_passphrase.go (about)

     1  package keystore
     2  
     3  import (
     4  	"bytes"
     5  	"crypto/aes"
     6  	crand "crypto/rand"
     7  	"crypto/sha256"
     8  	"encoding/hex"
     9  	"encoding/json"
    10  	"fmt"
    11  	"io/ioutil"
    12  	"path/filepath"
    13  
    14  	"github.com/neatio-net/neatio/utilities/common"
    15  	"github.com/neatio-net/neatio/utilities/common/math"
    16  	"github.com/neatio-net/neatio/utilities/crypto"
    17  	"github.com/neatio-net/neatio/utilities/crypto/randentropy"
    18  	"github.com/pborman/uuid"
    19  	"golang.org/x/crypto/pbkdf2"
    20  	"golang.org/x/crypto/scrypt"
    21  )
    22  
    23  const (
    24  	keyHeaderKDF = "scrypt"
    25  
    26  	StandardScryptN = 1 << 18
    27  
    28  	StandardScryptP = 1
    29  
    30  	LightScryptN = 1 << 12
    31  
    32  	LightScryptP = 6
    33  
    34  	scryptR     = 8
    35  	scryptDKLen = 32
    36  )
    37  
    38  type keyStorePassphrase struct {
    39  	keysDirPath string
    40  	scryptN     int
    41  	scryptP     int
    42  }
    43  
    44  func (ks keyStorePassphrase) GetKey(addr common.Address, filename, auth string) (*Key, error) {
    45  
    46  	keyjson, err := ioutil.ReadFile(filename)
    47  	if err != nil {
    48  		return nil, err
    49  	}
    50  	key, err := DecryptKey(keyjson, auth)
    51  	if err != nil {
    52  		return nil, err
    53  	}
    54  
    55  	if key.Address != addr {
    56  		return nil, fmt.Errorf("key content mismatch: have account %x, want %x", key.Address, addr)
    57  	}
    58  	return key, nil
    59  }
    60  
    61  func StoreKey(dir, auth string, scryptN, scryptP int) (common.Address, error) {
    62  	_, a, err := storeNewKey(&keyStorePassphrase{dir, scryptN, scryptP}, crand.Reader, auth)
    63  	return a.Address, err
    64  }
    65  
    66  func (ks keyStorePassphrase) StoreKey(filename string, key *Key, auth string) error {
    67  	keyjson, err := EncryptKey(key, auth, ks.scryptN, ks.scryptP)
    68  	if err != nil {
    69  		return err
    70  	}
    71  	return writeKeyFile(filename, keyjson)
    72  }
    73  
    74  func (ks keyStorePassphrase) JoinPath(filename string) string {
    75  	if filepath.IsAbs(filename) {
    76  		return filename
    77  	} else {
    78  		return filepath.Join(ks.keysDirPath, filename)
    79  	}
    80  }
    81  
    82  func EncryptKey(key *Key, auth string, scryptN, scryptP int) ([]byte, error) {
    83  	authArray := []byte(auth)
    84  	salt := randentropy.GetEntropyCSPRNG(32)
    85  	derivedKey, err := scrypt.Key(authArray, salt, scryptN, scryptR, scryptP, scryptDKLen)
    86  	if err != nil {
    87  		return nil, err
    88  	}
    89  	encryptKey := derivedKey[:16]
    90  	keyBytes := math.PaddedBigBytes(key.PrivateKey.D, 32)
    91  
    92  	iv := randentropy.GetEntropyCSPRNG(aes.BlockSize)
    93  	cipherText, err := aesCTRXOR(encryptKey, keyBytes, iv)
    94  	if err != nil {
    95  		return nil, err
    96  	}
    97  	mac := crypto.Keccak256(derivedKey[16:32], cipherText)
    98  
    99  	scryptParamsJSON := make(map[string]interface{}, 5)
   100  	scryptParamsJSON["n"] = scryptN
   101  	scryptParamsJSON["r"] = scryptR
   102  	scryptParamsJSON["p"] = scryptP
   103  	scryptParamsJSON["dklen"] = scryptDKLen
   104  	scryptParamsJSON["salt"] = hex.EncodeToString(salt)
   105  
   106  	cipherParamsJSON := cipherparamsJSON{
   107  		IV: hex.EncodeToString(iv),
   108  	}
   109  
   110  	cryptoStruct := cryptoJSON{
   111  		Cipher:       "aes-128-ctr",
   112  		CipherText:   hex.EncodeToString(cipherText),
   113  		CipherParams: cipherParamsJSON,
   114  		KDF:          keyHeaderKDF,
   115  		KDFParams:    scryptParamsJSON,
   116  		MAC:          hex.EncodeToString(mac),
   117  	}
   118  	encryptedKeyJSONV3 := encryptedKeyJSONV3{
   119  
   120  		key.Address.String(),
   121  		cryptoStruct,
   122  		key.Id.String(),
   123  		version,
   124  	}
   125  	return json.Marshal(encryptedKeyJSONV3)
   126  }
   127  
   128  func DecryptKey(keyjson []byte, auth string) (*Key, error) {
   129  
   130  	m := make(map[string]interface{})
   131  	if err := json.Unmarshal(keyjson, &m); err != nil {
   132  		return nil, err
   133  	}
   134  
   135  	var (
   136  		keyBytes, keyId []byte
   137  		err             error
   138  	)
   139  	if version, ok := m["version"].(string); ok && version == "1" {
   140  		k := new(encryptedKeyJSONV1)
   141  		if err := json.Unmarshal(keyjson, k); err != nil {
   142  			return nil, err
   143  		}
   144  		keyBytes, keyId, err = decryptKeyV1(k, auth)
   145  	} else {
   146  		k := new(encryptedKeyJSONV3)
   147  		if err := json.Unmarshal(keyjson, k); err != nil {
   148  			return nil, err
   149  		}
   150  		keyBytes, keyId, err = decryptKeyV3(k, auth)
   151  	}
   152  
   153  	if err != nil {
   154  		return nil, err
   155  	}
   156  	key := crypto.ToECDSAUnsafe(keyBytes)
   157  
   158  	return &Key{
   159  		Id:         uuid.UUID(keyId),
   160  		Address:    crypto.PubkeyToAddress(key.PublicKey),
   161  		PrivateKey: key,
   162  	}, nil
   163  }
   164  
   165  func decryptKeyV3(keyProtected *encryptedKeyJSONV3, auth string) (keyBytes []byte, keyId []byte, err error) {
   166  	if keyProtected.Version != version {
   167  		return nil, nil, fmt.Errorf("Version not supported: %v", keyProtected.Version)
   168  	}
   169  
   170  	if keyProtected.Crypto.Cipher != "aes-128-ctr" {
   171  		return nil, nil, fmt.Errorf("Cipher not supported: %v", keyProtected.Crypto.Cipher)
   172  	}
   173  
   174  	keyId = uuid.Parse(keyProtected.Id)
   175  	mac, err := hex.DecodeString(keyProtected.Crypto.MAC)
   176  	if err != nil {
   177  		return nil, nil, err
   178  	}
   179  
   180  	iv, err := hex.DecodeString(keyProtected.Crypto.CipherParams.IV)
   181  	if err != nil {
   182  		return nil, nil, err
   183  	}
   184  
   185  	cipherText, err := hex.DecodeString(keyProtected.Crypto.CipherText)
   186  	if err != nil {
   187  		return nil, nil, err
   188  	}
   189  
   190  	derivedKey, err := getKDFKey(keyProtected.Crypto, auth)
   191  	if err != nil {
   192  		return nil, nil, err
   193  	}
   194  
   195  	calculatedMAC := crypto.Keccak256(derivedKey[16:32], cipherText)
   196  	if !bytes.Equal(calculatedMAC, mac) {
   197  		return nil, nil, ErrDecrypt
   198  	}
   199  
   200  	plainText, err := aesCTRXOR(derivedKey[:16], cipherText, iv)
   201  	if err != nil {
   202  		return nil, nil, err
   203  	}
   204  	return plainText, keyId, err
   205  }
   206  
   207  func decryptKeyV1(keyProtected *encryptedKeyJSONV1, auth string) (keyBytes []byte, keyId []byte, err error) {
   208  	keyId = uuid.Parse(keyProtected.Id)
   209  	mac, err := hex.DecodeString(keyProtected.Crypto.MAC)
   210  	if err != nil {
   211  		return nil, nil, err
   212  	}
   213  
   214  	iv, err := hex.DecodeString(keyProtected.Crypto.CipherParams.IV)
   215  	if err != nil {
   216  		return nil, nil, err
   217  	}
   218  
   219  	cipherText, err := hex.DecodeString(keyProtected.Crypto.CipherText)
   220  	if err != nil {
   221  		return nil, nil, err
   222  	}
   223  
   224  	derivedKey, err := getKDFKey(keyProtected.Crypto, auth)
   225  	if err != nil {
   226  		return nil, nil, err
   227  	}
   228  
   229  	calculatedMAC := crypto.Keccak256(derivedKey[16:32], cipherText)
   230  	if !bytes.Equal(calculatedMAC, mac) {
   231  		return nil, nil, ErrDecrypt
   232  	}
   233  
   234  	plainText, err := aesCBCDecrypt(crypto.Keccak256(derivedKey[:16])[:16], cipherText, iv)
   235  	if err != nil {
   236  		return nil, nil, err
   237  	}
   238  	return plainText, keyId, err
   239  }
   240  
   241  func getKDFKey(cryptoJSON cryptoJSON, auth string) ([]byte, error) {
   242  	authArray := []byte(auth)
   243  	salt, err := hex.DecodeString(cryptoJSON.KDFParams["salt"].(string))
   244  	if err != nil {
   245  		return nil, err
   246  	}
   247  	dkLen := ensureInt(cryptoJSON.KDFParams["dklen"])
   248  
   249  	if cryptoJSON.KDF == keyHeaderKDF {
   250  		n := ensureInt(cryptoJSON.KDFParams["n"])
   251  		r := ensureInt(cryptoJSON.KDFParams["r"])
   252  		p := ensureInt(cryptoJSON.KDFParams["p"])
   253  		return scrypt.Key(authArray, salt, n, r, p, dkLen)
   254  
   255  	} else if cryptoJSON.KDF == "pbkdf2" {
   256  		c := ensureInt(cryptoJSON.KDFParams["c"])
   257  		prf := cryptoJSON.KDFParams["prf"].(string)
   258  		if prf != "hmac-sha256" {
   259  			return nil, fmt.Errorf("Unsupported PBKDF2 PRF: %s", prf)
   260  		}
   261  		key := pbkdf2.Key(authArray, salt, c, dkLen, sha256.New)
   262  		return key, nil
   263  	}
   264  
   265  	return nil, fmt.Errorf("Unsupported KDF: %s", cryptoJSON.KDF)
   266  }
   267  
   268  func ensureInt(x interface{}) int {
   269  	res, ok := x.(int)
   270  	if !ok {
   271  		res = int(x.(float64))
   272  	}
   273  	return res
   274  }