Fabric ENCChaincode 账本数据AES256加密解密和签名验证

目录

一、加密方式

二、填充方式

三、加密模式

四、源码解读

(一)Encrypter

(二)Decrypter

(三)EncrypterSigner

(四)DecrypterVerify

五、链码测试

Test1:验证加密解密

Test2:验证签名验证

Test3:验证多节点背书情况下IV的使用

六、总结


一、加密方式

AES256分组对称加密是指将明文数据分解为多个16字节的明文块,利用密钥分别对每个明文块进行加密,得到相同个数的16字节密文块,如下图所示:

Fabric ENCChaincode 账本数据AES256加密解密和签名验证_第1张图片

如果分解后有明文块不足16字节,就需要涉及填充和链加密模式。

二、填充方式

由于对明文数据进行了分块,那么就有可能存在分解后的明文块不足128位的情况,这就需要对明文块进行填充。

AES加密支持多种填充方式:NoPadding,PKCS5Padding,ZerosPadding,PKCS7Padding。

其中NoPadding表示不进行填充,这就需要自行检测和控制数据的长度;ZerosPadding表示用0填充缺少的位数;

PKCS5Padding和PKCS7Padding的填充方式在实际效果中是相同的,用缺少的位数进行填充,如块长度为11个字节,缺少5个字节,那么就填充5个字节的内容,每个字节的内容为十进制的5,如下图所示:

注意:如果块长度刚好为16字节,则需要在块后补16个字节的数据,每个字节数据为十进制的16,如下所示:

ENCChaincode使用了PKCS7Padding填充方式。

三、加密模式

ECB模式:

Fabric ENCChaincode 账本数据AES256加密解密和签名验证_第2张图片

CBC模式(密码分组连接模式):

Fabric ENCChaincode 账本数据AES256加密解密和签名验证_第3张图片

CFB模式(密码反馈模式):

Fabric ENCChaincode 账本数据AES256加密解密和签名验证_第4张图片

OFB模式(输出反馈模式):

Fabric ENCChaincode 账本数据AES256加密解密和签名验证_第5张图片

ENCChaincode使用了CBC(密码分解连接)模式。

四、源码解读

ENCKEY和DECKEY:用于分组对称加密和解密

命令 openssl rand -base64 32

ENCKEY=DECKEY=’hJM2KYj33vBq/+3GGybwyFB3chOkNo4lv1swAEMxC3E=’

IV:加密过程中使用的向量,ENCCC例子使用了CBC模式,IV需要提供给链码,若不提供则会随机生成,但如果背书策略指定需要由多个节点进行背书,那么就必须提供唯一的IV,否则节点在背书时会出现读写冲突。

命令 opensslrand -base64 16

IV=’ST56TUR9CYY+NZ41sorYVg==’

SIGKEY和VERKEY:用于签名和验证

命令 openssl ecparam -nameprime256v1 -genkey | tail -n5 | base64 -w0

SIGKEY=VERKEY='LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUtKRzhzMnlqNzJEcGo3L0o1OHFHQzdHa1R5cXQ1REkwZWJod01GamkxMVZvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFMWlEOUlyU1Ixdi9LOVN6TzVCSjVaUUpIZVdTblIxbE00b21iRTBwZ0NpUml6ZExtZkkyVgp6VE84ZE5PTHNhYlhCZGZyNHJUWDNhSkxzeHE5azBZUm1nPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo='

链码源文件:fabric/example/chaincode/go/enccc_example/enccc_example.go

(一)Encrypter

作用:把通过AES256位密钥进行加密的value写入账本。

源码分析:

1. 创建加密实体,参数为:ID,bccp实例,加密密钥encKey,IV(可选参数,若不提供则随机创建)

ent, err:= entities.NewAES256EncrypterEntity("ID", t.bccspInst, encKey, IV)

2. 加密和写入数据

err= encryptAndPutState(stub, ent, key, cleartextValue)

2.1 使用加密器实体对value进行加密

ciphertext, err := ent.Encrypt(cleartextValue) 

2.2 将加密后的value写入账本

stub.PutState(key, ciphertext) 

(二)Decrypter

作用:将账本value读出并通过AES256位密钥进行解密。

源码分析:

1. 创建加密实体,参数为:ID,bccp实例,加密密钥encKey,IV(可选参数,此处示例readme文档中描述:若不提供则随机创建,但与IV的数据结构描述不符)

ent, err:= entities.NewAES256EncrypterEntity("ID", t.bccspInst, encKey, IV)

2. 读取和解密

err= getStateAndDecrypt (stub, ent, key, cleartextValue)

2.1 读出key对应的value

ciphertext, err := stub.GetState(key)

2.2 对value进行解密

ent.Decrypt(ciphertext)

(三)EncrypterSigner

作用:对value使用AES256位密钥进行加密和prime256v1标准进行签名,并将value写入账本。

源码分析:

1. 创建加密签名实体,参数为:ID,bccp实例,加密密钥encKey,签名密钥sigKey

ent, err:= entities.NewAES256EncrypterECDSASignerEntity("ID", t.bccspInst,encKey, sigKey)

2. 对签名数据加密,写入账本

