3 Star 6 Fork 7

Gitee 极速下载/Hyperledger fabric

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
此仓库是为了提升国内下载速度的镜像仓库,每日同步一次。 原始仓库: https://github.com/hyperledger/fabric
克隆/下载
fileks.go 9.87 KB
一键复制 编辑 原始数据 按行查看 历史
Brett Logan 提交于 2020-03-28 20:09 . Address comments from #928
/*
Copyright IBM Corp. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/
package sw
import (
"bytes"
"crypto/ecdsa"
"encoding/hex"
"errors"
"fmt"
"io"
"io/ioutil"
"os"
"path/filepath"
"strings"
"sync"
"github.com/hyperledger/fabric/bccsp"
"github.com/hyperledger/fabric/bccsp/utils"
)
// NewFileBasedKeyStore instantiated a file-based key store at a given position.
// The key store can be encrypted if a non-empty password is specified.
// It can be also be set as read only. In this case, any store operation
// will be forbidden
func NewFileBasedKeyStore(pwd []byte, path string, readOnly bool) (bccsp.KeyStore, error) {
ks := &fileBasedKeyStore{}
return ks, ks.Init(pwd, path, readOnly)
}
// fileBasedKeyStore is a folder-based KeyStore.
// Each key is stored in a separated file whose name contains the key's SKI
// and flags to identity the key's type. All the keys are stored in
// a folder whose path is provided at initialization time.
// The KeyStore can be initialized with a password, this password
// is used to encrypt and decrypt the files storing the keys.
// A KeyStore can be read only to avoid the overwriting of keys.
type fileBasedKeyStore struct {
path string
readOnly bool
isOpen bool
pwd []byte
// Sync
m sync.Mutex
}
// Init initializes this KeyStore with a password, a path to a folder
// where the keys are stored and a read only flag.
// Each key is stored in a separated file whose name contains the key's SKI
// and flags to identity the key's type.
// If the KeyStore is initialized with a password, this password
// is used to encrypt and decrypt the files storing the keys.
// The pwd can be nil for non-encrypted KeyStores. If an encrypted
// key-store is initialized without a password, then retrieving keys from the
// KeyStore will fail.
// A KeyStore can be read only to avoid the overwriting of keys.
func (ks *fileBasedKeyStore) Init(pwd []byte, path string, readOnly bool) error {
// Validate inputs
// pwd can be nil
if len(path) == 0 {
return errors.New("an invalid KeyStore path provided. Path cannot be an empty string")
}
ks.m.Lock()
defer ks.m.Unlock()
if ks.isOpen {
return errors.New("keystore is already initialized")
}
ks.path = path
clone := make([]byte, len(pwd))
copy(ks.pwd, pwd)
ks.pwd = clone
ks.readOnly = readOnly
exists, err := dirExists(path)
if err != nil {
return err
}
if !exists {
err = ks.createKeyStore()
if err != nil {
return err
}
return ks.openKeyStore()
}
empty, err := dirEmpty(path)
if err != nil {
return err
}
if empty {
err = ks.createKeyStore()
if err != nil {
return err
}
}
return ks.openKeyStore()
}
// ReadOnly returns true if this KeyStore is read only, false otherwise.
// If ReadOnly is true then StoreKey will fail.
func (ks *fileBasedKeyStore) ReadOnly() bool {
return ks.readOnly
}
// GetKey returns a key object whose SKI is the one passed.
func (ks *fileBasedKeyStore) GetKey(ski []byte) (bccsp.Key, error) {
// Validate arguments
if len(ski) == 0 {
return nil, errors.New("invalid SKI. Cannot be of zero length")
}
suffix := ks.getSuffix(hex.EncodeToString(ski))
switch suffix {
case "key":
// Load the key
key, err := ks.loadKey(hex.EncodeToString(ski))
if err != nil {
return nil, fmt.Errorf("failed loading key [%x] [%s]", ski, err)
}
return &aesPrivateKey{key, false}, nil
case "sk":
// Load the private key
key, err := ks.loadPrivateKey(hex.EncodeToString(ski))
if err != nil {
return nil, fmt.Errorf("failed loading secret key [%x] [%s]", ski, err)
}
switch k := key.(type) {
case *ecdsa.PrivateKey:
return &ecdsaPrivateKey{k}, nil
default:
return nil, errors.New("secret key type not recognized")
}
case "pk":
// Load the public key
key, err := ks.loadPublicKey(hex.EncodeToString(ski))
if err != nil {
return nil, fmt.Errorf("failed loading public key [%x] [%s]", ski, err)
}
switch k := key.(type) {
case *ecdsa.PublicKey:
return &ecdsaPublicKey{k}, nil
default:
return nil, errors.New("public key type not recognized")
}
default:
return ks.searchKeystoreForSKI(ski)
}
}
// StoreKey stores the key k in this KeyStore.
// If this KeyStore is read only then the method will fail.
func (ks *fileBasedKeyStore) StoreKey(k bccsp.Key) (err error) {
if ks.readOnly {
return errors.New("read only KeyStore")
}
if k == nil {
return errors.New("invalid key. It must be different from nil")
}
switch kk := k.(type) {
case *ecdsaPrivateKey:
err = ks.storePrivateKey(hex.EncodeToString(k.SKI()), kk.privKey)
if err != nil {
return fmt.Errorf("failed storing ECDSA private key [%s]", err)
}
case *ecdsaPublicKey:
err = ks.storePublicKey(hex.EncodeToString(k.SKI()), kk.pubKey)
if err != nil {
return fmt.Errorf("failed storing ECDSA public key [%s]", err)
}
case *aesPrivateKey:
err = ks.storeKey(hex.EncodeToString(k.SKI()), kk.privKey)
if err != nil {
return fmt.Errorf("failed storing AES key [%s]", err)
}
default:
return fmt.Errorf("key type not reconigned [%s]", k)
}
return
}
func (ks *fileBasedKeyStore) searchKeystoreForSKI(ski []byte) (k bccsp.Key, err error) {
files, _ := ioutil.ReadDir(ks.path)
for _, f := range files {
if f.IsDir() {
continue
}
if f.Size() > (1 << 16) { //64k, somewhat arbitrary limit, considering even large keys
continue
}
raw, err := ioutil.ReadFile(filepath.Join(ks.path, f.Name()))
if err != nil {
continue
}
key, err := utils.PEMtoPrivateKey(raw, ks.pwd)
if err != nil {
continue
}
switch kk := key.(type) {
case *ecdsa.PrivateKey:
k = &ecdsaPrivateKey{kk}
default:
continue
}
if !bytes.Equal(k.SKI(), ski) {
continue
}
return k, nil
}
return nil, fmt.Errorf("key with SKI %x not found in %s", ski, ks.path)
}
func (ks *fileBasedKeyStore) getSuffix(alias string) string {
files, _ := ioutil.ReadDir(ks.path)
for _, f := range files {
if strings.HasPrefix(f.Name(), alias) {
if strings.HasSuffix(f.Name(), "sk") {
return "sk"
}
if strings.HasSuffix(f.Name(), "pk") {
return "pk"
}
if strings.HasSuffix(f.Name(), "key") {
return "key"
}
break
}
}
return ""
}
func (ks *fileBasedKeyStore) storePrivateKey(alias string, privateKey interface{}) error {
rawKey, err := utils.PrivateKeyToPEM(privateKey, ks.pwd)
if err != nil {
logger.Errorf("Failed converting private key to PEM [%s]: [%s]", alias, err)
return err
}
err = ioutil.WriteFile(ks.getPathForAlias(alias, "sk"), rawKey, 0600)
if err != nil {
logger.Errorf("Failed storing private key [%s]: [%s]", alias, err)
return err
}
return nil
}
func (ks *fileBasedKeyStore) storePublicKey(alias string, publicKey interface{}) error {
rawKey, err := utils.PublicKeyToPEM(publicKey, ks.pwd)
if err != nil {
logger.Errorf("Failed converting public key to PEM [%s]: [%s]", alias, err)
return err
}
err = ioutil.WriteFile(ks.getPathForAlias(alias, "pk"), rawKey, 0600)
if err != nil {
logger.Errorf("Failed storing private key [%s]: [%s]", alias, err)
return err
}
return nil
}
func (ks *fileBasedKeyStore) storeKey(alias string, key []byte) error {
pem, err := utils.AEStoEncryptedPEM(key, ks.pwd)
if err != nil {
logger.Errorf("Failed converting key to PEM [%s]: [%s]", alias, err)
return err
}
err = ioutil.WriteFile(ks.getPathForAlias(alias, "key"), pem, 0600)
if err != nil {
logger.Errorf("Failed storing key [%s]: [%s]", alias, err)
return err
}
return nil
}
func (ks *fileBasedKeyStore) loadPrivateKey(alias string) (interface{}, error) {
path := ks.getPathForAlias(alias, "sk")
logger.Debugf("Loading private key [%s] at [%s]...", alias, path)
raw, err := ioutil.ReadFile(path)
if err != nil {
logger.Errorf("Failed loading private key [%s]: [%s].", alias, err.Error())
return nil, err
}
privateKey, err := utils.PEMtoPrivateKey(raw, ks.pwd)
if err != nil {
logger.Errorf("Failed parsing private key [%s]: [%s].", alias, err.Error())
return nil, err
}
return privateKey, nil
}
func (ks *fileBasedKeyStore) loadPublicKey(alias string) (interface{}, error) {
path := ks.getPathForAlias(alias, "pk")
logger.Debugf("Loading public key [%s] at [%s]...", alias, path)
raw, err := ioutil.ReadFile(path)
if err != nil {
logger.Errorf("Failed loading public key [%s]: [%s].", alias, err.Error())
return nil, err
}
privateKey, err := utils.PEMtoPublicKey(raw, ks.pwd)
if err != nil {
logger.Errorf("Failed parsing private key [%s]: [%s].", alias, err.Error())
return nil, err
}
return privateKey, nil
}
func (ks *fileBasedKeyStore) loadKey(alias string) ([]byte, error) {
path := ks.getPathForAlias(alias, "key")
logger.Debugf("Loading key [%s] at [%s]...", alias, path)
pem, err := ioutil.ReadFile(path)
if err != nil {
logger.Errorf("Failed loading key [%s]: [%s].", alias, err.Error())
return nil, err
}
key, err := utils.PEMtoAES(pem, ks.pwd)
if err != nil {
logger.Errorf("Failed parsing key [%s]: [%s]", alias, err)
return nil, err
}
return key, nil
}
func (ks *fileBasedKeyStore) createKeyStore() error {
// Create keystore directory root if it doesn't exist yet
ksPath := ks.path
logger.Debugf("Creating KeyStore at [%s]...", ksPath)
err := os.MkdirAll(ksPath, 0755)
if err != nil {
return err
}
logger.Debugf("KeyStore created at [%s].", ksPath)
return nil
}
func (ks *fileBasedKeyStore) openKeyStore() error {
if ks.isOpen {
return nil
}
ks.isOpen = true
logger.Debugf("KeyStore opened at [%s]...done", ks.path)
return nil
}
func (ks *fileBasedKeyStore) getPathForAlias(alias, suffix string) string {
return filepath.Join(ks.path, alias+"_"+suffix)
}
func dirExists(path string) (bool, error) {
_, err := os.Stat(path)
if err == nil {
return true, nil
}
if os.IsNotExist(err) {
return false, nil
}
return false, err
}
func dirEmpty(path string) (bool, error) {
f, err := os.Open(path)
if err != nil {
return false, err
}
defer f.Close()
_, err = f.Readdir(1)
if err == io.EOF {
return true, nil
}
return false, err
}
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/mirrors/fabric.git
git@gitee.com:mirrors/fabric.git
mirrors
fabric
Hyperledger fabric
v2.1.1

搜索帮助