1. 程式人生 > >Fabric ENCChaincode 賬本資料AES256加密解密和簽名驗證

Fabric ENCChaincode 賬本資料AES256加密解密和簽名驗證

目錄

六、總結

一、加密方式

AES256分組對稱加密是指將明文資料分解為多個16位元組的明文塊,利用金鑰分別對每個明文塊進行加密,得到相同個數的16位元組密文塊,如下圖所示:

如果分解後有明文塊不足16位元組,就需要涉及填充和鏈加密模式。

二、填充方式

由於對明文資料進行了分塊,那麼就有可能存在分解後的明文塊不足128位的情況,這就需要對明文塊進行填充。

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

其中NoPadding表示不進行填充,這就需要自行檢測和控制資料的長度;ZerosPadding表示用0填充缺少的位數;

PKCS5Padding和PKCS7Padding的填充方式在實際效果中是相同的,用缺少的位數進行填充,如塊長度為11個位元組,缺少5個位元組,那麼就填充5個位元組的內容,每個位元組的內容為十進位制的5,如下圖所示:

注意:如果塊長度剛好為16位元組,則需要在塊後補16個位元組的資料,每個位元組資料為十進位制的16,如下所示:

ENCChaincode使用了PKCS7Padding填充方式。

三、加密模式

ECB模式:

CBC模式(密碼分組連線模式):

CFB模式(密碼反饋模式):

OFB模式(輸出反饋模式):

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())}

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,具體的簽名和驗證處理需要進一步研讀原始碼,目前在業務中還未找到此種方式的具體應用場景。

注:文中圖片來源於網路,如有侵犯請聯絡在下刪除