Skip to content

Commit 4a3f5ef

Browse files
Barry Mosakowskibmos299
Barry Mosakowski
authored andcommitted
[FAB-7066] Modifying the enccc example chaincode
The enccc_example.go was modified to clearly show the user the crypto function(s) being available for transactional data that has transient data passed for operations to include: - encrypt - decrypt - sign - verify The patch set removed the 'PUT' and 'GET' parameters for sample clarity. The README.md was also modified and the go tests modfied to test the modified and new functions added. Change-Id: I16b7894c1118cc7b9f722801ffe3a113be5dbece Signed-off-by: Barry Mosakowski <barry_moz@yahoo.com>
1 parent a2ebd1b commit 4a3f5ef

File tree

3 files changed

+154
-119
lines changed

3 files changed

+154
-119
lines changed

examples/chaincode/go/enccc_example/README.md

+26-12
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,25 @@
22

33
To test `EncCC` you need to first generate an AES 256 bit key as a base64
44
encoded string so that it can be passed as JSON to the peer chaincode
5-
invoke's transient parameter
5+
invoke's transient parameter.
66

7+
Note: Before getting started you must use govendor to add external dependencies. Please issue the following commands inside the "enccc_example" folder:
78
```
8-
ENCKEY=`openssl rand 32 -base64`
9+
govendor init
10+
govendor add +external
11+
```
12+
13+
Let's generate the encryption and decryption keys. The example will simulate a shared key so the key is used for both encryption and decryption.
14+
```
15+
ENCKEY=`openssl rand 32 -base64` && DECKEY=$ENCKEY
916
```
1017

1118
At this point, you can invoke the chaincode to encrypt key-value pairs as
12-
follows
19+
follows:
1320

21+
Note: the following assumes the env is initialized and peer has joined channel "my-ch".
1422
```
15-
peer chaincode invoke -n enccc -C my-ch -c '{"Args":["ENC","PUT","key","value"]}' --transient "{\"ENCKEY\":\"$ENCKEY\"}"
23+
peer chaincode invoke -n enccc -C my-ch -c '{"Args":["ENCRYPT","key1","value1"]}' --transient "{\"ENCKEY\":\"$ENCKEY\"}"
1624
```
1725

1826
This call will encrypt using a random IV. This may be undesirable for
@@ -28,39 +36,45 @@ IV=`openssl rand 16 -base64`
2836
Then, the IV may be specified in the transient field
2937

3038
```
31-
peer chaincode invoke -n enccc -C my-ch -c '{"Args":["ENC","PUT","key","value"]}' --transient "{\"ENCKEY\":\"$ENCKEY\",\"IV\":\"$IV\"}"
39+
peer chaincode invoke -n enccc -C my-ch -c '{"Args":["ENCRYPT","key2","value2"]}' --transient "{\"ENCKEY\":\"$ENCKEY\",\"IV\":\"$IV\"}"
3240
```
3341

3442
Two such invocations will produce equal KVS writes, which can be endorsed by multiple nodes.
3543

3644
The value can be retrieved back as follows
3745

3846
```
39-
peer chaincode query -n enccc -C my-ch -c '{"Args":["ENC","GET","key"]}' --transient "{\"ENCKEY\":\"$ENCKEY\"}"
47+
peer chaincode query -n enccc -C my-ch -c '{"Args":["DECRYPT","key1"]}' --transient "{\"DECKEY\":\"$DECKEY\"}"
48+
```
49+
```
50+
peer chaincode query -n enccc -C my-ch -c '{"Args":["DECRYPT","key2"]}' --transient "{\"DECKEY\":\"$DECKEY\"}"
4051
```
41-
4252
Note that in this case we use a chaincode query operation; while the use of the
4353
transient field guarantees that the content will not be written to the ledger,
4454
the chaincode decrypts the message and puts it in the proposal response. An
4555
invocation would persist the result in the ledger for all channel readers to
4656
see whereas a query can be discarded and so the result remains confidential.
4757

