github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/app/crypto/ethkeystore/passphrase_adapter.go (about) 1 package ethkeystore 2 3 import ( 4 "bytes" 5 "crypto/aes" 6 "crypto/cipher" 7 "crypto/sha256" 8 "encoding/hex" 9 "encoding/json" 10 "fmt" 11 12 "github.com/ethereum/go-ethereum/accounts/keystore" 13 ethcrypto "github.com/ethereum/go-ethereum/crypto" 14 "github.com/google/uuid" 15 "golang.org/x/crypto/pbkdf2" 16 "golang.org/x/crypto/scrypt" 17 ) 18 19 type encryptedKeyJSONV3ForWeb3 struct { 20 Address string `json:"address"` 21 Crypto keystore.CryptoJSON `json:"crypto"` 22 Id string `json:"id"` 23 Version int `json:"version"` 24 } 25 26 // DecryptKey decrypts a key from a json blob, returning the private key itself. 27 func DecryptKeyForWeb3(keyjson []byte, auth string) (*keystore.Key, error) { 28 // Parse the json into a simple map to fetch the key version 29 m := make(map[string]interface{}) 30 if err := json.Unmarshal(keyjson, &m); err != nil { 31 return nil, err 32 } 33 // Depending on the version try to parse one way or another 34 var ( 35 keyBytes, keyId []byte 36 err error 37 ) 38 if m["version"] == float64(3) { 39 k := new(encryptedKeyJSONV3ForWeb3) 40 if err := json.Unmarshal(keyjson, k); err != nil { 41 return nil, err 42 } 43 keyBytes, keyId, err = decryptKeyV3ForWeb3(k, auth) 44 } else { 45 return nil, fmt.Errorf("the veison must be equal to 3, got: %s", m["version"]) 46 } 47 // Handle any decryption errors and return the key 48 if err != nil { 49 return nil, err 50 } 51 key := ethcrypto.ToECDSAUnsafe(keyBytes) 52 id, err := uuid.FromBytes(keyId) 53 if err != nil { 54 return nil, err 55 } 56 return &keystore.Key{ 57 Id: id, 58 Address: ethcrypto.PubkeyToAddress(key.PublicKey), 59 PrivateKey: key, 60 }, nil 61 } 62 63 func decryptKeyV3ForWeb3(keyProtected *encryptedKeyJSONV3ForWeb3, auth string) (keyBytes []byte, keyId []byte, err error) { 64 if keyProtected.Version != 3 { 65 return nil, nil, fmt.Errorf("version not supported: %v", keyProtected.Version) 66 } 67 keyUUID, err := uuid.Parse(keyProtected.Id) 68 if err != nil { 69 return nil, nil, err 70 } 71 keyId = keyUUID[:] 72 plainText, err := DecryptDataV3ForWeb3(keyProtected.Crypto, auth) 73 if err != nil { 74 return nil, nil, err 75 } 76 return plainText, keyId, err 77 } 78 79 func DecryptDataV3ForWeb3(cryptoJson keystore.CryptoJSON, auth string) ([]byte, error) { 80 if cryptoJson.Cipher != "aes-128-ctr" { 81 return nil, fmt.Errorf("cipher not supported: %v", cryptoJson.Cipher) 82 } 83 mac, err := hex.DecodeString(cryptoJson.MAC) 84 if err != nil { 85 return nil, err 86 } 87 88 iv, err := hex.DecodeString(cryptoJson.CipherParams.IV) 89 if err != nil { 90 return nil, err 91 } 92 93 cipherText, err := hex.DecodeString(cryptoJson.CipherText) 94 if err != nil { 95 return nil, err 96 } 97 98 derivedKey, err := getKDFKey(cryptoJson, auth) 99 if err != nil { 100 return nil, err 101 } 102 103 bufferValue := bytes.Buffer{} 104 bufferValue.Write(derivedKey[16:32]) 105 bufferValue.Write(cipherText) 106 calculatedMAC := sha256.Sum256(bufferValue.Bytes()) 107 if !bytes.Equal(calculatedMAC[:], mac) { 108 return nil, keystore.ErrDecrypt 109 } 110 111 plainText, err := aesCTRXOR(derivedKey[:16], cipherText, iv) 112 if err != nil { 113 return nil, err 114 } 115 return plainText, err 116 } 117 118 func getKDFKey(cryptoJSON keystore.CryptoJSON, auth string) ([]byte, error) { 119 authArray := []byte(auth) 120 salt, err := hex.DecodeString(cryptoJSON.KDFParams["salt"].(string)) 121 if err != nil { 122 return nil, err 123 } 124 dkLen := ensureInt(cryptoJSON.KDFParams["dklen"]) 125 126 if cryptoJSON.KDF == "scrypt" { 127 n := ensureInt(cryptoJSON.KDFParams["n"]) 128 r := ensureInt(cryptoJSON.KDFParams["r"]) 129 p := ensureInt(cryptoJSON.KDFParams["p"]) 130 return scrypt.Key(authArray, salt, n, r, p, dkLen) 131 } else if cryptoJSON.KDF == "pbkdf2" { 132 c := ensureInt(cryptoJSON.KDFParams["c"]) 133 prf := cryptoJSON.KDFParams["prf"].(string) 134 if prf != "hmac-sha256" { 135 return nil, fmt.Errorf("unsupported PBKDF2 PRF: %s", prf) 136 } 137 key := pbkdf2.Key(authArray, salt, c, dkLen, sha256.New) 138 return key, nil 139 } 140 141 return nil, fmt.Errorf("unsupported KDF: %s", cryptoJSON.KDF) 142 } 143 144 // TODO: can we do without this when unmarshalling dynamic JSON? 145 // why do integers in KDF params end up as float64 and not int after 146 // unmarshal? 147 func ensureInt(x interface{}) int { 148 res, ok := x.(int) 149 if !ok { 150 res = int(x.(float64)) 151 } 152 return res 153 } 154 155 func aesCTRXOR(key, inText, iv []byte) ([]byte, error) { 156 // AES-128 is selected due to size of encryptKey. 157 aesBlock, err := aes.NewCipher(key) 158 if err != nil { 159 return nil, err 160 } 161 stream := cipher.NewCTR(aesBlock, iv) 162 outText := make([]byte, len(inText)) 163 stream.XORKeyStream(outText, inText) 164 return outText, err 165 }