func (store *KeyStore) GetPoisonKeyPair() (*keys.Keypair, error) {
	privatePath := store.GetPrivateKeyFilePath(PoisonKeyFilename)
	publicPath := store.GetPublicKeyFilePath(poisonKeyFilenamePublic)
	privateExists, err := store.fs.Exists(privatePath)
	if err != nil {
		return nil, err
	}
	publicExists, err := store.fs.Exists(publicPath)
	if err != nil {
		return nil, err
	}
	if privateExists && publicExists {
		private, err := store.loadPrivateKey(privatePath)
		if err != nil {
			return nil, err
		}
		if private.Value, err = store.encryptor.Decrypt(private.Value, []byte(PoisonKeyFilename)); err != nil {
			return nil, err
		}
		public, err := store.loadPublicKey(publicPath)
		if err != nil {
			return nil, err
		}
		return &keys.Keypair{Public: public, Private: private}, nil
	}
	log.Debug("Generate poison key pair")
	return store.generateKeyPair(PoisonKeyFilename, []byte(PoisonKeyFilename))
}
GetPoisonKeyPair generates EC keypair for encrypting/decrypting poison records, and writes it to fs
encrypting private key or reads existing keypair from fs.
Returns keypair or error if generation/decryption failed.
package filesystem
import (
	"crypto/rand"
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"runtime"
	"sync"
	"github.com/cossacklabs/acra/keystore"
	"github.com/cossacklabs/acra/keystore/lru"
	"github.com/cossacklabs/acra/utils"
	"github.com/cossacklabs/acra/zone"
	"github.com/cossacklabs/themis/gothemis/keys"
	log "github.com/sirupsen/logrus"
)
const PrivateFileMode = os.FileMode(0600)
const publicFileMode = os.FileMode(0644)
const keyDirMode = os.FileMode(0700)
type KeyStore struct {
	cache               keystore.Cache
	privateKeyDirectory string
	publicKeyDirectory  string
	fs                  Storage
	lock                *sync.RWMutex
	encryptor           keystore.KeyEncryptor
}
func NewFileSystemKeyStoreWithCacheSize(directory string, encryptor keystore.KeyEncryptor, cacheSize int) (*KeyStore, error) {
	return NewCustomFilesystemKeyStore().KeyDirectory(directory).Encryptor(encryptor).CacheSize(cacheSize).Build()
}
func NewFilesystemKeyStore(directory string, encryptor keystore.KeyEncryptor) (*KeyStore, error) {
	return NewCustomFilesystemKeyStore().KeyDirectory(directory).Encryptor(encryptor).Build()
}
func NewFilesystemKeyStoreTwoPath(privateKeyFolder, publicKeyFolder string, encryptor keystore.KeyEncryptor) (*KeyStore, error) {
	return NewCustomFilesystemKeyStore().KeyDirectories(privateKeyFolder, publicKeyFolder).Encryptor(encryptor).Build()
}
type KeyStoreBuilder struct {
	privateKeyDir string
	publicKeyDir  string
	encryptor     keystore.KeyEncryptor
	storage       Storage
	cacheSize     int
}
func NewCustomFilesystemKeyStore() *KeyStoreBuilder {
	return &KeyStoreBuilder{
		storage:   &fileStorage{},
		cacheSize: keystore.InfiniteCacheSize,
	}
}
func (b *KeyStoreBuilder) KeyDirectory(directory string) *KeyStoreBuilder {
	b.privateKeyDir = directory
	b.publicKeyDir = directory
	return b
}
func (b *KeyStoreBuilder) KeyDirectories(privateKeyDir, publicKeyDir string) *KeyStoreBuilder {
	b.privateKeyDir = privateKeyDir
	b.publicKeyDir = publicKeyDir
	return b
}
func (b *KeyStoreBuilder) Encryptor(encryptor keystore.KeyEncryptor) *KeyStoreBuilder {
	b.encryptor = encryptor
	return b
}
func (b *KeyStoreBuilder) Storage(storage Storage) *KeyStoreBuilder {
	b.storage = storage
	return b
}
func (b *KeyStoreBuilder) CacheSize(cacheSize int) *KeyStoreBuilder {
	b.cacheSize = cacheSize
	return b
}
var (
	errNoPrivateKeyDir = errors.New("private key directory not specified")
	errNoPublicKeyDir  = errors.New("public key directory not specified")
	errNoEncryptor     = errors.New("encryptor not specified")
)
func (b *KeyStoreBuilder) Build() (*KeyStore, error) {
	if b.privateKeyDir == "" {
		return nil, errNoPrivateKeyDir
	}
	if b.publicKeyDir == "" {
		return nil, errNoPublicKeyDir
	}
	if b.encryptor == nil {
		return nil, errNoEncryptor
	}
	return newFilesystemKeyStore(b.privateKeyDir, b.publicKeyDir, b.storage, b.encryptor, b.cacheSize)
}
func IsKeyDirectory(keyDirectory string) bool {
	fi, err := os.Stat(keyDirectory)
	if err != nil {
		log.WithError(err).WithField("path", keyDirectory).Debug("Failed to stat a key directory")
		return false
	}
	if !fi.IsDir() {
		log.WithField("path", keyDirectory).Debug("Not a key directory")
		return false
	}
	files, err := ioutil.ReadDir(keyDirectory)
	if err != nil {
		log.WithError(err).WithField("path", keyDirectory).Debug("Failed to read key directory")
		return false
	}
	if len(files) == 0 {
		log.WithField("path", keyDirectory).Debug("Key directory is empty")
		return false
	}
	return true
}
func newFilesystemKeyStore(privateKeyFolder, publicKeyFolder string, storage Storage, encryptor keystore.KeyEncryptor, cacheSize int) (*KeyStore, error) {
	fi, err := storage.Stat(privateKeyFolder)
	if err != nil && !os.IsNotExist(err) {
		return nil, err
	}
	if !os.IsNotExist(err) {
		const expectedPermission = "-rwx------"
		if runtime.GOOS == "linux" && fi.Mode().Perm().String() != expectedPermission {
			log.Errorf("Keystore folder has an incorrect permissions %s, expected: %s", fi.Mode().Perm().String(), expectedPermission)
			return nil, errors.New("keystore folder has an incorrect permissions")
		}
	}
	_, err = storage.Stat(publicKeyFolder)
	if err != nil && !os.IsNotExist(err) {
		return nil, err
	}
	var cache keystore.Cache
	if cacheSize == keystore.WithoutCache {
		cache = keystore.NoCache{}
	} else {
		cache, err = lru.NewCacheKeystoreWrapper(cacheSize)
		if err != nil {
			return nil, err
		}
	}
	store := &KeyStore{privateKeyDirectory: privateKeyFolder, publicKeyDirectory: publicKeyFolder,
		cache: cache, lock: &sync.RWMutex{}, encryptor: encryptor, fs: storage}
	return store, nil
}
func (store *KeyStore) generateKeyPair(filename string, clientID []byte) (*keys.Keypair, error) {
	keypair, err := keys.New(keys.TypeEC)
	if err != nil {
		return nil, err
	}
	if err := store.SaveKeyPairWithFilename(keypair, filename, clientID); err != nil {
		return nil, err
	}
	return keypair, nil
}
func (store *KeyStore) SaveKeyPairWithFilename(keypair *keys.Keypair, filename string, id []byte) error {
	privateKeysFolder := filepath.Dir(store.GetPrivateKeyFilePath(filename))
	err := store.fs.MkdirAll(privateKeysFolder, keyDirMode)
	if err != nil {
		return err
	}
	publicKeysFolder := filepath.Dir(store.GetPublicKeyFilePath(filename))
	err = store.fs.MkdirAll(publicKeysFolder, keyDirMode)
	if err != nil {
		return err
	}
	encryptedPrivate, err := store.encryptor.Encrypt(keypair.Private.Value, id)
	if err != nil {
		return err
	}
	err = store.WritePrivateKey(store.GetPrivateKeyFilePath(filename), encryptedPrivate)
	if err != nil {
		return err
	}
	err = store.WritePublicKey(store.GetPublicKeyFilePath(fmt.Sprintf("%s.pub", filename)), keypair.Public.Value)
	if err != nil {
		return err
	}
	store.cache.Add(filename, encryptedPrivate)
	return nil
}
func (store *KeyStore) generateKey(filename string, length uint8) ([]byte, error) {
	randomBytes := make([]byte, length)
	_, err := rand.Read(randomBytes)
	if err != nil {
		log.Error(err)
		return nil, err
	}
	dirpath := filepath.Dir(store.GetPrivateKeyFilePath(filename))
	err = store.fs.MkdirAll(dirpath, keyDirMode)
	if err != nil {
		log.Error(err)
		return nil, err
	}
	err = store.WritePrivateKey(store.GetPrivateKeyFilePath(filename), randomBytes)
	if err != nil {
		log.Error(err)
		return nil, err
	}
	return randomBytes, nil
}
func (store *KeyStore) WritePrivateKey(filename string, data []byte) error {
	return store.WriteKeyFile(filename, data, PrivateFileMode)
}
func (store *KeyStore) WritePublicKey(filename string, data []byte) error {
	return store.WriteKeyFile(filename, data, publicFileMode)
}
func (store *KeyStore) ReadKeyFile(filename string) ([]byte, error) {
	return store.fs.ReadFile(filename)
}
func (store *KeyStore) WriteKeyFile(filename string, data []byte, mode os.FileMode) error {
	tmpFilename, err := store.fs.TempFile(filename, mode)
	if err != nil {
		return err
	}
	err = store.fs.WriteFile(tmpFilename, data, mode)
	if err != nil {
		return err
	}
	err = store.backupHistoricalKeyFile(filename)
	if err != nil {
		return err
	}
	err = store.fs.Rename(tmpFilename, filename)
	if err != nil {
		return err
	}
	return nil
}
func (store *KeyStore) backupHistoricalKeyFile(filename string) error {
	_, err := store.fs.Stat(filename)
	if os.IsNotExist(err) {
		return nil
	}
	err = store.fs.MkdirAll(getHistoryDirName(filename), keyDirMode)
	if err != nil {
		return err
	}
	backupName := getNewHistoricalFileName(filename)
	err = store.fs.Link(filename, backupName)
	if err == nil {
		return nil
	}
	return store.fs.Copy(filename, backupName)
}
func (store *KeyStore) generateZoneKey(id []byte) ([]byte, []byte, error) {
	keypair, err := store.generateKeyPair(GetZoneKeyFilename(id), id)
	if err != nil {
		return []byte{}, []byte{}, err
	}
	store.lock.Lock()
	defer store.lock.Unlock()
	encryptedKey, err := store.encryptor.Encrypt(keypair.Private.Value, id)
	if err != nil {
		return nil, nil, nil
	}
	utils.ZeroizePrivateKey(keypair.Private)
	store.cache.Add(GetZoneKeyFilename(id), encryptedKey)
	return id, keypair.Public.Value, nil
}
func (store *KeyStore) GenerateZoneKey() ([]byte, []byte, error) {
	var id []byte
	for {
		id = zone.GenerateZoneID()
		if !store.HasZonePrivateKey(id) {
			break
		}
	}
	return store.generateZoneKey(id)
}
func (store *KeyStore) GetPrivateKeyFilePath(filename string) string {
	return fmt.Sprintf("%s%s%s", store.privateKeyDirectory, string(os.PathSeparator), filename)
}
func (store *KeyStore) GetPublicKeyFilePath(filename string) string {
	return fmt.Sprintf("%s%s%s", store.publicKeyDirectory, string(os.PathSeparator), filename)
}
func (store *KeyStore) GetHistoricalPrivateKeyFilenames(filename string) ([]string, error) {
	fullPath := filepath.Join(store.privateKeyDirectory, filename)
	paths, err := getHistoricalFilePaths(fullPath, store.fs)
	if err != nil {
		return nil, err
	}
	for i, path := range paths {
		p, err := filepath.Rel(store.privateKeyDirectory, path)
		if err != nil {
			return nil, err
		}
		paths[i] = p
	}
	return paths, nil
}
func (store *KeyStore) loadPrivateKey(path string) (*keys.PrivateKey, error) {
	fi, err := store.fs.Stat(path)
	if err != nil {
		return nil, err
	}
	if runtime.GOOS == "linux" && fi.Mode().Perm() > PrivateFileMode {
		log.Errorf("Private key file %v has incorrect permissions %s, expected: %s", path, fi.Mode().Perm().String(), PrivateFileMode.String())
		return nil, fmt.Errorf("private key file %v has incorrect permissions", path)
	}
	key, err := store.fs.ReadFile(path)
	if err != nil {
		return nil, err
	}
	return &keys.PrivateKey{Value: key}, nil
}
func (store *KeyStore) loadPublicKey(path string) (*keys.PublicKey, error) {
	key, err := store.fs.ReadFile(path)
	if err != nil {
		return nil, err
	}
	return &keys.PublicKey{Value: key}, nil
}
func (store *KeyStore) getPrivateKeyByFilename(id []byte, filename string) (*keys.PrivateKey, error) {
	store.lock.Lock()
	defer store.lock.Unlock()
	encryptedKey, ok := store.cache.Get(filename)
	if !ok {
		encryptedPrivateKey, err := store.loadPrivateKey(store.GetPrivateKeyFilePath(filename))
		if err != nil {
			return nil, err
		}
		encryptedKey = encryptedPrivateKey.Value
	}
	decryptedKey, err := store.encryptor.Decrypt(encryptedKey, id)
	if err != nil {
		return nil, err
	}
	log.Debugf("Load key from fs: %s", filename)
	store.cache.Add(filename, encryptedKey)
	return &keys.PrivateKey{Value: decryptedKey}, nil
}
func (store *KeyStore) getPrivateKeysByFilenames(id []byte, filenames []string) ([]*keys.PrivateKey, error) {
	privateKeys := make([]*keys.PrivateKey, len(filenames))
	for i, name := range filenames {
		key, err := store.getPrivateKeyByFilename(id, name)
		if err != nil {
			utils.ZeroizePrivateKeys(privateKeys)
			return nil, err
		}
		privateKeys[i] = key
	}
	return privateKeys, nil
}
func (store *KeyStore) getPublicKeyByFilename(filename string) (*keys.PublicKey, error) {
	binKey, ok := store.cache.Get(filename)
	if !ok {
		publicKey, err := store.loadPublicKey(filename)
		if err != nil {
			return nil, err
		}
		store.cache.Add(filename, publicKey.Value)
		return publicKey, nil
	}
	return &keys.PublicKey{Value: binKey}, nil
}
func (store *KeyStore) GetZonePublicKey(zoneID []byte) (*keys.PublicKey, error) {
	fname := store.GetPublicKeyFilePath(getZonePublicKeyFilename(zoneID))
	return store.getPublicKeyByFilename(fname)
}
func (store *KeyStore) GetClientIDEncryptionPublicKey(clientID []byte) (*keys.PublicKey, error) {
	fname := store.GetPublicKeyFilePath(
		getPublicKeyFilename(
			[]byte(GetServerDecryptionKeyFilename(clientID))))
	return store.getPublicKeyByFilename(fname)
}
func (store *KeyStore) GetZonePrivateKey(id []byte) (*keys.PrivateKey, error) {
	fname := GetZoneKeyFilename(id)
	return store.getPrivateKeyByFilename(id, fname)
}
func (store *KeyStore) HasZonePrivateKey(id []byte) bool {
	if !keystore.ValidateID(id) {
		return false
	}
	if len(id) == 0 {
		return false
	}
	fname := GetZoneKeyFilename(id)
	store.lock.RLock()
	defer store.lock.RUnlock()
	_, ok := store.cache.Get(fname)
	if ok {
		return true
	}
	exists, _ := store.fs.Exists(store.GetPrivateKeyFilePath(fname))
	return exists
}
func (store *KeyStore) GetZonePrivateKeys(id []byte) ([]*keys.PrivateKey, error) {
	filenames, err := store.GetHistoricalPrivateKeyFilenames(GetZoneKeyFilename(id))
	if err != nil {
		return nil, err
	}
	return store.getPrivateKeysByFilenames(id, filenames)
}
func (store *KeyStore) GetPeerPublicKey(id []byte) (*keys.PublicKey, error) {
	if !keystore.ValidateID(id) {
		return nil, keystore.ErrInvalidClientID
	}
	fname := getPublicKeyFilename(id)
	store.lock.Lock()
	defer store.lock.Unlock()
	key, ok := store.cache.Get(fname)
	if ok {
		log.Debugf("Load cached key: %s", fname)
		return &keys.PublicKey{Value: key}, nil
	}
	publicKey, err := store.loadPublicKey(store.GetPublicKeyFilePath(fname))
	if err != nil {
		return nil, err
	}
	log.Debugf("Load key from fs: %s", fname)
	store.cache.Add(fname, publicKey.Value)
	return publicKey, nil
}
func (store *KeyStore) GetPrivateKey(id []byte) (*keys.PrivateKey, error) {
	fname := getServerKeyFilename(id)
	return store.getPrivateKeyByFilename(id, fname)
}
func (store *KeyStore) GetServerDecryptionPrivateKey(id []byte) (*keys.PrivateKey, error) {
	fname := GetServerDecryptionKeyFilename(id)
	return store.getPrivateKeyByFilename(id, fname)
}
func (store *KeyStore) GetServerDecryptionPrivateKeys(id []byte) ([]*keys.PrivateKey, error) {
	filenames, err := store.GetHistoricalPrivateKeyFilenames(GetServerDecryptionKeyFilename(id))
	if err != nil {
		return nil, err
	}
	return store.getPrivateKeysByFilenames(id, filenames)
}
func (store *KeyStore) GenerateConnectorKeys(id []byte) error {
	if !keystore.ValidateID(id) {
		return keystore.ErrInvalidClientID
	}
	filename := getConnectorKeyFilename(id)
	_, err := store.generateKeyPair(filename, id)
	if err != nil {
		return err
	}
	return nil
}
func (store *KeyStore) GenerateServerKeys(id []byte) error {
	if !keystore.ValidateID(id) {
		return keystore.ErrInvalidClientID
	}
	filename := getServerKeyFilename(id)
	_, err := store.generateKeyPair(filename, id)
	if err != nil {
		return err
	}
	return nil
}
func (store *KeyStore) GenerateTranslatorKeys(id []byte) error {
	if !keystore.ValidateID(id) {
		return keystore.ErrInvalidClientID
	}
	filename := getTranslatorKeyFilename(id)
	_, err := store.generateKeyPair(filename, id)
	if err != nil {
		return err
	}
	return nil
}
func (store *KeyStore) GenerateDataEncryptionKeys(id []byte) error {
	if !keystore.ValidateID(id) {
		return keystore.ErrInvalidClientID
	}
	_, err := store.generateKeyPair(GetServerDecryptionKeyFilename(id), id)
	if err != nil {
		return err
	}
	return nil
}
func (store *KeyStore) ListKeys() ([]keystore.KeyDescription, error) {
	return nil, keystore.ErrNotImplemented
}
func (store *KeyStore) Reset() {
	store.cache.Clear()
}