diff options
author | Martin Holst Swende <martin@swende.se> | 2018-09-25 21:54:58 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-09-25 21:54:58 +0800 |
commit | d3441ebb563439bac0837d70591f92e2c6080303 (patch) | |
tree | cec46689f8ec4fd4570322e79ad7167c3b792c74 /signer/storage | |
parent | a95a601f35c49be6045de522138f639fbb68c885 (diff) | |
download | dexon-d3441ebb563439bac0837d70591f92e2c6080303.tar.gz dexon-d3441ebb563439bac0837d70591f92e2c6080303.tar.zst dexon-d3441ebb563439bac0837d70591f92e2c6080303.zip |
cmd/clef, signer: security fixes (#17554)
* signer: remove local path disclosure from extapi
* signer: show more data in cli ui
* rpc: make http server forward UA and Origin via Context
* signer, clef/core: ui changes + display UA and Origin
* signer: cliui - indicate less trust in remote headers, see https://github.com/ethereum/go-ethereum/issues/17637
* signer: prevent possibility swap KV-entries in aes_gcm storage, fixes #17635
* signer: remove ecrecover from external API
* signer,clef: default reject instead of warn + valideate new passwords. fixes #17632 and #17631
* signer: check calldata length even if no ABI signature is present
* signer: fix failing testcase
* clef: remove account import from external api
* signer: allow space in passwords, improve error messsage
* signer/storage: fix typos
Diffstat (limited to 'signer/storage')
-rw-r--r-- | signer/storage/aes_gcm_storage.go | 15 | ||||
-rw-r--r-- | signer/storage/aes_gcm_storage_test.go | 53 |
2 files changed, 60 insertions, 8 deletions
diff --git a/signer/storage/aes_gcm_storage.go b/signer/storage/aes_gcm_storage.go index 399637a44..900831867 100644 --- a/signer/storage/aes_gcm_storage.go +++ b/signer/storage/aes_gcm_storage.go @@ -63,7 +63,7 @@ func (s *AESEncryptedStorage) Put(key, value string) { log.Warn("Failed to read encrypted storage", "err", err, "file", s.filename) return } - ciphertext, iv, err := encrypt(s.key, []byte(value)) + ciphertext, iv, err := encrypt(s.key, []byte(value), []byte(key)) if err != nil { log.Warn("Failed to encrypt entry", "err", err) return @@ -90,7 +90,7 @@ func (s *AESEncryptedStorage) Get(key string) string { log.Warn("Key does not exist", "key", key) return "" } - entry, err := decrypt(s.key, encrypted.Iv, encrypted.CipherText) + entry, err := decrypt(s.key, encrypted.Iv, encrypted.CipherText, []byte(key)) if err != nil { log.Warn("Failed to decrypt key", "key", key) return "" @@ -129,7 +129,10 @@ func (s *AESEncryptedStorage) writeEncryptedStorage(creds map[string]storedCrede return nil } -func encrypt(key []byte, plaintext []byte) ([]byte, []byte, error) { +// encrypt encrypts plaintext with the given key, with additional data +// The 'additionalData' is used to place the (plaintext) KV-store key into the V, +// to prevent the possibility to alter a K, or swap two entries in the KV store with eachother. +func encrypt(key []byte, plaintext []byte, additionalData []byte) ([]byte, []byte, error) { block, err := aes.NewCipher(key) if err != nil { return nil, nil, err @@ -142,11 +145,11 @@ func encrypt(key []byte, plaintext []byte) ([]byte, []byte, error) { if err != nil { return nil, nil, err } - ciphertext := aesgcm.Seal(nil, nonce, plaintext, nil) + ciphertext := aesgcm.Seal(nil, nonce, plaintext, additionalData) return ciphertext, nonce, nil } -func decrypt(key []byte, nonce []byte, ciphertext []byte) ([]byte, error) { +func decrypt(key []byte, nonce []byte, ciphertext []byte, additionalData []byte) ([]byte, error) { block, err := aes.NewCipher(key) if err != nil { return nil, err @@ -155,7 +158,7 @@ func decrypt(key []byte, nonce []byte, ciphertext []byte) ([]byte, error) { if err != nil { return nil, err } - plaintext, err := aesgcm.Open(nil, nonce, ciphertext, nil) + plaintext, err := aesgcm.Open(nil, nonce, ciphertext, additionalData) if err != nil { return nil, err } diff --git a/signer/storage/aes_gcm_storage_test.go b/signer/storage/aes_gcm_storage_test.go index 77804905a..a421a8449 100644 --- a/signer/storage/aes_gcm_storage_test.go +++ b/signer/storage/aes_gcm_storage_test.go @@ -18,6 +18,7 @@ package storage import ( "bytes" + "encoding/json" "fmt" "io/ioutil" "testing" @@ -33,13 +34,13 @@ func TestEncryption(t *testing.T) { key := []byte("AES256Key-32Characters1234567890") plaintext := []byte("exampleplaintext") - c, iv, err := encrypt(key, plaintext) + c, iv, err := encrypt(key, plaintext, nil) if err != nil { t.Fatal(err) } fmt.Printf("Ciphertext %x, nonce %x\n", c, iv) - p, err := decrypt(key, iv, c) + p, err := decrypt(key, iv, c, nil) if err != nil { t.Fatal(err) } @@ -113,3 +114,51 @@ func TestEnd2End(t *testing.T) { t.Errorf("Expected bazonk->foobar, got '%v'", v) } } + +func TestSwappedKeys(t *testing.T) { + // It should not be possible to swap the keys/values, so that + // K1:V1, K2:V2 can be swapped into K1:V2, K2:V1 + log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(3), log.StreamHandler(colorable.NewColorableStderr(), log.TerminalFormat(true)))) + + d, err := ioutil.TempDir("", "eth-encrypted-storage-test") + if err != nil { + t.Fatal(err) + } + + s1 := &AESEncryptedStorage{ + filename: fmt.Sprintf("%v/vault.json", d), + key: []byte("AES256Key-32Characters1234567890"), + } + s1.Put("k1", "v1") + s1.Put("k2", "v2") + // Now make a modified copy + + creds := make(map[string]storedCredential) + raw, err := ioutil.ReadFile(s1.filename) + if err != nil { + t.Fatal(err) + } + if err = json.Unmarshal(raw, &creds); err != nil { + t.Fatal(err) + } + swap := func() { + // Turn it into K1:V2, K2:V2 + v1, v2 := creds["k1"], creds["k2"] + creds["k2"], creds["k1"] = v1, v2 + raw, err = json.Marshal(creds) + if err != nil { + t.Fatal(err) + } + if err = ioutil.WriteFile(s1.filename, raw, 0600); err != nil { + t.Fatal(err) + } + } + swap() + if v := s1.Get("k1"); v != "" { + t.Errorf("swapped value should return empty") + } + swap() + if v := s1.Get("k1"); v != "v1" { + t.Errorf("double-swapped value should work fine") + } +} |