github.com/unicornultrafoundation/go-u2u@v1.0.0-rc1.0.20240205080301-e74a83d3fadc/valkeystore/encryption/encryption.go (about)

     1  package encryption
     2  
     3  import (
     4  	"bytes"
     5  	"crypto/ecdsa"
     6  	"encoding/json"
     7  	"errors"
     8  	"fmt"
     9  	"io/ioutil"
    10  	"os"
    11  
    12  	"github.com/unicornultrafoundation/go-u2u/accounts/keystore"
    13  	"github.com/unicornultrafoundation/go-u2u/common"
    14  	"github.com/unicornultrafoundation/go-u2u/crypto"
    15  
    16  	"github.com/unicornultrafoundation/go-u2u/native/validatorpk"
    17  )
    18  
    19  var (
    20  	ErrNotSupportedType = errors.New("not supported key type")
    21  )
    22  
    23  type PrivateKey struct {
    24  	Type    uint8
    25  	Bytes   []byte
    26  	Decoded interface{}
    27  }
    28  
    29  type EncryptedKeyJSON struct {
    30  	Type      uint8               `json:"type"`
    31  	PublicKey string              `json:"pubkey"`
    32  	Crypto    keystore.CryptoJSON `json:"crypto"`
    33  }
    34  
    35  type Keystore struct {
    36  	scryptN int
    37  	scryptP int
    38  }
    39  
    40  func New(scryptN int, scryptP int) *Keystore {
    41  	return &Keystore{
    42  		scryptN: scryptN,
    43  		scryptP: scryptP,
    44  	}
    45  }
    46  
    47  func (ks Keystore) ReadKey(wantPubkey validatorpk.PubKey, filename, auth string) (*PrivateKey, error) {
    48  	// Load the key from the keystore and decrypt its contents
    49  	keyjson, err := ioutil.ReadFile(filename)
    50  	if err != nil {
    51  		return nil, err
    52  	}
    53  	key, err := DecryptKey(keyjson, auth)
    54  	if err != nil {
    55  		return nil, err
    56  	}
    57  	// Make sure we're really operating on the requested key (no swap attacks)
    58  	keySecp256k1 := key.Decoded.(*ecdsa.PrivateKey)
    59  	gotPubkey := crypto.FromECDSAPub(&keySecp256k1.PublicKey)
    60  	if bytes.Compare(wantPubkey.Raw, gotPubkey) != 0 {
    61  		return nil, fmt.Errorf("key content mismatch: have public key %X, want %X", gotPubkey, wantPubkey.Raw)
    62  	}
    63  	return key, nil
    64  }
    65  
    66  func (ks Keystore) StoreKey(filename string, pubkey validatorpk.PubKey, key []byte, auth string) error {
    67  	keyjson, err := ks.EncryptKey(pubkey, key, auth)
    68  	if err != nil {
    69  		return err
    70  	}
    71  	// Write into temporary file
    72  	tmpName, err := writeTemporaryKeyFile(filename, keyjson)
    73  	if err != nil {
    74  		return err
    75  	}
    76  	return os.Rename(tmpName, filename)
    77  }
    78  
    79  // EncryptKey encrypts a key using the specified scrypt parameters into a json
    80  // blob that can be decrypted later on.
    81  func (ks Keystore) EncryptKey(pubkey validatorpk.PubKey, key []byte, auth string) ([]byte, error) {
    82  	if pubkey.Type != validatorpk.Types.Secp256k1 {
    83  		return nil, ErrNotSupportedType
    84  	}
    85  	cryptoStruct, err := keystore.EncryptDataV3(key, []byte(auth), ks.scryptN, ks.scryptP)
    86  	if err != nil {
    87  		return nil, err
    88  	}
    89  	encryptedKeyJSON := EncryptedKeyJSON{
    90  		Type:      pubkey.Type,
    91  		PublicKey: common.Bytes2Hex(pubkey.Raw),
    92  		Crypto:    cryptoStruct,
    93  	}
    94  	return json.Marshal(encryptedKeyJSON)
    95  }
    96  
    97  // DecryptKey decrypts a key from a json blob, returning the private key itself.
    98  func DecryptKey(keyjson []byte, auth string) (*PrivateKey, error) {
    99  	// Parse the json into a simple map to fetch the key version
   100  	m := make(map[string]interface{})
   101  	if err := json.Unmarshal(keyjson, &m); err != nil {
   102  		return nil, err
   103  	}
   104  	var (
   105  		keyBytes []byte
   106  		err      error
   107  	)
   108  	k := new(EncryptedKeyJSON)
   109  	if err := json.Unmarshal(keyjson, k); err != nil {
   110  		return nil, err
   111  	}
   112  	if k.Type != validatorpk.Types.Secp256k1 {
   113  		return nil, ErrNotSupportedType
   114  	}
   115  	keyBytes, err = decryptKey_secp256k1(k, auth)
   116  	// Handle any decryption errors and return the key
   117  	if err != nil {
   118  		return nil, err
   119  	}
   120  
   121  	decoded, err := crypto.ToECDSA(keyBytes)
   122  	if err != nil {
   123  		return nil, err
   124  	}
   125  
   126  	return &PrivateKey{
   127  		Type:    k.Type,
   128  		Bytes:   keyBytes,
   129  		Decoded: decoded,
   130  	}, nil
   131  }
   132  
   133  func decryptKey_secp256k1(keyProtected *EncryptedKeyJSON, auth string) (keyBytes []byte, err error) {
   134  	plainText, err := keystore.DecryptDataV3(keyProtected.Crypto, auth)
   135  	if err != nil {
   136  		return nil, err
   137  	}
   138  	return plainText, err
   139  }