48-
To test signing, you also need to generate an ECDSA key for the appopriate
49-
curve, as follows
58+
To test signing and verifying, you also need to generate an ECDSA key for the appopriate
59+
curve, as follows.
5060

5161
```
52-
SIGKEY=`openssl ecparam -name prime256v1 -genkey | tail -n5 | base64 -w0`
62+
On Intel:
63+
SIGKEY=`openssl ecparam -name prime256v1 -genkey | tail -n5 | base64 -w0` && VERKEY=$SIGKEY
64+
65+
On Mac:
66+
SIGKEY=`openssl ecparam -name prime256v1 -genkey | tail -n5 | base64` && VERKEY=$SIGKEY
5367
```
5468

5569
At this point, you can invoke the chaincode to sign and then encrypt key-value
5670
pairs as follows
5771

5872
```
59-
peer chaincode invoke -n enccc -C my-ch -c '{"Args":["SIG","PUT","key","value"]}' --logging-level debug -o 127.0.0.1:7050 --transient "{\"ENCKEY\":\"$ENCKEY\",\"SIGKEY\":\"$SIGKEY\"}"
73+
peer chaincode invoke -n enccc -C my-ch -c '{"Args":["ENCRYPTSIGN","key3","value3"]}' --transient "{\"ENCKEY\":\"$ENCKEY\",\"SIGKEY\":\"$SIGKEY\"}"
6074
```
6175

6276
And similarly to retrieve them using a query
6377

6478
```
65-
peer chaincode query -n enccc -C my-ch -c '{"Args":["SIG","GET","key"]}' --logging-level debug -o 127.0.0.1:7050 --transient "{\"ENCKEY\":\"$ENCKEY\",\"SIGKEY\":\"$SIGKEY\"}"
79+
peer chaincode query -n enccc -C my-ch -c '{"Args":["DECRYPTVERIFY","key3"]}' --transient "{\"DECKEY\":\"$DECKEY\",\"VERKEY\":\"$VERKEY\"}"
6680
```

examples/chaincode/go/enccc_example/enccc_example.go

+108-75
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ import (
1616
pb "github.com/hyperledger/fabric/protos/peer"
1717
)
1818

19+
const DECKEY = "DECKEY"
20+
const VERKEY = "VERKEY"
1921
const ENCKEY = "ENCKEY"
2022
const SIGKEY = "SIGKEY"
2123
const IV = "IV"
@@ -30,101 +32,112 @@ func (t *EncCC) Init(stub shim.ChaincodeStubInterface) pb.Response {
3032
return shim.Success(nil)
3133
}
3234

