概述
题注
随着技术博客中的文章越写越多,越写越有经验,我也越来越喜欢把各种各样自己做的有意思的东西公开给大家了~通过技术博客也认识了全国各地的朋友们,他们涉及到的领域真是包罗万象:有做设计的,有做算法的,有做密码学的,还有很多很多好玩的,有趣的人。这也是我希望看到的:大家把自己的技术,自己的心得与其他人分享,一起努力一起进步!
这一篇博客实际上是一位技术朋友希望我能撰写的。他和他团队的小伙伴们在使用jPBC这个Library的时候遇到了很多的问题,希望如果有可能的话,能得到我的帮助。帮助倒是谈不上,能互相交流一下,玩一玩技术也是不错的~ jPBC我以前也配置过,不过那个时候其稳定版本是1.2.1,还并不是特别好用。这次再配置一遍,发现2.0.0的使用比1.2.1方便得多啊,而且竟然可以在Windows下面配置了!所以我赶快做了几个测试,并把我配置的全部过程分享给大家,希望能对大家的配置和开发有所帮助。
背景
Pairing-Based Cryptography
只要是最近10年做密码学的人,就不可能不知道传说中的Pairing-Based Cryptograhphy(PBC)。在现代密码学中,人们常常用两种群来构造安全的密码学算法,即类似RSA的phi (N)群,以及离散对数群。因为各种各样的原因(具体原因太理论了,在此我不详细展开,有兴趣的朋友们可以单独联系我,我们可以讨论一下~),类似RSA的phi (N)群基本已经淘汰不用,而离散对数群得到了广泛的应用。
大家可能有所了解,phi (N)群安全的最大基础是,N=p*q,其中p和q是两个大质数,且给定N,很难分解为p*q。这也就是我们常说的大合数分解问题。在离散对数群中,也有类似的一个难题,成为离散对数难题。给定群的生成元g,和某一个群中的元素g^x,求解x本身很困难。有的人要问了,这个挺简单的啊,求log不就行了吗?需要注意的是,在连续域上面,确实有求log的快速算法(比如用数学分析中的Taylor展示求法,或者各种数值分析中的逼近算法等等),但是这些算法都是逼近算法,并不能求出准确解。当然了,一般数的log结果也是一个无线不循环小数,只能用逼近算法求。但是,在离散对数群中,我们是在用整数和整数做解,根本没有逼近算法这么回事…有兴趣的同学,可以了解一下离散对数群,并且设置一个生成元g,来尝试求一求一个数的离散对数,就会发现只能用枚举的算法来求。
但是,在密码学中,这个计算困难假设不太好用,因此密码学家扩充了离散对数难题,提出了很多别的困难假设,以用于安全性证明。其中,最直接也是最简单的扩展,为计算Diffie-Hellman问题(Computataional Diffie-Hellman Problem,CDH),以及确定Diffie-Hellman问题(Decision Diffie-Hellman Problem,DDH)。
CDH问题是说,给定生成元g,两个群中的元素g^x,g^y,再不给定x,y的情况下,求g^{xy}。DDH问题是:同样给定生成元g,两个群中的元素g^x,g^y,再给定群的一个元素g^z,确定是否满足g^z = g^{xy}。CDH问题和DDH问题是很多加密方案和签名方案的安全基础,如著名的El Gamal加密方案。
但是,Bilinear Pairing的出现,使得DDH问题在某些特定群上面并不是一个困难问题了。Bilinear Pairing最早也是为了解决DDH问题,从而破解密码学方案而提出来的。Bilinear Pairing是一个函数e,其以两个群元素g^x,g^y为输入,求出e(g,g)^{xy}。这样一来,DDH问题就可以用Bilinear Pairing求解了:给定g,g^x,g^y,g^z,我们分别求e(g,g^z)和e(g^x,g^y),看看他们是不是相等即可。
那么,Bilinear Pairing在密码学方面有什么正面的用途吗?即:不用于破解密码学方案,而是来构建密码学方案的正面用途。在,2001年,Boneh和Franklin在论文《Identity-Based Encryption from the Weil Pairing》,提出了一个非常高效的Identity-Based Encryption方案。这也被认为是Bilinear Pairing的第一个实际应用。自此以后,Bilinear Pairing在密码学中有了越来越多的应用,这一类使用Bilinear Pairing的密码学方案被称为Pairing-Based Cryptography。在现代密码中,越来越多的公钥密码学方案都基于Bilinear Pairing做,如Hierarchical Identity-Based Encryption,Attribute-Based Encryption,Fully Secure Signature等等。可以这么说,Bilinear Pairing为公钥密码学进一步发展打开了一扇大门。
PBC与jPBC
Pairing虽然好用,在实际中到底如何使用呢?Boneh的一个学生,Ben Lynn,在Boneh的指导下开发了Pairing-Based Cryptography Library,完全实现了Bilinear Pairing。这一个Library现在成为了测试和使用Pairing-Based Cryptography的必备函数库,估计已经被用了上百万次了吧… 这个库是用Linux C开发的,非常好用!感兴趣的朋友们可以到PBC的官方网址:http://crypto.stanford.edu/pbc/ 对这个函数库做进一步的了解。
jPBC的全称是java Pairing-Based Cryptography Library,是PBC的一个Java封装,其官方网址为http://gas.dia.unisa.it/projects/jpbc/。要知道,并不是所有开发人员都能够熟练使用C的,在现在计算机的大潮中,广泛使用的语言基本已经是C++,Java,Python等面向对象语言了。因此,PBC面向其他语言的封装就显得十分重要。据我所知,除了jPBC以外,现在也出现了很多其他语言的PBC封装,如Python的封装,C++的封装等等。
作为一个Java的忠实用户,我个人当然最喜欢用Java啦,而且Java本身还有一个好处:开发的程序仅需要做很小的修改就可以移植到Android上面,做终端应用了。jPBC也具有这样的功能。具体如何在Android上使用jPBC,我还需要进一步的研究和配置。朋友们需要耐心等待我下面的博客了…
系统配置
在最新版本的jPBC 2.0.0中,PBC库已经被封装在了jar包中。也就是说,我们已经不需要再本地再编译PBC库,然后通过设定Native Library的形式使用jPBC了,只需要将jar包放置在工程下即可进行调用。这也就意味着,jPBC已经可以在Windows下面使用了!
我的系统配置截图如下:
jPBC 2.0.0在任意平台下的配置
首先,我们需要在官方网站上面留意,什么情况下才需要本地编译PBC后才能够使用,什么情况下可以直接使用jPBC。jPBC官方网站上面有如下的说法:
To use JPBC, add to your classpath the following jars:
- jpbc_2.0.0-api.jar and
- jpbc_2.0.0-plaf.jar.
To use the PBC Wrapper, a shared C library must be compiled and installed properly as shown here.
Then, to use the wrapper, include the following jars:
- jpbc_2.0.0-pbc.jar and
- jna-3.1.0.jar.
To use the Multilinear Maps, include the following jar:
- jpbc_2.0.0-mm.jar.
To use the cryptosystems provided by JPBC include the following jars:
- jpbc-crypto-2.0.0.jar and
- bcprov-jdk16-1.46.
这样一来,自然而然也就引入了下一个问题:现在的jPBC能否使用在Android环境下面呢?这个我自己还并没有测试,准备这几天有时间的话就试一试,然后发一个博客告诉大家结果啦。
回到主题,jPBC的配置流程如下:
(1) 在Eclipse中新建一个工程,在这里我的工程名字就为jPBC了。建立工程后,我们需要把jar包引入其中。在Eclipse中,jar包可以通过绝对路径引入(Import Extended jar),也可以通过相对路径引入(Import jar)。在此,为了工程的拷贝方便,我选择使用相对工程引入。因此,我们需要在jPBC工程中增加一个存放jar包的文件夹,并且把jar包存入其中。右键单击jPBC工程,选择New->Folder,如图所示:
随后,在弹出的对话框中,将这个文件夹起名为lib,文件夹位置放置在jPBC工程的根目录下,如图:
接下来,将jPBC中所有的jar文件拷贝到lib文件夹中。注意,虽然都拷贝过来了,但是有关PBC Wrapper的内容都无法使用,因为我们现在并没有本地Shared PBC Library。拷贝进lib后,右键点击jPBC工程,选择Refresh,我们就可以看到lib文件夹下面已经有jar文件了。然后,同样右键点击jPBC工程,选择Properties,再弹出的对话框中选择Java Bulid Path,如图所示。
在右面选择Add JARS,将jPBC的所有jar文件引入其中。在此我仅引入了jPBC核心的两个jar包,即为api和plaf,如图所示。
这样jPBC就算配置完成了。
Boneh-Boyen-Goh HIBE:一个简单的实例
Util.java
import it.unisa.dia.gas.jpbc.Element;
import it.unisa.dia.gas.jpbc.Pairing;
public class Util {
public static Element hash_id(Pairing pairing, String id){
byte[] byte_identity = id.getBytes();
Element hash = pairing.getZr().newElement().setFromHash(byte_identity, 0, byte_identity.length);
return hash;
}
}
BBGHIBEMasterKey.java
import it.unisa.dia.gas.jpbc.Element;
public class BBGHIBEMasterKey {
public Element alpha;
}
BBGHIBESecretKey.java
import it.unisa.dia.gas.jpbc.Element;
public class BBGHIBESecretKey {
public String[] identityVector;
public Element K_1;
public Element K_2;
public Element[] E;
}
BBGHIBECiphertext.java
import it.unisa.dia.gas.jpbc.Element;
public class BBGHIBECiphertext {
Element C_0;
Element C_1;
Element C_2;
}
BBGHIBE.java
import it.unisa.dia.gas.jpbc.Element;
import it.unisa.dia.gas.jpbc.Pairing;
import it.unisa.dia.gas.plaf.jpbc.pairing.PairingFactory;
public class BBGHIBE {
public static final boolean isDebug = true;
private Pairing pairing;
private int MAX_DEPTH;
//Public parameters
private Element g;
private Element h;
private Element[] u;
private Element E_g_g;
/**
* System setup algorithms, takes the max depth of hierarchy as input, and outputs the master secret key
* @param perperties The file name of the elliptic curve parameters
* @param D Maximal depth of hierarchy
* @return Master Secret Key
*/
public BBGHIBEMasterKey Setup(String perperties, int D){
// Generate curve parameters
pairing = PairingFactory.getPairing(perperties);
this.MAX_DEPTH = D;
//generate alpha
Element alpha = pairing.getZr().newRandomElement().getImmutable();
// Generate public parameters
this.g = pairing.getG1().newRandomElement().getImmutable();
this.h = pairing.getG1().newRandomElement().getImmutable();
this.u = new Element[this.MAX_DEPTH];
for (int i=0; i<this.u.length; i++){
this.u[i] = pairing.getG1().newRandomElement().getImmutable();
}
this.E_g_g = pairing.pairing(this.g, this.g).powZn(alpha).getImmutable();
//generate master secret key
BBGHIBEMasterKey masterKey = new BBGHIBEMasterKey();
masterKey.alpha = alpha.duplicate().getImmutable();
return masterKey;
}
/**
* Key Generation algorithm to generate secret key associated with the given identity vector
* @param msk master secret key
* @param identityVector the given identity vector
* @return secret key associated with the given identity vector
*/
public BBGHIBESecretKey KeyGen(BBGHIBEMasterKey msk, String[] identityVector){
//Determine the validity of Identity Vector
assert(identityVector.length <= this.MAX_DEPTH);
//generate the secret key
Element r = pairing.getZr().newRandomElement().getImmutable();
BBGHIBESecretKey secretKey = new BBGHIBESecretKey();
secretKey.identityVector = new String[identityVector.length];
System.arraycopy(identityVector, 0, secretKey.identityVector, 0, identityVector.length);
//compute K_1
secretKey.K_1 = this.g.powZn(r).getImmutable();
//compute K_2
secretKey.K_2 = this.h.duplicate();
for (int i=0; i<identityVector.length; i++){
secretKey.K_2 = secretKey.K_2.mul(this.u[i].powZn(Util.hash_id(pairing, identityVector[i])));
}
secretKey.K_2 = secretKey.K_2.powZn(r);
secretKey.K_2 = secretKey.K_2.mul(this.g.powZn(msk.alpha)).getImmutable();
//compute E
secretKey.E = new Element[this.MAX_DEPTH];
for (int i=identityVector.length; i<this.MAX_DEPTH; i++){
secretKey.E[i] = this.u[i].powZn(r).getImmutable();
}
return secretKey;
}
/**
* Delegation algorithm to delegate a secret key for the user's subordinate
* @param secretkey the secret key for the supervisor
* @param identity the identity for the user's subordinate
* @return secret key for the user's subordinate
*/
public BBGHIBESecretKey Delegate(BBGHIBESecretKey secretkey, String identity){
//Determine the validity of Identity Vector
assert(secretkey.identityVector.length < this.MAX_DEPTH);
//delegate the secret key
BBGHIBESecretKey delegateKey = new BBGHIBESecretKey();
String[] delegateIV = new String[secretkey.identityVector.length + 1];
System.arraycopy(secretkey.identityVector, 0, delegateIV, 0, secretkey.identityVector.length);
delegateIV[secretkey.identityVector.length] = identity;
delegateKey.identityVector = delegateIV;
Element r = pairing.getZr().newRandomElement().getImmutable();
//compute K_1
delegateKey.K_1 = secretkey.K_1.duplicate();
delegateKey.K_1 = delegateKey.K_1.mul(this.g.powZn(r)).getImmutable();
//compute K_2
delegateKey.K_2 = this.h.duplicate();
for (int i=0; i<delegateIV.length; i++){
delegateKey.K_2 = delegateKey.K_2.mul(this.u[i].powZn(Util.hash_id(pairing, delegateIV[i])));
}
delegateKey.K_2 = delegateKey.K_2.powZn(r);
delegateKey.K_2 = delegateKey.K_2.mul(secretkey.K_2);
delegateKey.K_2 = delegateKey.K_2.mul(secretkey.E[secretkey.identityVector.length].powZn(Util.hash_id(pairing, identity))).getImmutable();
//compute b
delegateKey.E = new Element[this.MAX_DEPTH];
for (int i=secretkey.identityVector.length; i<this.MAX_DEPTH; i++){
delegateKey.E[i] = this.u[i].powZn(r).mul(secretkey.E[i]).getImmutable();
}
return delegateKey;
}
/**
* Encrypt algorithm to an identity vector
* @param identityVector the target identity vector
* @return the ciphertext
*/
public BBGHIBECiphertext Encrypt(String[] identityVector){
//Determine the validity of Identity Vector
assert(identityVector.length <= this.MAX_DEPTH);
//Generate a random message
Element message = pairing.getGT().newRandomElement();
if (isDebug){
System.out.println("Infor - encrypt: the generated random message is " + message);
}
//Encrypt that message
Element s = pairing.getZr().newRandomElement().getImmutable();
BBGHIBECiphertext ciphertext = new BBGHIBECiphertext();
//compute C_0
ciphertext.C_0 = this.E_g_g.powZn(s).mul(message).getImmutable();
//compute C_2
ciphertext.C_2 = this.g.powZn(s).getImmutable();
//compute c_1
ciphertext.C_1 = this.h.duplicate();
for (int i=0; i<identityVector.length; i++){
ciphertext.C_1 = ciphertext.C_1.mul(this.u[i].powZn(Util.hash_id(pairing, identityVector[i])));
}
ciphertext.C_1 = ciphertext.C_1.powZn(s).getImmutable();
return ciphertext;
}
/**
* Decrypt the ciphertext using a secret key
* @param identityVector the receive identity vector
* @param ciphertext the ciphertext
* @param secretKey the secret key for the receiver or for the receiver's supervisor
* @return the message
*/
public Element decrypt(String[] identityVector, BBGHIBECiphertext ciphertext, BBGHIBESecretKey secretKey){
//Determine the validity of Identity Vector, the ciphertext and the secret key
//Secret Key Identity Vector depth needs to be smaller than ciphertext Identity Vector depth
assert(identityVector.length >= secretKey.identityVector.length);
//the identity vector for the secret key should match the receiver's identity vector
for (int i=0; i<secretKey.identityVector.length; i++){
assert(secretKey.identityVector[i].equals(identityVector[i]));
}
Element K = secretKey.K_2.duplicate();
for (int i=secretKey.identityVector.length; i<identityVector.length; i++){
K.mul(secretKey.E[i].powZn(Util.hash_id(pairing, identityVector[i])));
}
Element message = pairing.pairing(secretKey.K_1, ciphertext.C_1);
message = message.div(pairing.pairing(K, ciphertext.C_2));
message = message.mul(ciphertext.C_0);
System.out.println("Infor - decrypt: the message is " + message);
return message;
}
}
TestBBGHIBE.java
public class TestBBGHIBE {
private static void testBBEHIBE() {
BBGHIBE bbgHIBE = new BBGHIBE();
BBGHIBEMasterKey msk = bbgHIBE.Setup("a.properties", 7);
String[] testI1 = {"Depth 1"};
String testI2 = "Depth 2";
String testI3 = "Depth 3";
String testI4 = "Depth 4";
String testI5 = "Depth 5";
String testI6 = "Depth 6";
String testI7 = "Depth 7";
String[] receiver = new String[7];
receiver[0] = testI1[0];
receiver[1] = testI2;
receiver[2] = testI3;
receiver[3] = testI4;
receiver[4] = testI5;
receiver[5] = testI6;
receiver[6] = testI7;
String[] ciphertextIV = new String[7];
System.arraycopy(receiver, 0, ciphertextIV, 0, 7);
//KeyGen for depth 1
if (BBGHIBE.isDebug){
System.out.println("Generate secret key for user at depth 1");
}
BBGHIBESecretKey SKDepth1 = bbgHIBE.KeyGen(msk, testI1);
//Delegation for depth 2
if (BBGHIBE.isDebug){
System.out.println("Generate secret key for user at depth 2");
}
BBGHIBESecretKey SKDepth2 = bbgHIBE.Delegate(SKDepth1, testI2);
//Delegation for depth 3
if (BBGHIBE.isDebug){
System.out.println("Generate secret key for user at depth 3");
}
BBGHIBESecretKey SKDepth3 = bbgHIBE.Delegate(SKDepth2, testI3);
//Delegation for depth 4
if (BBGHIBE.isDebug){
System.out.println("Generate secret key for user at depth 4");
}
BBGHIBESecretKey SKDepth4 = bbgHIBE.Delegate(SKDepth3, testI4);
//Delegation for depth 5
if (BBGHIBE.isDebug){
System.out.println("Generate secret key for user at depth 5");
}
BBGHIBESecretKey SKDepth5 = bbgHIBE.Delegate(SKDepth4, testI5);
//Delegation for depth 6
if (BBGHIBE.isDebug){
System.out.println("Generate secret key for user at depth 6");
}
BBGHIBESecretKey SKDepth6 = bbgHIBE.Delegate(SKDepth5, testI6);
//Delegation for depth 7
if (BBGHIBE.isDebug){
System.out.println("Generate secret key for user at depth 7");
}
BBGHIBESecretKey SKDepth7 = bbgHIBE.Delegate(SKDepth6, testI7);
//encryption
if (BBGHIBE.isDebug){
System.out.println("Encryption");
}
BBGHIBECiphertext ciphertext = bbgHIBE.Encrypt(ciphertextIV);
//Decryption for depth 1
if (BBGHIBE.isDebug){
System.out.println("Dncryption for user at depth 1");
}
bbgHIBE.decrypt(ciphertextIV, ciphertext, SKDepth1);
//Decryption for depth 2
if (BBGHIBE.isDebug){
System.out.println("Dncryption for user at depth 2");
}
bbgHIBE.decrypt(ciphertextIV, ciphertext, SKDepth2);
//Decryption for depth 3
if (BBGHIBE.isDebug){
System.out.println("Dncryption for user at depth 3");
}
bbgHIBE.decrypt(ciphertextIV, ciphertext, SKDepth3);
//Decryption for depth 4
if (BBGHIBE.isDebug){
System.out.println("Dncryption for user at depth 4");
}
bbgHIBE.decrypt(ciphertextIV, ciphertext, SKDepth4);
//Decryption for depth 5
if (BBGHIBE.isDebug){
System.out.println("Dncryption for user at depth 5");
}
bbgHIBE.decrypt(ciphertextIV, ciphertext, SKDepth5);
//Decryption for depth 6
if (BBGHIBE.isDebug){
System.out.println("Dncryption for user at depth 6");
}
bbgHIBE.decrypt(ciphertextIV, ciphertext, SKDepth6);
//Decryption for depth 7
if (BBGHIBE.isDebug){
System.out.println("Dncryption for user at depth 7");
}
bbgHIBE.decrypt(ciphertextIV, ciphertext, SKDepth7);
}
public static void main(String[] args){
testBBEHIBE();
}
}
运行结果如图所示。
总结与未来
补充
在这个博客发表后,有几个朋友问我:完全按照上述配置,运行后会Throw Exception,如图。这个是我的问题,因为中间有一个步骤我给忽略掉了… 在源代码中有这样一行代码:
pairing = PairingFactory.getPairing(perperties);
这行代码的意思是,读取perperoties(这里我给拼错了…)中的参数,初始化Pairing。而Properties传进来的是一个路径。所以,我们需要把参数放置在这个路径里面。在我的调用过程中,其路径代码为:
BBGHIBEMasterKey msk = bbgHIBE.Setup("a.properties", 7);
这是一个相对路径。因此,我们需要把a.properties放置在工程的根目录下面。比如,如果工程路径为D:workspacesjPBC,那么a.properties就放在这个目录下面。那么,a.properties从哪里能够拿到呢?实际上,jPBC压缩包中,有一个param文件夹,里面放置的就是典型的参数,直接用里面的a.properties即可。
最后
以上就是精明墨镜为你收集整理的jPBC 2.0.0配置与测试(补充版)题注背景jPBC 2.0.0在任意平台下的配置Boneh-Boyen-Goh HIBE:一个简单的实例总结与未来 补充的全部内容,希望文章能够帮你解决jPBC 2.0.0配置与测试(补充版)题注背景jPBC 2.0.0在任意平台下的配置Boneh-Boyen-Goh HIBE:一个简单的实例总结与未来 补充所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复