github.com/arieschain/arieschain@v0.0.0-20191023063405-37c074544356/accounts/keystore/keystore_passphrase.go (about) 1 /* 2 3 This key store behaves as KeyStorePlain with the difference that 4 the private key is encrypted and on disk uses another JSON encoding. 5 6 The crypto is documented at https://github.com/quickchain/wiki/wiki/Web3-Secret-Storage-Definition 7 8 */ 9 10 package keystore 11 12 import ( 13 "bytes" 14 "crypto/aes" 15 crand "crypto/rand" 16 "crypto/sha256" 17 "encoding/hex" 18 "encoding/json" 19 "fmt" 20 "io/ioutil" 21 "path/filepath" 22 23 "github.com/quickchainproject/quickchain/common" 24 "github.com/quickchainproject/quickchain/common/math" 25 "github.com/quickchainproject/quickchain/crypto" 26 "github.com/quickchainproject/quickchain/crypto/randentropy" 27 "github.com/pborman/uuid" 28 "golang.org/x/crypto/pbkdf2" 29 "golang.org/x/crypto/scrypt" 30 ) 31 32 const ( 33 keyHeaderKDF = "scrypt" 34 35 // StandardScryptN is the N parameter of Scrypt encryption algorithm, using 256MB 36 // memory and taking approximately 1s CPU time on a modern processor. 37 StandardScryptN = 1 << 18 38 39 // StandardScryptP is the P parameter of Scrypt encryption algorithm, using 256MB 40 // memory and taking approximately 1s CPU time on a modern processor. 41 StandardScryptP = 1 42 43 // LightScryptN is the N parameter of Scrypt encryption algorithm, using 4MB 44 // memory and taking approximately 100ms CPU time on a modern processor. 45 LightScryptN = 1 << 12 46 47 // LightScryptP is the P parameter of Scrypt encryption algorithm, using 4MB 48 // memory and taking approximately 100ms CPU time on a modern processor. 49 LightScryptP = 6 50 51 scryptR = 8 52 scryptDKLen = 32 53 ) 54 55 type keyStorePassphrase struct { 56 keysDirPath string 57 scryptN int 58 scryptP int 59 } 60 61 func (ks keyStorePassphrase) GetKey(addr common.Address, filename, auth string) (*Key, error) { 62 // Load the key from the keystore and decrypt its contents 63 keyjson, err := ioutil.ReadFile(filename) 64 if err != nil { 65 return nil, err 66 } 67 key, err := DecryptKey(keyjson, auth) 68 if err != nil { 69 return nil, err 70 } 71 // Make sure we're really operating on the requested key (no swap attacks) 72 if key.Address != addr { 73 return nil, fmt.Errorf("key content mismatch: have account %x, want %x", key.Address, addr) 74 } 75 return key, nil 76 } 77 78 // StoreKey generates a key, encrypts with 'auth' and stores in the given directory 79 func StoreKey(dir, auth string, scryptN, scryptP int) (common.Address, error) { 80 _, a, err := storeNewKey(&keyStorePassphrase{dir, scryptN, scryptP}, crand.Reader, auth) 81 return a.Address, err 82 } 83 84 func (ks keyStorePassphrase) StoreKey(filename string, key *Key, auth string) error { 85 keyjson, err := EncryptKey(key, auth, ks.scryptN, ks.scryptP) 86 if err != nil { 87 return err 88 } 89 return writeKeyFile(filename, keyjson) 90 } 91 92 func (ks keyStorePassphrase) JoinPath(filename string) string { 93 if filepath.IsAbs(filename) { 94 return filename 95 } else { 96 return filepath.Join(ks.keysDirPath, filename) 97 } 98 } 99 100 // EncryptKey encrypts a key using the specified scrypt parameters into a json 101 // blob that can be decrypted later on. 102 func EncryptKey(key *Key, auth string, scryptN, scryptP int) ([]byte, error) { 103 authArray := []byte(auth) 104 salt := randentropy.GetEntropyCSPRNG(32) 105 derivedKey, err := scrypt.Key(authArray, salt, scryptN, scryptR, scryptP, scryptDKLen) 106 if err != nil { 107 return nil, err 108 } 109 encryptKey := derivedKey[:16] 110 keyBytes := math.PaddedBigBytes(key.PrivateKey.D, 32) 111 112 iv := randentropy.GetEntropyCSPRNG(aes.BlockSize) // 16 113 cipherText, err := aesCTRXOR(encryptKey, keyBytes, iv) 114 if err != nil { 115 return nil, err 116 } 117 mac := crypto.Keccak256(derivedKey[16:32], cipherText) 118 119 scryptParamsJSON := make(map[string]interface{}, 5) 120 scryptParamsJSON["n"] = scryptN 121 scryptParamsJSON["r"] = scryptR 122 scryptParamsJSON["p"] = scryptP 123 scryptParamsJSON["dklen"] = scryptDKLen 124 scryptParamsJSON["salt"] = hex.EncodeToString(salt) 125 126 cipherParamsJSON := cipherparamsJSON{ 127 IV: hex.EncodeToString(iv), 128 } 129 130 cryptoStruct := cryptoJSON{ 131 Cipher: "aes-128-ctr", 132 CipherText: hex.EncodeToString(cipherText), 133 CipherParams: cipherParamsJSON, 134 KDF: keyHeaderKDF, 135 KDFParams: scryptParamsJSON, 136 MAC: hex.EncodeToString(mac), 137 } 138 encryptedKeyJSONV3 := encryptedKeyJSONV3{ 139 "QCT" + hex.EncodeToString(key.Address[:]), 140 cryptoStruct, 141 key.Id.String(), 142 version, 143 } 144 return json.Marshal(encryptedKeyJSONV3) 145 } 146 147 // DecryptKey decrypts a key from a json blob, returning the private key itself. 148 func DecryptKey(keyjson []byte, auth string) (*Key, error) { 149 // Parse the json into a simple map to fetch the key version 150 m := make(map[string]interface{}) 151 if err := json.Unmarshal(keyjson, &m); err != nil { 152 return nil, err 153 } 154 // Depending on the version try to parse one way or another 155 var ( 156 keyBytes, keyId []byte 157 err error 158 ) 159 if version, ok := m["version"].(string); ok && version == "1" { 160 k := new(encryptedKeyJSONV1) 161 if err := json.Unmarshal(keyjson, k); err != nil { 162 return nil, err 163 } 164 keyBytes, keyId, err = decryptKeyV1(k, auth) 165 } else { 166 k := new(encryptedKeyJSONV3) 167 if err := json.Unmarshal(keyjson, k); err != nil { 168 return nil, err 169 } 170 keyBytes, keyId, err = decryptKeyV3(k, auth) 171 } 172 // Handle any decryption errors and return the key 173 if err != nil { 174 return nil, err 175 } 176 key := crypto.ToECDSAUnsafe(keyBytes) 177 178 return &Key{ 179 Id: uuid.UUID(keyId), 180 Address: crypto.PubkeyToAddress(key.PublicKey), 181 PrivateKey: key, 182 }, nil 183 } 184 185 func decryptKeyV3(keyProtected *encryptedKeyJSONV3, auth string) (keyBytes []byte, keyId []byte, err error) { 186 if keyProtected.Version != version { 187 return nil, nil, fmt.Errorf("Version not supported: %v", keyProtected.Version) 188 } 189 190 if keyProtected.Crypto.Cipher != "aes-128-ctr" { 191 return nil, nil, fmt.Errorf("Cipher not supported: %v", keyProtected.Crypto.Cipher) 192 } 193 194 keyId = uuid.Parse(keyProtected.Id) 195 mac, err := hex.DecodeString(keyProtected.Crypto.MAC) 196 if err != nil { 197 return nil, nil, err 198 } 199 200 iv, err := hex.DecodeString(keyProtected.Crypto.CipherParams.IV) 201 if err != nil { 202 return nil, nil, err 203 } 204 205 cipherText, err := hex.DecodeString(keyProtected.Crypto.CipherText) 206 if err != nil { 207 return nil, nil, err 208 } 209 210 derivedKey, err := getKDFKey(keyProtected.Crypto, auth) 211 if err != nil { 212 return nil, nil, err 213 } 214 215 calculatedMAC := crypto.Keccak256(derivedKey[16:32], cipherText) 216 if !bytes.Equal(calculatedMAC, mac) { 217 return nil, nil, ErrDecrypt 218 } 219 220 plainText, err := aesCTRXOR(derivedKey[:16], cipherText, iv) 221 if err != nil { 222 return nil, nil, err 223 } 224 return plainText, keyId, err 225 } 226 227 func decryptKeyV1(keyProtected *encryptedKeyJSONV1, auth string) (keyBytes []byte, keyId []byte, err error) { 228 keyId = uuid.Parse(keyProtected.Id) 229 mac, err := hex.DecodeString(keyProtected.Crypto.MAC) 230 if err != nil { 231 return nil, nil, err 232 } 233 234 iv, err := hex.DecodeString(keyProtected.Crypto.CipherParams.IV) 235 if err != nil { 236 return nil, nil, err 237 } 238 239 cipherText, err := hex.DecodeString(keyProtected.Crypto.CipherText) 240 if err != nil { 241 return nil, nil, err 242 } 243 244 derivedKey, err := getKDFKey(keyProtected.Crypto, auth) 245 if err != nil { 246 return nil, nil, err 247 } 248 249 calculatedMAC := crypto.Keccak256(derivedKey[16:32], cipherText) 250 if !bytes.Equal(calculatedMAC, mac) { 251 return nil, nil, ErrDecrypt 252 } 253 254 plainText, err := aesCBCDecrypt(crypto.Keccak256(derivedKey[:16])[:16], cipherText, iv) 255 if err != nil { 256 return nil, nil, err 257 } 258 return plainText, keyId, err 259 } 260 261 func getKDFKey(cryptoJSON cryptoJSON, auth string) ([]byte, error) { 262 authArray := []byte(auth) 263 salt, err := hex.DecodeString(cryptoJSON.KDFParams["salt"].(string)) 264 if err != nil { 265 return nil, err 266 } 267 dkLen := ensureInt(cryptoJSON.KDFParams["dklen"]) 268 269 if cryptoJSON.KDF == keyHeaderKDF { 270 n := ensureInt(cryptoJSON.KDFParams["n"]) 271 r := ensureInt(cryptoJSON.KDFParams["r"]) 272 p := ensureInt(cryptoJSON.KDFParams["p"]) 273 return scrypt.Key(authArray, salt, n, r, p, dkLen) 274 275 } else if cryptoJSON.KDF == "pbkdf2" { 276 c := ensureInt(cryptoJSON.KDFParams["c"]) 277 prf := cryptoJSON.KDFParams["prf"].(string) 278 if prf != "hmac-sha256" { 279 return nil, fmt.Errorf("Unsupported PBKDF2 PRF: %s", prf) 280 } 281 key := pbkdf2.Key(authArray, salt, c, dkLen, sha256.New) 282 return key, nil 283 } 284 285 return nil, fmt.Errorf("Unsupported KDF: %s", cryptoJSON.KDF) 286 } 287 288 // TODO: can we do without this when unmarshalling dynamic JSON? 289 // why do integers in KDF params end up as float64 and not int after 290 // unmarshal? 291 func ensureInt(x interface{}) int { 292 res, ok := x.(int) 293 if !ok { 294 res = int(x.(float64)) 295 } 296 return res 297 }