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 }