33-
// Encrypter exposes two functions: "PUT" that shows how to write state to the ledger after having
35+
// Encrypter exposes how to write state to the ledger after having
3436
// encrypted it with an AES 256 bit key that has been provided to the chaincode through the
35-
// transient field; and "GET" that shows how to read from the ledger and decrypt using an AES 256
36-
// bit key that has been provided to the chaincode through the transient field.
37-
func (t *EncCC) Encrypter(stub shim.ChaincodeStubInterface, f string, args []string, encKey, IV []byte) pb.Response {
37+
// transient field
38+
func (t *EncCC) Encrypter(stub shim.ChaincodeStubInterface, args []string, encKey, IV []byte) pb.Response {
3839
// create the encrypter entity - we give it an ID, the bccsp instance, the key and (optionally) the IV
3940
ent, err := entities.NewAES256EncrypterEntity("ID", t.bccspInst, encKey, IV)
4041
if err != nil {
4142
return shim.Error(fmt.Sprintf("entities.NewAES256EncrypterEntity failed, err %s", err))
4243
}
4344

44-
switch f {
45-
case "PUT":
46-
if len(args) != 2 {
47-
return shim.Error("Expected 2 parameters to PUT")
48-
}
45+
if len(args) != 2 {
46+
return shim.Error("Expected 2 parameters to function Encrypter")
47+
}
4948

50-
key := args[0]
51-
cleartextValue := []byte(args[1])
49+
key := args[0]
50+
cleartextValue := []byte(args[1])
5251

53-
// here, we encrypt cleartextValue and assign it to key
54-
err = encryptAndPutState(stub, ent, key, cleartextValue)
55-
if err != nil {
56-
return shim.Error(fmt.Sprintf("encryptAndPutState failed, err %+v", err))
57-
}
52+
// here, we encrypt cleartextValue and assign it to key
53+
err = encryptAndPutState(stub, ent, key, cleartextValue)
54+
if err != nil {
55+
return shim.Error(fmt.Sprintf("encryptAndPutState failed, err %+v", err))
56+
}
57+
return shim.Success(nil)
58+
}
5859

59-
return shim.Success(nil)
60-
case "GET":
61-
if len(args) != 1 {
62-
return shim.Error("Expected 1 parameters to GET")
63-
}
60+
// Decrypter exposes how to read from the ledger and decrypt using an AES 256
61+
// bit key that has been provided to the chaincode through the transient field.
62+
func (t *EncCC) Decrypter(stub shim.ChaincodeStubInterface, args []string, decKey, IV []byte) pb.Response {
63+
// create the encrypter entity - we give it an ID, the bccsp instance, the key and (optionally) the IV
64+
ent, err := entities.NewAES256EncrypterEntity("ID", t.bccspInst, decKey, IV)
65+
if err != nil {
66+
return shim.Error(fmt.Sprintf("entities.NewAES256EncrypterEntity failed, err %s", err))
67+
}
6468

65-
key := args[0]
69+
if len(args) != 1 {
70+
return shim.Error("Expected 1 parameters to function Decrypter")
71+
}
6672

67-
// here we decrypt the state associated to key
68-
cleartextValue, err := getStateAndDecrypt(stub, ent, key)
69-
if err != nil {
70-
return shim.Error(fmt.Sprintf("getStateAndDecrypt failed, err %+v", err))
71-
}
73+
key := args[0]
7274

73-
// here we return the decrypted value as a result
74-
return shim.Success(cleartextValue)
75-
default:
76-
return shim.Error(fmt.Sprintf("Unsupported function %s", f))
75+
// here we decrypt the state associated to key
76+
cleartextValue, err := getStateAndDecrypt(stub, ent, key)
77+
if err != nil {
78+
return shim.Error(fmt.Sprintf("getStateAndDecrypt failed, err %+v", err))
7779
}
80+
81+
// here we return the decrypted value as a result
82+
return shim.Success(cleartextValue)
7883
}
7984

80-
func (t *EncCC) EncrypterSigner(stub shim.ChaincodeStubInterface, f string, args []string, encKey, sigKey []byte) pb.Response {
85+
// EncrypterSigner exposes how to write state to the ledger after having received keys for
86+
// encrypting (AES 256 bit key) and signing (X9.62/SECG curve over a 256 bit prime field) that has been provided to the chaincode through the
87+
// transient field
88+
func (t *EncCC) EncrypterSigner(stub shim.ChaincodeStubInterface, args []string, encKey, sigKey []byte) pb.Response {
8189
// create the encrypter/signer entity - we give it an ID, the bccsp instance and the keys
8290
ent, err := entities.NewAES256EncrypterECDSASignerEntity("ID", t.bccspInst, encKey, sigKey)
8391
if err != nil {
84-
return shim.Error(fmt.Sprintf("entities.NewAES256EncrypterEntity failed, err %+v", err))
92+
return shim.Error(fmt.Sprintf("entities.NewAES256EncrypterEntity failed, err %s", err))
8593
}
8694

87-
switch f {
88-
case "PUT":
89-
if len(args) != 2 {
90-
return shim.Error("Expected 2 parameters to PUT")
91-
}
95+
if len(args) != 2 {
96+
return shim.Error("Expected 2 parameters to function EncrypterSigner")
97+
}
9298

93-
key := args[0]
94-
cleartextValue := []byte(args[1])
99+
key := args[0]
100+
cleartextValue := []byte(args[1])
95101

96-
// here, we sign cleartextValue, encrypt it and assign it to key
97-
err = signEncryptAndPutState(stub, ent, key, cleartextValue)
98-
if err != nil {
99-
return shim.Error(fmt.Sprintf("signEncryptAndPutState failed, err %+v", err))
100-
}
102+
// here, we sign cleartextValue, encrypt it and assign it to key
103+
err = signEncryptAndPutState(stub, ent, key, cleartextValue)
104+
if err != nil {
105+
return shim.Error(fmt.Sprintf("signEncryptAndPutState failed, err %+v", err))
106+
}
101107

102-
return shim.Success(nil)
103-
case "GET":
104-
if len(args) != 1 {
105-
return shim.Error("Expected 1 parameters to GET")
106-
}
108+
return shim.Success(nil)
109+
}
107110

108-
key := args[0]
111+
// DecrypterVerify exposes how to get state to the ledger after having received keys for
112+
// decrypting (AES 256 bit key) and verifying (X9.62/SECG curve over a 256 bit prime field) that has been provided to the chaincode through the
113+
// transient field
114+
func (t *EncCC) DecrypterVerify(stub shim.ChaincodeStubInterface, args []string, decKey, verKey []byte) pb.Response {
115+
// create the decrypter/verify entity - we give it an ID, the bccsp instance and the keys
116+
ent, err := entities.NewAES256EncrypterECDSASignerEntity("ID", t.bccspInst, decKey, verKey)
117+
if err != nil {
118+
return shim.Error(fmt.Sprintf("entities.NewAES256DecrypterEntity failed, err %s", err))
119+
}
109120

110-
// here we decrypt the state associated to key and verify it
111-
cleartextValue, err := getStateDecryptAndVerify(stub, ent, key)
112-
if err != nil {
113-
return shim.Error(fmt.Sprintf("getStateDecryptAndVerify failed, err %+v", err))
114-
}
121+
if len(args) != 1 {
122+
return shim.Error("Expected 1 parameters to function DecrypterVerify")
123+
}
124+
key := args[0]
115125

116-
// here we return the decrypted and verified value as a result
117-
return shim.Success(cleartextValue)
118-
default:
119-
return shim.Error(fmt.Sprintf("Unsupported function %s", f))
126+
// here we decrypt the state associated to key and verify it
127+
cleartextValue, err := getStateDecryptAndVerify(stub, ent, key)
128+
if err != nil {
129+
return shim.Error(fmt.Sprintf("getStateDecryptAndVerify failed, err %+v", err))
120130
}
131+
132+
// here we return the decrypted and verified value as a result
133+
return shim.Success(cleartextValue)
121134
}
122135

123-
// RangeDecrypter shows how range queries may be satisfied by using the encrypter
136+
// RangeDecrypter shows how range queries may be satisfied by using the decrypter
124137
// entity directly to decrypt previously encrypted key-value pairs
125-
func (t *EncCC) RangeDecrypter(stub shim.ChaincodeStubInterface, encKey []byte) pb.Response {
138+
func (t *EncCC) RangeDecrypter(stub shim.ChaincodeStubInterface, decKey []byte) pb.Response {
126139
// create the encrypter entity - we give it an ID, the bccsp instance and the key
127-
ent, err := entities.NewAES256EncrypterEntity("ID", t.bccspInst, encKey, nil)
140+
ent, err := entities.NewAES256EncrypterEntity("ID", t.bccspInst, decKey, nil)
128141
if err != nil {
129142
return shim.Error(fmt.Sprintf("entities.NewAES256EncrypterEntity failed, err %s", err))
130143
}
@@ -137,9 +150,10 @@ func (t *EncCC) RangeDecrypter(stub shim.ChaincodeStubInterface, encKey []byte)
137150
return shim.Success(bytes)
138151
}
139152

140-
// Invoke for this chaincode exposes two functions: "ENC" to demonstrate
141-
// the use of an Entity that can encrypt, and "SIG" to demonstrate the use
142-
// of an Entity that can encrypt and sign
153+
// Invoke for this chaincode exposes functions to ENCRYPT, DECRYPT transactional
154+
// data. It also supports an example to ENCRYPT and SIGN and DECRYPT and
155+
// VERIFY. The Initialization Vector (IV) can be passed in as a parm to
156+
// ensure peers have deterministic data.
143157
func (t *EncCC) Invoke(stub shim.ChaincodeStubInterface) pb.Response {
144158
// get arguments and transient
145159
f, args := stub.GetFunctionAndParameters()
@@ -149,15 +163,24 @@ func (t *EncCC) Invoke(stub shim.ChaincodeStubInterface) pb.Response {
149163
}
150164

151165
switch f {
152-
case "ENC":
166+
case "ENCRYPT":
153167
// make sure there's a key in transient - the assumption is that
154168
// it's associated to the string "ENCKEY"
155169
if _, in := tMap[ENCKEY]; !in {
156-
return shim.Error(fmt.Sprintf("Expected transient key %s", ENCKEY))
170+
return shim.Error(fmt.Sprintf("Expected transient encryption key %s", ENCKEY))
171+
}
172+
173+
return t.Encrypter(stub, args[0:], tMap[ENCKEY], tMap[IV])
174+
case "DECRYPT":
175+
176+
// make sure there's a key in transient - the assumption is that
177+
// it's associated to the string "DECKEY"
178+
if _, in := tMap[DECKEY]; !in {
179+
return shim.Error(fmt.Sprintf("Expected transient decryption key %s", DECKEY))
157180
}
158181

159-
return t.Encrypter(stub, args[0], args[1:], tMap[ENCKEY], tMap[IV])
160-
case "SIG":
182+
return t.Decrypter(stub, args[0:], tMap[DECKEY], tMap[IV])
183+
case "ENCRYPTSIGN":
161184
// make sure keys are there in the transient map - the assumption is that they
162185
// are associated to the string "ENCKEY" and "SIGKEY"
163186
if _, in := tMap[ENCKEY]; !in {
@@ -166,15 +189,25 @@ func (t *EncCC) Invoke(stub shim.ChaincodeStubInterface) pb.Response {
166189
return shim.Error(fmt.Sprintf("Expected transient key %s", SIGKEY))
167190
}
168191

169-
return t.EncrypterSigner(stub, args[0], args[1:], tMap[ENCKEY], tMap[SIGKEY])
170-
case "RANGE":
192+
return t.EncrypterSigner(stub, args[0:], tMap[ENCKEY], tMap[SIGKEY])
193+
case "DECRYPTVERIFY":
194+
// make sure keys are there in the transient map - the assumption is that they
195+
// are associated to the string "DECKEY" and "VERKEY"
196+
if _, in := tMap[DECKEY]; !in {
197+
return shim.Error(fmt.Sprintf("Expected transient key %s", DECKEY))
198+
} else if _, in := tMap[VERKEY]; !in {
199+
return shim.Error(fmt.Sprintf("Expected transient key %s", VERKEY))
200+
}
201+
202+
return t.DecrypterVerify(stub, args[0:], tMap[DECKEY], tMap[VERKEY])
203+
case "RANGEQUERY":
171204
// make sure there's a key in transient - the assumption is that
172205
// it's associated to the string "ENCKEY"
173-
if _, in := tMap[ENCKEY]; !in {
174-
return shim.Error(fmt.Sprintf("Expected transient key %s", ENCKEY))
206+
if _, in := tMap[DECKEY]; !in {
207+
return shim.Error(fmt.Sprintf("Expected transient key %s", DECKEY))
175208
}
176209

177-
return t.RangeDecrypter(stub, tMap[ENCKEY])
210+
return t.RangeDecrypter(stub, tMap[DECKEY])
178211
default:
179212
return shim.Error(fmt.Sprintf("Unsupported function %s", f))
180213
}

0 commit comments

Comments
 (0)