-
Notifications
You must be signed in to change notification settings - Fork 91
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- implement secret keeper demo - readme - create unit test mock rollback attack --------- Signed-off-by: chenchanglew <[email protected]> Signed-off-by: chenchanglew <[email protected]>
- Loading branch information
1 parent
4d8f776
commit 6ad8d82
Showing
6 changed files
with
588 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
ecc | ||
ecc-bundle | ||
enclave.json | ||
private.pem | ||
public.pem | ||
mrenclave | ||
details.env |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
# Copyright 2019 Intel Corporation | ||
# Copyright IBM Corp. All Rights Reserved. | ||
# | ||
# SPDX-License-Identifier: Apache-2.0 | ||
|
||
TOP = ../../.. | ||
include $(TOP)/ecc_go/build.mk | ||
|
||
CC_NAME ?= fpc-secret-keeper-go |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
# Secret Keeper | ||
|
||
Secret Keeper is a demo application designed to securely store sensitive information, acting as a digital vault. It's ideal for users who need to manage access to shared secrets within a team or organization. | ||
|
||
## Functions | ||
|
||
Secret Keeper provides the following functionalities: | ||
|
||
- **InitSecretKeeper**: Initializes the application with default authorization and secret values. Intended for one-time use at application setup. Note: While potential misuse is considered low-risk, it's recommended to secure access to this function. | ||
|
||
- **RevealSecret**: Allows authorized users to view the currently stored secret. | ||
|
||
- **LockSecret**: Enables authorized users to update the secret value. This action replaces the existing secret. | ||
|
||
- **AddUser**: Permits authorized users to add a new user to the authorization list, granting them access to all functions. | ||
|
||
- **RemoveUser**: Allows authorized users to remove an existing user from the authorization list, revoking their access. | ||
|
||
## Example Usage | ||
|
||
To demonstrate Secret Keeper's capabilities, you can deploy the chaincode to [the-simple-testing-network](https://github.com/hyperledger/fabric-private-chaincode/tree/main/samples/deployment/fabric-smart-client/the-simple-testing-network) and then invoke it with the [simple-cli-go](https://github.com/hyperledger/fabric-private-chaincode/tree/main/samples/application/simple-cli-go). | ||
|
||
1. Initialize Secret Keeper: | ||
``` | ||
./fpcclient invoke initSecretKeeper | ||
``` | ||
2. Reveal the secret as Alice: | ||
``` | ||
./fpcclient query revealSecret Alice | ||
``` | ||
3. Change the secret as Bob: | ||
``` | ||
./fpcclient invoke lockSecret Bob NewSecret | ||
``` | ||
4. Attempt to reveal the secret as Alice (now updated): | ||
``` | ||
./fpcclient query revealSecret Alice | ||
``` | ||
5. Remove Bob's access as Alice: | ||
``` | ||
./fpcclient invoke removeUser Alice Bob | ||
``` | ||
6. Attempt to reveal the secret as Bob (should fail): | ||
``` | ||
./fpcclient query revealSecret Bob // (will failed) | ||
``` | ||
7. Re-add Bob to the authorization list as Alice: | ||
``` | ||
./fpcclient invoke addUser Alice Bob | ||
``` | ||
8. Bob can now reveal the secret successfully: | ||
``` | ||
./fpcclient query revealSecret Bob // (will success) | ||
``` |
205 changes: 205 additions & 0 deletions
205
samples/chaincode/secret-keeper-go/chaincode/secret-keeper.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,205 @@ | ||
/* | ||
Copyright IBM Corp. All Rights Reserved. | ||
SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package chaincode | ||
|
||
import ( | ||
"encoding/json" | ||
"fmt" | ||
|
||
"github.com/hyperledger/fabric-contract-api-go/contractapi" | ||
) | ||
|
||
const OK = "OK" | ||
const AUTH_LIST_KEY = "AUTH_LIST_KEY" | ||
const SECRET_KEY = "SECRET_KEY" | ||
|
||
type SecretKeeper struct { | ||
contractapi.Contract | ||
} | ||
|
||
type AuthSet struct { | ||
Pubkey map[string]struct{} | ||
} | ||
|
||
type Secret struct { | ||
Value string `json:"Value"` | ||
} | ||
|
||
func (t *SecretKeeper) InitSecretKeeper(ctx contractapi.TransactionContextInterface) error { | ||
// init authSet | ||
pubkeyset := make(map[string]struct{}) | ||
pubkeyset["Alice"] = struct{}{} | ||
pubkeyset["Bob"] = struct{}{} | ||
authSet := AuthSet{ | ||
Pubkey: pubkeyset, | ||
} | ||
|
||
authSetJson, err := json.Marshal(authSet) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
err = ctx.GetStub().PutState(AUTH_LIST_KEY, authSetJson) | ||
if err != nil { | ||
return fmt.Errorf("failed to put %s to world state. %v", AUTH_LIST_KEY, err) | ||
} | ||
|
||
// init secret | ||
secret := Secret{ | ||
Value: "DefaultSecret", | ||
} | ||
|
||
secretJson, err := json.Marshal(secret) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
err = ctx.GetStub().PutState(SECRET_KEY, secretJson) | ||
if err != nil { | ||
return fmt.Errorf("failed to put %s to world state. %v", SECRET_KEY, err) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func (t *SecretKeeper) AddUser(ctx contractapi.TransactionContextInterface, sig string, pubkey string) error { | ||
// check if the user allow to update authSet | ||
valid, err := VerifySig(ctx, sig) | ||
if err != nil { | ||
return err | ||
} | ||
if !valid { | ||
return fmt.Errorf("user are not allowed to perform this action") | ||
} | ||
|
||
// update the value | ||
authSet, _ := GetAuthList(ctx) | ||
authSet.Pubkey[pubkey] = struct{}{} | ||
|
||
authSetJson, err := json.Marshal(authSet) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
err = ctx.GetStub().PutState(AUTH_LIST_KEY, authSetJson) | ||
if err != nil { | ||
return fmt.Errorf("failed to put %s to world state. %v", AUTH_LIST_KEY, err) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func (t *SecretKeeper) RemoveUser(ctx contractapi.TransactionContextInterface, sig string, pubkey string) error { | ||
// check if the user allow to update authSet | ||
valid, err := VerifySig(ctx, sig) | ||
if err != nil { | ||
return err | ||
} | ||
if !valid { | ||
return fmt.Errorf("user are not allowed to perform this action") | ||
} | ||
|
||
// update the value | ||
authSet, _ := GetAuthList(ctx) | ||
delete(authSet.Pubkey, pubkey) | ||
|
||
authSetJson, err := json.Marshal(authSet) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
err = ctx.GetStub().PutState(AUTH_LIST_KEY, authSetJson) | ||
if err != nil { | ||
return fmt.Errorf("failed to put %s to world state. %v", AUTH_LIST_KEY, err) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func (t *SecretKeeper) LockSecret(ctx contractapi.TransactionContextInterface, sig string, value string) error { | ||
// check if the user allow to update secret | ||
valid, err := VerifySig(ctx, sig) | ||
if err != nil { | ||
return err | ||
} | ||
if !valid { | ||
return fmt.Errorf("user are not allowed to perform this action") | ||
} | ||
|
||
// update the value | ||
newSecret := Secret{ | ||
Value: value, | ||
} | ||
|
||
newSecretJson, err := json.Marshal(newSecret) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
err = ctx.GetStub().PutState(SECRET_KEY, newSecretJson) | ||
if err != nil { | ||
return fmt.Errorf("failed to put %s to world state. %v", SECRET_KEY, err) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func (t *SecretKeeper) RevealSecret(ctx contractapi.TransactionContextInterface, sig string) (*Secret, error) { | ||
// check if the user allow to view the secret. | ||
valid, err := VerifySig(ctx, sig) | ||
if err != nil { | ||
return nil, err | ||
} | ||
if !valid { | ||
return nil, fmt.Errorf("user are not allowed to perform this action") | ||
} | ||
|
||
// reveal secret | ||
secretJson, err := ctx.GetStub().GetState(SECRET_KEY) | ||
if err != nil { | ||
return nil, fmt.Errorf("failed to read from world state: %v", err) | ||
} | ||
if secretJson == nil { | ||
return nil, fmt.Errorf("the asset %s does not exist", SECRET_KEY) | ||
} | ||
var secret Secret | ||
err = json.Unmarshal(secretJson, &secret) | ||
if err != nil { | ||
return nil, err | ||
} | ||
return &secret, nil | ||
} | ||
|
||
func GetAuthList(ctx contractapi.TransactionContextInterface) (*AuthSet, error) { | ||
authSetJson, err := ctx.GetStub().GetState(AUTH_LIST_KEY) | ||
if err != nil { | ||
return nil, fmt.Errorf("failed to read from world state: %v", err) | ||
} | ||
if authSetJson == nil { | ||
return nil, fmt.Errorf("the asset %s does not exist", AUTH_LIST_KEY) | ||
} | ||
|
||
var authSet AuthSet | ||
err = json.Unmarshal(authSetJson, &authSet) | ||
if err != nil { | ||
return nil, err | ||
} | ||
return &authSet, nil | ||
} | ||
|
||
func VerifySig(ctx contractapi.TransactionContextInterface, sig string) (bool, error) { | ||
authSet, err := GetAuthList(ctx) | ||
if err != nil { | ||
return false, err | ||
} | ||
|
||
if _, exist := authSet.Pubkey[sig]; exist { | ||
return true, nil | ||
} | ||
|
||
return false, nil | ||
} |
Oops, something went wrong.