diff options
Diffstat (limited to 'crypto')
-rw-r--r-- | crypto/crypto.go | 13 | ||||
-rw-r--r-- | crypto/key.go | 25 | ||||
-rw-r--r-- | crypto/key_store_passphrase.go | 46 | ||||
-rw-r--r-- | crypto/key_store_plain.go | 49 | ||||
-rw-r--r-- | crypto/key_store_test.go | 18 | ||||
-rw-r--r-- | crypto/secp256k1/secp256.go | 6 | ||||
-rw-r--r-- | crypto/secp256k1/secp256_rand.go | 5 |
7 files changed, 95 insertions, 67 deletions
diff --git a/crypto/crypto.go b/crypto/crypto.go index 4b2cc7bb4..d56b9112f 100644 --- a/crypto/crypto.go +++ b/crypto/crypto.go @@ -92,7 +92,7 @@ func ToECDSAPub(pub []byte) *ecdsa.PublicKey { } func FromECDSAPub(pub *ecdsa.PublicKey) []byte { - if pub == nil { + if pub == nil || pub.X == nil || pub.Y == nil { return nil } return elliptic.Marshal(S256(), pub.X, pub.Y) @@ -133,8 +133,7 @@ func ImportPreSaleKey(keyStore KeyStore2, keyJSON []byte, password string) (*Key if err != nil { return nil, err } - id := uuid.NewRandom() - key.Id = &id + key.Id = uuid.NewRandom() err = keyStore.StoreKey(key, password) return key, err } @@ -167,9 +166,10 @@ func decryptPreSaleKey(fileContent []byte, password string) (key *Key, err error ecKey := ToECDSA(ethPriv) key = &Key{ Id: nil, + Address: PubkeyToAddress(ecKey.PublicKey), PrivateKey: ecKey, } - derivedAddr := ethutil.Bytes2Hex(key.Address()) + derivedAddr := ethutil.Bytes2Hex(key.Address) expectedAddr := preSaleKeyStruct.EthAddr if derivedAddr != expectedAddr { err = errors.New("decrypted addr not equal to expected addr") @@ -223,3 +223,8 @@ func PKCS7Unpad(in []byte) []byte { } return in[:len(in)-int(padding)] } + +func PubkeyToAddress(p ecdsa.PublicKey) []byte { + pubBytes := FromECDSAPub(&p) + return Sha3(pubBytes[1:])[12:] +} diff --git a/crypto/key.go b/crypto/key.go index ca29b691f..b9ad34f47 100644 --- a/crypto/key.go +++ b/crypto/key.go @@ -33,7 +33,9 @@ import ( ) type Key struct { - Id *uuid.UUID // Version 4 "random" for unique id not derived from key data + Id uuid.UUID // Version 4 "random" for unique id not derived from key data + // to simplify lookups we also store the address + Address []byte // we only store privkey as pubkey/address can be derived from it // privkey in this struct is always in plaintext PrivateKey *ecdsa.PrivateKey @@ -41,6 +43,7 @@ type Key struct { type plainKeyJSON struct { Id []byte + Address []byte PrivateKey []byte } @@ -51,18 +54,15 @@ type cipherJSON struct { } type encryptedKeyJSON struct { - Id []byte - Crypto cipherJSON -} - -func (k *Key) Address() []byte { - pubBytes := FromECDSAPub(&k.PrivateKey.PublicKey) - return Sha3(pubBytes[1:])[12:] + Id []byte + Address []byte + Crypto cipherJSON } func (k *Key) MarshalJSON() (j []byte, err error) { jStruct := plainKeyJSON{ - *k.Id, + k.Id, + k.Address, FromECDSA(k.PrivateKey), } j, err = json.Marshal(jStruct) @@ -78,8 +78,8 @@ func (k *Key) UnmarshalJSON(j []byte) (err error) { u := new(uuid.UUID) *u = keyJSON.Id - k.Id = u - + k.Id = *u + k.Address = keyJSON.Address k.PrivateKey = ToECDSA(keyJSON.PrivateKey) return err @@ -101,7 +101,8 @@ func NewKey(rand io.Reader) *Key { id := uuid.NewRandom() key := &Key{ - Id: &id, + Id: id, + Address: PubkeyToAddress(privateKeyECDSA.PublicKey), PrivateKey: privateKeyECDSA, } return key diff --git a/crypto/key_store_passphrase.go b/crypto/key_store_passphrase.go index 80bf49d68..0862b7886 100644 --- a/crypto/key_store_passphrase.go +++ b/crypto/key_store_passphrase.go @@ -69,6 +69,7 @@ import ( "crypto/aes" "crypto/cipher" crand "crypto/rand" + "encoding/hex" "encoding/json" "errors" "io" @@ -96,21 +97,26 @@ func (ks keyStorePassphrase) GenerateNewKey(rand io.Reader, auth string) (key *K return GenerateNewKeyDefault(ks, rand, auth) } -func (ks keyStorePassphrase) GetKey(keyId *uuid.UUID, auth string) (key *Key, err error) { - keyBytes, err := DecryptKey(ks, keyId, auth) +func (ks keyStorePassphrase) GetKey(keyAddr []byte, auth string) (key *Key, err error) { + keyBytes, keyId, err := DecryptKey(ks, keyAddr, auth) if err != nil { return nil, err } key = &Key{ - Id: keyId, + Id: uuid.UUID(keyId), + Address: keyAddr, PrivateKey: ToECDSA(keyBytes), } return key, err } +func (ks keyStorePassphrase) GetKeyAddresses() (addresses [][]byte, err error) { + return GetKeyAddresses(ks.keysDirPath) +} + func (ks keyStorePassphrase) StoreKey(key *Key, auth string) (err error) { authArray := []byte(auth) - salt := getEntropyCSPRNG(32) + salt := GetEntropyCSPRNG(32) derivedKey, err := scrypt.Key(authArray, salt, scryptN, scryptr, scryptp, scryptdkLen) if err != nil { return err @@ -125,7 +131,7 @@ func (ks keyStorePassphrase) StoreKey(key *Key, auth string) (err error) { return err } - iv := getEntropyCSPRNG(aes.BlockSize) // 16 + iv := GetEntropyCSPRNG(aes.BlockSize) // 16 AES256CBCEncrypter := cipher.NewCBCEncrypter(AES256Block, iv) cipherText := make([]byte, len(toEncrypt)) AES256CBCEncrypter.CryptBlocks(cipherText, toEncrypt) @@ -136,7 +142,8 @@ func (ks keyStorePassphrase) StoreKey(key *Key, auth string) (err error) { cipherText, } keyStruct := encryptedKeyJSON{ - *key.Id, + key.Id, + key.Address, cipherStruct, } keyJSON, err := json.Marshal(keyStruct) @@ -144,54 +151,53 @@ func (ks keyStorePassphrase) StoreKey(key *Key, auth string) (err error) { return err } - return WriteKeyFile(key.Id.String(), ks.keysDirPath, keyJSON) + return WriteKeyFile(key.Address, ks.keysDirPath, keyJSON) } -func (ks keyStorePassphrase) DeleteKey(keyId *uuid.UUID, auth string) (err error) { +func (ks keyStorePassphrase) DeleteKey(keyAddr []byte, auth string) (err error) { // only delete if correct passphrase is given - _, err = DecryptKey(ks, keyId, auth) + _, _, err = DecryptKey(ks, keyAddr, auth) if err != nil { return err } - keyDirPath := path.Join(ks.keysDirPath, keyId.String()) + keyDirPath := path.Join(ks.keysDirPath, hex.EncodeToString(keyAddr)) return os.RemoveAll(keyDirPath) } -func DecryptKey(ks keyStorePassphrase, keyId *uuid.UUID, auth string) (keyBytes []byte, err error) { - fileContent, err := GetKeyFile(ks.keysDirPath, keyId) +func DecryptKey(ks keyStorePassphrase, keyAddr []byte, auth string) (keyBytes []byte, keyId []byte, err error) { + fileContent, err := GetKeyFile(ks.keysDirPath, keyAddr) if err != nil { - return nil, err + return nil, nil, err } keyProtected := new(encryptedKeyJSON) err = json.Unmarshal(fileContent, keyProtected) + keyId = keyProtected.Id salt := keyProtected.Crypto.Salt - iv := keyProtected.Crypto.IV - cipherText := keyProtected.Crypto.CipherText authArray := []byte(auth) derivedKey, err := scrypt.Key(authArray, salt, scryptN, scryptr, scryptp, scryptdkLen) if err != nil { - return nil, err + return nil, nil, err } plainText, err := aesCBCDecrypt(derivedKey, cipherText, iv) if err != nil { - return nil, err + return nil, nil, err } keyBytes = plainText[:len(plainText)-32] keyBytesHash := plainText[len(plainText)-32:] if !bytes.Equal(Sha3(keyBytes), keyBytesHash) { err = errors.New("Decryption failed: checksum mismatch") - return nil, err + return nil, nil, err } - return keyBytes, err + return keyBytes, keyId, err } -func getEntropyCSPRNG(n int) []byte { +func GetEntropyCSPRNG(n int) []byte { mainBuff := make([]byte, n) _, err := io.ReadFull(crand.Reader, mainBuff) if err != nil { diff --git a/crypto/key_store_plain.go b/crypto/key_store_plain.go index b6e2a309a..6b76962a0 100644 --- a/crypto/key_store_plain.go +++ b/crypto/key_store_plain.go @@ -24,7 +24,7 @@ package crypto import ( - "code.google.com/p/go-uuid/uuid" + "encoding/hex" "encoding/json" "fmt" "io" @@ -38,9 +38,10 @@ import ( type KeyStore2 interface { // create new key using io.Reader entropy source and optionally using auth string GenerateNewKey(io.Reader, string) (*Key, error) - GetKey(*uuid.UUID, string) (*Key, error) // key from id and auth string - StoreKey(*Key, string) error // store key optionally using auth string - DeleteKey(*uuid.UUID, string) error // delete key by id and auth string + GetKey([]byte, string) (*Key, error) // key from addr and auth string + GetKeyAddresses() ([][]byte, error) // get all addresses + StoreKey(*Key, string) error // store key optionally using auth string + DeleteKey([]byte, string) error // delete key by addr and auth string } type keyStorePlain struct { @@ -72,8 +73,8 @@ func GenerateNewKeyDefault(ks KeyStore2, rand io.Reader, auth string) (key *Key, return key, err } -func (ks keyStorePlain) GetKey(keyId *uuid.UUID, auth string) (key *Key, err error) { - fileContent, err := GetKeyFile(ks.keysDirPath, keyId) +func (ks keyStorePlain) GetKey(keyAddr []byte, auth string) (key *Key, err error) { + fileContent, err := GetKeyFile(ks.keysDirPath, keyAddr) if err != nil { return nil, err } @@ -83,32 +84,50 @@ func (ks keyStorePlain) GetKey(keyId *uuid.UUID, auth string) (key *Key, err err return key, err } +func (ks keyStorePlain) GetKeyAddresses() (addresses [][]byte, err error) { + return GetKeyAddresses(ks.keysDirPath) +} + func (ks keyStorePlain) StoreKey(key *Key, auth string) (err error) { keyJSON, err := json.Marshal(key) if err != nil { return err } - err = WriteKeyFile(key.Id.String(), ks.keysDirPath, keyJSON) + err = WriteKeyFile(key.Address, ks.keysDirPath, keyJSON) return err } -func (ks keyStorePlain) DeleteKey(keyId *uuid.UUID, auth string) (err error) { - keyDirPath := path.Join(ks.keysDirPath, keyId.String()) +func (ks keyStorePlain) DeleteKey(keyAddr []byte, auth string) (err error) { + keyDirPath := path.Join(ks.keysDirPath, hex.EncodeToString(keyAddr)) err = os.RemoveAll(keyDirPath) return err } -func GetKeyFile(keysDirPath string, keyId *uuid.UUID) (fileContent []byte, err error) { - id := keyId.String() - return ioutil.ReadFile(path.Join(keysDirPath, id, id)) +func GetKeyFile(keysDirPath string, keyAddr []byte) (fileContent []byte, err error) { + fileName := hex.EncodeToString(keyAddr) + return ioutil.ReadFile(path.Join(keysDirPath, fileName, fileName)) } -func WriteKeyFile(id string, keysDirPath string, content []byte) (err error) { - keyDirPath := path.Join(keysDirPath, id) - keyFilePath := path.Join(keyDirPath, id) +func WriteKeyFile(addr []byte, keysDirPath string, content []byte) (err error) { + addrHex := hex.EncodeToString(addr) + keyDirPath := path.Join(keysDirPath, addrHex) + keyFilePath := path.Join(keyDirPath, addrHex) err = os.MkdirAll(keyDirPath, 0700) // read, write and dir search for user if err != nil { return err } return ioutil.WriteFile(keyFilePath, content, 0600) // read, write for user } + +func GetKeyAddresses(keysDirPath string) (addresses [][]byte, err error) { + fileInfos, err := ioutil.ReadDir(keysDirPath) + if err != nil { + return nil, err + } + addresses = make([][]byte, len(fileInfos)) + for i, fileInfo := range fileInfos { + addresses[i] = make([]byte, 40) + addresses[i] = []byte(fileInfo.Name()) + } + return addresses, err +} diff --git a/crypto/key_store_test.go b/crypto/key_store_test.go index 54efc739a..0d229ab65 100644 --- a/crypto/key_store_test.go +++ b/crypto/key_store_test.go @@ -15,12 +15,12 @@ func TestKeyStorePlain(t *testing.T) { } k2 := new(Key) - k2, err = ks.GetKey(k1.Id, pass) + k2, err = ks.GetKey(k1.Address, pass) if err != nil { t.Fatal(err) } - if !reflect.DeepEqual(k1.Id, k2.Id) { + if !reflect.DeepEqual(k1.Address, k2.Address) { t.Fatal(err) } @@ -28,7 +28,7 @@ func TestKeyStorePlain(t *testing.T) { t.Fatal(err) } - err = ks.DeleteKey(k2.Id, pass) + err = ks.DeleteKey(k2.Address, pass) if err != nil { t.Fatal(err) } @@ -42,11 +42,11 @@ func TestKeyStorePassphrase(t *testing.T) { t.Fatal(err) } k2 := new(Key) - k2, err = ks.GetKey(k1.Id, pass) + k2, err = ks.GetKey(k1.Address, pass) if err != nil { t.Fatal(err) } - if !reflect.DeepEqual(k1.Id, k2.Id) { + if !reflect.DeepEqual(k1.Address, k2.Address) { t.Fatal(err) } @@ -54,7 +54,7 @@ func TestKeyStorePassphrase(t *testing.T) { t.Fatal(err) } - err = ks.DeleteKey(k2.Id, pass) // also to clean up created files + err = ks.DeleteKey(k2.Address, pass) // also to clean up created files if err != nil { t.Fatal(err) } @@ -68,17 +68,17 @@ func TestKeyStorePassphraseDecryptionFail(t *testing.T) { t.Fatal(err) } - _, err = ks.GetKey(k1.Id, "bar") // wrong passphrase + _, err = ks.GetKey(k1.Address, "bar") // wrong passphrase if err == nil { t.Fatal(err) } - err = ks.DeleteKey(k1.Id, "bar") // wrong passphrase + err = ks.DeleteKey(k1.Address, "bar") // wrong passphrase if err == nil { t.Fatal(err) } - err = ks.DeleteKey(k1.Id, pass) // to clean up + err = ks.DeleteKey(k1.Address, pass) // to clean up if err != nil { t.Fatal(err) } diff --git a/crypto/secp256k1/secp256.go b/crypto/secp256k1/secp256.go index 53ad9b477..c01598b84 100644 --- a/crypto/secp256k1/secp256.go +++ b/crypto/secp256k1/secp256.go @@ -124,11 +124,7 @@ int secp256k1_ecdsa_sign_compact(const unsigned char *msg, int msglen, */ func Sign(msg []byte, seckey []byte) ([]byte, error) { - //var nonce []byte = RandByte(32) - nonce := make([]byte, 32) - for i := range msg { - nonce[i] = msg[i] ^ seckey[i] - } + nonce := RandByte(32) var sig []byte = make([]byte, 65) var recid C.int diff --git a/crypto/secp256k1/secp256_rand.go b/crypto/secp256k1/secp256_rand.go index 5e8035e0f..bb10025fc 100644 --- a/crypto/secp256k1/secp256_rand.go +++ b/crypto/secp256k1/secp256_rand.go @@ -49,7 +49,8 @@ func init() { _rand = mrand.New(mrand.NewSource(int64(seed1 ^ seed2 ^ seed3))) } -func saltByte(buff []byte) []byte { +func saltByte(n int) []byte { + buff := make([]byte, n) for i := 0; i < len(buff); i++ { var v uint64 = uint64(_rand.Int63()) var b byte @@ -75,7 +76,7 @@ func RandByte(n int) []byte { return nil } - buff2 := RandByteWeakCrypto(n) + buff2 := saltByte(n) for i := 0; i < n; i++ { buff[i] ^= buff2[2] } |