-
Notifications
You must be signed in to change notification settings - Fork 256
隐私保护
linj edited this page Nov 23, 2022
·
1 revision
数据的隐私保护是联盟链的关键技术之一,传统的隐私保护方案一般都是使用非对称加密算法对数据加密上链,获取数据时再解密。这些方案仅仅解决数据单方面的隐私保存,而无法做到隐私数据的动态分享。chain33联盟链使用代理重加密方案,结合存证合约,实现隐私数据的加密存储和动态分享。
代理重加密
(Proxy Re-Encryption, PRE)是一种密钥转换算法,可以将数据所有人owner
公钥加密的密文转换为另一种密文,转换的密文可以由被授权人recipient
的私钥进行解密。密文转换过程由一个半可信的代理服务器proxy
执行,在执行该过程前,代理节点需要持有一个由授权人到被授权人的转换密钥,一般由授权人提前生成并发送给代理节点。通过转换密钥无法直接解析密文,最终还需要被授权人的私钥才能解密,所以代理节点没办法获取到明文信息。
chain33代理重加密功能组件包括:
- chain33-pre代理重加密节点
- chain33-sdk代理重加密接口
- chain33存证合约
- 数据所有人
owner
将隐私数据加密,通过存证合约保存在区块链上 - 数据所有人
owner
对被授权人recipient
生成重加密转换秘钥 - 数据所有人
owner
将转换秘钥分发到代理重加密节点proxy
- 被授权人
recipient
在区块链上查询隐私数据 - 被授权人
recipient
向重加密节点proxy
申请重加密 - 被授权人
recipient
解密数据
搭建方法参考联盟链开发环境搭建
wget https://bty33.oss-cn-shanghai.aliyuncs.com/chain33-Pre.tar.gz
tar xzvf chain33-Pre.tar.gz
cd chain33-Pre
根据实际情况配置服务端口和节点私钥
# 对外重加密服务端口
bindAddr=":11801"
# 节点操作私钥
preServerKey="0x123456789abcdef0fedcba987654321"
./chain33-pre -f chain33.pre.toml
数据所有人owner
// 生成账户
AccountInfo alice = new AccountInfo();
alice.setPrivateKey(OwnerPrivateKey);
alice.setPublicKey(TransactionUtil.getHexPubKeyFromPrivKey(OwnerPrivateKey));
// 生成对称秘钥
EncryptKey encryptKey = PreUtils.GenerateEncryptKey(HexUtil.fromHexString(alice.getPublicKey()));
// 生成重加密密钥分片
KeyFrag[] kFrags = new KeyFrag[numSplit];
try {
kFrags = PreUtils.GenerateKeyFragments(HexUtil.fromHexString(alice.getPrivateKey()),
HexUtil.fromHexString(RecipientPubKey), numSplit, threshold);
} catch (Exception e) {
e.printStackTrace();
}
// 密钥分片发送到代理节点
String dhProof = PreUtils.ECDH(ServerPub, alice.getPrivateKey());
for(int i = 0; i < preClient.length; i++) {
boolean result = preClient[i].sendKeyFragment(alice.getPublicKey(), RecipientPubKey, encryptKey.getPubProofR(),
encryptKey.getPubProofU(), 100, dhProof, kFrags[i]);
if (!result) {
System.out.println("sendKeyFragment failed");
return;
}
}
// 数据加密
byte[] iv = AesUtil.generateIv();
byte[] cipher = AesUtil.encrypt(content, encryptKey.getShareKey(), iv);
System.out.println(cipher);
// 通过存证合约保存加密数据
byte[] contentHash;
try {
contentHash = TransactionUtil.Sha256(content.getBytes("utf-8"));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
return;
}
String txEncode = StorageUtil.createEncryptNotaryStorage(cipher, contentHash, iv,
"chain33-storage-key-pre-"+kFrags[0].getPrecurPub(), "", "storage", OwnerPrivateKey);
String submitTransaction = chain33Client.submitTransaction(txEncode);
数据被授权人recipient
// 生成账户
AccountInfo bob = new AccountInfo();
bob.setPrivateKey(RecipientPrivateKey);
bob.setPublicKey(TransactionUtil.getHexPubKeyFromPrivKey(RecipientPrivateKey));
// 申请重加密,需要两边的公钥
ReKeyFrag[] reKeyFrags = new ReKeyFrag[threshold];
for(int i = 0; i < threshold; i++) {
reKeyFrags[i] = preClient[i].reencrypt(OwnerPubKey, bob.getPublicKey());
}
// 解密对称密钥,需要被授权人私钥
byte[] shareKeyBob;
try {
shareKeyBob = PreUtils.AssembleReencryptFragment(HexUtil.fromHexString(bob.getPrivateKey()), reKeyFrags);
} catch (Exception e) {
e.printStackTrace();
return;
}
// 从链上获取密文
JSONObject resultJson = chain33Client.queryStorage("chain33-storage-key-pre-"+reKeyFrags[0].getPrecurPub());
JSONObject resultArray = resultJson.getJSONObject("encryptStorage");
String content = resultArray.getString("encryptContent");
byte[] fromHexString = HexUtil.fromHexString(content);
// 解密
String text = AesUtil.decrypt(fromHexString, HexUtil.toHexString(shareKeyBob));
详细示例,请参考PreOwner和PreRecipient
hello world