diff --git a/ecc_go/chaincode/enclave_go/skvs_stub.go b/ecc_go/chaincode/enclave_go/skvs_stub.go new file mode 100644 index 000000000..27b9d94ce --- /dev/null +++ b/ecc_go/chaincode/enclave_go/skvs_stub.go @@ -0,0 +1,111 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package enclave_go + +import ( + "crypto/sha256" + "fmt" + + "github.com/hyperledger/fabric-chaincode-go/shim" + "github.com/hyperledger/fabric-private-chaincode/internal/protos" + "github.com/hyperledger/fabric/protoutil" + "github.com/pkg/errors" + "google.golang.org/protobuf/proto" +) + +type skvsStub struct { + *EnclaveStub +} + +func NewSkvsStub(cc shim.Chaincode) *skvsStub { + enclaveStub := NewEnclaveStub(cc) + return &skvsStub{enclaveStub} +} + +func (e *skvsStub) ChaincodeInvoke(stub shim.ChaincodeStubInterface, chaincodeRequestMessageBytes []byte) ([]byte, error) { + logger.Warning("==== SKVS ChaincodeInvoke ====") + + signedProposal, err := stub.GetSignedProposal() + if err != nil { + return nil, fmt.Errorf("cannot get signed proposal: %s", err.Error()) + } + + if err := e.verifySignedProposal(stub, chaincodeRequestMessageBytes); err != nil { + return nil, errors.Wrap(err, "signed proposal verification failed") + } + + // unmarshal chaincodeRequest + chaincodeRequestMessage := &protos.ChaincodeRequestMessage{} + err = proto.Unmarshal(chaincodeRequestMessageBytes, chaincodeRequestMessage) + if err != nil { + return nil, err + } + + // get key transport message including the encryption keys for request and response + keyTransportMessage, err := e.extractKeyTransportMessage(chaincodeRequestMessage) + if err != nil { + return nil, errors.Wrap(err, "cannot extract keyTransportMessage") + } + + // decrypt request + cleartextChaincodeRequest, err := e.extractCleartextChaincodeRequest(chaincodeRequestMessage, keyTransportMessage) + if err != nil { + return nil, errors.Wrap(err, "cannot decrypt chaincode request") + } + + // create a new instance of a FPC RWSet that we pass to the stub and later return with the response + rwset := NewReadWriteSet() + + // Invoke chaincode + // we wrap the stub with our FpcStubInterface + // ** Implement our own FpcStubInterface + skvsStub := NewSkvsStubInterface(stub, cleartextChaincodeRequest.GetInput(), rwset, e.ccKeys) + ccResponse := e.ccRef.Invoke(skvsStub) + // ** + // fpcStub := NewFpcStubInterface(stub, cleartextChaincodeRequest.GetInput(), rwset, e.ccKeys) + // ccResponse := e.ccRef.Invoke(fpcStub) + + // marshal chaincode response + ccResponseBytes, err := protoutil.Marshal(&ccResponse) + if err != nil { + return nil, err + } + + //encrypt response + encryptedResponse, err := e.csp.EncryptMessage(keyTransportMessage.GetResponseEncryptionKey(), ccResponseBytes) + if err != nil { + return nil, err + } + + chaincodeRequestMessageHash := sha256.Sum256(chaincodeRequestMessageBytes) + + response := &protos.ChaincodeResponseMessage{ + EncryptedResponse: encryptedResponse, + FpcRwSet: rwset.ToFPCKVSet(), + EnclaveId: e.identity.GetEnclaveId(), + Proposal: signedProposal, + ChaincodeRequestMessageHash: chaincodeRequestMessageHash[:], + } + + responseBytes, err := proto.Marshal(response) + if err != nil { + return nil, err + } + + // create signature + sig, err := e.identity.Sign(responseBytes) + if err != nil { + return nil, err + } + + signedResponse := &protos.SignedChaincodeResponseMessage{ + ChaincodeResponseMessage: responseBytes, + Signature: sig, + } + + return proto.Marshal(signedResponse) +} diff --git a/ecc_go/chaincode/enclave_go/skvs_stub_interface.go b/ecc_go/chaincode/enclave_go/skvs_stub_interface.go new file mode 100644 index 000000000..64aa92ce3 --- /dev/null +++ b/ecc_go/chaincode/enclave_go/skvs_stub_interface.go @@ -0,0 +1,115 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package enclave_go + +import ( + "encoding/json" + + "github.com/hyperledger/fabric-chaincode-go/shim" + pb "github.com/hyperledger/fabric-protos-go/peer" + "github.com/pkg/errors" +) + +type SkvsStubInterface struct { + *FpcStubInterface + allDataOld map[string][]byte + allDataNew map[string][]byte + key string +} + +func NewSkvsStubInterface(stub shim.ChaincodeStubInterface, input *pb.ChaincodeInput, rwset *readWriteSet, sep StateEncryptionFunctions) *SkvsStubInterface { + logger.Warning("==== Get New Skvs Interface =====") + fpcStub := NewFpcStubInterface(stub, input, rwset, sep) + skvsStub := SkvsStubInterface{fpcStub, map[string][]byte{}, map[string][]byte{}, "SKVS"} + err := skvsStub.InitSKVS() + if err != nil { + logger.Warningf("Error!! Initializing SKVS failed") + } + return &skvsStub +} + +func (s *SkvsStubInterface) InitSKVS() error { + logger.Warningf(" === Initializing SKVS === ") + + // get current state, this will only operate once + encValue, err := s.GetPublicState(s.key) + if err != nil { + return nil + } + + if len(encValue) == 0 { + logger.Warningf("SKVS is empty, Initiating.") + } else { + value, err := s.sep.DecryptState(encValue) + if err != nil { + return err + } + logger.Warningf("SKVS has default value, loading current value.") + + err = json.Unmarshal(value, &s.allDataOld) + if err != nil { + logger.Errorf("SKVS Json unmarshal error: %s", err) + return err + } + err = json.Unmarshal(value, &s.allDataNew) + if err != nil { + logger.Errorf("SKVS Json unmarshal error: %s", err) + return err + } + } + + logger.Warningf("SKVS Init finish, allDataOld: %s, allDataNew: %s", s.allDataOld, s.allDataNew) + return nil +} + +func (s *SkvsStubInterface) GetState(key string) ([]byte, error) { + logger.Warningf("Calling Get State (Start), key: %s, alldataOld: %s", key, s.allDataOld) + value, found := s.allDataOld[key] + if !found { + return nil, errors.New("skvs allDataOld key not found") + } + logger.Warningf("Calling Get State (End), key: %s, value: %x", key, value) + return value, nil +} + +func (s *SkvsStubInterface) PutState(key string, value []byte) error { + logger.Warningf("Calling Put State (Start), key: %s, value: %x, alldata: %s", key, value, s.allDataNew) + + s.allDataNew[key] = value + byteAllData, err := json.Marshal(s.allDataNew) + if err != nil { + return err + } + encValue, err := s.sep.EncryptState(byteAllData) + if err != nil { + return err + } + logger.Warningf("Calling Put State (End), put encValue: %x", encValue) + + return s.PutPublicState(s.key, encValue) +} + +func (s *SkvsStubInterface) DelState(key string) error { + delete(s.allDataNew, key) + byteAllData, err := json.Marshal(s.allDataNew) + if err != nil { + return err + } + encValue, err := s.sep.EncryptState(byteAllData) + if err != nil { + return err + } + return s.PutPublicState(s.key, encValue) +} + +func (s *SkvsStubInterface) GetStateByRange(startKey string, endKey string) (shim.StateQueryIteratorInterface, error) { + panic("not implemented") // TODO: Implement +} + +func (s *SkvsStubInterface) GetStateByRangeWithPagination(startKey string, endKey string, pageSize int32, bookmark string) (shim.StateQueryIteratorInterface, *pb.QueryResponseMetadata, error) { + panic("not implemented") // TODO: Implement +} diff --git a/ecc_go/chaincode/singleKVS.go b/ecc_go/chaincode/singleKVS.go new file mode 100644 index 000000000..b78c54185 --- /dev/null +++ b/ecc_go/chaincode/singleKVS.go @@ -0,0 +1,29 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package chaincode + +import ( + "github.com/hyperledger/fabric-chaincode-go/shim" + "github.com/hyperledger/fabric-private-chaincode/ecc/chaincode" + "github.com/hyperledger/fabric-private-chaincode/ecc/chaincode/ercc" + "github.com/hyperledger/fabric-private-chaincode/ecc_go/chaincode/enclave_go" + "github.com/hyperledger/fabric-private-chaincode/internal/endorsement" + "github.com/hyperledger/fabric/common/flogging" +) + +var logger = flogging.MustGetLogger("enclave_go") + +func NewSkvsChaincode(cc shim.Chaincode) *chaincode.EnclaveChaincode { + logger.Info("Creating new SKVS Chaincode") + ecc := &chaincode.EnclaveChaincode{ + Enclave: enclave_go.NewSkvsStub(cc), + Validator: endorsement.NewValidator(), + Extractor: &chaincode.ExtractorImpl{}, + Ercc: &ercc.StubImpl{}, + } + return ecc +} diff --git a/samples/chaincode/secret-keeper-go/main.go b/samples/chaincode/secret-keeper-go/main.go index a8f707f1b..1dc1af38a 100644 --- a/samples/chaincode/secret-keeper-go/main.go +++ b/samples/chaincode/secret-keeper-go/main.go @@ -23,13 +23,14 @@ func main() { // create chaincode secretChaincode, _ := contractapi.NewChaincode(&chaincode.SecretKeeper{}) - chaincode := fpc.NewPrivateChaincode(secretChaincode) + // chaincode := fpc.NewPrivateChaincode(secretChaincode) + skvsChaincode := fpc.NewSkvsChaincode(secretChaincode) // start chaincode as a service server := &shim.ChaincodeServer{ CCID: ccid, Address: addr, - CC: chaincode, + CC: skvsChaincode, TLSProps: shim.TLSProperties{ Disabled: true, // just for testing good enough },