func NewExportedPlaintextSymmetricKey(symmetricPath string, purpose string) *ExportedKey {
	return &ExportedKey{
		Purpose:       purpose,
		SymmetricPath: symmetricPath,
	}
}
NewExportedPlaintextSymmetricKey makes an ExportedKey for an unencrypted symmetric key file.
package filesystem
import (
	"io/ioutil"
	"path/filepath"
	"strings"
	"github.com/cossacklabs/acra/utils"
	"github.com/cossacklabs/themis/gothemis/keys"
)
type KeyExportEnumerator interface {
	EnumerateExportedKeyPaths() ([]string, error)
}
type KeyExport interface {
	KeyExportEnumerator
	ExportPublicKey(key ExportedKey) (*keys.PublicKey, error)
	ExportPrivateKey(key ExportedKey) (*keys.PrivateKey, error)
	ExportKeyPair(key ExportedKey) (*keys.Keypair, error)
	ExportSymmetricKey(key ExportedKey) ([]byte, error)
	ExportPlaintextSymmetricKey(key ExportedKey) ([]byte, error)
}
type KeyFileClassifier interface {
	ClassifyExportedKey(path string) *ExportedKey
}
type ExportedKey struct {
	Purpose string
	ID      []byte
	PublicPath    string
	PrivatePath   string
	SymmetricPath string
}
const (
	PurposeAuthenticationSymKey       = "auth_key"
	PurposePoisonRecordKeyPair        = "poison_key"
	PurposeStorageClientKeyPair       = "storage"
	PurposeStorageZoneKeyPair         = "zone"
	PurposeTransportConnectorKeyPair  = "connector"
	PurposeTransportTranslatorKeyPair = "translator"
	PurposeTransportServerKeyPair     = "server"
)
func (store *KeyStore) ExportPublicKey(key ExportedKey) (*keys.PublicKey, error) {
	if key.PublicPath == "" {
		return nil, nil
	}
	return utils.LoadPublicKey(key.PublicPath)
}
func (store *KeyStore) ExportPrivateKey(key ExportedKey) (*keys.PrivateKey, error) {
	if key.PrivatePath == "" {
		return nil, nil
	}
	privateKey, err := utils.LoadPrivateKey(key.PrivatePath)
	if err != nil {
		return nil, err
	}
	decryptedKey, err := store.encryptor.Decrypt(privateKey.Value, key.ID)
	if err != nil {
		return nil, err
	}
	privateKey.Value = decryptedKey
	return privateKey, nil
}
func (store *KeyStore) ExportKeyPair(key ExportedKey) (*keys.Keypair, error) {
	publicKey, err := store.ExportPublicKey(key)
	if err != nil {
		return nil, err
	}
	privateKey, err := store.ExportPrivateKey(key)
	if err != nil {
		return nil, err
	}
	return &keys.Keypair{Public: publicKey, Private: privateKey}, nil
}
func (store *KeyStore) ExportSymmetricKey(key ExportedKey) ([]byte, error) {
	if key.SymmetricPath == "" {
		return nil, nil
	}
	encrypted, err := utils.ReadFile(key.SymmetricPath)
	if err != nil {
		return nil, err
	}
	keyValue, err := store.encryptor.Decrypt(encrypted, key.ID)
	if err != nil {
		return nil, err
	}
	return keyValue, nil
}
func (store *KeyStore) ExportPlaintextSymmetricKey(key ExportedKey) ([]byte, error) {
	if key.SymmetricPath == "" {
		return nil, nil
	}
	return utils.ReadFile(key.SymmetricPath)
}
type DefaultKeyFileClassifier struct{}
var defaultClassifier = &DefaultKeyFileClassifier{}
func EnumerateExportedKeys(enumerator KeyExportEnumerator) ([]ExportedKey, error) {
	return EnumerateExportedKeysByClass(enumerator, defaultClassifier)
}
func EnumerateExportedKeysByClass(enumerator KeyExportEnumerator, classifier KeyFileClassifier) ([]ExportedKey, error) {
	keyPaths, err := enumerator.EnumerateExportedKeyPaths()
	if err != nil {
		return nil, err
	}
	keyMap := make(map[string]*ExportedKey)
	for _, path := range keyPaths {
		if key := classifier.ClassifyExportedKey(path); key != nil {
			id := key.fusedID()
			keyInMap, exists := keyMap[id]
			if exists {
				keyInMap.addPathFrom(key)
			} else {
				keyMap[id] = key
			}
		}
	}
	exportedKeys := make([]ExportedKey, 0, len(keyMap))
	for _, key := range keyMap {
		exportedKeys = append(exportedKeys, *key)
	}
	return exportedKeys, nil
}
func (store *KeyStore) EnumerateExportedKeyPaths() ([]string, error) {
	paths := make([]string, 0)
	directories := []string{store.privateKeyDirectory}
	if store.publicKeyDirectory != store.privateKeyDirectory {
		directories = append(directories, store.publicKeyDirectory)
	}
	for i := 0; i < len(directories); i++ {
		files, err := ioutil.ReadDir(directories[i])
		if err != nil {
			return nil, err
		}
		for _, file := range files {
			path := filepath.Join(directories[i], file.Name())
			if file.IsDir() {
				directories = append(directories, path)
			} else {
				paths = append(paths, path)
			}
		}
	}
	return paths, nil
}
func (key *ExportedKey) fusedID() string {
	return key.Purpose + string(key.ID)
}
func (key *ExportedKey) addPathFrom(other *ExportedKey) {
	if other.PublicPath != "" {
		key.PublicPath = other.PublicPath
	}
	if other.PrivatePath != "" {
		key.PrivatePath = other.PrivatePath
	}
	if other.SymmetricPath != "" {
		key.SymmetricPath = other.SymmetricPath
	}
}
func NewExportedSymmetricKey(symmetricPath string, context []byte, purpose string) *ExportedKey {
	return &ExportedKey{
		Purpose:       purpose,
		ID:            context,
		SymmetricPath: symmetricPath,
	}
}