diff --git a/cmd/burrow/commands/configure.go b/cmd/burrow/commands/configure.go
index a964e2f9eb86b330eb34327ccfb8d31bbdc43c1b..b06f9a9a0d11882f54df922d581e2e0ef514b8f0 100644
--- a/cmd/burrow/commands/configure.go
+++ b/cmd/burrow/commands/configure.go
@@ -94,7 +94,7 @@ func Configure(output Output) func(cmd *cli.Cmd) {
 				if err != nil {
 					output.Fatalf("Could not read GenesisSpec: %v", err)
 				}
-				keyStore := keys.NewKeyStore(conf.Keys.KeysDirectory)
+				keyStore := keys.NewKeyStore(conf.Keys.KeysDirectory, conf.Keys.AllowBadFilePermissions, logging.NewNoopLogger())
 				if *generateKeysOpt != "" {
 					keyClient := keys.NewLocalKeyClient(keyStore, logging.NewNoopLogger())
 					conf.GenesisDoc, err = genesisSpec.GenesisDoc(keyClient)
diff --git a/cmd/burrow/commands/keys.go b/cmd/burrow/commands/keys.go
index 10b3c4fe240425a8b1fb8d48252af480befe306e..0b2fd9cd503a1399c2cf44484b7526d92845ec61 100644
--- a/cmd/burrow/commands/keys.go
+++ b/cmd/burrow/commands/keys.go
@@ -11,9 +11,11 @@ import (
 	"io/ioutil"
 
 	"github.com/howeyc/gopass"
+	"github.com/hyperledger/burrow/config"
 	"github.com/hyperledger/burrow/crypto"
 	"github.com/hyperledger/burrow/keys"
 	"github.com/hyperledger/burrow/keys/pbkeys"
+	"github.com/hyperledger/burrow/logging/lifecycle"
 	"github.com/jawher/mow.cli"
 	"google.golang.org/grpc"
 )
@@ -45,10 +47,34 @@ func Keys(output Output) func(cmd *cli.Cmd) {
 		}
 
 		cmd.Command("server", "run keys server", func(cmd *cli.Cmd) {
-			keysDir := cmd.StringOpt("dir", keys.DefaultKeysDir, "specify the location of the directory containing key files")
+			keysDir := cmd.StringOpt("dir", "", "specify the location of the directory containing key files")
+			badPerm := cmd.BoolOpt("allow-bad-perm", false, "Allow unix key file permissions to be readable other than user")
+			configOpt := cmd.StringOpt("c config", "", "Use the a specified burrow config file")
+
+			var conf *config.BurrowConfig
+
+			cmd.Before = func() {
+				var err error
+				conf, err = obtainBurrowConfig(*configOpt, "")
+				if err != nil {
+					output.Fatalf("Could not obtain config: %v", err)
+				}
+			}
 
 			cmd.Action = func() {
-				err := keys.StartStandAloneServer(*keysDir, *keysHost, *keysPort)
+				logger, err := lifecycle.NewLoggerFromLoggingConfig(conf.Logging)
+				if err != nil {
+					output.Fatalf("could not generate logger from logging config: %v", err)
+				}
+
+				if badPerm != nil {
+					conf.Keys.AllowBadFilePermissions = *badPerm
+				}
+				if keysDir != nil {
+					conf.Keys.KeysDirectory = *keysDir
+				}
+
+				err = keys.StartStandAloneServer(conf.Keys.KeysDirectory, *keysHost, *keysPort, conf.Keys.AllowBadFilePermissions, logger)
 				if err != nil {
 					output.Fatalf("Failed to start server: %v", err)
 				}
diff --git a/config/config.go b/config/config.go
index 1a73e9faa4b9c8d075e1f5365b46230b0bd694d9..a120986d4a80324656acc00738d3c900187d6247 100644
--- a/config/config.go
+++ b/config/config.go
@@ -63,7 +63,7 @@ func (conf *BurrowConfig) Kernel(ctx context.Context) (*core.Kernel, error) {
 			return nil, err
 		}
 	} else {
-		keyStore = keys.NewKeyStore(conf.Keys.KeysDirectory)
+		keyStore = keys.NewKeyStore(conf.Keys.KeysDirectory, conf.Keys.AllowBadFilePermissions, logger)
 		keyClient = keys.NewLocalKeyClient(keyStore, logger)
 	}
 
diff --git a/core/kernel.go b/core/kernel.go
index 437c43fcb9f24a07307ac7f186fa1271d6188912..555b78885dfe3e53833891bb41a4be734a72f3eb 100644
--- a/core/kernel.go
+++ b/core/kernel.go
@@ -219,7 +219,7 @@ func NewKernel(ctx context.Context, keyClient keys.KeyClient, privValidator tm_t
 
 				if keyConfig.GRPCServiceEnabled {
 					if keyStore == nil {
-						ks = keys.NewKeyStore(keyConfig.KeysDirectory)
+						ks = keys.NewKeyStore(keyConfig.KeysDirectory, keyConfig.AllowBadFilePermissions, logger)
 					}
 					pbkeys.RegisterKeysServer(grpcServer, &ks)
 				}
diff --git a/core/kernel_test.go b/core/kernel_test.go
index e02ef7cd60463e64b0590a102be606cd7693c0e3..68cb5f9dd34264b09d0d65de7c577cf26d55eaa8 100644
--- a/core/kernel_test.go
+++ b/core/kernel_test.go
@@ -65,7 +65,7 @@ func bootWaitBlocksShutdown(privValidator tm_types.PrivValidator, genesisDoc *ge
 	tmConf *tm_config.Config, logger *logging.Logger,
 	blockChecker func(block *tm_types.EventDataNewBlock) (cont bool)) error {
 
-	keyStore := keys.NewKeyStore(keys.DefaultKeysDir)
+	keyStore := keys.NewKeyStore(keys.DefaultKeysDir, false, logger)
 	keyClient := keys.NewLocalKeyClient(keyStore, logging.NewNoopLogger())
 	kern, err := NewKernel(context.Background(), keyClient, privValidator, genesisDoc, tmConf,
 		rpc.DefaultRPCConfig(), keys.DefaultKeysConfig(), &keyStore, nil, logger)
diff --git a/keys/config.go b/keys/config.go
index d50d61338f9934dbb9301c36ee6878142e1ac81c..c954a63e29677bb58841df48fba3b3572488ceaf 100644
--- a/keys/config.go
+++ b/keys/config.go
@@ -1,16 +1,18 @@
 package keys
 
 type KeysConfig struct {
-	GRPCServiceEnabled bool
-	RemoteAddress      string
-	KeysDirectory      string
+	GRPCServiceEnabled      bool
+	AllowBadFilePermissions bool
+	RemoteAddress           string
+	KeysDirectory           string
 }
 
 func DefaultKeysConfig() *KeysConfig {
 	return &KeysConfig{
 		// Default Monax keys port
-		GRPCServiceEnabled: true,
-		RemoteAddress:      "",
-		KeysDirectory:      DefaultKeysDir,
+		GRPCServiceEnabled:      true,
+		AllowBadFilePermissions: false,
+		RemoteAddress:           "",
+		KeysDirectory:           DefaultKeysDir,
 	}
 }
diff --git a/keys/core.go b/keys/core.go
index 8642a820b331dc99c5ea8c43f30d99210886d433..dc003b68eeb35b7596d5a0b914fe60a90e117987 100644
--- a/keys/core.go
+++ b/keys/core.go
@@ -38,12 +38,6 @@ func returnNamesDir(dir string) (string, error) {
 	return dir, checkMakeDataDir(dir)
 }
 
-//-----
-
-func NewKeyStore(dir string) KeyStore {
-	return KeyStore{keysDirPath: dir}
-}
-
 //----------------------------------------------------------------
 func writeKey(keyDir string, addr, keyJson []byte) ([]byte, error) {
 	dir, err := returnDataDir(keyDir)
diff --git a/keys/key_store.go b/keys/key_store.go
index fe6c3d54ba306ea46a3dc17ebe1141216be17df3..990c4233550ee93842a177fc4e729dd81f05e136 100644
--- a/keys/key_store.go
+++ b/keys/key_store.go
@@ -1,9 +1,362 @@
 package keys
 
 import (
+	"crypto/aes"
+	"crypto/cipher"
+	"crypto/rand"
+	"encoding/json"
+	"fmt"
+	"io/ioutil"
+	"os"
+	"path"
+	"strings"
+	"sync"
+
 	"github.com/hyperledger/burrow/crypto"
+	"github.com/hyperledger/burrow/logging"
+	"github.com/hyperledger/burrow/logging/structure"
+	"github.com/tmthrgd/go-hex"
+
+	"golang.org/x/crypto/scrypt"
 )
 
+const (
+	scryptN       = 1 << 18
+	scryptr       = 8
+	scryptp       = 1
+	scryptdkLen   = 32
+	CryptoNone    = "none"
+	CryptoAESGCM  = "scrypt-aes-gcm"
+	HashEd25519   = "go-crypto-0.5.0"
+	HashSecp256k1 = "btc"
+)
+
+//-----------------------------------------------------------------------------
+// json encodings
+
+// addresses should be hex encoded
+
+type keyJSON struct {
+	CurveType   string
+	Address     string
+	PublicKey   []byte
+	AddressHash string
+	PrivateKey  privateKeyJSON
+}
+
+type privateKeyJSON struct {
+	Crypto     string
+	Plain      []byte `json:",omitempty"`
+	Salt       []byte `json:",omitempty"`
+	Nonce      []byte `json:",omitempty"`
+	CipherText []byte `json:",omitempty"`
+}
+
+func (k *Key) MarshalJSON() (j []byte, err error) {
+	jStruct := keyJSON{
+		CurveType:   k.CurveType.String(),
+		Address:     hex.EncodeToString(k.Address[:]),
+		PublicKey:   k.Pubkey(),
+		AddressHash: k.PublicKey.AddressHashType(),
+		PrivateKey:  privateKeyJSON{Crypto: CryptoNone, Plain: k.PrivateKey.RawBytes()},
+	}
+	j, err = json.Marshal(jStruct)
+	return j, err
+}
+
+func (k *Key) UnmarshalJSON(j []byte) (err error) {
+	keyJ := new(keyJSON)
+	err = json.Unmarshal(j, &keyJ)
+	if err != nil {
+		return err
+	}
+	if len(keyJ.PrivateKey.Plain) == 0 {
+		return fmt.Errorf("no private key")
+	}
+	curveType, err := crypto.CurveTypeFromString(keyJ.CurveType)
+	if err != nil {
+		curveType = crypto.CurveTypeEd25519
+	}
+	k2, err := NewKeyFromPriv(curveType, keyJ.PrivateKey.Plain)
+	if err != nil {
+		return err
+	}
+
+	k.Address = k2.Address
+	k.CurveType = curveType
+	k.PublicKey = k2.PrivateKey.GetPublicKey()
+	k.PrivateKey = k2.PrivateKey
+
+	return nil
+}
+
+// returns the address if valid, nil otherwise
+func IsValidKeyJson(j []byte) []byte {
+	j1 := new(keyJSON)
+	e1 := json.Unmarshal(j, &j1)
+	if e1 == nil {
+		addr, _ := hex.DecodeString(j1.Address)
+		return addr
+	}
+	return nil
+}
+
+func NewKeyStore(dir string, AllowBadFilePermissions bool, logger *logging.Logger) KeyStore {
+	return KeyStore{
+		keysDirPath:             dir,
+		AllowBadFilePermissions: AllowBadFilePermissions,
+		logger:                  logger.With(structure.ComponentKey, "keys").WithScope("NewKeyStore"),
+	}
+}
+
+type KeyStore struct {
+	sync.Mutex
+	AllowBadFilePermissions bool
+	keysDirPath             string
+	logger                  *logging.Logger
+}
+
+func (ks KeyStore) Gen(passphrase string, curveType crypto.CurveType) (key *Key, err error) {
+	defer func() {
+		if r := recover(); r != nil {
+			err = fmt.Errorf("GenerateNewKey error: %v", r)
+		}
+	}()
+	key, err = NewKey(curveType)
+	if err != nil {
+		return nil, err
+	}
+	err = ks.StoreKey(passphrase, key)
+	return key, err
+}
+
+func (ks KeyStore) GetKey(passphrase string, keyAddr []byte) (*Key, error) {
+	ks.Lock()
+	defer ks.Unlock()
+	dataDirPath, err := returnDataDir(ks.keysDirPath)
+	if err != nil {
+		return nil, err
+	}
+	fileContent, err := ks.GetKeyFile(dataDirPath, keyAddr)
+	if err != nil {
+		return nil, err
+	}
+	key := new(keyJSON)
+	if err = json.Unmarshal(fileContent, key); err != nil {
+		return nil, err
+	}
+
+	if len(key.PrivateKey.CipherText) > 0 {
+		return DecryptKey(passphrase, key)
+	} else {
+		key := new(Key)
+		err = key.UnmarshalJSON(fileContent)
+		return key, err
+	}
+}
+
+func (ks KeyStore) AllKeys() ([]*Key, error) {
+
+	dataDirPath, err := returnDataDir(ks.keysDirPath)
+	if err != nil {
+		return nil, err
+	}
+	addrs, err := GetAllAddresses(dataDirPath)
+	if err != nil {
+		return nil, err
+	}
+
+	var list []*Key
+
+	for _, addr := range addrs {
+		k, err := ks.GetKey("", addr)
+		if err != nil {
+			return nil, err
+		}
+		list = append(list, k)
+	}
+
+	return list, nil
+}
+
+func DecryptKey(passphrase string, keyProtected *keyJSON) (*Key, error) {
+	salt := keyProtected.PrivateKey.Salt
+	nonce := keyProtected.PrivateKey.Nonce
+	cipherText := keyProtected.PrivateKey.CipherText
+
+	curveType, err := crypto.CurveTypeFromString(keyProtected.CurveType)
+	if err != nil {
+		return nil, err
+	}
+	authArray := []byte(passphrase)
+	derivedKey, err := scrypt.Key(authArray, salt, scryptN, scryptr, scryptp, scryptdkLen)
+	if err != nil {
+		return nil, err
+	}
+	aesBlock, err := aes.NewCipher(derivedKey)
+	if err != nil {
+		return nil, err
+	}
+	gcm, err := cipher.NewGCM(aesBlock)
+	if err != nil {
+		return nil, err
+	}
+	plainText, err := gcm.Open(nil, nonce, cipherText, nil)
+	if err != nil {
+		pkey, _ := NewKeyFromPub(curveType, keyProtected.PublicKey)
+		return pkey, err
+	}
+	address, err := crypto.AddressFromHexString(keyProtected.Address)
+	if err != nil {
+		return nil, err
+	}
+	k, err := NewKeyFromPriv(curveType, plainText)
+	if err != nil {
+		return nil, err
+	}
+	if address != k.Address {
+		return nil, fmt.Errorf("address does not match")
+	}
+	return k, nil
+}
+
+func (ks KeyStore) GetAllAddresses() (addresses [][]byte, err error) {
+	ks.Lock()
+	defer ks.Unlock()
+	return GetAllAddresses(ks.keysDirPath)
+}
+
+func (ks KeyStore) StoreKey(passphrase string, key *Key) error {
+	ks.Lock()
+	defer ks.Unlock()
+	if passphrase != "" {
+		return ks.StoreKeyEncrypted(passphrase, key)
+	} else {
+		return ks.StoreKeyPlain(key)
+	}
+}
+
+func (ks KeyStore) StoreKeyPlain(key *Key) (err error) {
+	keyJSON, err := json.Marshal(key)
+	if err != nil {
+		return err
+	}
+	dataDirPath, err := returnDataDir(ks.keysDirPath)
+	if err != nil {
+		return err
+	}
+	err = WriteKeyFile(key.Address[:], dataDirPath, keyJSON)
+	return err
+}
+
+func (ks KeyStore) StoreKeyEncrypted(passphrase string, key *Key) error {
+	authArray := []byte(passphrase)
+	salt := make([]byte, 32)
+	_, err := rand.Read(salt)
+	if err != nil {
+		return err
+	}
+
+	derivedKey, err := scrypt.Key(authArray, salt, scryptN, scryptr, scryptp, scryptdkLen)
+	if err != nil {
+		return err
+	}
+
+	toEncrypt := key.PrivateKey.RawBytes()
+
+	AES256Block, err := aes.NewCipher(derivedKey)
+	if err != nil {
+		return err
+	}
+
+	gcm, err := cipher.NewGCM(AES256Block)
+	if err != nil {
+		return err
+	}
+
+	// XXX: a GCM nonce may only be used once per key ever!
+	nonce := make([]byte, gcm.NonceSize())
+	_, err = rand.Read(nonce)
+	if err != nil {
+		return err
+	}
+
+	// (dst, nonce, plaintext, extradata)
+	cipherText := gcm.Seal(nil, nonce, toEncrypt, nil)
+
+	cipherStruct := privateKeyJSON{
+		Crypto: CryptoAESGCM, Salt: salt, Nonce: nonce, CipherText: cipherText,
+	}
+	keyStruct := keyJSON{
+		CurveType:   key.CurveType.String(),
+		Address:     strings.ToUpper(hex.EncodeToString(key.Address[:])),
+		PublicKey:   key.Pubkey(),
+		AddressHash: key.PublicKey.AddressHashType(),
+		PrivateKey:  cipherStruct,
+	}
+	keyJSON, err := json.Marshal(keyStruct)
+	if err != nil {
+		return err
+	}
+	dataDirPath, err := returnDataDir(ks.keysDirPath)
+	if err != nil {
+		return err
+	}
+
+	return WriteKeyFile(key.Address[:], dataDirPath, keyJSON)
+}
+
+func (ks KeyStore) DeleteKey(passphrase string, keyAddr []byte) (err error) {
+	dataDirPath, err := returnDataDir(ks.keysDirPath)
+	if err != nil {
+		return err
+	}
+	keyDirPath := path.Join(dataDirPath, strings.ToUpper(hex.EncodeToString(keyAddr))+".json")
+	return os.Remove(keyDirPath)
+}
+
+func (ks *KeyStore) GetKeyFile(dataDirPath string, keyAddr []byte) (fileContent []byte, err error) {
+	filename := path.Join(dataDirPath, strings.ToUpper(hex.EncodeToString(keyAddr))+".json")
+	fileInfo, err := os.Stat(filename)
+	if err != nil {
+		return nil, err
+	}
+	if (uint32(fileInfo.Mode()) & 0077) != 0 {
+		ks.logger.InfoMsg("file should be accessible by user only", filename)
+		if !ks.AllowBadFilePermissions {
+			return nil, fmt.Errorf("file %s should be accessible by user only", filename)
+		}
+	}
+	return ioutil.ReadFile(filename)
+}
+
+func WriteKeyFile(addr []byte, dataDirPath string, content []byte) (err error) {
+	addrHex := strings.ToUpper(hex.EncodeToString(addr))
+	keyFilePath := path.Join(dataDirPath, addrHex+".json")
+	err = os.MkdirAll(dataDirPath, 0700) // read, write and dir search for user
+	if err != nil {
+		return err
+	}
+	return ioutil.WriteFile(keyFilePath, content, 0600) // read, write for user
+}
+
+func GetAllAddresses(dataDirPath string) (addresses [][]byte, err error) {
+	fileInfos, err := ioutil.ReadDir(dataDirPath)
+	if err != nil {
+		return nil, err
+	}
+	addresses = make([][]byte, len(fileInfos))
+	for i, fileInfo := range fileInfos {
+		addr := strings.TrimSuffix(fileInfo.Name(), "json")
+		address, err := hex.DecodeString(addr)
+		if err != nil {
+			continue
+		}
+		addresses[i] = address
+	}
+	return addresses, err
+}
+
 type Key struct {
 	CurveType  crypto.CurveType
 	Address    crypto.Address
diff --git a/keys/key_store_file.go b/keys/key_store_file.go
deleted file mode 100644
index 25c2f56728c7c436250bda1837c5b90c81874180..0000000000000000000000000000000000000000
--- a/keys/key_store_file.go
+++ /dev/null
@@ -1,336 +0,0 @@
-package keys
-
-import (
-	"crypto/aes"
-	"crypto/cipher"
-	"crypto/rand"
-	"encoding/json"
-	"fmt"
-	"io/ioutil"
-	"os"
-	"path"
-	"strings"
-	"sync"
-
-	"github.com/hyperledger/burrow/crypto"
-	"github.com/tmthrgd/go-hex"
-
-	"golang.org/x/crypto/scrypt"
-)
-
-const (
-	scryptN       = 1 << 18
-	scryptr       = 8
-	scryptp       = 1
-	scryptdkLen   = 32
-	CryptoNone    = "none"
-	CryptoAESGCM  = "scrypt-aes-gcm"
-	HashEd25519   = "go-crypto-0.5.0"
-	HashSecp256k1 = "btc"
-)
-
-//-----------------------------------------------------------------------------
-// json encodings
-
-// addresses should be hex encoded
-
-type keyJSON struct {
-	CurveType   string
-	Address     string
-	PublicKey   []byte
-	AddressHash string
-	PrivateKey  privateKeyJSON
-}
-
-type privateKeyJSON struct {
-	Crypto     string
-	Plain      []byte `json:",omitempty"`
-	Salt       []byte `json:",omitempty"`
-	Nonce      []byte `json:",omitempty"`
-	CipherText []byte `json:",omitempty"`
-}
-
-func (k *Key) MarshalJSON() (j []byte, err error) {
-	jStruct := keyJSON{
-		CurveType:   k.CurveType.String(),
-		Address:     hex.EncodeToString(k.Address[:]),
-		PublicKey:   k.Pubkey(),
-		AddressHash: k.PublicKey.AddressHashType(),
-		PrivateKey:  privateKeyJSON{Crypto: CryptoNone, Plain: k.PrivateKey.RawBytes()},
-	}
-	j, err = json.Marshal(jStruct)
-	return j, err
-}
-
-func (k *Key) UnmarshalJSON(j []byte) (err error) {
-	keyJ := new(keyJSON)
-	err = json.Unmarshal(j, &keyJ)
-	if err != nil {
-		return err
-	}
-	if len(keyJ.PrivateKey.Plain) == 0 {
-		return fmt.Errorf("no private key")
-	}
-	curveType, err := crypto.CurveTypeFromString(keyJ.CurveType)
-	if err != nil {
-		curveType = crypto.CurveTypeEd25519
-	}
-	k2, err := NewKeyFromPriv(curveType, keyJ.PrivateKey.Plain)
-	if err != nil {
-		return err
-	}
-
-	k.Address = k2.Address
-	k.CurveType = curveType
-	k.PublicKey = k2.PrivateKey.GetPublicKey()
-	k.PrivateKey = k2.PrivateKey
-
-	return nil
-}
-
-// returns the address if valid, nil otherwise
-func IsValidKeyJson(j []byte) []byte {
-	j1 := new(keyJSON)
-	e1 := json.Unmarshal(j, &j1)
-	if e1 == nil {
-		addr, _ := hex.DecodeString(j1.Address)
-		return addr
-	}
-	return nil
-}
-
-type KeyStore struct {
-	sync.Mutex
-	keysDirPath string
-}
-
-func (ks KeyStore) Gen(passphrase string, curveType crypto.CurveType) (key *Key, err error) {
-	defer func() {
-		if r := recover(); r != nil {
-			err = fmt.Errorf("GenerateNewKey error: %v", r)
-		}
-	}()
-	key, err = NewKey(curveType)
-	if err != nil {
-		return nil, err
-	}
-	err = ks.StoreKey(passphrase, key)
-	return key, err
-}
-
-func (ks KeyStore) GetKey(passphrase string, keyAddr []byte) (*Key, error) {
-	ks.Lock()
-	defer ks.Unlock()
-	dataDirPath, err := returnDataDir(ks.keysDirPath)
-	if err != nil {
-		return nil, err
-	}
-	fileContent, err := GetKeyFile(dataDirPath, keyAddr)
-	if err != nil {
-		return nil, err
-	}
-	key := new(keyJSON)
-	if err = json.Unmarshal(fileContent, key); err != nil {
-		return nil, err
-	}
-
-	if len(key.PrivateKey.CipherText) > 0 {
-		return DecryptKey(passphrase, key)
-	} else {
-		key := new(Key)
-		err = key.UnmarshalJSON(fileContent)
-		return key, err
-	}
-}
-
-func (ks KeyStore) AllKeys() ([]*Key, error) {
-
-	dataDirPath, err := returnDataDir(ks.keysDirPath)
-	if err != nil {
-		return nil, err
-	}
-	addrs, err := GetAllAddresses(dataDirPath)
-	if err != nil {
-		return nil, err
-	}
-
-	var list []*Key
-
-	for _, addr := range addrs {
-		k, err := ks.GetKey("", addr)
-		if err != nil {
-			return nil, err
-		}
-		list = append(list, k)
-	}
-
-	return list, nil
-}
-
-func DecryptKey(passphrase string, keyProtected *keyJSON) (*Key, error) {
-	salt := keyProtected.PrivateKey.Salt
-	nonce := keyProtected.PrivateKey.Nonce
-	cipherText := keyProtected.PrivateKey.CipherText
-
-	curveType, err := crypto.CurveTypeFromString(keyProtected.CurveType)
-	if err != nil {
-		return nil, err
-	}
-	authArray := []byte(passphrase)
-	derivedKey, err := scrypt.Key(authArray, salt, scryptN, scryptr, scryptp, scryptdkLen)
-	if err != nil {
-		return nil, err
-	}
-	aesBlock, err := aes.NewCipher(derivedKey)
-	if err != nil {
-		return nil, err
-	}
-	gcm, err := cipher.NewGCM(aesBlock)
-	if err != nil {
-		return nil, err
-	}
-	plainText, err := gcm.Open(nil, nonce, cipherText, nil)
-	if err != nil {
-		pkey, _ := NewKeyFromPub(curveType, keyProtected.PublicKey)
-		return pkey, err
-	}
-	address, err := crypto.AddressFromHexString(keyProtected.Address)
-	if err != nil {
-		return nil, err
-	}
-	k, err := NewKeyFromPriv(curveType, plainText)
-	if err != nil {
-		return nil, err
-	}
-	if address != k.Address {
-		return nil, fmt.Errorf("address does not match")
-	}
-	return k, nil
-}
-
-func (ks KeyStore) GetAllAddresses() (addresses [][]byte, err error) {
-	ks.Lock()
-	defer ks.Unlock()
-	return GetAllAddresses(ks.keysDirPath)
-}
-
-func (ks KeyStore) StoreKey(passphrase string, key *Key) error {
-	ks.Lock()
-	defer ks.Unlock()
-	if passphrase != "" {
-		return ks.StoreKeyEncrypted(passphrase, key)
-	} else {
-		return ks.StoreKeyPlain(key)
-	}
-}
-
-func (ks KeyStore) StoreKeyPlain(key *Key) (err error) {
-	keyJSON, err := json.Marshal(key)
-	if err != nil {
-		return err
-	}
-	dataDirPath, err := returnDataDir(ks.keysDirPath)
-	if err != nil {
-		return err
-	}
-	err = WriteKeyFile(key.Address[:], dataDirPath, keyJSON)
-	return err
-}
-
-func (ks KeyStore) StoreKeyEncrypted(passphrase string, key *Key) error {
-	authArray := []byte(passphrase)
-	salt := make([]byte, 32)
-	_, err := rand.Read(salt)
-	if err != nil {
-		return err
-	}
-
-	derivedKey, err := scrypt.Key(authArray, salt, scryptN, scryptr, scryptp, scryptdkLen)
-	if err != nil {
-		return err
-	}
-
-	toEncrypt := key.PrivateKey.RawBytes()
-
-	AES256Block, err := aes.NewCipher(derivedKey)
-	if err != nil {
-		return err
-	}
-
-	gcm, err := cipher.NewGCM(AES256Block)
-	if err != nil {
-		return err
-	}
-
-	// XXX: a GCM nonce may only be used once per key ever!
-	nonce := make([]byte, gcm.NonceSize())
-	_, err = rand.Read(nonce)
-	if err != nil {
-		return err
-	}
-
-	// (dst, nonce, plaintext, extradata)
-	cipherText := gcm.Seal(nil, nonce, toEncrypt, nil)
-
-	cipherStruct := privateKeyJSON{
-		Crypto: CryptoAESGCM, Salt: salt, Nonce: nonce, CipherText: cipherText,
-	}
-	keyStruct := keyJSON{
-		CurveType:   key.CurveType.String(),
-		Address:     strings.ToUpper(hex.EncodeToString(key.Address[:])),
-		PublicKey:   key.Pubkey(),
-		AddressHash: key.PublicKey.AddressHashType(),
-		PrivateKey:  cipherStruct,
-	}
-	keyJSON, err := json.Marshal(keyStruct)
-	if err != nil {
-		return err
-	}
-	dataDirPath, err := returnDataDir(ks.keysDirPath)
-	if err != nil {
-		return err
-	}
-
-	return WriteKeyFile(key.Address[:], dataDirPath, keyJSON)
-}
-
-func (ks KeyStore) DeleteKey(passphrase string, keyAddr []byte) (err error) {
-	dataDirPath, err := returnDataDir(ks.keysDirPath)
-	if err != nil {
-		return err
-	}
-	keyDirPath := path.Join(dataDirPath, strings.ToUpper(hex.EncodeToString(keyAddr))+".json")
-	return os.Remove(keyDirPath)
-}
-
-func GetKeyFile(dataDirPath string, keyAddr []byte) (fileContent []byte, err error) {
-	fileName := strings.ToUpper(hex.EncodeToString(keyAddr))
-	return ioutil.ReadFile(path.Join(dataDirPath, fileName+".json"))
-}
-
-func WriteKeyFile(addr []byte, dataDirPath string, content []byte) (err error) {
-	addrHex := strings.ToUpper(hex.EncodeToString(addr))
-	keyFilePath := path.Join(dataDirPath, addrHex+".json")
-	err = os.MkdirAll(dataDirPath, 0700) // read, write and dir search for user
-	if err != nil {
-		return err
-	}
-	return ioutil.WriteFile(keyFilePath, content, 0600) // read, write for user
-}
-
-func GetAllAddresses(dataDirPath string) (addresses [][]byte, err error) {
-	fileInfos, err := ioutil.ReadDir(dataDirPath)
-	if err != nil {
-		return nil, err
-	}
-	addresses = make([][]byte, len(fileInfos))
-	for i, fileInfo := range fileInfos {
-		addr := strings.TrimSuffix(fileInfo.Name(), "json")
-		address, err := hex.DecodeString(addr)
-		if err != nil {
-			continue
-		}
-		addresses[i] = address
-	}
-	return addresses, err
-}
diff --git a/keys/server.go b/keys/server.go
index 3ffa0e4375084c987baf075fea31fdc00dc5e8f5..563bf5b5fa837bbe7c59e20abb94c473a036e509 100644
--- a/keys/server.go
+++ b/keys/server.go
@@ -10,6 +10,7 @@ import (
 
 	"github.com/hyperledger/burrow/crypto"
 	"github.com/hyperledger/burrow/keys/pbkeys"
+	"github.com/hyperledger/burrow/logging"
 	"github.com/tmthrgd/go-hex"
 	"golang.org/x/crypto/ripemd160"
 	"google.golang.org/grpc"
@@ -19,13 +20,13 @@ import (
 // all cli commands pass through the http KeyStore
 // the KeyStore process also maintains the unlocked accounts
 
-func StartStandAloneServer(keysDir, host, port string) error {
+func StartStandAloneServer(keysDir, host, port string, AllowBadFilePermissions bool, logger *logging.Logger) error {
 	listen, err := net.Listen("tcp", host+":"+port)
 	if err != nil {
 		return err
 	}
 
-	ks := NewKeyStore(keysDir)
+	ks := NewKeyStore(keysDir, AllowBadFilePermissions, logger)
 
 	grpcServer := grpc.NewServer()
 	pbkeys.RegisterKeysServer(grpcServer, &ks)
diff --git a/keys/server_test.go b/keys/server_test.go
index 614daaecb6f9eba0950acc29d9b1d43feef7f72a..5ee1e204f571b3d61781b0ca73ef4b6aaf126761 100644
--- a/keys/server_test.go
+++ b/keys/server_test.go
@@ -14,6 +14,7 @@ import (
 	"github.com/hyperledger/burrow/crypto"
 	"github.com/hyperledger/burrow/execution/evm/sha3"
 	"github.com/hyperledger/burrow/keys/pbkeys"
+	"github.com/hyperledger/burrow/logging"
 	tm_crypto "github.com/tendermint/go-crypto"
 	"google.golang.org/grpc"
 )
@@ -36,8 +37,10 @@ var (
 // start the server
 func init() {
 	failedCh := make(chan error)
+	testDir := "test_scratch/" + DefaultKeysDir
+	os.RemoveAll(testDir)
 	go func() {
-		err := StartStandAloneServer(DefaultKeysDir, DefaultHost, TestPort)
+		err := StartStandAloneServer(testDir, DefaultHost, TestPort, false, logging.NewNoopLogger())
 		failedCh <- err
 	}()
 	tick := time.NewTicker(time.Second)
diff --git a/keys/test.sh b/keys/test.sh
index 7bb16ed18f12b9ee425fdc03a178aaa4d91fb7cb..768242531c70fe9ef26c925655cd9eeb71211767 100755
--- a/keys/test.sh
+++ b/keys/test.sh
@@ -8,9 +8,11 @@
 
 burrow_bin=${burrow_bin:-burrow}
 
+keys_dir=./keys/test_scratch/.keys
+
 echo "-----------------------------"
 echo "starting the server"
-$burrow_bin keys server &
+$burrow_bin keys server --dir $keys_dir &
 keys_pid=$!
 sleep 1
 echo "-----------------------------"
@@ -88,7 +90,7 @@ do
 	echo "... $CURVETYPE"
 	# create a key, get its address and priv, backup the json, delete the key
 	ADDR=`$burrow_bin keys gen --curvetype $CURVETYPE --no-password`
-	DIR=.keys/data
+	DIR=$keys_dir/data
 	FILE=$DIR/$ADDR.json
 	PRIV=`cat $FILE |  jq -r .PrivateKey.Plain`
 	HEXPRIV=`echo -n "$PRIV" | base64 -d | xxd -p -u -c 256`