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 }