github.com/halybang/go-ethereum@v1.0.5-0.20180325041310-3b262bc1367c/accounts/keystore/key.go (about) 1 // Copyright 2014 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package keystore 18 19 import ( 20 "bytes" 21 "crypto/ecdsa" 22 "encoding/hex" 23 "encoding/json" 24 "fmt" 25 "io" 26 "io/ioutil" 27 "os" 28 "path/filepath" 29 "strings" 30 "time" 31 32 "errors" 33 34 "github.com/btcsuite/btcd/btcec" 35 "github.com/pborman/uuid" 36 "github.com/wanchain/go-wanchain/accounts" 37 "github.com/wanchain/go-wanchain/common" 38 "github.com/wanchain/go-wanchain/common/math" 39 "github.com/wanchain/go-wanchain/crypto" 40 ) 41 42 const ( 43 version = 3 44 ) 45 46 type Key struct { 47 Id uuid.UUID // Version 4 "random" for unique id not derived from key data 48 // to simplify lookups we also store the address 49 Address common.Address 50 // we only store privkey as pubkey/address can be derived from it 51 // privkey in this struct is always in plaintext 52 PrivateKey *ecdsa.PrivateKey 53 // add a second privkey for privary 54 PrivateKey2 *ecdsa.PrivateKey 55 // compact wanchain address format 56 WAddress common.WAddress 57 } 58 59 // Used to import and export raw keypair 60 type keyPair struct { 61 D string `json:"privateKey"` 62 D1 string `json:"privateKey1"` 63 } 64 65 type keyStore interface { 66 // Loads and decrypts the key from disk 67 GetKey(addr common.Address, filename string, auth string) (*Key, error) 68 // Loads an encrypted keyfile from disk 69 GetEncryptedKey(addr common.Address, filename string) (*Key, error) 70 // Writes and encrypts the key 71 StoreKey(filename string, k *Key, auth string) error 72 // Joins filename with the key directory unless it is already absolute. 73 JoinPath(filename string) string 74 } 75 76 type plainKeyJSON struct { 77 Address string `json:"address"` 78 PrivateKey string `json:"privatekey"` 79 Id string `json:"id"` 80 Version int `json:"version"` 81 } 82 83 type encryptedKeyJSONV3 struct { 84 Address string `json:"address"` 85 Crypto cryptoJSON `json:"crypto"` 86 Crypto2 cryptoJSON `json:"crypto2"` 87 Id string `json:"id"` 88 Version int `json:"version"` 89 WAddress string `json:"waddress"` 90 } 91 92 type encryptedKeyJSONV1 struct { 93 Address string `json:"address"` 94 Crypto cryptoJSON `json:"crypto"` 95 Id string `json:"id"` 96 Version string `json:"version"` 97 } 98 99 type cryptoJSON struct { 100 Cipher string `json:"cipher"` 101 CipherText string `json:"ciphertext"` 102 CipherParams cipherparamsJSON `json:"cipherparams"` 103 KDF string `json:"kdf"` 104 KDFParams map[string]interface{} `json:"kdfparams"` 105 MAC string `json:"mac"` 106 } 107 108 type cipherparamsJSON struct { 109 IV string `json:"iv"` 110 } 111 112 func (k *Key) MarshalJSON() (j []byte, err error) { 113 jStruct := plainKeyJSON{ 114 k.Address.Hex()[2:], 115 hex.EncodeToString(crypto.FromECDSA(k.PrivateKey)), 116 k.Id.String(), 117 version, 118 } 119 j, err = json.Marshal(jStruct) 120 return j, err 121 } 122 123 func (k *Key) UnmarshalJSON(j []byte) (err error) { 124 keyJSON := new(plainKeyJSON) 125 err = json.Unmarshal(j, &keyJSON) 126 if err != nil { 127 return err 128 } 129 130 u := new(uuid.UUID) 131 *u = uuid.Parse(keyJSON.Id) 132 k.Id = *u 133 addr, err := hex.DecodeString(keyJSON.Address) 134 if err != nil { 135 return err 136 } 137 privkey, err := crypto.HexToECDSA(keyJSON.PrivateKey) 138 if err != nil { 139 return err 140 } 141 142 k.Address = common.BytesToAddress(addr) 143 k.PrivateKey = privkey 144 145 return nil 146 } 147 148 func newKeyFromECDSA(sk1, sk2 *ecdsa.PrivateKey) *Key { 149 id := uuid.NewRandom() 150 key := &Key{ 151 Id: id, 152 Address: crypto.PubkeyToAddress(sk1.PublicKey), 153 PrivateKey: sk1, 154 PrivateKey2: sk2, 155 } 156 157 updateWaddress(key) 158 return key 159 } 160 161 // updateWaddress adds WAddress field to the Key struct 162 func updateWaddress(k *Key) { 163 k.WAddress = *GenerateWaddressFromPK(&k.PrivateKey.PublicKey, &k.PrivateKey2.PublicKey) 164 } 165 166 // ECDSAPKCompression serializes a public key in a 33-byte compressed format from btcec 167 func ECDSAPKCompression(p *ecdsa.PublicKey) []byte { 168 const pubkeyCompressed byte = 0x2 169 b := make([]byte, 0, 33) 170 format := pubkeyCompressed 171 if p.Y.Bit(0) == 1 { 172 format |= 0x1 173 } 174 b = append(b, format) 175 b = append(b, math.PaddedBigBytes(p.X, 32)...) 176 return b 177 } 178 179 // NewKeyForDirectICAP generates a key whose address fits into < 155 bits so it can fit 180 // into the Direct ICAP spec. for simplicity and easier compatibility with other libs, we 181 // retry until the first byte is 0. 182 func NewKeyForDirectICAP(rand io.Reader) *Key { 183 randBytes := make([]byte, 64*2) 184 _, err := rand.Read(randBytes) 185 if err != nil { 186 panic("key generation: could not read from random source: " + err.Error()) 187 } 188 reader := bytes.NewReader(randBytes) 189 sk1, err := ecdsa.GenerateKey(crypto.S256(), reader) 190 if err != nil { 191 panic("key generation: ecdsa.GenerateKey failed: " + err.Error()) 192 } 193 194 sk2, err := ecdsa.GenerateKey(crypto.S256(), reader) 195 if err != nil { 196 panic("key generation: ecdsa.GenerateKey failed: " + err.Error()) 197 } 198 key := newKeyFromECDSA(sk1, sk2) 199 if !strings.HasPrefix(key.Address.Hex(), "0x00") { 200 return NewKeyForDirectICAP(rand) 201 } 202 return key 203 } 204 205 func newKey(rand io.Reader) (*Key, error) { 206 privateKeyECDSA, err := ecdsa.GenerateKey(crypto.S256(), rand) 207 if err != nil { 208 return nil, err 209 } 210 211 privateKeyECDSA2, err := ecdsa.GenerateKey(crypto.S256(), rand) 212 if err != nil { 213 return nil, err 214 } 215 return newKeyFromECDSA(privateKeyECDSA, privateKeyECDSA2), nil 216 } 217 218 func storeNewKey(ks keyStore, rand io.Reader, auth string) (*Key, accounts.Account, error) { 219 key, err := newKey(rand) 220 if err != nil { 221 return nil, accounts.Account{}, err 222 } 223 a := accounts.Account{Address: key.Address, URL: accounts.URL{Scheme: KeyStoreScheme, Path: ks.JoinPath(keyFileName(key.Address))}} 224 if err := ks.StoreKey(a.URL.Path, key, auth); err != nil { 225 zeroKey(key.PrivateKey) 226 return nil, a, err 227 } 228 return key, a, err 229 } 230 231 func writeKeyFile(file string, content []byte) error { 232 // Create the keystore directory with appropriate permissions 233 // in case it is not present yet. 234 const dirPerm = 0700 235 if err := os.MkdirAll(filepath.Dir(file), dirPerm); err != nil { 236 return err 237 } 238 // Atomic write: create a temporary hidden file first 239 // then move it into place. TempFile assigns mode 0600. 240 f, err := ioutil.TempFile(filepath.Dir(file), "."+filepath.Base(file)+".tmp") 241 if err != nil { 242 return err 243 } 244 if _, err := f.Write(content); err != nil { 245 f.Close() 246 os.Remove(f.Name()) 247 return err 248 } 249 f.Close() 250 return os.Rename(f.Name(), file) 251 } 252 253 // keyFileName implements the naming convention for keyfiles: 254 // UTC--<created_at UTC ISO8601>-<address hex> 255 func keyFileName(keyAddr common.Address) string { 256 ts := time.Now().UTC() 257 return fmt.Sprintf("UTC--%s--%s", toISO8601(ts), keyAddr.Hex()[2:]) 258 } 259 260 func toISO8601(t time.Time) string { 261 var tz string 262 name, offset := t.Zone() 263 if name == "UTC" { 264 tz = "Z" 265 } else { 266 tz = fmt.Sprintf("%03d00", offset/3600) 267 } 268 return fmt.Sprintf("%04d-%02d-%02dT%02d-%02d-%02d.%09d%s", t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second(), t.Nanosecond(), tz) 269 } 270 271 // GeneratePKPairFromWAddress represents the keystore to retrieve public key-pair from given WAddress 272 func GeneratePKPairFromWAddress(w []byte) (*ecdsa.PublicKey, *ecdsa.PublicKey, error) { 273 if len(w) != common.WAddressLength { 274 return nil, nil, ErrWAddressInvalid 275 } 276 277 tmp := make([]byte, 33) 278 copy(tmp[:], w[:33]) 279 curve := btcec.S256() 280 PK1, err := btcec.ParsePubKey(tmp, curve) 281 if err != nil { 282 return nil, nil, err 283 } 284 285 copy(tmp[:], w[33:]) 286 PK2, err := btcec.ParsePubKey(tmp, curve) 287 if err != nil { 288 return nil, nil, err 289 } 290 291 return (*ecdsa.PublicKey)(PK1), (*ecdsa.PublicKey)(PK2), nil 292 } 293 294 func GenerateWaddressFromPK(A *ecdsa.PublicKey, B *ecdsa.PublicKey) *common.WAddress { 295 var tmp common.WAddress 296 copy(tmp[:33], ECDSAPKCompression(A)) 297 copy(tmp[33:], ECDSAPKCompression(B)) 298 return &tmp 299 } 300 301 func WaddrFromUncompressedRawBytes(raw []byte) (*common.WAddress, error) { 302 if len(raw) != 32*2*2 { 303 return nil, errors.New("invalid uncompressed wan address len") 304 } 305 306 pub := make([]byte, 65) 307 pub[0] = 0x004 308 copy(pub[1:], raw[:64]) 309 A := crypto.ToECDSAPub(pub) 310 copy(pub[1:], raw[64:]) 311 B := crypto.ToECDSAPub(pub) 312 return GenerateWaddressFromPK(A, B), nil 313 } 314 315 func WaddrToUncompressedRawBytes(waddr []byte) ([]byte, error) { 316 if len(waddr) != common.WAddressLength { 317 return nil, ErrWAddressInvalid 318 } 319 320 A, B, err := GeneratePKPairFromWAddress(waddr) 321 if err != nil { 322 return nil, err 323 } 324 325 u := make([]byte, 32*2*2) 326 ax := math.PaddedBigBytes(A.X, 32) 327 ay := math.PaddedBigBytes(A.Y, 32) 328 bx := math.PaddedBigBytes(B.X, 32) 329 by := math.PaddedBigBytes(B.Y, 32) 330 copy(u[0:], ax[:32]) 331 copy(u[32:], ay[:32]) 332 copy(u[64:], bx[:32]) 333 copy(u[96:], by[:32]) 334 335 return u, nil 336 } 337 338 // LoadECDSAPair loads a secp256k1 private key pair from the given file 339 func LoadECDSAPair(file string) (*ecdsa.PrivateKey, *ecdsa.PrivateKey, error) { 340 // read the given file including private key pair 341 kp := keyPair{} 342 343 raw, err := ioutil.ReadFile(file) 344 if err != nil { 345 return nil, nil, err 346 } 347 348 err = json.Unmarshal(raw, &kp) 349 if err != nil { 350 return nil, nil, err 351 } 352 353 // Decode the key pair 354 d, err := hex.DecodeString(kp.D) 355 if err != nil { 356 return nil, nil, err 357 } 358 d1, err := hex.DecodeString(kp.D1) 359 if err != nil { 360 return nil, nil, err 361 } 362 363 // Generate ecdsa private keys 364 sk, err := crypto.ToECDSA(d) 365 if err != nil { 366 return nil, nil, err 367 } 368 369 sk1, err := crypto.ToECDSA(d1) 370 if err != nil { 371 return nil, nil, err 372 } 373 374 return sk, sk1, err 375 } 376 377 // ExportECDSAPair returns an ecdsa-private-key pair 378 // func ExportECDSAPair(d, d1, fp string) error { 379 // kp := keyPair{ 380 // D: d, 381 // D1: d1, 382 // } 383 // log.Info("Exporting ECDSA Prikave-Key-Pair", "file", fp) 384 // fh, err := os.OpenFile(fp, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.ModePerm) 385 // if err != nil { 386 // return err 387 // } 388 // defer fh.Close() 389 390 // var fileWriter io.Writer = fh 391 // err = json.NewEncoder(fileWriter).Encode(kp) 392 // return err 393 // } 394 395 // func ExportECDSAPairStr(d, d1 string) (string, error) { 396 // kp := keyPair{ 397 // D: d, 398 // D1: d1, 399 // } 400 // r, err := json.Marshal(kp) 401 // if err != nil { 402 // return "", err 403 // } 404 405 // return string(r), err 406 // }