err= signEncryptAndPutState(stub, ent, key, cleartextValue)

2.1 创建一个签名消息,value作为Payload,加密签名实体的ID作为ID,签名消息数据结构如下图所示:

msg := &entities.SignedMessage{Payload: value,ID: []byte(ent.ID())}

Fabric ENCChaincode 账本数据AES256加密解密和签名验证_第6张图片

2.2 利用加密签名实体对SignedMessage进行签名,签名后的信息作为签名消息的Sig字段

err := msg.Sign(ent)

2.3 序列化SignedMessage

b, err := msg.ToBytes()

2.4 对序列化的签名信息进行加密并写入账本

encryptAndPutState(stub, ent, key, b) 

(四)DecrypterVerify

作用:从账本中读取数据,使用AES256位密钥进行解密和prime256v1标准验证签名。

源码分析:

1. 创建加密签名实体,参数为:ID,bccp实例,加密密钥encKey,签名密钥sigKey

ent, err:= entities.NewAES256EncrypterECDSASignerEntity("ID", t.bccspInst,encKey, sigKey)

2. 读取数据,解密并验证签名

cleartextValue, err :=getStateDecryptAndVerify(stub, ent, key)

2.1 读取账本数据并解密

val, err := getStateAndDecrypt(stub, ent, key)

2.2 创建SignedMessage对象msg

msg := &entities.SignedMessage{} 

将序列化的val解码至msg中

err = msg.FromBytes(val) 

2.3 验证签名

 

ok, err := msg.Verify(ent)

五、链码测试

使用e2e_cli示例网络结构:一个orderer节点,分属两个Org的四个peer节点。

修改了script.sh脚本,在所有peer节点安装、实例化ENCCC(ENC Chaincode)

测试过程中的ENCKEY、DECKEY、DECKEY1、IV、SIGKEY、VERKEY、VERKEY1已经设置为cli容器的环境变量

Test1:验证加密解密

使用ENCKEY将value写入账本:

peerchaincode invoke -o orderer.example.com:7050 --tls --cafile $ORDERER_CA -C $CHANNEL_NAME -n enccc -c'{"Args":["ENCRYPT","a","100"]}'--transient"{\"ENCKEY\":\"$ENCKEY\",\"IV\":\"$IV\"}

结果:数据可正确加密写入

使用DECKEY读取value:

peer chaincode query -C $CHANNEL_NAME -n enccc -c '{"Args":["DECRYPT","a"]}' --transient "{\"DECKEY\":\"$DECKEY\"}"

结果:数据正确读出并解密

使用DECKEY1读取value:

peer chaincode query -C $CHANNEL_NAME -n enccc -c '{"Args":["DECRYPT","a"]}' --transient "{\"DECKEY\":\"$DECKEY1\"}"

结果:由于DECKEY1 not equal ENCKEY,导致解密失败

Test2:验证签名验证

使用ENCKEY和SIGKEY将value写入账本:

peer chaincode invoke -o orderer.example.com:7050  --tls --cafile $ORDERER_CA -C $CHANNEL_NAME -n enccc -c '{"Args":["ENCRYPTSIGN","b","200"]}' --transient "{\"ENCKEY\":\"$ENCKEY\",\"SIGKEY\":\"$SIGKEY\"}"

结果:数据正确签名加密,写入账本

使用ENCKEY和VERKEY读取value:

peer chaincode query -C $CHANNEL_NAME -n enccc -c '{"Args":["DECRYPTVERIFY","b"]}' --transient "{\"DECKEY\":\"$DECKEY\",\"VERKEY\":\"$VERKEY\"}"

结果:数据正确读出并解密,验证签名通过

使用ENCKEY和VERKEY1读取value:

peer chaincode query -C $CHANNEL_NAME -n enccc -c '{"Args":["DECRYPTVERIFY","b"]}' --transient "{\"DECKEY\":\"$DECKEY\",\"VERKEY\":\"$VERKEY1\"}"

结果:数据正确读出并解密,签名验证不通过

Test3:验证多节点背书情况下IV的使用

测试组织结构如下:

Org1:peer0,peer1

Org2:peer0,peer1

背书策略指定需要Org1和Org2各一个peer进行背书,在不提供IV的情况下,可正常运行。

示例程序enccc_example的readme文档中描述IV是AES256分组对称加密的初始化向量,在不提供时会随机创建,导致最终的加密结果不同,多节点背书验证时会无法通过验证,但源码中对IV的描述为:只有不为空时才使用IV。

 

六、总结

enccc_example作为一个示例链码,为我们提供了一种对账本数据进行加密的解决方案,若要通过加密对数据进行隔离,则需要针对业务进行一定的修改,目前还在根据业务探索如何使用加密进行数据隔离,大家有好的想法阔以私信在下。

签名和验证部分采用了prime256v1标准,但通过测试发现签名和验证需要使用相同的key,具体的签名和验证处理需要进一步研读源码,目前在业务中还未找到此种方式的具体应用场景。

参考资料:对称加密和分组加密中的四种模式(ECB、CBC、CFB、OFB)

注:文中图片来源于网络,如有侵犯请联系在下删除

你可能感兴趣的:(Fabric)